diff --git a/Directory.Build.props b/Directory.Build.props index 0b999b18d37dbe..1b441f7f653871 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -69,6 +69,7 @@ $(RepoRoot)LICENSE.TXT + true diff --git a/docs/area-owners.md b/docs/area-owners.md index 9eb3216fec37a0..1cdef1b4cb9829 100644 --- a/docs/area-owners.md +++ b/docs/area-owners.md @@ -14,7 +14,7 @@ Below table shows the combined area owners on this repository: | area-HostModel | @vitek-karas @swaroop-sridhar | | | area-ILTools-coreclr | @BruceForstall @dotnet/jit-contrib | | | area-Infrastructure-coreclr | @jeffschwMSFT @jashook @trylek | | -| area-Infrastructure-installer | @dleeapho @dagood | | +| area-Infrastructure-installer | @dleeapho @NikolaMilosavljevic | | | area-Infrastructure-libraries | @ViktorHofer @ericstj @safern @Anipik | Covers:
| | area-Infrastructure | @ViktorHofer @jeffschwMSFT @dleeapho | | | area-Interop-coreclr | @jeffschwMSFT @AaronRobinsonMSFT | | @@ -22,7 +22,7 @@ Below table shows the combined area owners on this repository: | area-PAL-coreclr | @janvorli | | | area-R2RDump-coreclr | @nattress | | | area-ReadyToRun-coreclr | @nattress | | -| area-Setup | @dagood @dleeapho | Distro-specific (Linux, Mac and Windows) setup packages and msi files | +| area-Setup | @NikolaMilosavljevic @dleeapho | Distro-specific (Linux, Mac and Windows) setup packages and msi files | | area-Single-File | @swaroop-sridhar | | | area-SDK | @janvorli | General development issues and overlap with the SDK and CLI | | area-Serialization | @StephenMolloy @HongGit | Packages: Excluded: | diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/CMakeLists.txt b/docs/design/coreclr/profiling/sample-profilers/stacksampling/CMakeLists.txt deleted file mode 100644 index 710fcfd12a2d53..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required (VERSION 3.14) - -project(CorProfiler) - -if(NOT WIN32) - set(BASE_SOURCES ) - add_compile_options(-Wno-invalid-noreturn -Wno-pragma-pack -Wno-int-to-pointer-cast -fPIC -fms-extensions -DBIT64 -DPAL_STDCPP_COMPAT -DPLATFORM_UNIX -DHOST_64BIT -std=c++11) - add_link_options(--no-undefined -pthread) - - include_directories($ENV{CORECLR_PATH}/src/pal/inc/rt $ENV{CORECLR_PATH}/src/pal/inc $ENV{CORECLR_PATH}/src/inc) -endif(NOT WIN32) - -if (WIN32) - set(BASE_SOURCES src/CorProfiler.def) -endif(WIN32) - -include_directories($CORECLR_BIN/inc $ENV{CORECLR_PATH}/src/pal/prebuilt/inc) - -set(SOURCES ${BASE_SOURCES} src/ClassFactory.cpp src/CorProfiler.cpp src/dllmain.cpp src/sampler.cpp $ENV{CORECLR_PATH}/src/pal/prebuilt/idl/corprof_i.cpp) - -add_library(CorProfiler SHARED ${SOURCES}) \ No newline at end of file diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/build.cmd b/docs/design/coreclr/profiling/sample-profilers/stacksampling/build.cmd deleted file mode 100644 index 331dcf5e05b527..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/build.cmd +++ /dev/null @@ -1,66 +0,0 @@ -@echo off -setlocal - -if not defined BuildOS ( - set BuildOS=Windows -) - -if not defined BuildArch ( - set BuildArch=x64 -) - -if not defined BuildType ( - set BuildType=Debug -) - -if not defined CORECLR_PATH ( - set CORECLR_PATH=C:/git/runtime/src/coreclr -) - -if not defined CORECLR_BIN ( - set CORECLR_BIN=C:/git/runtime/artifacts/bin/coreclr/%BuildOS%.%BuildArch%.%BuildType% -) - -set VS_COM_CMD_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" - -if not defined VS_CMD_PATH ( - if exist %VS_COM_CMD_PATH% ( - set VS_CMD_PATH=%VS_COM_CMD_PATH% - ) else ( - echo No VS developer command prompt detected! - goto :EOF - ) -) - -echo CORECLR_PATH : %CORECLR_PATH% -echo BuildOS : %BuildOS% -echo BuildArch : %BuildArch% -echo BuildType : %BuildType% -echo VS PATH : %VS_CMD_PATH% - -echo. -echo Building - -if not exist bin\ ( - mkdir bin -) - -pushd bin - -cmake -G "Visual Studio 16 2019" ..\ -DCMAKE_BUILD_TYPE=Debug - -echo Calling VS Developer Command Prompt to build -call %VS_CMD_PATH% - -msbuild -v:m CorProfiler.sln - -popd - -echo. -echo. -echo. -echo Done building - -echo Copying binary to main directory -copy /y bin\Debug\CorProfiler.dll . - diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/build.sh b/docs/design/coreclr/profiling/sample-profilers/stacksampling/build.sh deleted file mode 100644 index 78bb71c799fa5d..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/build.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -[ -z "${BuildOS:-}" ] && export BuildOS=Linux -[ -z "${BuildArch:-}" ] && export BuildArch=x64 -[ -z "${BuildType:-}" ] && export BuildType=Debug - -[ -z "${CORECLR_PATH:-}" ] && export CORECLR_PATH=~/git/runtime/src/coreclr -[ -z "${CORECLR_BIN:-}" ] && export CORECLR_BIN=~/git/runtime/artifacts/bin/coreclr/$BuildOS.$BuildArch.$BuildType - -printf ' CORECLR_PATH : %s\n' "$CORECLR_PATH" -printf ' BuildOS : %s\n' "$BuildOS" -printf ' BuildArch : %s\n' "$BuildArch" -printf ' BuildType : %s\n' "$BuildType" - -printf ' Building ...' - -if [ ! -d "bin/" ]; then - mkdir bin/ -fi - -pushd bin - -export CC=/usr/bin/clang -export CXX=/usr/bin/clang++ -cmake ../ -DCMAKE_BUILD_TYPE=Debug - -make -j8 - -popd - -printf ' Copying libCorProfiler.so to main directory\n' -cp bin/libCorProfiler.so . - -printf 'Done.\n' diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/ClassFactory.cpp b/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/ClassFactory.cpp deleted file mode 100644 index 87db0a75b8b4c1..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/ClassFactory.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#include "ClassFactory.h" -#include "CorProfiler.h" - -ClassFactory::ClassFactory() : refCount(0) -{ -} - -ClassFactory::~ClassFactory() -{ -} - -HRESULT STDMETHODCALLTYPE ClassFactory::QueryInterface(REFIID riid, void **ppvObject) -{ - if (riid == IID_IUnknown || riid == IID_IClassFactory) - { - *ppvObject = this; - this->AddRef(); - return S_OK; - } - - *ppvObject = nullptr; - return E_NOINTERFACE; -} - -ULONG STDMETHODCALLTYPE ClassFactory::AddRef() -{ - return std::atomic_fetch_add(&this->refCount, 1) + 1; -} - -ULONG STDMETHODCALLTYPE ClassFactory::Release() -{ - int count = std::atomic_fetch_sub(&this->refCount, 1) - 1; - if (count <= 0) - { - delete this; - } - - return count; -} - -HRESULT STDMETHODCALLTYPE ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) -{ - if (pUnkOuter != nullptr) - { - *ppvObject = nullptr; - return CLASS_E_NOAGGREGATION; - } - - CorProfiler* profiler = new CorProfiler(); - if (profiler == nullptr) - { - return E_FAIL; - } - - return profiler->QueryInterface(riid, ppvObject); -} - -HRESULT STDMETHODCALLTYPE ClassFactory::LockServer(BOOL fLock) -{ - return S_OK; -} \ No newline at end of file diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/ClassFactory.h b/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/ClassFactory.h deleted file mode 100644 index 10368a604b49d6..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/ClassFactory.h +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#pragma once - -#include "unknwn.h" -#include - -class ClassFactory : public IClassFactory -{ -private: - std::atomic refCount; -public: - ClassFactory(); - virtual ~ClassFactory(); - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override; - ULONG STDMETHODCALLTYPE AddRef(void) override; - ULONG STDMETHODCALLTYPE Release(void) override; - HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) override; - HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) override; -}; \ No newline at end of file diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/CorProfiler.cpp b/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/CorProfiler.cpp deleted file mode 100644 index 8d29e1c22444f1..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/CorProfiler.cpp +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#include "CorProfiler.h" -#include "corhlpr.h" -#include "profiler_pal.h" -#include "sampler.h" -#include -#include - -using std::shared_ptr; - -CorProfiler::CorProfiler() : - refCount(0), - corProfilerInfo(nullptr), - sampler(), - jitEventCount(0) -{ - -} - -CorProfiler::~CorProfiler() -{ - if (this->corProfilerInfo != nullptr) - { - this->corProfilerInfo->Release(); - this->corProfilerInfo = nullptr; - } -} - -HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown *pICorProfilerInfoUnk) -{ - printf("Initialize profiler!\n"); - - HRESULT hr = pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo10, (void**)&corProfilerInfo); - if (hr != S_OK) - { - printf("Got HR %X from QI for ICorProfilerInfo4", hr); - return E_FAIL; - } - - corProfilerInfo->SetEventMask2(COR_PRF_ENABLE_STACK_SNAPSHOT | COR_PRF_MONITOR_JIT_COMPILATION, 0); - - sampler = shared_ptr(new Sampler(corProfilerInfo, this)); - sampler->Start(); - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::Shutdown() -{ - if (this->corProfilerInfo != nullptr) - { - this->corProfilerInfo->Release(); - this->corProfilerInfo = nullptr; - } - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::AppDomainCreationStarted(AppDomainID appDomainId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::AppDomainCreationFinished(AppDomainID appDomainId, HRESULT hrStatus) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::AppDomainShutdownStarted(AppDomainID appDomainId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::AppDomainShutdownFinished(AppDomainID appDomainId, HRESULT hrStatus) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::AssemblyLoadStarted(AssemblyID assemblyId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::AssemblyLoadFinished(AssemblyID assemblyId, HRESULT hrStatus) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::AssemblyUnloadStarted(AssemblyID assemblyId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::AssemblyUnloadFinished(AssemblyID assemblyId, HRESULT hrStatus) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ModuleLoadStarted(ModuleID moduleId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ModuleLoadFinished(ModuleID moduleId, HRESULT hrStatus) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ModuleUnloadStarted(ModuleID moduleId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ModuleUnloadFinished(ModuleID moduleId, HRESULT hrStatus) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ModuleAttachedToAssembly(ModuleID moduleId, AssemblyID AssemblyId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ClassLoadStarted(ClassID classId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ClassLoadFinished(ClassID classId, HRESULT hrStatus) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ClassUnloadStarted(ClassID classId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ClassUnloadFinished(ClassID classId, HRESULT hrStatus) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::FunctionUnloadStarted(FunctionID functionId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::JITCompilationFinished(FunctionID functionId, HRESULT hrStatus, BOOL fIsSafeToBlock) -{ - ++jitEventCount; - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::JITCachedFunctionSearchStarted(FunctionID functionId, BOOL *pbUseCachedFunction) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::JITCachedFunctionSearchFinished(FunctionID functionId, COR_PRF_JIT_CACHE result) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::JITFunctionPitched(FunctionID functionId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::JITInlining(FunctionID callerId, FunctionID calleeId, BOOL *pfShouldInline) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ThreadCreated(ThreadID threadId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ThreadDestroyed(ThreadID threadId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ThreadAssignedToOSThread(ThreadID managedThreadId, DWORD osThreadId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RemotingClientInvocationStarted() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RemotingClientSendingMessage(GUID *pCookie, BOOL fIsAsync) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RemotingClientReceivingReply(GUID *pCookie, BOOL fIsAsync) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RemotingClientInvocationFinished() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RemotingServerReceivingMessage(GUID *pCookie, BOOL fIsAsync) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RemotingServerInvocationStarted() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RemotingServerInvocationReturned() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RemotingServerSendingReply(GUID *pCookie, BOOL fIsAsync) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::UnmanagedToManagedTransition(FunctionID functionId, COR_PRF_TRANSITION_REASON reason) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ManagedToUnmanagedTransition(FunctionID functionId, COR_PRF_TRANSITION_REASON reason) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RuntimeSuspendStarted(COR_PRF_SUSPEND_REASON suspendReason) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RuntimeSuspendFinished() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RuntimeSuspendAborted() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RuntimeResumeStarted() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RuntimeResumeFinished() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RuntimeThreadSuspended(ThreadID threadId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RuntimeThreadResumed(ThreadID threadId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::MovedReferences(ULONG cMovedObjectIDRanges, ObjectID oldObjectIDRangeStart[], ObjectID newObjectIDRangeStart[], ULONG cObjectIDRangeLength[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ObjectAllocated(ObjectID objectId, ClassID classId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ObjectsAllocatedByClass(ULONG cClassCount, ClassID classIds[], ULONG cObjects[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ObjectReferences(ObjectID objectId, ClassID classId, ULONG cObjectRefs, ObjectID objectRefIds[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RootReferences(ULONG cRootRefs, ObjectID rootRefIds[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionThrown(ObjectID thrownObjectId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionSearchFunctionEnter(FunctionID functionId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionSearchFunctionLeave() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionSearchFilterEnter(FunctionID functionId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionSearchFilterLeave() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionSearchCatcherFound(FunctionID functionId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionOSHandlerEnter(UINT_PTR __unused) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionOSHandlerLeave(UINT_PTR __unused) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionUnwindFunctionEnter(FunctionID functionId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionUnwindFunctionLeave() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionUnwindFinallyEnter(FunctionID functionId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionUnwindFinallyLeave() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionCatcherEnter(FunctionID functionId, ObjectID objectId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionCatcherLeave() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::COMClassicVTableCreated(ClassID wrappedClassId, REFGUID implementedIID, void *pVTable, ULONG cSlots) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::COMClassicVTableDestroyed(ClassID wrappedClassId, REFGUID implementedIID, void *pVTable) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionCLRCatcherFound() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionCLRCatcherExecute() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ThreadNameChanged(ThreadID threadId, ULONG cchName, WCHAR name[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::SurvivingReferences(ULONG cSurvivingObjectIDRanges, ObjectID objectIDRangeStart[], ULONG cObjectIDRangeLength[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::GarbageCollectionFinished() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::FinalizeableObjectQueued(DWORD finalizerFlags, ObjectID objectID) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::RootReferences2(ULONG cRootRefs, ObjectID rootRefIds[], COR_PRF_GC_ROOT_KIND rootKinds[], COR_PRF_GC_ROOT_FLAGS rootFlags[], UINT_PTR rootIds[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::HandleCreated(GCHandleID handleId, ObjectID initialObjectId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::HandleDestroyed(GCHandleID handleId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::InitializeForAttach(IUnknown *pCorProfilerInfoUnk, void *pvClientData, UINT cbClientData) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ProfilerAttachComplete() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ProfilerDetachSucceeded() -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ReJITCompilationStarted(FunctionID functionId, ReJITID rejitId, BOOL fIsSafeToBlock) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::GetReJITParameters(ModuleID moduleId, mdMethodDef methodId, ICorProfilerFunctionControl *pFunctionControl) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ReJITCompilationFinished(FunctionID functionId, ReJITID rejitId, HRESULT hrStatus, BOOL fIsSafeToBlock) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ReJITError(ModuleID moduleId, mdMethodDef methodId, FunctionID functionId, HRESULT hrStatus) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::MovedReferences2(ULONG cMovedObjectIDRanges, ObjectID oldObjectIDRangeStart[], ObjectID newObjectIDRangeStart[], SIZE_T cObjectIDRangeLength[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::SurvivingReferences2(ULONG cSurvivingObjectIDRanges, ObjectID objectIDRangeStart[], SIZE_T cObjectIDRangeLength[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ConditionalWeakTableElementReferences(ULONG cRootRefs, ObjectID keyRefIds[], ObjectID valueRefIds[], GCHandleID rootIds[]) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::GetAssemblyReferences(const WCHAR *wszAssemblyPath, ICorProfilerAssemblyReferenceProvider *pAsmRefProvider) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::ModuleInMemorySymbolsUpdated(ModuleID moduleId) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::DynamicMethodJITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock, LPCBYTE ilHeader, ULONG cbILHeader) -{ - return S_OK; -} - -HRESULT STDMETHODCALLTYPE CorProfiler::DynamicMethodJITCompilationFinished(FunctionID functionId, HRESULT hrStatus, BOOL fIsSafeToBlock) -{ - return S_OK; -} - -bool CorProfiler::IsRuntimeExecutingManagedCode() -{ - return jitEventCount.load() > 0; -} diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/CorProfiler.def b/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/CorProfiler.def deleted file mode 100644 index ddb536cb3066f3..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/CorProfiler.def +++ /dev/null @@ -1,4 +0,0 @@ -LIBRARY CorProfiler -EXPORTS - DllGetClassObject private - diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/CorProfiler.h b/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/CorProfiler.h deleted file mode 100644 index 1d41f6bfd7a2d9..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/CorProfiler.h +++ /dev/null @@ -1,211 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include "cor.h" -#include "corprof.h" -#include "sampler.h" - -#define SHORT_LENGTH 32 -#define STRING_LENGTH 256 -#define LONG_LENGTH 1024 - -template -class COMPtrHolder -{ -public: - COMPtrHolder() - { - m_ptr = NULL; - } - - COMPtrHolder(MetaInterface* ptr) - { - if (ptr != NULL) - { - ptr->AddRef(); - } - m_ptr = ptr; - } - - ~COMPtrHolder() - { - if (m_ptr != NULL) - { - m_ptr->Release(); - m_ptr = NULL; - } - } - MetaInterface* operator->() - { - return m_ptr; - } - - MetaInterface** operator&() - { - // _ASSERT(m_ptr == NULL); - return &m_ptr; - } - - operator MetaInterface*() - { - return m_ptr; - } -private: - MetaInterface* m_ptr; -}; - -class CorProfiler : public ICorProfilerCallback8 -{ -private: - std::atomic refCount; - std::shared_ptr sampler; - - std::atomic jitEventCount; - -public: - ICorProfilerInfo10* corProfilerInfo; - - CorProfiler(); - virtual ~CorProfiler(); - HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk) override; - HRESULT STDMETHODCALLTYPE Shutdown() override; - HRESULT STDMETHODCALLTYPE AppDomainCreationStarted(AppDomainID appDomainId) override; - HRESULT STDMETHODCALLTYPE AppDomainCreationFinished(AppDomainID appDomainId, HRESULT hrStatus) override; - HRESULT STDMETHODCALLTYPE AppDomainShutdownStarted(AppDomainID appDomainId) override; - HRESULT STDMETHODCALLTYPE AppDomainShutdownFinished(AppDomainID appDomainId, HRESULT hrStatus) override; - HRESULT STDMETHODCALLTYPE AssemblyLoadStarted(AssemblyID assemblyId) override; - HRESULT STDMETHODCALLTYPE AssemblyLoadFinished(AssemblyID assemblyId, HRESULT hrStatus) override; - HRESULT STDMETHODCALLTYPE AssemblyUnloadStarted(AssemblyID assemblyId) override; - HRESULT STDMETHODCALLTYPE AssemblyUnloadFinished(AssemblyID assemblyId, HRESULT hrStatus) override; - HRESULT STDMETHODCALLTYPE ModuleLoadStarted(ModuleID moduleId) override; - HRESULT STDMETHODCALLTYPE ModuleLoadFinished(ModuleID moduleId, HRESULT hrStatus) override; - HRESULT STDMETHODCALLTYPE ModuleUnloadStarted(ModuleID moduleId) override; - HRESULT STDMETHODCALLTYPE ModuleUnloadFinished(ModuleID moduleId, HRESULT hrStatus) override; - HRESULT STDMETHODCALLTYPE ModuleAttachedToAssembly(ModuleID moduleId, AssemblyID AssemblyId) override; - HRESULT STDMETHODCALLTYPE ClassLoadStarted(ClassID classId) override; - HRESULT STDMETHODCALLTYPE ClassLoadFinished(ClassID classId, HRESULT hrStatus) override; - HRESULT STDMETHODCALLTYPE ClassUnloadStarted(ClassID classId) override; - HRESULT STDMETHODCALLTYPE ClassUnloadFinished(ClassID classId, HRESULT hrStatus) override; - HRESULT STDMETHODCALLTYPE FunctionUnloadStarted(FunctionID functionId) override; - HRESULT STDMETHODCALLTYPE JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock) override; - HRESULT STDMETHODCALLTYPE JITCompilationFinished(FunctionID functionId, HRESULT hrStatus, BOOL fIsSafeToBlock) override; - HRESULT STDMETHODCALLTYPE JITCachedFunctionSearchStarted(FunctionID functionId, BOOL* pbUseCachedFunction) override; - HRESULT STDMETHODCALLTYPE JITCachedFunctionSearchFinished(FunctionID functionId, COR_PRF_JIT_CACHE result) override; - HRESULT STDMETHODCALLTYPE JITFunctionPitched(FunctionID functionId) override; - HRESULT STDMETHODCALLTYPE JITInlining(FunctionID callerId, FunctionID calleeId, BOOL* pfShouldInline) override; - HRESULT STDMETHODCALLTYPE ThreadCreated(ThreadID threadId) override; - HRESULT STDMETHODCALLTYPE ThreadDestroyed(ThreadID threadId) override; - HRESULT STDMETHODCALLTYPE ThreadAssignedToOSThread(ThreadID managedThreadId, DWORD osThreadId) override; - HRESULT STDMETHODCALLTYPE RemotingClientInvocationStarted() override; - HRESULT STDMETHODCALLTYPE RemotingClientSendingMessage(GUID* pCookie, BOOL fIsAsync) override; - HRESULT STDMETHODCALLTYPE RemotingClientReceivingReply(GUID* pCookie, BOOL fIsAsync) override; - HRESULT STDMETHODCALLTYPE RemotingClientInvocationFinished() override; - HRESULT STDMETHODCALLTYPE RemotingServerReceivingMessage(GUID* pCookie, BOOL fIsAsync) override; - HRESULT STDMETHODCALLTYPE RemotingServerInvocationStarted() override; - HRESULT STDMETHODCALLTYPE RemotingServerInvocationReturned() override; - HRESULT STDMETHODCALLTYPE RemotingServerSendingReply(GUID* pCookie, BOOL fIsAsync) override; - HRESULT STDMETHODCALLTYPE UnmanagedToManagedTransition(FunctionID functionId, COR_PRF_TRANSITION_REASON reason) override; - HRESULT STDMETHODCALLTYPE ManagedToUnmanagedTransition(FunctionID functionId, COR_PRF_TRANSITION_REASON reason) override; - HRESULT STDMETHODCALLTYPE RuntimeSuspendStarted(COR_PRF_SUSPEND_REASON suspendReason) override; - HRESULT STDMETHODCALLTYPE RuntimeSuspendFinished() override; - HRESULT STDMETHODCALLTYPE RuntimeSuspendAborted() override; - HRESULT STDMETHODCALLTYPE RuntimeResumeStarted() override; - HRESULT STDMETHODCALLTYPE RuntimeResumeFinished() override; - HRESULT STDMETHODCALLTYPE RuntimeThreadSuspended(ThreadID threadId) override; - HRESULT STDMETHODCALLTYPE RuntimeThreadResumed(ThreadID threadId) override; - HRESULT STDMETHODCALLTYPE MovedReferences(ULONG cMovedObjectIDRanges, ObjectID oldObjectIDRangeStart[], ObjectID newObjectIDRangeStart[], ULONG cObjectIDRangeLength[]) override; - HRESULT STDMETHODCALLTYPE ObjectAllocated(ObjectID objectId, ClassID classId) override; - HRESULT STDMETHODCALLTYPE ObjectsAllocatedByClass(ULONG cClassCount, ClassID classIds[], ULONG cObjects[]) override; - HRESULT STDMETHODCALLTYPE ObjectReferences(ObjectID objectId, ClassID classId, ULONG cObjectRefs, ObjectID objectRefIds[]) override; - HRESULT STDMETHODCALLTYPE RootReferences(ULONG cRootRefs, ObjectID rootRefIds[]) override; - HRESULT STDMETHODCALLTYPE ExceptionThrown(ObjectID thrownObjectId) override; - HRESULT STDMETHODCALLTYPE ExceptionSearchFunctionEnter(FunctionID functionId) override; - HRESULT STDMETHODCALLTYPE ExceptionSearchFunctionLeave() override; - HRESULT STDMETHODCALLTYPE ExceptionSearchFilterEnter(FunctionID functionId) override; - HRESULT STDMETHODCALLTYPE ExceptionSearchFilterLeave() override; - HRESULT STDMETHODCALLTYPE ExceptionSearchCatcherFound(FunctionID functionId) override; - HRESULT STDMETHODCALLTYPE ExceptionOSHandlerEnter(UINT_PTR __unused) override; - HRESULT STDMETHODCALLTYPE ExceptionOSHandlerLeave(UINT_PTR __unused) override; - HRESULT STDMETHODCALLTYPE ExceptionUnwindFunctionEnter(FunctionID functionId) override; - HRESULT STDMETHODCALLTYPE ExceptionUnwindFunctionLeave() override; - HRESULT STDMETHODCALLTYPE ExceptionUnwindFinallyEnter(FunctionID functionId) override; - HRESULT STDMETHODCALLTYPE ExceptionUnwindFinallyLeave() override; - HRESULT STDMETHODCALLTYPE ExceptionCatcherEnter(FunctionID functionId, ObjectID objectId) override; - HRESULT STDMETHODCALLTYPE ExceptionCatcherLeave() override; - HRESULT STDMETHODCALLTYPE COMClassicVTableCreated(ClassID wrappedClassId, REFGUID implementedIID, void* pVTable, ULONG cSlots) override; - HRESULT STDMETHODCALLTYPE COMClassicVTableDestroyed(ClassID wrappedClassId, REFGUID implementedIID, void* pVTable) override; - HRESULT STDMETHODCALLTYPE ExceptionCLRCatcherFound() override; - HRESULT STDMETHODCALLTYPE ExceptionCLRCatcherExecute() override; - HRESULT STDMETHODCALLTYPE ThreadNameChanged(ThreadID threadId, ULONG cchName, WCHAR name[]) override; - HRESULT STDMETHODCALLTYPE GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason) override; - HRESULT STDMETHODCALLTYPE SurvivingReferences(ULONG cSurvivingObjectIDRanges, ObjectID objectIDRangeStart[], ULONG cObjectIDRangeLength[]) override; - HRESULT STDMETHODCALLTYPE GarbageCollectionFinished() override; - HRESULT STDMETHODCALLTYPE FinalizeableObjectQueued(DWORD finalizerFlags, ObjectID objectID) override; - HRESULT STDMETHODCALLTYPE RootReferences2(ULONG cRootRefs, ObjectID rootRefIds[], COR_PRF_GC_ROOT_KIND rootKinds[], COR_PRF_GC_ROOT_FLAGS rootFlags[], UINT_PTR rootIds[]) override; - HRESULT STDMETHODCALLTYPE HandleCreated(GCHandleID handleId, ObjectID initialObjectId) override; - HRESULT STDMETHODCALLTYPE HandleDestroyed(GCHandleID handleId) override; - HRESULT STDMETHODCALLTYPE InitializeForAttach(IUnknown* pCorProfilerInfoUnk, void* pvClientData, UINT cbClientData) override; - HRESULT STDMETHODCALLTYPE ProfilerAttachComplete() override; - HRESULT STDMETHODCALLTYPE ProfilerDetachSucceeded() override; - HRESULT STDMETHODCALLTYPE ReJITCompilationStarted(FunctionID functionId, ReJITID rejitId, BOOL fIsSafeToBlock) override; - HRESULT STDMETHODCALLTYPE GetReJITParameters(ModuleID moduleId, mdMethodDef methodId, ICorProfilerFunctionControl* pFunctionControl) override; - HRESULT STDMETHODCALLTYPE ReJITCompilationFinished(FunctionID functionId, ReJITID rejitId, HRESULT hrStatus, BOOL fIsSafeToBlock) override; - HRESULT STDMETHODCALLTYPE ReJITError(ModuleID moduleId, mdMethodDef methodId, FunctionID functionId, HRESULT hrStatus) override; - HRESULT STDMETHODCALLTYPE MovedReferences2(ULONG cMovedObjectIDRanges, ObjectID oldObjectIDRangeStart[], ObjectID newObjectIDRangeStart[], SIZE_T cObjectIDRangeLength[]) override; - HRESULT STDMETHODCALLTYPE SurvivingReferences2(ULONG cSurvivingObjectIDRanges, ObjectID objectIDRangeStart[], SIZE_T cObjectIDRangeLength[]) override; - HRESULT STDMETHODCALLTYPE ConditionalWeakTableElementReferences(ULONG cRootRefs, ObjectID keyRefIds[], ObjectID valueRefIds[], GCHandleID rootIds[]) override; - HRESULT STDMETHODCALLTYPE GetAssemblyReferences(const WCHAR* wszAssemblyPath, ICorProfilerAssemblyReferenceProvider* pAsmRefProvider) override; - HRESULT STDMETHODCALLTYPE ModuleInMemorySymbolsUpdated(ModuleID moduleId) override; - - HRESULT STDMETHODCALLTYPE DynamicMethodJITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock, LPCBYTE ilHeader, ULONG cbILHeader) override; - HRESULT STDMETHODCALLTYPE DynamicMethodJITCompilationFinished(FunctionID functionId, HRESULT hrStatus, BOOL fIsSafeToBlock) override; - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override - { - if (riid == __uuidof(ICorProfilerCallback8) || - riid == __uuidof(ICorProfilerCallback7) || - riid == __uuidof(ICorProfilerCallback6) || - riid == __uuidof(ICorProfilerCallback5) || - riid == __uuidof(ICorProfilerCallback4) || - riid == __uuidof(ICorProfilerCallback3) || - riid == __uuidof(ICorProfilerCallback2) || - riid == __uuidof(ICorProfilerCallback) || - riid == IID_IUnknown) - { - *ppvObject = this; - this->AddRef(); - return S_OK; - } - - *ppvObject = nullptr; - return E_NOINTERFACE; - } - - ULONG STDMETHODCALLTYPE AddRef(void) override - { - return std::atomic_fetch_add(&this->refCount, 1) + 1; - } - - ULONG STDMETHODCALLTYPE Release(void) override - { - int count = std::atomic_fetch_sub(&this->refCount, 1) - 1; - - if (count <= 0) - { - delete this; - } - - return count; - } - - bool IsRuntimeExecutingManagedCode(); -}; \ No newline at end of file diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/dllmain.cpp b/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/dllmain.cpp deleted file mode 100644 index ce04d31387eaa8..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/dllmain.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#include "ClassFactory.h" - -const IID IID_IUnknown = { 0x00000000, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; - -const IID IID_IClassFactory = { 0x00000001, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; - -BOOL STDMETHODCALLTYPE DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) -{ - return TRUE; -} - -extern "C" HRESULT STDMETHODCALLTYPE DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) -{ - // {cf0d821e-299b-5307-a3d8-b283c03916dd} - const GUID CLSID_CorProfiler = { 0xcf0d821e, 0x299b, 0x5307, { 0xa3, 0xd8, 0xb2, 0x83, 0xc0, 0x39, 0x16, 0xdd } }; - - if (ppv == nullptr || rclsid != CLSID_CorProfiler) - { - return E_FAIL; - } - - auto factory = new ClassFactory; - if (factory == nullptr) - { - return E_FAIL; - } - - return factory->QueryInterface(riid, ppv); -} - -extern "C" HRESULT STDMETHODCALLTYPE DllCanUnloadNow() -{ - return S_OK; -} \ No newline at end of file diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/profiler_pal.h b/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/profiler_pal.h deleted file mode 100644 index fc02e24e887d0f..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/profiler_pal.h +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#pragma once - -#ifndef WIN32 -#include -#include "pal_mstypes.h" -#include "pal.h" -#include "ntimage.h" -#include "corhdr.h" - -#define CoTaskMemAlloc(cb) malloc(cb) -#define CoTaskMemFree(cb) free(cb) - -#define UINT_PTR_FORMAT "lx" - -#define PROFILER_STUB __attribute__((visibility("hidden"))) EXTERN_C void STDMETHODCALLTYPE - -#else -#define PROFILER_STUB EXTERN_C void STDMETHODCALLTYPE -#define UINT_PTR_FORMAT "llx" -#endif diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/sampler.cpp b/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/sampler.cpp deleted file mode 100644 index 69ec930200f7b4..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/sampler.cpp +++ /dev/null @@ -1,380 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#include "CorProfiler.h" -#include "sampler.h" -#include -#include -#include -#include -#include -#include - -using std::wstring_convert; -using std::codecvt_utf8; -using std::string; - -ManualEvent Sampler::s_waitEvent; -Sampler *Sampler::s_instance = nullptr; - -HRESULT __stdcall DoStackSnapshotStackSnapShotCallbackWrapper( - FunctionID funcId, - UINT_PTR ip, - COR_PRF_FRAME_INFO frameInfo, - ULONG32 contextSize, - BYTE context[], - void* clientData) -{ - return Sampler::Instance()->StackSnapshotCallback(funcId, - ip, - frameInfo, - contextSize, - context, - clientData); -} - -Sampler::Sampler(ICorProfilerInfo10* pProfInfo, CorProfiler *parent) : - m_workerThread(DoSampling, pProfInfo, parent) -{ - Sampler::s_instance = this; -} - -// static -void Sampler::DoSampling(ICorProfilerInfo10 *pProfInfo, CorProfiler *parent) -{ - Sampler::Instance()->corProfilerInfo = parent->corProfilerInfo; - - pProfInfo->InitializeCurrentThread(); - - while (true) - { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - s_waitEvent.Wait(); - - if (!parent->IsRuntimeExecutingManagedCode()) - { - printf("Runtime has not started executing managed code yet.\n"); - continue; - } - - printf("Suspending runtime\n"); - HRESULT hr = pProfInfo->SuspendRuntime(); - if (FAILED(hr)) - { - printf("Error suspending runtime... hr=0x%x \n", hr); - continue; - } - - ICorProfilerThreadEnum* threadEnum = nullptr; - hr = pProfInfo->EnumThreads(&threadEnum); - if (FAILED(hr)) - { - printf("Error getting thread enumerator\n"); - continue; - } - - ThreadID threadID; - ULONG numReturned; - while ((hr = threadEnum->Next(1, &threadID, &numReturned)) == S_OK) - { - printf("Starting stack walk for managed thread id=0x%" PRIx64 "\n", (uint64_t)threadID); - - hr = pProfInfo->DoStackSnapshot(threadID, - DoStackSnapshotStackSnapShotCallbackWrapper, - COR_PRF_SNAPSHOT_REGISTER_CONTEXT, - NULL, - NULL, - 0); - if (FAILED(hr)) - { - if (hr == E_FAIL) - { - printf("Managed thread id=0x%" PRIx64 " has no managed frames to walk \n", (uint64_t)threadID); - } - else - { - printf("DoStackSnapshot for thread id=0x%" PRIx64 " failed with hr=0x%x \n", (uint64_t)threadID, hr); - } - } - - printf("Ending stack walk for managed thread id=0x%" PRIx64 "\n", (uint64_t)threadID); - } - - printf("Resuming runtime\n"); - hr = pProfInfo->ResumeRuntime(); - if (FAILED(hr)) - { - printf("ResumeRuntime failed with hr=0x%x \n", hr); - } - } -} - -void Sampler::Start() -{ - s_waitEvent.Signal(); -} - -void Sampler::Stop() -{ - s_waitEvent.Reset(); -} - -HRESULT Sampler::StackSnapshotCallback(FunctionID funcId, UINT_PTR ip, COR_PRF_FRAME_INFO frameInfo, ULONG32 contextSize, BYTE context[], void* clientData) -{ - WSTRING functionName = GetFunctionName(funcId, frameInfo); - -#if WIN32 - wstring_convert, wchar_t> convert; -#else // WIN32 - wstring_convert, char16_t> convert; -#endif // WIN32 - - string printable = convert.to_bytes(functionName); - printf(" %s (funcId=0x%" PRIx64 ")\n", printable.c_str(), (uint64_t)funcId); - return S_OK; -} - -WSTRING Sampler::GetModuleName(ModuleID modId) -{ - WCHAR moduleFullName[STRING_LENGTH]; - ULONG nameLength = 0; - AssemblyID assemID; - - if (modId == NULL) - { - printf("NULL modId passed to GetModuleName\n"); - return WSTR("Unknown"); - } - - HRESULT hr = corProfilerInfo->GetModuleInfo(modId, - NULL, - STRING_LENGTH, - &nameLength, - moduleFullName, - &assemID); - if (FAILED(hr)) - { - printf("GetModuleInfo failed with hr=0x%x\n", hr); - return WSTR("Unknown"); - } - - WCHAR *ptr = NULL; - WCHAR *index = moduleFullName; - // Find the last occurence of the \ character - while (*index != 0) - { - if (*index == '\\' || *index == '/') - { - ptr = index; - } - - ++index; - } - - if (ptr == NULL) - { - return moduleFullName; - } - // Skip the last \ in the string - ++ptr; - - WSTRING moduleName; - while (*ptr != 0) - { - moduleName += *ptr; - ++ptr; - } - - return moduleName; -} - - -WSTRING Sampler::GetClassName(ClassID classId) -{ - ModuleID modId; - mdTypeDef classToken; - ClassID parentClassID; - ULONG32 nTypeArgs; - ClassID typeArgs[SHORT_LENGTH]; - HRESULT hr = S_OK; - - if (classId == NULL) - { - printf("NULL classId passed to GetClassName\n"); - return WSTR("Unknown"); - } - - hr = corProfilerInfo->GetClassIDInfo2(classId, - &modId, - &classToken, - &parentClassID, - SHORT_LENGTH, - &nTypeArgs, - typeArgs); - if (CORPROF_E_CLASSID_IS_ARRAY == hr) - { - // We have a ClassID of an array. - return WSTR("ArrayClass"); - } - else if (CORPROF_E_CLASSID_IS_COMPOSITE == hr) - { - // We have a composite class - return WSTR("CompositeClass"); - } - else if (CORPROF_E_DATAINCOMPLETE == hr) - { - // type-loading is not yet complete. Cannot do anything about it. - return WSTR("DataIncomplete"); - } - else if (FAILED(hr)) - { - printf("GetClassIDInfo returned hr=0x%x for classID=0x%" PRIx64 "\n", hr, (uint64_t)classId); - return WSTR("Unknown"); - } - - COMPtrHolder pMDImport; - hr = corProfilerInfo->GetModuleMetaData(modId, - (ofRead | ofWrite), - IID_IMetaDataImport, - (IUnknown **)&pMDImport ); - if (FAILED(hr)) - { - printf("GetModuleMetaData failed with hr=0x%x\n", hr); - return WSTR("Unknown"); - } - - - WCHAR wName[LONG_LENGTH]; - DWORD dwTypeDefFlags = 0; - hr = pMDImport->GetTypeDefProps(classToken, - wName, - LONG_LENGTH, - NULL, - &dwTypeDefFlags, - NULL); - if (FAILED(hr)) - { - printf("GetTypeDefProps failed with hr=0x%x\n", hr); - return WSTR("Unknown"); - } - - WSTRING name = GetModuleName(modId); - name += WSTR(" "); - name += wName; - - if (nTypeArgs > 0) - { - name += WSTR("<"); - } - - for(ULONG32 i = 0; i < nTypeArgs; i++) - { - name += GetClassName(typeArgs[i]); - - if ((i + 1) != nTypeArgs) - { - name += WSTR(", "); - } - } - - if (nTypeArgs > 0) - { - name += WSTR(">"); - } - - return name; -} - -WSTRING Sampler::GetFunctionName(FunctionID funcID, const COR_PRF_FRAME_INFO frameInfo) -{ - if (funcID == NULL) - { - return WSTR("Unknown_Native_Function"); - } - - ClassID classId = NULL; - ModuleID moduleId = NULL; - mdToken token = NULL; - ULONG32 nTypeArgs = NULL; - ClassID typeArgs[SHORT_LENGTH]; - - HRESULT hr = corProfilerInfo->GetFunctionInfo2(funcID, - frameInfo, - &classId, - &moduleId, - &token, - SHORT_LENGTH, - &nTypeArgs, - typeArgs); - if (FAILED(hr)) - { - printf("GetFunctionInfo2 failed with hr=0x%x\n", hr); - } - - COMPtrHolder pIMDImport; - hr = corProfilerInfo->GetModuleMetaData(moduleId, - ofRead, - IID_IMetaDataImport, - (IUnknown **)&pIMDImport); - if (FAILED(hr)) - { - printf("GetModuleMetaData failed with hr=0x%x\n", hr); - } - - WCHAR funcName[STRING_LENGTH]; - hr = pIMDImport->GetMethodProps(token, - NULL, - funcName, - STRING_LENGTH, - 0, - 0, - NULL, - NULL, - NULL, - NULL); - if (FAILED(hr)) - { - printf("GetMethodProps failed with hr=0x%x\n", hr); - } - - WSTRING name; - - // If the ClassID returned from GetFunctionInfo is 0, then the function is a shared generic function. - if (classId != 0) - { - name += GetClassName(classId); - } - else - { - name += WSTR("SharedGenericFunction"); - } - - name += WSTR("::"); - - name += funcName; - - // Fill in the type parameters of the generic method - if (nTypeArgs > 0) - { - name += WSTR("<"); - } - - for(ULONG32 i = 0; i < nTypeArgs; i++) - { - name += GetClassName(typeArgs[i]); - - if ((i + 1) != nTypeArgs) - { - name += WSTR(", "); - } - } - - if (nTypeArgs > 0) - { - name += WSTR(">"); - } - - return name; -} diff --git a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/sampler.h b/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/sampler.h deleted file mode 100644 index 8cd0fd17dd47e3..00000000000000 --- a/docs/design/coreclr/profiling/sample-profilers/stacksampling/src/sampler.h +++ /dev/null @@ -1,103 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#pragma once - -#include -#include -#include -#include -#include - -#if WIN32 -#define WSTRING std::wstring -#define WSTR(str) L##str -#else // WIN32 -#define WSTRING std::u16string -#define WSTR(str) u##str -#endif // WIN32 - -class CorProfiler; - -class ManualEvent -{ -private: - std::mutex m_mtx; - std::condition_variable m_cv; - bool m_set = false; - - static void DoNothing() - { - - } - -public: - ManualEvent() = default; - ~ManualEvent() = default; - ManualEvent(ManualEvent& other) = delete; - ManualEvent(ManualEvent&& other) = delete; - ManualEvent& operator= (ManualEvent& other) = delete; - ManualEvent& operator= (ManualEvent&& other) = delete; - - void Wait(std::function spuriousCallback = DoNothing) - { - std::unique_lock lock(m_mtx); - while (!m_set) - { - m_cv.wait(lock, [&]() { return m_set; }); - if (!m_set) - { - spuriousCallback(); - } - } - } - - void Signal() - { - std::unique_lock lock(m_mtx); - m_set = true; - } - - void Reset() - { - std::unique_lock lock(m_mtx); - m_set = false; - } -}; - -class Sampler -{ -private: - static Sampler* s_instance; - - std::thread m_workerThread; - static ManualEvent s_waitEvent; - - ICorProfilerInfo10* corProfilerInfo; - - static void DoSampling(ICorProfilerInfo10* pProfInfo, CorProfiler *parent); - - WSTRING GetClassName(ClassID classId); - WSTRING GetModuleName(ModuleID modId); - WSTRING GetFunctionName(FunctionID funcID, const COR_PRF_FRAME_INFO frameInfo); -public: - static Sampler* Instance() - { - return s_instance; - } - - Sampler(ICorProfilerInfo10* pProfInfo, CorProfiler *parent); - ~Sampler() = default; - - void Start(); - void Stop(); - - HRESULT StackSnapshotCallback(FunctionID funcId, - UINT_PTR ip, - COR_PRF_FRAME_INFO frameInfo, - ULONG32 contextSize, - BYTE context[], - void* clientData); -}; - diff --git a/docs/design/features/OnStackReplacement.md b/docs/design/features/OnStackReplacement.md new file mode 100644 index 00000000000000..905696875046ea --- /dev/null +++ b/docs/design/features/OnStackReplacement.md @@ -0,0 +1,1111 @@ +# On Stack Replacement in the CLR + +Design Sketch and Prototype Assessment + +Andy Ayers + +Initial: 7 July 2019 — +Revised: 25 February 2020 + +## Overview + +On Stack Replacement allows the code executed by currently running methods to be +changed in the middle of method execution, while those methods are active "on +stack." This document describes design considerations and challenges involved in +implementing basic On Stack Replacement for the CLR, presents the results of +some prototype investigations, and describes how OSR might be used to re-host +Edit and Continue and support more general transitions like deoptimization. + +* [Background](#1-Background) +* [Design Principles](#2-Design-Principles) +* [An Overview of OSR](#3-An-Overview-of-OSR) +* [Complications](#4-Complications) +* [The Prototype](#5-The-Prototype) +* [Edit and Continue](#6-Edit-and-Continue) +* [Deoptimization](#7-Deoptimization) +* [References](#8-References) + +## 1. Background + +On Stack Replacement (hereafter _OSR_) refers to a set of techniques for +migrating active stack frames from one version of code to another. + +The two versions of the code involved in OSR may arise from different program +sources (as in Edit and Continue) or different approaches to compiling or +executing a single program (say, unoptimized code versus optimized code). The +goal of OSR is to transparently redirect execution from an old version of code +into a new version, even when in the middle of executing the old version. + +Initial work on OSR was pioneered in Self [[1](#1)] as an approach for debugging +optimized code. But in the years since, OSR has mainly seen adoption on +platforms like Java [[2](#2), [3](#3)] and JavaScript that rely heavily on +adaptive recompilation of code. + +The ability to adaptively recompile and switch code versions while methods are +running provides some key advantages: + +* Platforms can offer both quick start up and excellent steady-state + performance, interpreting or quickly jitting to enable initial method + execution, and using OSR to update the methods with better performing or more + completely compiled versions as needed. + +* Platforms can take advantage of transient program facts and recover when those + facts no longer become true. For example, a platform may compile virtual or + interface calls as direct calls initially and use OSR to update to more + general versions of code when overriding methods or other interface + implementations arrive on scene. + +The CLR already supports various mechanisms for changing the code for a method +in a runtime instance. Edit and Continue implements true OSR but is supported +only on some architectures, works only when code is running under a managed +debugger, and is supported only for unoptimized to unoptimized code. Profiler +rejit and tiered compilation can update code used in future invocations of +methods, but not code running in currently active methods. + +In this document we will vary a bit from the literature and use OSR to refer +strictly to the case where we are transitioning execution **from** an +unoptimized code instance (either to another unoptimized instance or an +optimized instance). We will use _deoptimization_ (_deopt_) to describe the +transition from an optimized code instance to some other code instance +(typically to an unoptimized instance). + +We envision OSR as a technology that will allow us to enable tiered compilation +by default: performance-critical applications will no longer risk seeing key +methods trapped in unoptimized tier0 code, and straightforwardly written +microbenchmarks (e.g. all code in main) will perform as expected, as no matter +how they are coded, they will be able to transition to optimized code. + +OSR also provides key building blocks for an eventual implementation of deopt +and the ability of our platforms to make strong speculative bets in code +generation. + +In addition, OSR will also allow us to experiment with so-called _deferred +compilation_, where the jit initially only compiles parts of methods that it +believes likely to execute (say, based on heuristics or prior runs). If an +uncompiled part of a method is reached at runtime, OSR can trigger recompilation +of the missing part or recompilation of the entire method. + +The remainder of this document describes OSR in more detail, providing a design +sketch and some key design choice points, the results and insights gained from +creating a fully functional prototype, and a list of open issues and areas +requiring further investigation. We will also mention _deopt_ in passing and +describe why it presents a different and larger set of challenges. + +## 2. Design Principles + +As we consider proposals for implementing OSR, we will try and satisfy the +following design principles: + +* Pay as you go. The costs of OSR should be limited to methods that can benefit + from OSR, and where possible, paid largely when OSR actually happens. + +* Impose few restrictions on optimized codegen. We should not have to restrict + or dumb down optimized codegen to allow transitions to it via OSR + +* Anticipate likely changes in jit codegen strategy. We should support enabling + some optimizations (devirtualization, early branch pruning, some expression + opts) at Tier0 without having to radically alter our approach. + +* Design for testability. We should be able to force OSR transitions wherever + possible and with alternative stress strategies. + +* Full diagnostic experience. OSR should not inhibit user ability to debug or + reason about logical behavior of their programs. OSR activities should be + tracked via suitable eventing mechanisms. + +## 3 An overview of OSR + +OSR enables transitioning from older unoptimized code to new code +while the old code is active in some stack frames. An implementation +must come up with solutions to several related sub problems, which we +describe briefly here, and in more detail below. + +* **Patchpoints** : Identify where in the original method OSR is possible. +We will use the term _patchpoint_ to describe a particular location in a +method's code that supports OSR transitions. +* **Triggers** : Determine what will trigger an OSR transition +* **Alternatives** : Have means to prepare a suitable alternative code +version covering all or part of the method (loops, for instance), and +having one or possibly many entry points. +* **Transitions**: Remap the stack frame(s) as needed to carry out the +OSR transition + +### 3.1 Patchpoints + +A _patchpoint_ is a point in a version of code where OSR is possible. +Patchpoints are similar in many ways to GC safepoints. At a patchpoint, the live +state of the ongoing computation must be identifiable (for a GC safepoint, only +the live GC references need be so identified). All live registers and stack +slots must be enumerable, and logically described in terms of concepts visible +in the IL. Additional state like the return address, implicit arguments, and so +on must also be accounted for. + +As with GC safepoints, patchpoints can be handled in a _fully interruptible_ +manner where most any instruction boundary is a patchpoint, or a _partially +interruptible_ manner, where only some instruction boundaries are patchpoints. +Also, as with GC, it is acceptable (if suboptimal) to over-identify the live +state at a patch point. For instance, the live set can include values that never +end up being consumed by the new method (the upshot here is that we can simply +decide all the visible IL state is live everywhere, and so avoid running +liveness analysis in Tier0.) + +Also, as with GC safepoints, it is desirable to keep the volume of information +that must be retained to describe patchpoints to a minimum. Most methods +executions will never undergo OSR transition and so the information generated +will never be consulted. To try and keep OSR a _pay as you go_ technique, it is +important that this information be cheap to generate and store. + +#### 3.1.1 Choosing Patchpoints + +Most commonly, patchpoints are chosen to be the places in the code that are +targets of loop back edges. This is a partially interruptible scheme. This +ensures that no loop in the method can iterate without hitting a patchpoint, and +so that the method itself cannot execute indefinitely between patchpoints. Note +by this rule, methods that do not contain any loops will not have any +patchpoints. + +From a compilation standpoint, it would be ideal if patchpoints were also IL +stack empty points, as this tends to minimize and regularize the live state. +However, there is no guarantee that execution of a method will reach stack empty +points with any frequency. So, a fully general patchpoint mechanism must handle +the case where the evaluation stack is not empty. However, it may be acceptable +to only allow patchpoints at stack empty points, as loops that execute with +non-empty evaluation stacks are likely rare. + +It is also beneficial if patchpoint selection works via a fairly simple set of +rules, and here we propose that using the set of _lexical back edges_ or +backwards branches in IL is a reasonable choice. These can be identified by a +single scan over a method's IL. + +When generating unoptimized code, it is thus sufficient to note the target of +any backwards branch in IL, the set of those locations (filtered to just the +subset where the IL stack is empty) are the candidate patchpoints in the method. + +We can also rely on the fact that in our current unoptimized code, no IL state +is kept in registers across IL stack empty points—all the IL state is +stored in the native stack frame. This means that each patchpoint's live state +description is the same—he set of stack frame locations holding the IL +state. + +So, with the above restrictions, a single patchpoint descriptor suffices for the +entire method (analogous to the concept of _untracked_ GC lifetimes in the GC +info). Further, this information is a superset of the current GC info, so the +additional data needed to describe a patchpoint is simply the set of live non-GC +slots on the native stack frame. + +[Note: more general schemes like _deopt_ will require something more +sophisticated.] + +#### 3.1.2 Option I: non-stack empty patchpoints + +If it turns out we must also allow patchpoints at non-stack empty points, then +some per-patchpoint state will be needed to map the logical state of the +evaluation stack into actual stack slots on the methods frame. This state will +vary from patchpoint to patchpoint. + +#### 3.1.3 Option II: fully interruptible patchpoints + +Patchpoints can be much more fine-grained, at any block boundary or even within +blocks, so long as the correspondence of the generated code to the inspiring IL +is well understood. However fine-grained patchpoints in our proposed version of +OSR do not seem to offer much in the way of advantages, given that we are also +proposing synchronous triggers and transitions, and transitioning from +unoptimized code. A fine-grained patchpoint mechanism would require more +metadata to describe each transition point. + +#### 3.1.4 The Prototype + +In the prototype, patchpoints are the set of IL boundaries in a method that are +stack-empty and the targets of lexical back edges. The live state of the +original method is just the IL-visible locals and arguments, plus a few special +values found in certain frames (GS Cookie, etc). + +### 3.2 Triggers + +When OSR is used to enable transfer control from an unoptimized method into +optimized code, the most natural trigger is a count of the number of times a +patchpoint in the method is reached. Once a threshold is reached at a +patchpoint, the system can begin preparation of the alternative code version +that will work for that patchpoint. + +This counting can be done fairly efficiently, at least in comparison to the +ambient unoptimized code in the method, by using counters on the local frame. +When the threshold is reached, control can transfer to a local policy block; +this can check whether an alternative version needs to be prepared, is already +being prepared, or is ready for transfer. Since this policy logic is common to +all patchpoints it most likely should be encapsulated as a helper. In +pseudocode: + +``` +Patchpoint: // each assigned a dense set of IDs + + if (++counter[ppID] > threshold) call PatchpointHelper(ppID) +``` +The helper can use the return address to determine which patchpoint is making +the request. To keep overheads manageable, we might instead want to down-count +and pass the counter address to the helper. +``` +Patchpoint: // each assigned a dense set of IDs + + if (--counter[ppID] <= 0) call PatchpointHelper(ppID, &counter[ppID]) +``` +The helper logic would be similar to the following: +``` +PatchpointHelper(int ppID, int* counter) +{ + void* patchpointSite = _ReturnAddress(); + PPState s = GetState(patchpointSite); + + switch (s) + { + case Unknown: + *counter = initialThreshold; + SetState(s, Active); + return; + + case Active: + *counter = checkThreshold; + SetState(s, Pending); + RequestAlternative(ppID); + return; + + case Pending: + *counter = checkThreshold; + return; + + case Ready: + Transition(...); // does not return + } +} +``` +Here `RequestAlternative` would queue up a request to produce the alternative +code version; when that request completes the patchpoint state would be set to +Ready. So the cost for a patchpoint would be an initial helper call (to set the +Active threshold), then counting, then a second helper call (to request and set +the pending threshold), then counting, and, depending on how long the request +took, more callbacks in pending state. + +Note that just because a patchpoint is hit often enough to reach Active state, +there is no guarantee that the patchpoint will be reached again in the future. +So, it is possible to trigger alternative version compilations that end up never +getting used, if those alternative versions are patchpoint specific. In a +pathological case a method might have an entire sequence of patchpoints that +reach Active state and trigger alternative versions, none of which ever get +used. + +In this scheme, the local frame of the method would have one local counter per +patchpoint. + +#### 3.2.1 Option I: one global counter per patchpoint + +Instead of keeping the counters on the local frame, they could be kept in global +storage associated with the method, to give an absolute count of patchpoint +frequency over all invocations of the method. This would help trigger +transitions in methods in use across multiple threads or methods that are a weak +mixture of iteration and recursion. Because there would now be shared counter +state, we'd have to think though how to handle the concurrent access. Likely +we'd implement something like we do for IBC and have a method fetch and locally +cache the address of its counter vector locally in the prolog. + +#### 3.2.2 Option II: shared counters + +Alternatively, all patchpoints in a method could share one counter slot (either +local or global), this would save space but would lead to somewhat more frequent +callbacks into the runtime and slightly higher likelihood that useless +alternatives would be created. + +#### 3.2.3 Option III: synchronous OSR + +Independent of the counter scheme, the runtime could also block and +synchronously produce and then transition to the alternative version. This would +eliminate the potential for wasted alternates (though depending on other +choices, we still might produce multiple alternates for a method). It would also +hold up progress of the app, as the thread could just as well continue executing +the unoptimized code past the patchpoint. We might consider transitioning to +synchronous OSR selectively for methods that have a track record of generating +useless versions. This is entirely a runtime policy and would not impact jitted +codegen. + +Note: If OSR is used for EnC or for _deopt_ when an invariant changes, then +synchronous transitions are required as in general, the old method cannot safely +execute past a patchpoint. If the delay from jitting code is a concern it may be +possible to fall back to an interpreter for a time while the new version of the +method is jitted, though this would require that the system also support +OSR-style transitions from interpreted methods to compiled methods... + +#### 3.2.4 Option IV: share counter space with Tiered Compilation + +A final option here is to use global counters and also add a counter at method +entry. The entry counter could be used for two purposes: first to trigger tiered +jitting of the entire method, and second, to help normalize the per-patchpoint +counters so as to provide relative profile weights for the blocks in the method +when it is rejitted (either via tiering or OSR). We note that the set of +observation points from patchpoint counters is fairly sparse (not as detailed as +what we get from IBC, say) but it may be sufficient to build a reasonable +profile. + +#### 3.2.5 The Prototype + +In the prototype OSR transitions are synchronous; there is one local patchpoint +counter per frame shared by all patchpoints; patchpoint IDs are IL offsets. + +### 3.3 Alternative Versions + +When a patchpoint is hit often enough, the runtime should produce an alternative +version of the code that can be transitioned to at that patchpoint. + +There are several choice points for alternatives: + +* Whether to tailor the alternative code specifically to that patchpoint or have + the alternative handle multiple (or perhaps all) the patchpoints in a method. + We'll call the former a single-entry alternative, and the latter + multi-entry alternatives (and, in the limit, whole-method alternatives). + +* Whether the alternative version encompasses the remainder of the method, or + just some part of the method. We'll call these whole and partial + alternatives. + +* If a partial method alternative, whether the part of the method compiled + includes the entire remainder of the method, or just some fragment that + includes the patchpoint (say the enclosing loop nest). + +* Whether or not the alternative entry points include the code to build up the + alternative stack frames, or setup of the new frame happens via some runtime + logic. + +* Whether or not the alternate version is tailored to the actual runtime state + at the point of the trigger. For instance, specific argument or local values, + or actual types. + +The partial alternatives obviously are special versions that can only be used by +OSR. The whole method alternative could also be conceivably used as the +optimized version of the method, but the additional entry points may result some +loss of optimizations. So, in general, the OSR alternatives are likely distinct +from the Tier-1 versions of methods and are used only for active frame +transitions. New calls to methods can be handled via the existing tiering +mechanisms. + +[Note there are some interesting dynamics here that may warrant further +consideration. A method that is seldomly called with a hot loop will eventually +trigger both OSR (from the loop) and Tier1 recompilation (from the calls). We +might consider deferring tiered recompilation for such methods, as the +unoptimized versions can readily transition to OSR alternates in code that +matters for performance.] + +Taken together there are various combinations of these alternatives that make +sense, and various tradeoffs to consider. We explore a few of these below. + +#### 3.3.1 Option 1: Partial Method with Transition Prolog + +In this option, the runtime invokes the jit with a method, IL offset, and the +original method mapping of stack frame state to IL state at that offset. The jit +uses the logical PC (IL offset) to determine the scope of the alternative +fragment. Here the scope is the IL in the method reachable from the patchpoint. + +For the entry point it creates a specialized transition prolog that sets up a +normal frame, and takes the values of the locals from the old stack frame and +copies them to the new stack slots, and pushes& any live evaluation stack +arguments. Arguments passed in registers are restored to the right registers. +Control then transfers to the IL offset of the patchpoint. Any IL in the method +not reachable from the patchpoint is dead code and can be removed (including the +original method entry point). This new partial method is then jitted more or +less normally (modulo the generation of the special prolog). + +It might be possible to express this new prolog in IL or something similar. At +any rate it seems likely the impact on the jit overall can be mostly localized +to the &importer and prolog generation stages and the rest of the jit would +operate more or less as it does today. + +This alternative version can be used any time the original method reaches the +inspiring patchpoint. + +#### 3.3.2 Option 2: Partial Tailored Method with Transition Prolog + +If the runtime also passes the triggering stack frame to the jit, the jit can +incorporate the values in that frame (or information derived from the frame +values) into the alternative method codegen. This creates a tailored alternative +that can only be used at this patchpoint from this specific original method +invocation. The potential benefit here is that the code in the method may be +more optimizable with the additional context, and since OSR alternatives are +likely to be lightly used there may not be much downside to specializing exactly +for this trigger instance. This alternative likely implies synchronous OSR. + +#### 3.3.3 Option 3: Full Method with Multiple Entry Points + +Instead of generating an alternative that can only be used to transition from +one specific patchpoint, the alternative method can offer multiple entry points +to allow transition from some or all of the patchpoints in the original method. + +Note: After thinking about this a bit more, I think we can implement this +variant without needing multiple prologs—instead we can pass the IL offset +of the OSR entry point as a hidden argument to the OSR method, and have a switch +on that argument in the first body block to jump to the right place in the +method. This might be a viable option to control the potential explosion of OSR +variants for methods with many patchpoints. This method would still be OSR +specific—that is, it could not also serve as a normally callable Tier1 +method. + +#### 3.3.4 Option 4: Method Fragment + +If the alternative method is just a fragment of the entire method, then in +addition to a specialized entry point, the jit will have to create specialized +exit points that either transition back to the unoptimized method, or else use +synchronous OSR to invoke jitting of the method code that comes after the +fragment. + +#### 3.3.5 Prototype + +The prototype generates partial methods with transition prolog. Per 4.1 below, +the OSR method frame incorporates the (live portion of the) original method +frame instead of supplanting it. + +### 3.4 Transitions + +A transition can happen once an OSR capable method reaches a patchpoint where a +suitable alternative version is ready. Because transitions will likely require +changes in stack frame size it is much simpler to consider transitions only for +methods at the top of the stack. This means that methods that are invoked +recursively may be transitioned by OSR gradually as the stack unwinds. + +Abstractly, the actual transition could work something like the following: the +runtime would copy the top stack frame into temporary storage, then carefully +unwind the current frame. Then the alternative method would be put in place and +invoked, being passed the copy of the original frame as an argument. + +However, the presence of original frame addresses and values derived from those +addresses in the original frame's live state complicates matters (more on this +in [Section 4.1](#Addresses-of-Locals)). So the OSR method needs to ensure that +any "address-exposed" local ends up at the exact same stack location in the OSR +frame as it did in the original method frame. The simplest way to accomplish +this is to just leave the original frame in place, and have the OSR frame +"incorporate" it as part of its frame. + +#### 3.4.1 The Prototype + +The original method conditionally calls to the patchpoint helper at +patchpoints. The helper will return if there is no transition. + +For a transition, the helper will capture context and virtually unwind itself +and the original method from the stack to recover callee-save register values +live into the original method and then restore the callee FP and SP values into +the context (preserving the original method frame); then set the context IP to +the OSR method entry and restore context. OSR method will incorporate the +original method frame as part of its frame. + +## 4 Complications + +### 4.1 Addresses of Locals + +If the live state at the patchpoint includes addresses of locals (or addresses +of arguments, if the OSR transition pushes a new frame), either these addresses +must be updated to properly reflect the new locations or the address-taken +locals must end up in the same relative location in the frame. The jit might +require some hardening to ensure that address of local is always properly +described at patchpoints. + +Detection of address-taken locals (especially in a non-optimizing jit) may +require some attention. We frequently see `ldloca` in IL that is consumed in a +dereference before a stack empty point; such locals are transiently exposed but +their addresses would not be live at our proposed set of patchpoints (note +`ldflda` can cause similar issues if it exposes addresses if local struct +fields). + +Arithmetic done on addresses of locals might not be stable across an OSR +transition (that is, different values could be obtained for a given piece of +code before and after the transition). While in general there is no guarantee +about the values produced by this kind of code it is not unreasonable to expect +that the value would not change over the lifetime of a given method's +execution. It is not clear how much code might depend on this. + +This problem could be partially solved by requiring any address-taken local to +appear at the same stack location in the alternative method frame and by +requiring that the OSR frame supplant the original frame (this is how EnC +works). In that case all address-taken locals would be at the same address. +Ensuring that this is possible likely entails other restrictions like reserving +a maximally large register save area for the original method. + +However, it seems simplest to just preserve the original method frame, or at +least the portion of it that contains the live state, and allow the OSR method +to access the original frame values, either as initial values or as the actual +homes for that state. + +### 4.2 Localloc + +Methods with localloc pose similar challenges to those posed by methods with +address taken locals. Room is made on the original method stack for the localloc +storage, and a native pointer to that storage is part of the live state of the +method. The live state may also include pointers and other values derived from +that address. So, the alternative version must use that same location; a +copy/fixup procedure to allow this storage to be relocated in some manner seems +impractical. + +In addition, localloc makes describing the local frame more complex, as the size +of the frame and the location of particular bits of live state can vary. +Typically, the jit will use multiple frame pointers in a localloc frame to allow +for relative addressing. + +In the most complex case, the original method will have executed one or more +locallocs before hitting the patchpoint, and the OSR variant will then execute +more locallocs. Such cases might require the OSR method to maintain 3 or more +frame pointers. + +### 4.3 Funclets + +When control is executing in a funclet there are effectively two activation +records on the stack that share a single frame: the parent frame and the +funclet frame. The funclet frame is largely a stub frame and most of the frame +state is kept in the parent frame. + +These two frames are not adjacent; they are separated by some number of runtime +frames. This means it is going to be difficult for our system to handle +patchpoints within funclets; even if we could update the code the funclet is +running we would not be able to update the parent frame. + +The proposal here is to disallow patchpoints within funclets so that we do not +attempt OSR transitions when the top of stack frame is a funclet frame. One +hopes that performance critical loops rarely appear in catch or finally clauses. + +EnC has similar restrictions. + +### 4.4 GC + +There is a brief window of time during the transition where there are GC live +values on both the original and alternative frames (and the original frame may +have been copied off-stack). Since the transition is done via a runtime helper, +it seems prudent to forbid GC during this part of the transition, which should +be relatively brief. + +### 4.5 Diagnostics + +Alternative methods will never be called — they are only transitioned to +by active original methods, so likely no special work is needed to make them +compatible with the current profiler guarantees for IL modifications ("new +invocations" of the method invoke the new version). + +We may need to update the mechanisms that the runtime uses to notify profilers +of new native code versions of a method. + +The jit will generate the same debug info mappings as it does today, and so the +debugging experience when debugging an alternative should be similar to the +experience debugging a Tier1 method. Likewise, the code publishing aspects +should be common, so for instance active breakpoints should get applied. + +[Note: I have verified this on simple examples using the VS debugger; a source +breakpoint set in the original method is applied to the OSR method too.] + +We need to decide what happens if the debugger tries to use SetIP on an OSR +method for an IL offset that is not within the range of IL compiled; likely +we'll just have to fail the request. + +Breakpoints set at native code addresses won't transfer to the corresponding +points in OSR methods. We have the same issue with Tiered compilation already. + +OSR (exclusive of EnC) will be disabled for debuggable code. + +Debugging through an OSR transition (say a single-step that triggers OSR) may +require special consideration. This is something that needs further +investigation. + +**Prototype: The OSR methods have somewhat unusual unwind records that may be +confusing the (Windbg) debugger stack trace.** + +### 4.6 Proposed Tier-0 Optimizations + +We have been assuming up until this point that the original method was not +optimized in any way, and so its live state is safely over-approximated by the +values of all locals, arguments, evaluation stack entries. This means that any +value truly live at a reachable patchpoint (capable of influencing future +computation) is included in the live set. The reported live set might well be +larger, of course. The alternative method will likely run liveness and pick from +this set only the values it sees as truly live. + +This means that we can run optimizations in the original method so long as they +do not alter the computation of the over-approximated live set at any +patchpoint. + +The proposed Tier0 optimizations fit into this category, so long as we restrict +patchpoints to stack-empty points: we may prune away unreachable code paths (say +from HW intrinsic checks or provably true or false predicate evaluations &mdash +;patchpoints in pruned sections would be unreachable) and simplify computations. +Optimizing expressions may reduce the truly live set but so long as all stores +to locals and args are kept live the base values needed for any alternate +version of the code will be available. + +### 4.7 Alternative Method Optimizations + +In options where the alternative method has multiple entry points, one must be +wary of early aggressive optimizations done when optimizing the alternative. The +original version of the method may hit a patchpoint while executing code that +can be optimized away by the more aggressive alternative method compiler (e.g. +it may be executing a series of type equality tests in a generic method that the +optimizing jit can evaluate at jit time). But with our simple patchpoint +recognition algorithm the alternate compiler can quickly verify that the +patchpoint IL offset is a viable entry point and ensure that the code at that +offset is not optimized away. If it turns out that the entry point code is +optimizable then we may choose to peel one iteration from the entry point loop +(because with our patchpoint strategy, execution in the alternate method will +immediately hit a loop top once it is out of the prolog) and allow the in-loop +versions to be optimized. + +### 4.8 Prologs and Unwind + +The alternative version of the method will, in all likelihood, need to save and +restore a different set of callee-saves registers than the original version. But +since the original stack frame has already saved some registers, the alternative +version prolog will either need to save a superset of those registers or else +restore the value of some registers in its prolog. So, the alternative version +needs to know which registers the original saved and where in the stack they are +stored. + +If we want to preserve frame offsets for address-taken locals then we may face a +conflict as altering the number of callee save slots may alter frame offsets for +locals. One thought here is that we could perhaps implement a chained unwind +scheme, where there is an initial prolog that emulates the original version +prolog and duplicates its saves, and then a subsequent "shrink wrapped" prolog +& epilog that saves any additional registers in a disjoint area. + +**Prototype:** When it is time to transition, the patchpoint helper virtually +unwinds two frames from the stack—its own frame, and the frame for the +original method. So the unwound context restores the callee saves done by the +original method. That turns out to be sufficient. + +You might think the helper would need to carefully save all the register state +on entry, but that's not the case. Because the original method is un-optimized, +there isn't any live IL state in registers across the call to the patchpoint +helper—all the live IL state for the method is on the original +frame—so the argument and caller-save registers are dead at the +patchpoint. Thus only part of register state that is significant for ongoing +computation is the callee-saves, which are recovered via virtual unwind, and the +frame and stack pointers of the original method, which are likewise recovered by +virtual unwind. + +With this context in hand, the helper then "calls" the OSR method by restoring +the context. The OSR method performs its own callee-saves as needed, and +recovers the arguments/IL state from the original frame. + +If we were to support patchpoints in optimized code things would be more +complicated. + +### 4.9 Synchronous Methods + +OSR methods only need add the code to release the synchronous method monitor. +This must still be done in a try-finally to ensure release even on exceptional +exit. + +### 4.10 Profile Enter/Leave Hooks + +OSR methods only need to support the method exit hook. + +## 5 The Prototype + +Based on the above, we developed a prototype implementation of OSR to gain +experience, gather data, and test out assumptions. + +The prototype chose the following options: +* Patchpoints: lexical back edge targets that are stack empty and not in try + regions; live state is all locals and args + specials (thus no liveness needed + at Tier0) +* Trigger: one shared counter per frame. Initial value configurable at runtime. + Patchpoints decrement the counter and conditionally call the runtime helper if + the value is zero or negative. +* Alternatives: partial method tailored to each patchpoint. OSR method + incorporates the original method frame. +* Transition: synchronous—once the patchpoint has been hit often enough a + new alternative is jitted. + +The prototype works for x64 on Windows and Linux, and can pass the basic (pri0) +tests suites with an aggressive transition policy (produce the OSR method and +transition the first time each patchpoint is hit). + +### 5.1 Example Codegen + +Consider the following simple method: +```C# + public static int F(int from, int to) + { + int result = 0; + for (int i = from; i < to; i++) + { + result += i; + } + return result; + } + +``` +Normal (Tier0, x64 windows) codegen for the method is: +```asm +; Tier-0 compilation + +G_M6138_IG01: + 55 push rbp + 4883EC10 sub rsp, 16 + 488D6C2410 lea rbp, [rsp+10H] + 33C0 xor rax, rax + 8945FC mov dword ptr [rbp-04H], eax // result + 8945F8 mov dword ptr [rbp-08H], eax // i + 894D10 mov dword ptr [rbp+10H], ecx // from + 895518 mov dword ptr [rbp+18H], edx // to + +G_M6138_IG02: + 33C0 xor eax, eax + 8945FC mov dword ptr [rbp-04H], eax + 8B4510 mov eax, dword ptr [rbp+10H] + 8945F8 mov dword ptr [rbp-08H], eax + EB11 jmp SHORT G_M6138_IG04 + +G_M6138_IG03: + 8B45FC mov eax, dword ptr [rbp-04H] + 0345F8 add eax, dword ptr [rbp-08H] // result += i + 8945FC mov dword ptr [rbp-04H], eax + 8B45F8 mov eax, dword ptr [rbp-08H] + FFC0 inc eax + 8945F8 mov dword ptr [rbp-08H], eax + +G_M6138_IG04: + 8B45F8 mov eax, dword ptr [rbp-08H] + 3B4518 cmp eax, dword ptr [rbp+18H] + 7CE7 jl SHORT G_M6138_IG03 // i < to ? + 8B45FC mov eax, dword ptr [rbp-04H] + +G_M6138_IG05: + 488D6500 lea rsp, [rbp] + 5D pop rbp + C3 ret +``` +with OSR enabled (and patchpoint counter initial value = 2), this becomes: +```asm +; Tier-0 compilation + Patchpoints + +G_M6138_IG01: + 55 push rbp + 4883EC30 sub rsp, 48 + 488D6C2430 lea rbp, [rsp+30H] + 33C0 xor rax, rax + 8945FC mov dword ptr [rbp-04H], eax // result + 8945F8 mov dword ptr [rbp-08H], eax // i + 894D10 mov dword ptr [rbp+10H], ecx // from + 895518 mov dword ptr [rbp+18H], edx // to + +G_M6138_IG02: + 33C9 xor ecx, ecx + 894DFC mov dword ptr [rbp-04H], ecx // result = 0 + 8B4D10 mov ecx, dword ptr [rbp+10H] + 894DF8 mov dword ptr [rbp-08H], ecx // i = from + C745F002000000 mov dword ptr [rbp-10H], 2 // patchpointCounter = 2 + EB2D jmp SHORT G_M6138_IG06 + +G_M6138_IG03: + 8B4DF0 mov ecx, dword ptr [rbp-10H] // patchpointCounter-- + FFC9 dec ecx + 894DF0 mov dword ptr [rbp-10H], ecx + 837DF000 cmp dword ptr [rbp-10H], 0 // ... > 0 ? + 7F0E jg SHORT G_M6138_IG05 + +G_M6138_IG04: ;; bbWeight=0.01 + 488D4DF0 lea rcx, bword ptr [rbp-10H] // &patchpointCounter + BA06000000 mov edx, 6 // ilOffset + E808CA465F call CORINFO_HELP_PATCHPOINT + +G_M6138_IG05: + 8B45FC mov eax, dword ptr [rbp-04H] + 0345F8 add eax, dword ptr [rbp-08H] + 8945FC mov dword ptr [rbp-04H], eax + 8B45F8 mov eax, dword ptr [rbp-08H] + FFC0 inc eax + 8945F8 mov dword ptr [rbp-08H], eax + +G_M6138_IG06: + 8B4DF8 mov ecx, dword ptr [rbp-08H] + 3B4D18 cmp ecx, dword ptr [rbp+18H] + 7CCB jl SHORT G_M6138_IG03 + 8B45FC mov eax, dword ptr [rbp-04H] + +G_M6138_IG07: + 488D6500 lea rsp, [rbp] + 5D pop rbp + C3 ret +``` +Because Tier0 is unoptimized code, the patchpoint sequence is currently +unoptimized. This leads to a moderate amount of code bloat in methods with +patchpoints. The overall code size impact of patchpoints (as measured by +`jit-diff`) is around 2%, but this is this is an understatement of the impact to +methods that have patchpoints, as most Tier0 methods won't require patchpoints. +This is something that can be improved. + +The OSR method for this patchpoint is: +```asm +; Tier-1 compilation +; OSR variant for entry point 0x6 + +G_M6138_IG01: + 8B542450 mov edx, dword ptr [rsp+50H] // to + 8B4C2434 mov ecx, dword ptr [rsp+34H] // result + 8B442430 mov eax, dword ptr [rsp+30H] // i + +G_M6138_IG02: ;; bbWeight=8 + 03C8 add ecx, eax + FFC0 inc eax + 3BC2 cmp eax, edx + 7CF8 jl SHORT G_M6138_IG02 + +G_M6138_IG03: + 8BC1 mov eax, ecx + +G_M6138_IG04: + 4883C438 add rsp, 56 + 5D pop rbp + C3 ret +``` +Here the live state is `result`, `i`, and `to`. These are kept in registers and +initialized in the prolog to the values they had in the original frame. The jit +request for the OSR method includes 'OSR_INFO" metadata describing the original +method frame, so the jit can compute the correct addresses for original frame +slots in the OSR method. + +Because the OSR method is entered with the original method frame still active, +the OSR method has asymmetric prolog and epilog sequences. This is reflected in +the unwind data for the OSR method by recording a "phantom prolog" to account +for actions taken by the original method. These are at code offset 0 so happen +"instantaneously" when the method is entered. +``` + UnwindCodes: + CodeOffset: 0x00 UnwindOp: UWOP_ALLOC_SMALL (2) OpInfo: 6 * 8 + 8 = 56 = 0x38 + CodeOffset: 0x00 UnwindOp: UWOP_PUSH_NONVOL (0) OpInfo: rbp (5) +``` +By way of comparison, here is the full Tier-1 version of the method. +```asm +G_M6138_IG01: + +G_M6138_IG02: + 33C0 xor eax, eax + 3BCA cmp ecx, edx + 7D08 jge SHORT G_M6138_IG04 + +G_M6138_IG03: ;; bbWeight=4 + 03C1 add eax, ecx + FFC1 inc ecx + 3BCA cmp ecx, edx + 7CF8 jl SHORT G_M6138_IG03 + +G_M6138_IG04: + C3 ret +``` +Note the inner loop codegen is very similar to the OSR variant. This is typical. +It is often possible to diff the Tier1 and OSR codegen and see that the latter +is just a partial version of the former, with different register usage and +different stack offsets. + +### 5.2 More Complex Examples + +If the OSR method needs to save and restore registers, then the epilog will have +two stack pointer adjustments: the first to reach the register save area on the +OSR frame, the second to reach the saved RBP and return address on the original +frame. + +For example: +```asm + 4883C440 add rsp, 64 + 5B pop rbx + 5E pop rsi + 5F pop rdi + 4883C448 add rsp, 72 + 5D pop rbp + C3 ret +``` +with unwind info: +``` + UnwindCodes: + CodeOffset: 0x07 UnwindOp: UWOP_ALLOC_SMALL (2) OpInfo: 7 * 8 + 8 = 64 = 0x40 + CodeOffset: 0x03 UnwindOp: UWOP_PUSH_NONVOL (0) OpInfo: rbx (3) + CodeOffset: 0x02 UnwindOp: UWOP_PUSH_NONVOL (0) OpInfo: rsi (6) + CodeOffset: 0x01 UnwindOp: UWOP_PUSH_NONVOL (0) OpInfo: rdi (7) + CodeOffset: 0x00 UnwindOp: UWOP_ALLOC_SMALL (2) OpInfo: 8 * 8 + 8 = 72 = 0x48 + CodeOffset: 0x00 UnwindOp: UWOP_PUSH_NONVOL (0) OpInfo: rbp (5) +``` + +If the OSR method needs to save RBP, we may see two RBP restores in the epilog; +this does not appear to cause problems during execution, as the "last one wins" +when unwinding. + +However, the debugger (at least windbg) may end up being confused; any tool +simply following the RBP chain will see the original frame is still "linked" +into the active stack. + +### 5.3 PatchpointInfo + +As noted above, when the jit is invoked to create the OSR method, it asks the +runtime for some extra data: +* The IL offset of the OSR entry point +* `PatchpointInfo`: a description of the original method frame + +`PatchpointInfo` is produced by the jit when jitting the Tier0 method. It is +allocated by the runtime similarly to other codegen metadata like GC info and +unwind info and is likewise associated with the original method. When the +runtime helper decides to kick off an OSR jit, it sets things up so that the jit +can retrieve this data. + +Since the `PatchpointInfo` is produced and consumed by the jit its format is +largely opaque to the runtime. It has the following general layout: +```C++ +struct PatchpointInfo +{ + unsigned m_patchpointInfoSize; + unsigned m_ilSize; + unsigned m_numberOfLocals; + int m_fpToSpDelta; + int m_genericContextArgOffset; + int m_keptAliveThisOffset; + int m_securityCookieOffset; + int m_offsetAndExposureData[]; +}; +``` +The key values are the `fpToSpDelta` which describes the extent of the original +frame, and the `offsetAndExposureData` which describe the offset of each local +on the original frame. + +### 5.4 Performance Impact + +The prototype is mainly intended to show that OSR can be used to improve startup +without compromising steady-state performance: with OSR, we can safely use the +quick jit for almost all methods. + +We are currently evaluating the performance impact of OSR on some realistic +scenarios. + +Initial data shows a general improvement in startup time, in particular for +applications where startup was impacted by disabling quick-jitting of methods +with loops (see dotnet/coreclr#24252). + +### 5.5 Prototype Limitations and Workarounds + +* x64 only +* Struct promotion is currently disabled for OSR methods +* No OSR for synchronous methods +* No OSR for methods with profiler hooks +* No OSR for methods with localloc +* No OSR from "handler" regions (catch/finally/filter) + +The prototype trigger strategy is a hybrid: it has a per-frame local counter and +a per-patchpoint global counter (kept by the runtime). This is probably +something we need to re-assess. + +## 6 Edit and Continue + +As mentioned in the introduction, OSR is similar to Edit and Continue (EnC). EnC +transitions from an original unoptimized version of a method to a new +unoptimized version with slightly different IL. The CLR already supports EnC on +some platforms, and we briefly review the current implementation here. Our main +interest here is in edits to method IL for an active method, so we focus on that +aspect. + +### 6.1 Current EnC Support + +Method modification in EnC works roughly as follows. A process being debugged is +stopped at a breakpoint. The user makes a source edit and hits apply. The source +edit is vetted by the language compiler as suitable for EnC and metadata edits +are sent to the runtime via the debugger. For method modifications these edits +create a new version of method IL. Any subsequent invocations of that method +will use that new IL. + +To update currently active versions, the debugger also adds special breakpoints +to the plausible patchpoints of the original method's native code. Execution +then resumes. When one of those special breakpoints is hit, an original +method's active frame is at the top of the stack, and the frame can be +transitioned over to the new version. The remapping is done by using the debug +information generated by the jit for both the old and new versions of the +method. As part of this the runtime verifies that locals remain at the same +addresses in the old and new stack frames (thus avoiding the complication noted +earlier in [Section 4.1](#Addresses-of-Locals)). + +The jit is notified if a method is going to potentially be eligible for EnC and +takes some precautions to ensure the EnC transition can be handled by the +runtime: for instance, the jit will always save the same set of registers and +use a frame pointer. + +So, for EnC, we see that: + +- The viable patchpoints are determined by the debugger (via + EnCSequencePointHelper). These are restricted to be stack empty points (since + debug info will not describe contents of the evaluation stack) that are not in + filter or handlers. They are a broader set than we envision needing for OSR. +- The necessary mapping information (stack frame layout, native to IL mapping, + and native offsets of stack empty points) is present in the debug stream + generated by the jit for the original method. +- The trigger is a set of special breakpoints placed into the original method + native code by the debugger when an edit is applied to the method. +- When an EnC breakpoint is hit, the debugger can choose whether or not to + initiate a transition. +- If the debugger initiates a transition, it is done synchronously: the new + version of the method is jitted if necessary and the currently active frame is + transitioned over to the new version, via ResumeInUpdatedFunction. Of interest + here are the lower-level methods used here to update the frame: + FixContextAndResume and FixContextForEnC. +- The alternative version is a full method and can be used to transition from + any patchpoint in the original method. +- The jit modifies its codegen somewhat to facilitate the transition. It does + not, however, explicitly model the alternate entry points. + +## 7 Deoptimization + +Up until this point we have been assuming the original method was not optimized +or was optimized in a manner that did not alter its reported live state. + +More general optimizations break this property and so additional bookkeeping and +some restrictions on optimizations may be necessary to allow OSR transitions +from optimized code. We touch on this briefly below. + +Optimizations can either increase or decrease live state. + +For instance, unused computations can be removed, and unused local updates +("dead stores") can be skipped. Registers holding no longer live locals can be +reused for other values (as can stack slots, though the current jit does not do +this). + +Other optimizations can increase the live state. The classic example is inlining +— a call to a method is expanded inline, and so at patchpoints within the +inline body, there are now arguments and locals to the original method, plus +arguments and locals to the inline method. If we wish to make an OSR transition +from such a patchpoint to say unoptimized code, we need to effectively undo the +inlining, creating two frames (or more generally N frames) in place of the +original frame, and two alternate methods (or N alternate methods). + +The general solution is to first ensure that the live state never decreases. The +patchpoint locations are determined early, and any values truly live at a +patchpoint at that initial stage of compilation are forced to remain live at +that patchpoint always. So, some dead store elimination is inhibited, and some +forms of code motion are inhibited (e.g. one cannot sink a store to a local out +of a loop, as the patchpoint at loop top would not observe the updated value). + +With all the "naive" state guaranteed live at a patchpoint, and any additions to +live state via inlining carefully tracked, one can transition from optimized +code via OSR. + +Given the need to preserve address artifacts, this transition must be done +gradually—first creating a frame for the innermost inlined method that +extends the original frame, then, when this innermost method returns, creating a +frame for the next innermost inlined method, and so on, until finally the +root method frame returns and can clean up the optimized method frame as well. + +Each of these (presumably, unoptimized) deopt target methods will need to be +custom-crafted to access the optimized method frame. + +This same consideration makes it challenging to implement deopt fallbacks to +an interpreter; the interpreter will likewise need to keep some of its state +in the original method frame. + +We currently don't have any need to transfer control out of jitted optimized +code (Tier1), though one could potentially imagine supporting this to better +debug optimized code. The really strong motivations for deoptimization may come +about when the system is optimizing based on "currently true" information that +has now become invalid. + +## 8 References + +1. U. Holzle, C. Chambers and D. Ungar, "Debugging Optimized + Code with Dynamic Deoptimization," in _ACM PLDI_, 1992. +2. M. Paleczny, C. Vick and C. Click, "The Java Hotspot(tm) + Server Compiler," in _USENIX Java Virtual Machine Research and + Technology Symposium_, 2001. +3. S. Fink and F. Qian, "Design, Implementation and + Evaluation of Adaptive Recompilation with On-Stack Replacement," in _In + International Symposium on Code Generation and Optimization (CGO)_, 2003. diff --git a/docs/design/features/host-download-urls.md b/docs/design/features/host-download-urls.md index c2253ed57fffed..eefbccb8738bcf 100644 --- a/docs/design/features/host-download-urls.md +++ b/docs/design/features/host-download-urls.md @@ -21,8 +21,8 @@ It's also part of the error when an SDK command is executed and there's no SDK i ``` ## Install prerequisites link -> https://go.microsoft.com/fwlink/?linkid=798306 for Windows -> https://go.microsoft.com/fwlink/?linkid=2063366 for OSX +> https://go.microsoft.com/fwlink/?linkid=798306 for Windows +> https://go.microsoft.com/fwlink/?linkid=2063366 for OSX > https://go.microsoft.com/fwlink/?linkid=2063370 for Linux This URL is part of the error message when the host fails to load `hostfxr`. @@ -45,7 +45,7 @@ This will happen when the host can't find `hostfxr`, typically when there's no . In this case the URL will contain these parameters: * `missing_runtime=true` - this marks the case of missing runtime. -* `apphost_version=` - the version of the `apphost` which was used to create the executable for the app. For example `apphost_version=5.0.0-preview.2.20155.1`. Currently this is only included if the host is a GUI app - see dotnet/runtime#33569 to include it always. +* `apphost_version=` - the version of the `apphost` which was used to create the executable for the app. For example `apphost_version=5.0.0-preview.2.20155.1`. This is included in all cases in 5.0 and above and it may be included in 3.1 only for GUI apps. In this case the `apphost_version` parameter could be used by the website to determine the major version of the runtime to offer (using latest minor/patch). Also if there's a `gui=true` we should offer the `WindowsDesktop` runtime installer. diff --git a/docs/workflow/building/mono/README.md b/docs/workflow/building/mono/README.md index c751144bd28ec5..36db7c252e34f6 100644 --- a/docs/workflow/building/mono/README.md +++ b/docs/workflow/building/mono/README.md @@ -19,7 +19,7 @@ Once you've built the whole runtime and assuming you want to work with just mono ``` or on Windows, ```bat -build.cmd --subsetCategory mono +build.cmd -subsetCategory mono ``` When the build completes, product binaries will be dropped in the `artifacts\bin\mono\..` folder. @@ -45,7 +45,7 @@ To generate nuget packages: ``` or on Windows, ```bat -build.cmd --subsetCategory mono -pack (with optional release configuration) +build.cmd -subsetCategory mono -pack (with optional release configuration) ``` The following packages will be created under `artifacts\packages\\Shipping`: diff --git a/eng/Tools.props b/eng/Tools.props index 4c399288ad250f..32fc0f6f6d4fcf 100644 --- a/eng/Tools.props +++ b/eng/Tools.props @@ -2,6 +2,9 @@ false true + + <_RepoToolManifest Condition="'$(ContinuousIntegrationBuild)' == 'true'" /> - 5.0.0-beta.20162.4 - 5.0.0-beta.20162.3 - 5.0.0-beta.20162.3 - 5.0.0-beta.20162.3 - 5.0.0-beta.20162.3 - 5.0.0-beta.20162.3 - 2.5.1-beta.20162.3 - 5.0.0-beta.20162.3 - 5.0.0-beta.20162.3 - 5.0.0-beta.20162.3 + 5.0.0-beta.20168.2 + 5.0.0-beta.20168.2 + 5.0.0-beta.20168.2 + 5.0.0-beta.20168.2 + 5.0.0-beta.20168.2 + 5.0.0-beta.20168.2 + 2.5.1-beta.20168.2 + 5.0.0-beta.20168.2 + 5.0.0-beta.20168.2 + 5.0.0-beta.20168.2 5.0.0-alpha.1.20080.9 5.0.0-alpha.1.20080.9 @@ -114,7 +114,7 @@ 4.8.0 - 16.6.0-preview-20200316-01 + 16.6.0-preview-20200318-01 2.4.1 2.0.5 12.0.3 @@ -123,7 +123,7 @@ 3.1.0-preview-20200129.1 - 0.1.6-prerelease.20166.1 + 0.1.6-prerelease.20169.1 6.0.1-alpha.1.20166.1 6.0.1-alpha.1.20166.1 diff --git a/eng/codeOptimization.targets b/eng/codeOptimization.targets index cbd2474984592a..24e9c761407cfb 100644 --- a/eng/codeOptimization.targets +++ b/eng/codeOptimization.targets @@ -9,7 +9,7 @@ IBCMerge optimizations on Mac for now to unblock the offical build. See issue https://github.com/dotnet/runtime/issues/33303 --> - false + false $__ToolchainDir/sysroot/androi echo "Now to build coreclr, libraries and installers; run:" echo ROOTFS_DIR=\$\(realpath $__ToolchainDir/sysroot\) ./build.sh --cross --arch $__BuildArch \ - --subsetCategory coreclr \ - --subsetCategory libraries \ + --subsetCategory coreclr +echo ROOTFS_DIR=\$\(realpath $__ToolchainDir/sysroot\) ./build.sh --cross --arch $__BuildArch \ + --subsetCategory libraries +echo ROOTFS_DIR=\$\(realpath $__ToolchainDir/sysroot\) ./build.sh --cross --arch $__BuildArch \ --subsetCategory installer diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml index b722975f9c288f..055304ad89bf65 100644 --- a/eng/common/templates/job/publish-build-assets.yml +++ b/eng/common/templates/job/publish-build-assets.yml @@ -37,6 +37,12 @@ jobs: - name: _BuildConfig value: ${{ parameters.configuration }} - group: Publish-Build-Assets + # Skip component governance and codesign validation for SDL. These jobs + # create no content. + - name: skipComponentGovernanceDetection + value: true + - name: runCodesignValidationInjection + value: false steps: - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml index 9505cf170f0fec..61488fd7679afd 100644 --- a/eng/common/templates/post-build/common-variables.yml +++ b/eng/common/templates/post-build/common-variables.yml @@ -90,3 +90,10 @@ variables: value: https://dotnetclimsrc.blob.core.windows.net/dotnet/index.json - name: InternalInstallersBlobFeedKey value: $(dotnetclimsrc-access-key) + + # Skip component governance and codesign validation for SDL. These jobs + # create no content. + - name: skipComponentGovernanceDetection + value: true + - name: runCodesignValidationInjection + value: false \ No newline at end of file diff --git a/eng/install-native-dependencies.sh b/eng/install-native-dependencies.sh index a73d4918c521bb..e837b017c7cba1 100644 --- a/eng/install-native-dependencies.sh +++ b/eng/install-native-dependencies.sh @@ -23,8 +23,18 @@ elif [ "$1" = "OSX" ]; then if [ "$?" != "0" ]; then exit 1; fi +elif [ "$1" = "iOS" ]; then + brew update + brew upgrade + if [ "$?" != "0" ]; then + exit 1; + fi + brew install openssl autoconf automake libtool pkg-config python3 + if [ "$?" != "0" ]; then + exit 1; + fi else - echo "Must pass \"Linux\" or \"OSX\" as first argument." + echo "Must pass \"Linux\", \"iOS\" or \"OSX\" as first argument." exit 1 fi diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake index 174cce725d557e..4fccb81a0c714a 100644 --- a/eng/native/configureplatform.cmake +++ b/eng/native/configureplatform.cmake @@ -1,15 +1,19 @@ include(CheckPIESupported) include(${CMAKE_CURRENT_LIST_DIR}/functions.cmake) +# If set, indicates that this is not an officially supported release +# Keep in sync with IsPrerelease in Directory.Build.props +set(PRERELEASE 1) + #---------------------------------------- # Detect and set platform variable names # - for non-windows build platform & architecture is detected using inbuilt CMAKE variables and cross target component configure # - for windows we use the passed in parameter to CMAKE to determine build arch #---------------------------------------- set(CLR_CMAKE_HOST_OS ${CMAKE_SYSTEM_NAME}) -if(CLR_CMAKE_HOST_OS STREQUAL Linux) +if(CLR_CMAKE_HOST_OS STREQUAL Linux OR CLR_CMAKE_HOST_OS STREQUAL Android) set(CLR_CMAKE_HOST_UNIX 1) - if(CLR_CROSS_COMPONENTS_BUILD) + if(CLR_CROSS_COMPONENTS_BUILD AND NOT CLR_CMAKE_HOST_OS STREQUAL Android) # CMAKE_HOST_SYSTEM_PROCESSOR returns the value of `uname -p` on host. if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL amd64) if(CLR_CMAKE_TARGET_ARCH STREQUAL "arm" OR CLR_CMAKE_TARGET_ARCH STREQUAL "armel") @@ -36,7 +40,7 @@ if(CLR_CMAKE_HOST_OS STREQUAL Linux) elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l) set(CLR_CMAKE_HOST_UNIX_ARM 1) set(CLR_CMAKE_HOST_UNIX_ARMV7L 1) - elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL arm) + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL arm OR CMAKE_SYSTEM_PROCESSOR STREQUAL armv7-a) set(CLR_CMAKE_HOST_UNIX_ARM 1) elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) set(CLR_CMAKE_HOST_UNIX_ARM64 1) @@ -54,10 +58,12 @@ if(CLR_CMAKE_HOST_OS STREQUAL Linux) set(LINUX_ID_FILE "${CMAKE_SYSROOT}${LINUX_ID_FILE}") endif() - execute_process( - COMMAND bash -c "source ${LINUX_ID_FILE} && echo \$ID" - OUTPUT_VARIABLE CLR_CMAKE_LINUX_ID - OUTPUT_STRIP_TRAILING_WHITESPACE) + if(EXISTS ${LINUX_ID_FILE}) + execute_process( + COMMAND bash -c "source ${LINUX_ID_FILE} && echo \$ID" + OUTPUT_VARIABLE CLR_CMAKE_LINUX_ID + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() if(DEFINED CLR_CMAKE_LINUX_ID) if(CLR_CMAKE_LINUX_ID STREQUAL tizen) @@ -66,12 +72,14 @@ if(CLR_CMAKE_HOST_OS STREQUAL Linux) elseif(CLR_CMAKE_LINUX_ID STREQUAL alpine) set(CLR_CMAKE_HOST_ALPINE_LINUX 1) set(CLR_CMAKE_HOST_OS ${CLR_CMAKE_LINUX_ID}) - elseif(CLR_CMAKE_LINUX_ID STREQUAL android) - set(CLR_CMAKE_HOST_ANDROID 1) - set(CLR_CMAKE_HOST_OS ${CLR_CMAKE_LINUX_ID}) endif() endif(DEFINED CLR_CMAKE_LINUX_ID) -endif(CLR_CMAKE_HOST_OS STREQUAL Linux) + + if(CLR_CMAKE_HOST_OS STREQUAL Android) + set(CLR_CMAKE_HOST_ANDROID 1) + set(CLR_CMAKE_HOST_OS ${CLR_CMAKE_HOST_OS}) + endif() +endif(CLR_CMAKE_HOST_OS STREQUAL Linux OR CLR_CMAKE_HOST_OS STREQUAL Android) if(CLR_CMAKE_HOST_OS STREQUAL Darwin) set(CLR_CMAKE_HOST_UNIX 1) @@ -233,11 +241,11 @@ if(CLR_CMAKE_TARGET_OS STREQUAL alpine) set(CLR_CMAKE_TARGET_ALPINE_LINUX 1) endif(CLR_CMAKE_TARGET_OS STREQUAL alpine) -if(CLR_CMAKE_TARGET_OS STREQUAL android) +if(CLR_CMAKE_TARGET_OS STREQUAL Android) set(CLR_CMAKE_TARGET_UNIX 1) set(CLR_CMAKE_TARGET_LINUX 1) set(CLR_CMAKE_TARGET_ANDROID 1) -endif(CLR_CMAKE_TARGET_OS STREQUAL android) +endif(CLR_CMAKE_TARGET_OS STREQUAL Android) if(CLR_CMAKE_TARGET_OS STREQUAL Darwin) set(CLR_CMAKE_TARGET_UNIX 1) diff --git a/eng/native/configuretools.cmake b/eng/native/configuretools.cmake index b59504a10e7616..b91237da89bfb7 100644 --- a/eng/native/configuretools.cmake +++ b/eng/native/configuretools.cmake @@ -1,6 +1,4 @@ -if(NOT CLR_CMAKE_CONFIGURE_PLATFORM_INCLUDED) - message(FATAL_ERROR "configuretools.cmake needs to be included after configureplatform.cmake") -endif() +include(${CMAKE_CURRENT_LIST_DIR}/configureplatform.cmake) # Get the version of the compiler that is in the file name for tool location. set (CLR_CMAKE_COMPILER_FILE_NAME_VERSION "") @@ -52,7 +50,9 @@ if(NOT WIN32) if(NOT CLR_CMAKE_TARGET_DARWIN AND NOT CLR_CMAKE_TARGET_IOS) locate_toolchain_exec(objdump CMAKE_OBJDUMP) - if(CMAKE_CROSSCOMPILING AND NOT DEFINED CLR_CROSS_COMPONENTS_BUILD AND (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l OR + if(CMAKE_SYSTEM_NAME STREQUAL Android) + set(TOOSET_PREFIX ${ANDROID_TOOLCHAIN_PREFIX}) + elseif(CMAKE_CROSSCOMPILING AND NOT DEFINED CLR_CROSS_COMPONENTS_BUILD AND (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l OR CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL arm)) set(TOOLSET_PREFIX "${TOOLCHAIN}-") else() diff --git a/eng/native/functions.cmake b/eng/native/functions.cmake index aa2c9411ab68d7..cc806fed263433 100644 --- a/eng/native/functions.cmake +++ b/eng/native/functions.cmake @@ -1,10 +1,10 @@ function(clr_unknown_arch) if (WIN32) - message(FATAL_ERROR "Only AMD64, ARM64, ARM and I386 are supported") + message(FATAL_ERROR "Only AMD64, ARM64, ARM and I386 are supported. Found: ${CMAKE_SYSTEM_PROCESSOR}") elseif(CLR_CROSS_COMPONENTS_BUILD) - message(FATAL_ERROR "Only AMD64, I386 host are supported for linux cross-architecture component") + message(FATAL_ERROR "Only AMD64, I386 host are supported for linux cross-architecture component. Found: ${CMAKE_SYSTEM_PROCESSOR}") else() - message(FATAL_ERROR "Only AMD64, ARM64 and ARM are supported") + message(FATAL_ERROR "Only AMD64, ARM64 and ARM are supported. Found: ${CMAKE_SYSTEM_PROCESSOR}") endif() endfunction() diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index 4858cc154478c6..38a01a7c5f5f36 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -198,6 +198,66 @@ jobs: # asArray: [] # ${{ insert }}: ${{ parameters.jobParameters }} +# iOS x64 + +- ${{ if containsValue(parameters.platforms, 'iOS_x64') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + osGroup: iOS + archType: x64 + platform: iOS_x64 + jobParameters: + runtimeFlavor: mono + stagedBuild: ${{ parameters.stagedBuild }} + buildConfig: ${{ parameters.buildConfig }} + ${{ if eq(parameters.passPlatforms, true) }}: + platforms: ${{ parameters.platforms }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + managedTestBuildOsGroup: OSX + ${{ insert }}: ${{ parameters.jobParameters }} + +# iOS arm + +- ${{ if containsValue(parameters.platforms, 'iOS_arm') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + osGroup: iOS + archType: arm + platform: iOS_x64 + jobParameters: + runtimeFlavor: mono + stagedBuild: ${{ parameters.stagedBuild }} + buildConfig: ${{ parameters.buildConfig }} + ${{ if eq(parameters.passPlatforms, true) }}: + platforms: ${{ parameters.platforms }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + managedTestBuildOsGroup: OSX + ${{ insert }}: ${{ parameters.jobParameters }} + +# iOS arm64 + +- ${{ if containsValue(parameters.platforms, 'iOS_arm64') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + osGroup: iOS + archType: arm64 + platform: iOS_x64 + jobParameters: + runtimeFlavor: mono + stagedBuild: ${{ parameters.stagedBuild }} + buildConfig: ${{ parameters.buildConfig }} + ${{ if eq(parameters.passPlatforms, true) }}: + platforms: ${{ parameters.platforms }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + managedTestBuildOsGroup: OSX + ${{ insert }}: ${{ parameters.jobParameters }} + # macOS x64 - ${{ if or(containsValue(parameters.platforms, 'OSX_x64'), eq(parameters.platformGroup, 'all')) }}: diff --git a/eng/pipelines/common/xplat-setup.yml b/eng/pipelines/common/xplat-setup.yml index 817443e041e4cf..d644907ae3d63d 100644 --- a/eng/pipelines/common/xplat-setup.yml +++ b/eng/pipelines/common/xplat-setup.yml @@ -87,6 +87,10 @@ jobs: ${{ if eq(parameters.osGroup, 'OSX') }}: vmImage: 'macOS-10.14' + # Public OSX Build Pool + ${{ if eq(parameters.osGroup, 'iOS') }}: + vmImage: 'macOS-10.14' + # Official Build Windows Pool ${{ if and(eq(parameters.osGroup, 'Windows_NT'), ne(variables['System.TeamProject'], 'public')) }}: name: NetCoreInternal-Pool diff --git a/eng/pipelines/coreclr/jit-experimental.yml b/eng/pipelines/coreclr/jit-experimental.yml new file mode 100644 index 00000000000000..e49b0ce4ca57ac --- /dev/null +++ b/eng/pipelines/coreclr/jit-experimental.yml @@ -0,0 +1,41 @@ +trigger: none + +pr: none + +schedules: +- cron: "0 22 * * 0,6" + displayName: Sun at 2:00 PM (UTC-8:00) + branches: + include: + - master + always: true + +jobs: +# +# Checkout repository +# +- template: /eng/pipelines/common/checkout-job.yml + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/build-coreclr-and-libraries-job.yml + buildConfig: checked + platforms: + - Linux_x64 + - Windows_NT_x64 + jobParameters: + testGroup: jit-experimental + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/coreclr/templates/test-job.yml + buildConfig: checked + platforms: + - Linux_x64 + - Windows_NT_x64 + helixQueueGroup: ci + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + managedOsxBuild: false + jobParameters: + testGroup: jit-experimental + liveLibrariesBuildConfig: Release diff --git a/eng/pipelines/coreclr/templates/build-job.yml b/eng/pipelines/coreclr/templates/build-job.yml index 83308bbcd06d9f..3274634f5a39d6 100644 --- a/eng/pipelines/coreclr/templates/build-job.yml +++ b/eng/pipelines/coreclr/templates/build-job.yml @@ -1,20 +1,20 @@ parameters: - buildConfig: '' archType: '' + buildConfig: '' + compilerName: 'clang' + condition: true + container: '' + crossrootfsDir: '' + isOfficialBuild: false osGroup: '' osSubgroup: '' platform: '' - container: '' - testGroup: '' - crossrootfsDir: '' - timeoutInMinutes: '' + pool: '' signBinaries: false stagedBuild: false + testGroup: '' + timeoutInMinutes: '' variables: {} - pool: '' - isOfficialBuild: false - condition: true - useGCC: false ### Product build jobs: @@ -33,10 +33,10 @@ jobs: condition: ${{ parameters.condition }} # Compute job name from template parameters - ${{ if eq(parameters.useGCC, true) }}: - name: ${{ format('coreclr_gcc_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} + ${{ if eq(parameters.compilerName, 'gcc') }}: + name: ${{ format('coreclr_{0}_product_build_{1}{1}_{3}_{4}', parameters.compilerName, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} displayName: ${{ format('CoreCLR GCC Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - ${{ if eq(parameters.useGCC, false) }}: + ${{ if eq(parameters.compilerName, 'clang') }}: name: ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} displayName: ${{ format('CoreCLR Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} @@ -60,17 +60,13 @@ jobs: - ${{ if eq(parameters.buildConfig, 'Release') }}: - name: stripSymbolsArg value: '-stripsymbols' - - name: clangArg - value: '' - - name: gccArg + - name: compilerArg value: '' - name: publishLogsArtifactPrefix value: 'BuildLogs_CoreCLR' - - ${{ if eq(parameters.useGCC, true) }}: - - name: gccArg + - ${{ if eq(parameters.compilerName, 'gcc') }}: + - name: compilerArg value: '-gcc' - - name: clangArg - value: '' - name: publishLogsArtifactPrefix value: 'BuildLogs_CoreCLR_GCC' # workaround for gcc directory not in PATH @@ -78,20 +74,20 @@ jobs: value: /opt/rh/devtoolset-7/root/usr/bin/gcc - name: CLR_CXX value: /opt/rh/devtoolset-7/root/usr/bin/g++ - - ${{ if and(ne(parameters.osGroup, 'Windows_NT'), not(parameters.useGCC)) }}: - - name: clangArg + - ${{ if and(ne(parameters.osGroup, 'Windows_NT'), eq(parameters.compilerName, 'clang')) }}: + - name: compilerArg value: '-clang9' # Our FreeBSD doesn't yet detect available clang versions, so pass it explicitly. - ${{ if eq(parameters.osGroup, 'FreeBSD') }}: - - name: clangArg + - name: compilerArg value: '-clang6.0' # Building for x64 MUSL happens on Alpine Linux and we need to use the stable version available there - ${{ if and(eq(parameters.osGroup, 'Linux'), eq(parameters.osSubgroup, '_musl'), eq(parameters.archType, 'x64')) }}: - - name: clangArg + - name: compilerArg value: '' # AppleClang has different version scheme, so we let complier introspection pick up the available clang from PATH - ${{ if eq(parameters.osGroup, 'OSX') }}: - - name: clangArg + - name: compilerArg value: '' - ${{ if and(ne(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: # Variables used to publish packages to blob feed @@ -141,7 +137,7 @@ jobs: # Build CoreCLR Runtime - ${{ if ne(parameters.osGroup, 'Windows_NT') }}: - - script: $(coreClrRepoRootDir)build-runtime$(scriptExt) $(buildConfig) $(archType) $(crossArg) -ci $(clangArg) $(gccArg) $(stripSymbolsArg) $(officialBuildIdArg) + - script: $(coreClrRepoRootDir)build-runtime$(scriptExt) $(buildConfig) $(archType) $(crossArg) -ci $(compilerArg) $(stripSymbolsArg) $(officialBuildIdArg) displayName: Build CoreCLR Runtime - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: - script: set __TestIntermediateDir=int&&$(coreClrRepoRootDir)build-runtime$(scriptExt) $(buildConfig) $(archType) -ci $(enforcePgoArg) $(officialBuildIdArg) @@ -156,7 +152,7 @@ jobs: displayName: Build managed product components and packages # Build native test components - - script: $(coreClrRepoRootDir)build-test$(scriptExt) skipmanaged $(buildConfig) $(archType) $(crossArg) $(priorityArg) $(clangArg) $(gccArg) skipgeneratelayout + - script: $(coreClrRepoRootDir)build-test$(scriptExt) skipmanaged $(buildConfig) $(archType) $(crossArg) $(priorityArg) $(compilerArg) skipgeneratelayout displayName: Build native test components # Sign on Windows @@ -173,7 +169,7 @@ jobs: condition: always() # We only test on clang binaries. - - ${{ if eq(parameters.useGCC, false) }}: + - ${{ if eq(parameters.compilerName, 'clang') }}: # Publish product output directory for consumption by tests. - template: /eng/pipelines/common/upload-artifact-step.yml parameters: diff --git a/eng/pipelines/coreclr/templates/format-job.yml b/eng/pipelines/coreclr/templates/format-job.yml index 740585c6dfc612..e71b66b1f27d8e 100644 --- a/eng/pipelines/coreclr/templates/format-job.yml +++ b/eng/pipelines/coreclr/templates/format-job.yml @@ -26,7 +26,11 @@ jobs: name: ${{ format('format_{0}{1}_{2}', parameters.osGroup, parameters.osSubgroup, parameters.archType) }} displayName: ${{ format('Formatting {0}{1} {2}', parameters.osGroup, parameters.osSubgroup, parameters.archType) }} helixType: 'format' - pool: ${{ parameters.pool }} + ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + pool: + vmImage: 'windows-2019' + ${{ if ne(parameters.osGroup, 'Windows_NT') }}: + pool: ${{ parameters.pool }} variables: ${{ parameters.variables }} condition: ${{ parameters.condition }} steps: @@ -38,6 +42,12 @@ jobs: version: '3.x' includePreviewVersions: true installationPath: $(Agent.ToolsDirectory)/dotnet + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.x' + addToPath: true + architecture: 'x64' + condition: ${{ eq(parameters.osGroup, 'Windows_NT') }} - task: PythonScript@0 displayName: Run tests/scripts/format.py inputs: diff --git a/eng/pipelines/coreclr/templates/helix-queues-setup.yml b/eng/pipelines/coreclr/templates/helix-queues-setup.yml index 12fb8ad042b3c5..e35a69e6f7d5b0 100644 --- a/eng/pipelines/coreclr/templates/helix-queues-setup.yml +++ b/eng/pipelines/coreclr/templates/helix-queues-setup.yml @@ -116,9 +116,8 @@ jobs: # Windows_NT arm - ${{ if eq(parameters.platform, 'Windows_NT_arm') }}: - # Currently blocked by https://github.com/dotnet/runtime/issues/32320 - # - ${{ if and(eq(variables['System.TeamProject'], 'public'), in(parameters.jobParameters.helixQueueGroup, 'pr', 'ci', 'libraries')) }}: - # - Windows.10.Arm64v8.Open + - ${{ if and(eq(variables['System.TeamProject'], 'public'), in(parameters.jobParameters.helixQueueGroup, 'pr', 'ci', 'libraries')) }}: + - Windows.10.Arm64v8.Open - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - Windows.10.Arm64 diff --git a/eng/pipelines/coreclr/templates/run-test-job.yml b/eng/pipelines/coreclr/templates/run-test-job.yml index ffe1e50a06bcc3..8be5c5eb49eab3 100644 --- a/eng/pipelines/coreclr/templates/run-test-job.yml +++ b/eng/pipelines/coreclr/templates/run-test-job.yml @@ -100,7 +100,7 @@ jobs: # TODO: update these numbers as they were determined long ago ${{ if eq(parameters.testGroup, 'innerloop') }}: timeoutInMinutes: 150 - ${{ if in(parameters.testGroup, 'outerloop') }}: + ${{ if in(parameters.testGroup, 'outerloop', 'jit-experimental') }}: timeoutInMinutes: 270 ${{ if in(parameters.testGroup, 'gc-longrunning', 'gc-simulator') }}: timeoutInMinutes: 480 @@ -232,7 +232,7 @@ jobs: ${{ if and(ne(parameters.corefxTests, true), eq(parameters.testGroup, 'innerloop')) }}: timeoutPerTestCollectionInMinutes: 30 timeoutPerTestInMinutes: 10 - ${{ if in(parameters.testGroup, 'outerloop') }}: + ${{ if in(parameters.testGroup, 'outerloop', 'jit-experimental') }}: timeoutPerTestCollectionInMinutes: 120 timeoutPerTestInMinutes: 10 ${{ if in(parameters.testGroup, 'gc-longrunning', 'gc-simulator') }}: @@ -378,6 +378,13 @@ jobs: scenarios: - jitelthookenabled - jitelthookenabled_tiered + ${{ if in(parameters.testGroup, 'jit-experimental') }}: + scenarios: + - jitosr + - jitosr_stress + - jitguardeddevirtualization + - jitehwritethru + - jitobjectstackallocation # Publish Logs - task: PublishPipelineArtifact@1 diff --git a/eng/pipelines/libraries/base-job.yml b/eng/pipelines/libraries/base-job.yml index 85ea99f75c30f5..e24d0d3328bbc4 100644 --- a/eng/pipelines/libraries/base-job.yml +++ b/eng/pipelines/libraries/base-job.yml @@ -40,7 +40,8 @@ jobs: - _BuildConfig: ${{ parameters.buildConfig }} - _msbuildCommonParameters: '' - - _stripSymbolsArg: '' + # rename this variable, due to collision with build-native.proj + - _stripSymbolsArgYaml: '' - _runtimeOSArg: '' - _finalFrameworkArg: '' - _buildScript: $(_buildScriptFileName)$(scriptExt) @@ -70,6 +71,10 @@ jobs: - ${{ if eq(parameters.osGroup, 'WebAssembly') }}: - _runtimeOSArg: -os ${{ parameters.osGroup }} + # force a value for OS when cross-building iOS on OSX + - ${{ if eq(parameters.osGroup, 'iOS') }}: + - _runtimeOSArg: -os ${{ parameters.osGroup }} + - ${{ if ne(parameters.framework, '') }}: - _finalFrameworkArg: -framework ${{ parameters.framework }} - _extraHelixArguments: /p:BuildTargetFramework=${{ parameters.framework }} @@ -107,9 +112,9 @@ jobs: - ${{ if ne(parameters.osGroup, 'Windows_NT') }}: - _buildScript: ./$(_buildScriptFileName)$(scriptExt) - ${{ if eq(parameters.isOfficialBuild, 'true') }}: - - _stripSymbolsArg: -stripSymbols + - _stripSymbolsArgYaml: -stripSymbols - - _buildArguments: -configuration ${{ parameters.buildConfig }} -ci -arch ${{ parameters.archType }} $(_finalFrameworkArg) $(_stripSymbolsArg) $(_testScopeArg) $(_warnAsErrorArg) $(_runtimeOSArg) $(_msbuildCommonParameters) $(_runtimeArtifactsPathArg) $(_crossBuildPropertyArg) + - _buildArguments: -configuration ${{ parameters.buildConfig }} -ci -arch ${{ parameters.archType }} $(_finalFrameworkArg) $(_stripSymbolsArgYaml) $(_testScopeArg) $(_warnAsErrorArg) $(_runtimeOSArg) $(_msbuildCommonParameters) $(_runtimeArtifactsPathArg) $(_crossBuildPropertyArg) - ${{ parameters.variables }} dependsOn: diff --git a/eng/pipelines/mono/templates/build-job.yml b/eng/pipelines/mono/templates/build-job.yml index d23bfded5a4e8f..e554e749a1c83c 100644 --- a/eng/pipelines/mono/templates/build-job.yml +++ b/eng/pipelines/mono/templates/build-job.yml @@ -67,6 +67,9 @@ jobs: value: /p:OutputRid=linux-musl-${{ parameters.archType }} - name: _PortableBuild value: true + - ${{ if eq(parameters.osGroup, 'iOS') }}: + - name: osOverride + value: -os iOS - ${{ parameters.variables }} steps: @@ -75,7 +78,7 @@ jobs: # Linux builds use docker images with dependencies preinstalled, # and FreeBSD builds use a build agent with dependencies # preinstalled, so we only need this step for OSX and Windows. - - ${{ if eq(parameters.osGroup, 'OSX') }}: + - ${{ if in(parameters.osGroup, 'OSX', 'iOS') }}: - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup) displayName: Install native dependencies - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: @@ -85,10 +88,10 @@ jobs: # Build - ${{ if ne(parameters.osGroup, 'Windows_NT') }}: - - script: ./mono$(scriptExt) -configuration $(buildConfig) -arch $(archType) -ci /p:MonoEnableLLVM=${{ parameters.llvm }} + - script: ./mono$(scriptExt) -configuration $(buildConfig) -arch $(archType) $(osOverride) -ci /p:MonoEnableLLVM=${{ parameters.llvm }} displayName: Build product - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: - - script: mono$(scriptExt) -configuration $(buildConfig) -arch $(archType) -ci /p:MonoEnableLLVM=${{ parameters.llvm }} + - script: mono$(scriptExt) -configuration $(buildConfig) -arch $(archType) $(osOverride) -ci /p:MonoEnableLLVM=${{ parameters.llvm }} displayName: Build product # Publish product output directory for consumption by tests. @@ -104,10 +107,10 @@ jobs: # Build packages - ${{ if and(ne(parameters.llvm, true), ne(parameters.osGroup, 'Windows_NT')) }}: - - script: ./mono$(scriptExt) -configuration $(buildConfig) -arch $(archType) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }} -pack $(OutputRidArg) + - script: ./mono$(scriptExt) -configuration $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }} -pack $(OutputRidArg) displayName: Build nupkg - ${{ if and(ne(parameters.llvm, true), eq(parameters.osGroup, 'Windows_NT')) }}: - - script: mono$(scriptExt) -configuration $(buildConfig) -arch $(archType) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }} -pack $(OutputRidArg) + - script: mono$(scriptExt) -configuration $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }} -pack $(OutputRidArg) displayName: Build nupkg # Save packages using the prepare-signed-artifacts format. diff --git a/eng/pipelines/mono/templates/xplat-job.yml b/eng/pipelines/mono/templates/xplat-job.yml index 8d7465d7f88453..2cd61dc7e7f3e4 100644 --- a/eng/pipelines/mono/templates/xplat-job.yml +++ b/eng/pipelines/mono/templates/xplat-job.yml @@ -56,7 +56,7 @@ jobs: agentOs: Ubuntu ${{ if eq(parameters.osGroup, 'FreeBSD') }}: agentOs: FreeBSD - ${{ if eq(parameters.osGroup, 'OSX') }}: + ${{ if in(parameters.osGroup, 'OSX', 'iOS') }}: agentOs: MacOS ${{ if eq(parameters.osGroup, 'Windows_NT') }}: agentOs: Windows_NT diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index 7619c2e533e1b8..a49a4b1bbda73e 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -69,6 +69,9 @@ stages: runtimeFlavor: mono buildConfig: release platforms: + - iOS_x64 + - iOS_arm + - iOS_arm64 - OSX_x64 - Linux_x64 - Linux_arm @@ -104,6 +107,22 @@ stages: isOfficialBuild: ${{ variables.isOfficialBuild }} liveRuntimeBuildConfig: release + # + # Build libraries using live CoreLib from Mono + # + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/libraries/build-job.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - iOS_x64 + - iOS_arm + - iOS_arm64 + jobParameters: + isOfficialBuild: ${{ variables.isOfficialBuild }} + liveRuntimeBuildConfig: release + # # Build libraries AllConfigurations for packages # diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 4965c687d5ba2a..8f909825a4311b 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -154,7 +154,7 @@ jobs: - Linux_x64 jobParameters: testGroup: innerloop - useGCC: true + compilerName: gcc condition: >- or( eq(dependencies.checkout.outputs['SetPathVars_coreclr.containsChange'], true), @@ -202,7 +202,8 @@ jobs: # # Build CoreCLR Formatting Job -# Only when CoreCLR is changed +# Only when CoreCLR is changed, and only in the 'master' branch (no release branches; +# both CI and PR builds). # - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -212,9 +213,13 @@ jobs: - Windows_NT_x64 jobParameters: condition: >- - or( - eq(dependencies.checkout.outputs['SetPathVars_coreclr.containsChange'], true), - eq(variables['isFullMatrix'], true)) + and( + or( + eq(variables['Build.SourceBranchName'], 'master'), + eq(variables['System.PullRequest.TargetBranch'], 'master')), + or( + eq(dependencies.checkout.outputs['SetPathVars_coreclr.containsChange'], true), + eq(variables['isFullMatrix'], true))) # # Build Mono debug @@ -226,6 +231,9 @@ jobs: runtimeFlavor: mono buildConfig: debug platforms: + - iOS_x64 + - iOS_arm + - iOS_arm64 - OSX_x64 - Linux_x64 - Linux_arm @@ -253,6 +261,9 @@ jobs: runtimeFlavor: mono buildConfig: release platforms: + - iOS_x64 + - iOS_arm + - iOS_arm64 - OSX_x64 - Linux_x64 - Linux_arm @@ -357,6 +368,34 @@ jobs: - Windows_NT_x64 jobParameters: liveRuntimeBuildConfig: release + +# +# Build libraries using Mono CoreLib only +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/libraries/build-job.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - iOS_arm + - iOS_arm64 + - iOS_x64 + jobParameters: + liveRuntimeBuildConfig: release + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/libraries/build-job.yml + buildConfig: Debug + runtimeFlavor: mono + platforms: + - iOS_arm + - iOS_arm64 + - iOS_x64 + jobParameters: + liveRuntimeBuildConfig: debug + # # Libraries Build that only run when libraries is changed # diff --git a/global.json b/global.json index 6d71700e679e06..d3834c617f6cef 100644 --- a/global.json +++ b/global.json @@ -5,17 +5,17 @@ "rollForward": "major" }, "tools": { - "dotnet": "5.0.100-preview.2.20157.1" + "dotnet": "5.0.100-preview.3.20168.11" }, "native-tools": { "cmake": "3.14.2", - "python": "2.7.15" + "python3": "3.7.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "5.0.0-beta.20162.3", - "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20162.3", - "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "5.0.0-beta.20162.3", - "Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20162.3", + "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "5.0.0-beta.20168.2", + "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20168.2", + "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "5.0.0-beta.20168.2", + "Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20168.2", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", "Microsoft.NET.Sdk.IL": "5.0.0-alpha.1.20076.2", "Microsoft.Build.NoTargets": "1.0.53", diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 7e2b66caeec025..0e75f4473640dd 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_policy(SET CMP0042 NEW) # Set the project name project(CoreCLR) -include(${CLR_ENG_NATIVE_DIR}/configureplatform.cmake) +include(${CLR_ENG_NATIVE_DIR}/configuretools.cmake) if (CLR_CMAKE_HOST_WIN32) message(STATUS "VS_PLATFORM_TOOLSET is ${CMAKE_VS_PLATFORM_TOOLSET}") @@ -30,7 +30,6 @@ if(CORECLR_SET_RPATH) endif(CORECLR_SET_RPATH) OPTION(CLR_CMAKE_ENABLE_CODE_COVERAGE "Enable code coverage" OFF) -OPTION(CLR_CMAKE_WARNINGS_ARE_ERRORS "Warnings are errors" ON) # Ensure other tools are present if (CLR_CMAKE_HOST_WIN32) @@ -110,11 +109,14 @@ else (CLR_CMAKE_HOST_WIN32) endif() endif(CLR_CMAKE_HOST_WIN32) +if(CLR_CMAKE_TARGET_ANDROID) + add_definitions(-DTARGET_ANDROID) +endif() + #---------------------------------------------------- # Configure compiler settings for environment #---------------------------------------------------- include(configurecompiler.cmake) -include(${CLR_ENG_NATIVE_DIR}/configuretools.cmake) #---------------------------------------------------- # Cross target Component build specific configuration @@ -141,6 +143,18 @@ endif(NOT CLR_CROSS_COMPONENTS_BUILD) # - do not depend on clr's compile definitions #----------------------------------------- if(CLR_CMAKE_HOST_UNIX) + if(CLR_CMAKE_TARGET_ANDROID) + find_library(LZMA NAMES lzma) + if(LZMA STREQUAL LZMA-NOTFOUND) + message(FATAL_ERROR "Cannot find liblzma.") + endif(LZMA STREQUAL LZMA-NOTFOUND) + + find_library(ANDROID_GLOB NAMES android-glob) + if(ANDROID_GLOB STREQUAL ANDROID_GLOB-NOTFOUND) + message(FATAL_ERROR "Cannot find android-glob.") + endif() + endif() + add_subdirectory(src/pal) add_subdirectory(src/hosts) endif(CLR_CMAKE_HOST_UNIX) diff --git a/src/coreclr/build-runtime.sh b/src/coreclr/build-runtime.sh index 0de4a51ce5f091..b22383cfaa7556 100755 --- a/src/coreclr/build-runtime.sh +++ b/src/coreclr/build-runtime.sh @@ -105,11 +105,6 @@ build_cross_architecture_components() handle_arguments_local() { case "$1" in - ignorewarnings|-ignorewarnings) - __IgnoreWarnings=1 - __CMakeArgs="-DCLR_CMAKE_WARNINGS_ARE_ERRORS=OFF $__CMakeArgs" - ;; - nopgooptimize|-nopgooptimize) __PgoOptimize=0 __SkipRestoreOptData=1 @@ -149,7 +144,6 @@ __RepoRootDir="$(cd "$__ProjectRoot"/../..; pwd -P)" __BuildArch= __BuildType=Debug __CodeCoverage=0 -__IgnoreWarnings=0 # Set the various build properties here so that CMake and MSBuild can pick them up __Compiler=clang diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index a58e3af0d76043..2ea61f45e3177a 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -1,9 +1,5 @@ include(clrfeatures.cmake) -# If set, indicates that this is not an officially supported release -# Keep in sync with IsPrerelease in dir.props -set(PRERELEASE 1) - # Features we're currently flighting, but don't intend to ship in officially supported releases if (PRERELEASE) add_definitions(-DFEATURE_UTF8STRING) @@ -197,6 +193,9 @@ endif(FEATURE_ENABLE_NO_ADDRESS_SPACE_RANDOMIZATION) add_definitions(-DFEATURE_SVR_GC) add_definitions(-DFEATURE_SYMDIFF) add_compile_definitions($<$>>:FEATURE_TIERED_COMPILATION>) +if (CLR_CMAKE_TARGET_ARCH_AMD64) + add_compile_definitions($<$>>:FEATURE_ON_STACK_REPLACEMENT>) +endif (CLR_CMAKE_TARGET_ARCH_AMD64) if (CLR_CMAKE_TARGET_WIN32) add_definitions(-DFEATURE_TYPEEQUIVALENCE) endif(CLR_CMAKE_TARGET_WIN32) diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake index 078b4e73ac8044..9025602a3c68c3 100644 --- a/src/coreclr/clrfeatures.cmake +++ b/src/coreclr/clrfeatures.cmake @@ -11,7 +11,7 @@ if(NOT DEFINED FEATURE_PERFTRACING AND FEATURE_EVENT_TRACE) endif(NOT DEFINED FEATURE_PERFTRACING AND FEATURE_EVENT_TRACE) if(NOT DEFINED FEATURE_DBGIPC) - if(CLR_CMAKE_TARGET_UNIX AND (NOT CLR_CMAKE_TARGET_ANDROID)) + if(CLR_CMAKE_TARGET_UNIX) set(FEATURE_DBGIPC 1) endif() endif(NOT DEFINED FEATURE_DBGIPC) diff --git a/src/coreclr/configurecompiler.cmake b/src/coreclr/configurecompiler.cmake index 792ea045f05086..c460aad3908e81 100644 --- a/src/coreclr/configurecompiler.cmake +++ b/src/coreclr/configurecompiler.cmake @@ -288,10 +288,10 @@ if (CLR_CMAKE_HOST_UNIX) endif() endif(CLR_CMAKE_HOST_DARWIN) - if (CLR_CMAKE_WARNINGS_ARE_ERRORS) - # All warnings that are not explicitly disabled are reported as errors + # Suppress warnings-as-errors in release branches to reduce servicing churn + if (PRERELEASE) add_compile_options(-Werror) - endif(CLR_CMAKE_WARNINGS_ARE_ERRORS) + endif(PRERELEASE) # Disabled common warnings add_compile_options(-Wno-unused-variable) diff --git a/src/coreclr/dir.common.props b/src/coreclr/dir.common.props index 0758a5f404b915..5ab02aec8387c1 100644 --- a/src/coreclr/dir.common.props +++ b/src/coreclr/dir.common.props @@ -33,14 +33,12 @@ - $(MSBuildThisFileDirectory)..\..\ $(MSBuildThisFileDirectory) - $(RootRepoDir)artifacts\obj\coreclr\$(MSBuildProjectName)\ + $(RepoRoot)artifacts\obj\coreclr\$(MSBuildProjectName)\ $(ProjectDir)src\ - $(RootRepoDir)artifacts\ - $(RootBinDir)bin\coreclr\$(PlatformConfigPathPart)\ + $(ArtifactsDir)bin\coreclr\$(PlatformConfigPathPart)\ false $(PackageVersion) - - preview8 @@ -83,21 +79,6 @@ Portable - - - - - coreclr - - - true - - - - - true - - false diff --git a/src/coreclr/src/CMakeLists.txt b/src/coreclr/src/CMakeLists.txt index b6584b2de78301..262e6b7d021c3e 100644 --- a/src/coreclr/src/CMakeLists.txt +++ b/src/coreclr/src/CMakeLists.txt @@ -16,9 +16,9 @@ endif(CLR_CMAKE_TARGET_WIN32 AND FEATURE_EVENT_TRACE) add_subdirectory(debug/dbgutil) if(CLR_CMAKE_HOST_UNIX) - if(CLR_CMAKE_HOST_LINUX AND NOT CLR_CMAKE_HOST_UNIX_X86) + if(CLR_CMAKE_HOST_LINUX AND NOT CLR_CMAKE_HOST_UNIX_X86 AND NOT CLR_CMAKE_HOST_ANDROID) add_subdirectory(debug/createdump) - endif(CLR_CMAKE_HOST_LINUX AND NOT CLR_CMAKE_HOST_UNIX_X86) + endif(CLR_CMAKE_HOST_LINUX AND NOT CLR_CMAKE_HOST_UNIX_X86 AND NOT CLR_CMAKE_HOST_ANDROID) # Include the dummy c++ include files include_directories("pal/inc/rt/cpp") diff --git a/src/coreclr/src/System.Private.CoreLib/ILLinkTrim.xml b/src/coreclr/src/System.Private.CoreLib/ILLinkTrim.xml index 1dc8146af724d6..ff08dc62974c14 100644 --- a/src/coreclr/src/System.Private.CoreLib/ILLinkTrim.xml +++ b/src/coreclr/src/System.Private.CoreLib/ILLinkTrim.xml @@ -8,8 +8,6 @@ - - diff --git a/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata b/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata index 5d45345491c369..141a5c2a73ce0d 100644 --- a/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata +++ b/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata @@ -5,3 +5,6 @@ normaliz.dll!NormalizeString user32.dll!GetProcessWindowStation user32.dll!GetUserObjectInformationW + + +kernel32.dll!GetGeoInfo \ No newline at end of file diff --git a/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/WindowsRuntime/ExceptionSupport.cs b/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/WindowsRuntime/ExceptionSupport.cs index 504f428f54d30e..c7feb47db624e7 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/WindowsRuntime/ExceptionSupport.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/WindowsRuntime/ExceptionSupport.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices.WindowsRuntime; namespace Internal.Runtime.InteropServices.WindowsRuntime @@ -13,6 +14,7 @@ public static class ExceptionSupport /// Attach restricted error information to the exception if it may apply to that exception, returning /// back the input value /// + [return: NotNullIfNotNull("e")] public static Exception? AttachRestrictedErrorInfo(Exception? e) { // If there is no exception, then the restricted error info doesn't apply to it diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs b/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs index c71747cb041f9e..fc8a9650f63b7e 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs @@ -84,8 +84,16 @@ public static GCMemoryInfo GetGCMemoryInfo() [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] internal static extern int _EndNoGCRegion(); + // keep in sync with GC_ALLOC_FLAGS in gcinterface.h + internal enum GC_ALLOC_FLAGS + { + GC_ALLOC_NO_FLAGS = 0, + GC_ALLOC_ZEROING_OPTIONAL = 16, + GC_ALLOC_PINNED_OBJECT_HEAP = 64, + }; + [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern Array AllocateNewArray(IntPtr typeHandle, int length, bool zeroingOptional); + internal static extern Array AllocateNewArray(IntPtr typeHandle, int length, GC_ALLOC_FLAGS flags); [MethodImpl(MethodImplOptions.InternalCall)] private static extern int GetGenerationWR(IntPtr handle); @@ -651,31 +659,74 @@ internal static void UnregisterMemoryLoadChangeNotification(Action notification) } /// - /// Skips zero-initialization of the array if possible. - /// If T contains object references, the array is always zero-initialized. + /// Allocate an array while skipping zero-initialization if possible. /// + /// Specifies the type of the array element. + /// Specifies the length of the array. + /// Specifies whether the allocated array must be pinned. + /// + /// If pinned is set to true, must not be a reference type or a type that contains object references. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] // forced to ensure no perf drop for small memory buffers (hot path) - internal static T[] AllocateUninitializedArray(int length) + public static T[] AllocateUninitializedArray(int length, bool pinned = false) { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) + if (!pinned) { - return new T[length]; - } + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + { + return new T[length]; + } - // for debug builds we always want to call AllocateNewArray to detect AllocateNewArray bugs + // for debug builds we always want to call AllocateNewArray to detect AllocateNewArray bugs #if !DEBUG - // small arrays are allocated using `new[]` as that is generally faster. - if (length < 2048 / Unsafe.SizeOf()) + // small arrays are allocated using `new[]` as that is generally faster. + if (length < 2048 / Unsafe.SizeOf()) + { + return new T[length]; + } +#endif + } + else if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - return new T[length]; + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); } -#endif + // kept outside of the small arrays hot path to have inlining without big size growth - return AllocateNewUninitializedArray(length); + return AllocateNewUninitializedArray(length, pinned); // remove the local function when https://github.com/dotnet/coreclr/issues/5329 is implemented - static T[] AllocateNewUninitializedArray(int length) - => Unsafe.As(AllocateNewArray(typeof(T[]).TypeHandle.Value, length, zeroingOptional: true)); + static T[] AllocateNewUninitializedArray(int length, bool pinned) + { + GC_ALLOC_FLAGS flags = GC_ALLOC_FLAGS.GC_ALLOC_ZEROING_OPTIONAL; + if (pinned) + flags |= GC_ALLOC_FLAGS.GC_ALLOC_PINNED_OBJECT_HEAP; + + return Unsafe.As(AllocateNewArray(typeof(T[]).TypeHandle.Value, length, flags)); + } + } + + /// + /// Allocate an array. + /// + /// Specifies the type of the array element. + /// Specifies the length of the array. + /// Specifies whether the allocated array must be pinned. + /// + /// If pinned is set to true, must not be a reference type or a type that contains object references. + /// + public static T[] AllocateArray(int length, bool pinned = false) + { + GC_ALLOC_FLAGS flags = GC_ALLOC_FLAGS.GC_ALLOC_NO_FLAGS; + + if (pinned) + { + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); + + flags = GC_ALLOC_FLAGS.GC_ALLOC_PINNED_OBJECT_HEAP; + } + + return Unsafe.As(AllocateNewArray(typeof(T[]).TypeHandle.Value, length, flags)); } } } diff --git a/src/coreclr/src/ToolBox/SOS/CMakeLists.txt b/src/coreclr/src/ToolBox/SOS/CMakeLists.txt index 1fb8efbfe57b29..e8de022432839e 100644 --- a/src/coreclr/src/ToolBox/SOS/CMakeLists.txt +++ b/src/coreclr/src/ToolBox/SOS/CMakeLists.txt @@ -5,4 +5,3 @@ if(CLR_CMAKE_TARGET_WIN32) endif(CLR_CMAKE_TARGET_WIN32) _install(FILES SOS_README.md DESTINATION .) -_install(FILES SOS_README.md DESTINATION sharedFramework) diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/compileresult.cpp index b8c006040c4f27..5a6f82f5a0ec15 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/compileresult.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/compileresult.cpp @@ -326,6 +326,38 @@ bool CompileResult::repSetVars(CORINFO_METHOD_HANDLE* ftn, ULONG32* cVars, ICorD return true; } +// Note - Ownership of patchpointInfo is transfered with this call. In replay icorjitinfo we should free it. +void CompileResult::recSetPatchpointInfo(PatchpointInfo* patchpointInfo) +{ + if (SetPatchpointInfo == nullptr) + SetPatchpointInfo = new LightWeightMap(); + + Agnostic_SetPatchpointInfo value; + value.index = (DWORD)SetPatchpointInfo->AddBuffer((const unsigned char*) patchpointInfo, patchpointInfo->PatchpointInfoSize()); + SetPatchpointInfo->Add(0, value); +} +void CompileResult::dmpSetPatchpointInfo(DWORD key, const Agnostic_SetPatchpointInfo& value) +{ + PatchpointInfo* patchpointInfo = (PatchpointInfo*)SetPatchpointInfo->GetBuffer(value.index); + printf("SetPatchpointInfo key %u, index %u{", key, value.index); + // todo -- dump contents + printf("}"); + SetPatchpointInfo->Unlock(); +} +bool CompileResult::repSetPatchpointInfo(PatchpointInfo** patchpointInfo) +{ + if ((SetPatchpointInfo == nullptr) || (SetPatchpointInfo->GetCount() == 0)) + { + *patchpointInfo = nullptr; + return false; + } + + Agnostic_SetPatchpointInfo value; + value = SetPatchpointInfo->Get(0); + *patchpointInfo = (PatchpointInfo*)SetPatchpointInfo->GetBuffer(value.index); + return true; +} + void CompileResult::recAllocGCInfo(size_t size, void* retval) { allocGCInfoDets.size = size; diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/compileresult.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/compileresult.h index 9fa9e454462b65..8fce7ab8e9f168 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/compileresult.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/compileresult.h @@ -112,6 +112,10 @@ class CompileResult DWORD cVars; DWORD vars_offset; }; + struct Agnostic_SetPatchpointInfo + { + DWORD index; + }; struct Agnostic_CORINFO_EH_CLAUSE2 { DWORD Flags; @@ -200,6 +204,10 @@ class CompileResult void dmpSetVars(DWORD key, const Agnostic_SetVars& value); bool repSetVars(CORINFO_METHOD_HANDLE* ftn, ULONG32* cVars, ICorDebugInfo::NativeVarInfo** vars); + void recSetPatchpointInfo(PatchpointInfo* patchpointInfo); + void dmpSetPatchpointInfo(DWORD key, const Agnostic_SetPatchpointInfo& value); + bool repSetPatchpointInfo(PatchpointInfo** patchpointInfo); + void recAllocGCInfo(size_t size, void* retval); void recAllocGCInfoCapture(); void dmpAllocGCInfo(DWORD key, const Agnostic_AllocGCInfo& value); diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/crlwmlist.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/crlwmlist.h index 72fa54043a5484..b42077de7abe4f 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/crlwmlist.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/crlwmlist.h @@ -41,6 +41,7 @@ LWM(SetEHcount, DWORD, DWORD) LWM(SetEHinfo, DWORD, CompileResult::Agnostic_CORINFO_EH_CLAUSE2) LWM(SetMethodAttribs, DWORDLONG, DWORD) LWM(SetVars, DWORD, CompileResult::Agnostic_SetVars) +LWM(SetPatchpointInfo, DWORD, CompileResult::Agnostic_SetPatchpointInfo) #undef LWM #undef DENSELWM diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h index ec468a1f04a821..bb642229cc75ad 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h @@ -180,6 +180,15 @@ void getGSCookie(GSCookie* pCookieVal, // OUT GSCookie** ppCookieVal // OUT ); +// Provide patchpoint info for the method currently being jitted. +void setPatchpointInfo( + PatchpointInfo* patchpointInfo + ); + +PatchpointInfo* getOSRInfo( + unsigned * ilOffset // OUT + ); + /**********************************************************************************/ // // ICorModuleInfo diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h index a7b4c019d5c92f..18abd23e676cf2 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h @@ -112,6 +112,7 @@ LWM(GetMethodSync, DWORDLONG, DLDL) LWM(GetMethodVTableOffset, DWORDLONG, DDD) LWM(GetNewArrHelper, DWORDLONG, DWORD) LWM(GetNewHelper, Agnostic_GetNewHelper, DD) +LWM(GetOSRInfo, DWORD, Agnostic_GetOSRInfo) LWM(GetParentType, DWORDLONG, DWORDLONG) LWM(GetProfilingHandle, DWORD, Agnostic_GetProfilingHandle) LWM(GetReadyToRunHelper, GetReadyToRunHelper_TOKENin, GetReadyToRunHelper_TOKENout) @@ -153,5 +154,6 @@ LWM(TryResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, TryResolveTokenValue) LWM(SatisfiesClassConstraints, DWORDLONG, DWORD) LWM(SatisfiesMethodConstraints, DLDL, DWORD) + #undef LWM #undef DENSELWM diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index 4ca96bd58a4c1e..a988f27211322a 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -727,6 +727,7 @@ void MethodContext::repCompileMethod(CORINFO_METHOD_INFO* info, unsigned* flags) info->locals.pSig = (PCCOR_SIGNATURE)CompileMethod->GetBuffer(value.info.locals.pSig_Index); info->locals.scope = (CORINFO_MODULE_HANDLE)value.info.locals.scope; info->locals.token = (mdToken)value.info.locals.token; + *flags = (unsigned)value.flags; DEBUG_REP(dmpCompileMethod(0, value)); } @@ -1124,7 +1125,7 @@ void MethodContext::recGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes, DW void MethodContext::dmpGetJitFlags(DWORD key, DD value) { CORJIT_FLAGS* jitflags = (CORJIT_FLAGS*)GetJitFlags->GetBuffer(value.A); - printf("GetJitFlags key %u sizeInBytes-%u jitFlags-%016llX", key, value.B, jitflags->GetFlagsRaw()); + printf("GetJitFlags key %u sizeInBytes-%u jitFlags-%016llX instructionSetFlags-%016llX", key, value.B, jitflags->GetFlagsRaw(), jitflags->GetInstructionSetFlagsRaw()); GetJitFlags->Unlock(); } DWORD MethodContext::repGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes) @@ -3965,6 +3966,39 @@ void MethodContext::repGetGSCookie(GSCookie* pCookieVal, GSCookie** ppCookieVal) *ppCookieVal = (GSCookie*)value.B; } +void MethodContext::recGetOSRInfo(PatchpointInfo* patchpointInfo, unsigned* ilOffset) +{ + if (GetOSRInfo == nullptr) + { + GetOSRInfo = new LightWeightMap(); + } + + Agnostic_GetOSRInfo value; + + value.index = (DWORD)GetOSRInfo->AddBuffer((const unsigned char*) patchpointInfo, patchpointInfo->PatchpointInfoSize()); + value.ilOffset = *ilOffset; + + // use 0 for key + DWORD key = 0; + GetOSRInfo->Add(key, value); + DEBUG_REC(dmpGetOSRInfo(key, value)); +} + +void MethodContext::dmpGetOSRInfo(DWORD key, const Agnostic_GetOSRInfo& value) +{ + // todo - dump patchpoint info? + printf("GetOSRInfo key %u, value patchpointInfo-%u {...} iloffset-%u\n", + key, value.index, value.ilOffset); +} + +PatchpointInfo* MethodContext::repGetOSRInfo(unsigned* ilOffset) +{ + DWORD key = 0; + Agnostic_GetOSRInfo value = GetOSRInfo->Get(key); + *ilOffset = value.ilOffset; + return (PatchpointInfo*)GetOSRInfo->GetBuffer(value.index); +} + void MethodContext::recGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, void** ppIndirection, diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h index 0e7ee454a9ed4a..f87703d6d131b6 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -176,6 +176,11 @@ class MethodContext DWORD targetAbi; DWORD osType; }; + struct Agnostic_GetOSRInfo + { + DWORD index; + unsigned ilOffset; + }; struct Agnostic_GetFieldAddress { DWORDLONG ppIndirection; @@ -1000,6 +1005,10 @@ class MethodContext void dmpGetGSCookie(DWORD key, DLDL value); void repGetGSCookie(GSCookie* pCookieVal, GSCookie** ppCookieVal); + void recGetOSRInfo(PatchpointInfo* patchpointInfo, unsigned* ilOffset); + void dmpGetOSRInfo(DWORD key, const Agnostic_GetOSRInfo& value); + PatchpointInfo* repGetOSRInfo(unsigned* ilOffset); + void recGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, void** ppIndirection, @@ -1335,7 +1344,7 @@ class MethodContext }; // ********************* Please keep this up-to-date to ease adding more *************** -// Highest packet number: 175 +// Highest packet number: 177 // ************************************************************************************* enum mcPackets { @@ -1446,6 +1455,7 @@ enum mcPackets Packet_GetMethodVTableOffset = 78, Packet_GetNewArrHelper = 79, Packet_GetNewHelper = 80, + Packet_GetOSRInfo = 177, // Added 3/5/2020 Packet_GetParentType = 81, Packet_GetPInvokeUnmanagedTarget = 82, // Retired 2/18/2020 Packet_GetProfilingHandle = 83, @@ -1514,6 +1524,7 @@ enum mcPackets PacketCR_SetEHinfo = 128, PacketCR_SetMethodAttribs = 129, PacketCR_SetVars = 130, + PacketCR_SetPatchpointInfo = 176, // added 8/5/2019 PacketCR_RecordCallSite = 146, // Added 10/28/2013 - to support indirect calls }; diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/runtimedetails.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/runtimedetails.h index 3d6c7e23512d5b..a8723ce16b9f8d 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/runtimedetails.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/runtimedetails.h @@ -25,6 +25,7 @@ #include #include #include +#include /// Turn back on direct access to a few OS level things... #undef HeapCreate diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp index c7235d08169210..603ebb6e54eeae 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -365,6 +365,23 @@ void interceptor_ICJI::getGSCookie(GSCookie* pCookieVal, // OUT mc->recGetGSCookie(pCookieVal, ppCookieVal); } +// Provide patchpoint info for the method currently being jitted. +void interceptor_ICJI::setPatchpointInfo(PatchpointInfo* patchpointInfo) +{ + mc->cr->AddCall("setPatchpointInfo"); + mc->cr->recSetPatchpointInfo(patchpointInfo); // Since the EE frees, we've gotta record before its sent to the EE. + original_ICorJitInfo->setPatchpointInfo(patchpointInfo); +} + +// Get OSR info for the method currently being jitted +PatchpointInfo* interceptor_ICJI::getOSRInfo(unsigned* ilOffset) +{ + mc->cr->AddCall("getOSRInfo"); + PatchpointInfo* patchpointInfo = original_ICorJitInfo->getOSRInfo(ilOffset); + mc->recGetOSRInfo(patchpointInfo, ilOffset); + return patchpointInfo; +} + /**********************************************************************************/ // // ICorModuleInfo diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp index e2792149e87e28..4974c13bb39404 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -262,6 +262,20 @@ void interceptor_ICJI::getGSCookie(GSCookie* pCookieVal, // OUT original_ICorJitInfo->getGSCookie(pCookieVal, ppCookieVal); } +// Provide patchpoint info for the method currently being jitted. +void interceptor_ICJI::setPatchpointInfo(PatchpointInfo* patchpointInfo) +{ + mcs->AddCall("setPatchpointInfo"); + original_ICorJitInfo->setPatchpointInfo(patchpointInfo); +} + +// Get OSR info for the method currently being jitted +PatchpointInfo* interceptor_ICJI::getOSRInfo(unsigned* ilOffset) +{ + mcs->AddCall("getOSRInfo"); + return original_ICorJitInfo->getOSRInfo(ilOffset); +} + /**********************************************************************************/ // // ICorModuleInfo diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp index 71b0fa5ba40e7a..0cf00e3b9c90e3 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -237,6 +237,19 @@ void interceptor_ICJI::getGSCookie(GSCookie* pCookieVal, // OUT original_ICorJitInfo->getGSCookie(pCookieVal, ppCookieVal); } + +// Provide patchpoint info for the method currently being jitted. +void interceptor_ICJI::setPatchpointInfo(PatchpointInfo* patchpointInfo) +{ + original_ICorJitInfo->setPatchpointInfo(patchpointInfo); +} + +// Get OSR info for the method currently being jitted +PatchpointInfo* interceptor_ICJI::getOSRInfo(unsigned* ilOffset) +{ + return original_ICorJitInfo->getOSRInfo(ilOffset); +} + /**********************************************************************************/ // // ICorModuleInfo diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp index c6085854efca6f..4b6b2d4aa73381 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp @@ -288,6 +288,21 @@ void MyICJI::getGSCookie(GSCookie* pCookieVal, // OUT jitInstance->mc->repGetGSCookie(pCookieVal, ppCookieVal); } +// Provide patchpoint info for the method currently being jitted. +void MyICJI::setPatchpointInfo(PatchpointInfo* patchpointInfo) +{ + jitInstance->mc->cr->AddCall("setPatchpointInfo"); + jitInstance->mc->cr->recSetPatchpointInfo(patchpointInfo); + freeArray(patchpointInfo); // See note in recSetPatchpointInfo... we own destroying this array +} + +// Get OSR info for the method currently being jitted +PatchpointInfo* MyICJI::getOSRInfo(unsigned* ilOffset) +{ + jitInstance->mc->cr->AddCall("getOSRInfo"); + return jitInstance->mc->repGetOSRInfo(ilOffset); +} + /**********************************************************************************/ // // ICorModuleInfo diff --git a/src/coreclr/src/debug/daccess/daccess.cpp b/src/coreclr/src/debug/daccess/daccess.cpp index fea12eb75fcacc..cf25b1c4eb5461 100644 --- a/src/coreclr/src/debug/daccess/daccess.cpp +++ b/src/coreclr/src/debug/daccess/daccess.cpp @@ -5615,12 +5615,7 @@ ClrDataAccess::Initialize(void) // Thus, when DAC is initialized, initialize utilcode with the base address of the runtime loaded in the // target process. This is similar to work done in CorDB::SetTargetCLR for mscordbi. - // Initialize UtilCode for SxS scenarios - CoreClrCallbacks cccallbacks; - cccallbacks.m_hmodCoreCLR = (HINSTANCE)m_globalBase; // Base address of the runtime in the target process - cccallbacks.m_pfnIEE = NULL; - cccallbacks.m_pfnGetCORSystemDirectory = NULL; - InitUtilcode(cccallbacks); + g_hmodCoreCLR = (HINSTANCE)m_globalBase; // Base address of the runtime in the target process return S_OK; } diff --git a/src/coreclr/src/debug/dbgutil/CMakeLists.txt b/src/coreclr/src/debug/dbgutil/CMakeLists.txt index 0ff9188e0c3511..bd96e9baa1e052 100644 --- a/src/coreclr/src/debug/dbgutil/CMakeLists.txt +++ b/src/coreclr/src/debug/dbgutil/CMakeLists.txt @@ -1,12 +1,11 @@ +set(CMAKE_INCLUDE_CURRENT_DIR ON) + if(CLR_CMAKE_HOST_WIN32) + include_directories(${CLR_DIR}/src/inc/llvm) #use static crt add_definitions(-MT) endif(CLR_CMAKE_HOST_WIN32) -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -include_directories(${CLR_DIR}/src/inc/llvm) - add_definitions(-DPAL_STDCPP_COMPAT) if(CLR_CMAKE_TARGET_ALPINE_LINUX) diff --git a/src/coreclr/src/debug/di/rsmain.cpp b/src/coreclr/src/debug/di/rsmain.cpp index f58026a889ed9a..5ab2d7d685f9e8 100644 --- a/src/coreclr/src/debug/di/rsmain.cpp +++ b/src/coreclr/src/debug/di/rsmain.cpp @@ -1433,11 +1433,7 @@ HRESULT Cordb::SetTargetCLR(HMODULE hmodTargetCLR) // the same model because coreclr.dll isn't in this process and hmodTargetCLR // is the debuggee target, not the coreclr.dll to bind utilcode to.. - CoreClrCallbacks cccallbacks; - cccallbacks.m_hmodCoreCLR = hmodTargetCLR; - cccallbacks.m_pfnIEE = NULL; - cccallbacks.m_pfnGetCORSystemDirectory = NULL; - InitUtilcode(cccallbacks); + g_hmodCoreCLR = hmodTargetCLR; return S_OK; } diff --git a/src/coreclr/src/debug/ee/controller.h b/src/coreclr/src/debug/ee/controller.h index 2775fe6f21aa5b..155b020b01c74b 100644 --- a/src/coreclr/src/debug/ee/controller.h +++ b/src/coreclr/src/debug/ee/controller.h @@ -1174,8 +1174,6 @@ class DebuggerController virtual void DebuggerDetachClean(); public: - static const BYTE *g_pMSCorEEStart, *g_pMSCorEEEnd; - static const BYTE *GetILPrestubDestination(const BYTE *prestub); static const BYTE *GetILFunctionCode(MethodDesc *fd); diff --git a/src/coreclr/src/debug/ee/debugger.cpp b/src/coreclr/src/debug/ee/debugger.cpp index 93d0edc6838d34..cbf6df50871e5e 100644 --- a/src/coreclr/src/debug/ee/debugger.cpp +++ b/src/coreclr/src/debug/ee/debugger.cpp @@ -1751,7 +1751,7 @@ void Debugger::SendRawEvent(const DebuggerIPCEvent * pManagedEvent) // The debugger can then use ReadProcessMemory to read through this array. ULONG_PTR rgData [] = { CLRDBG_EXCEPTION_DATA_CHECKSUM, - (ULONG_PTR) g_pMSCorEE, + (ULONG_PTR) g_hThisInst, (ULONG_PTR) pManagedEvent }; @@ -5669,7 +5669,7 @@ bool Debugger::FirstChanceNativeException(EXCEPTION_RECORD *exception, // Ignore any notification exceptions sent from code:Debugger.SendRawEvent. // This is not a common case, but could happen in some cases described // in SendRawEvent. Either way, Left-Side and VM should just ignore these. - if (IsEventDebuggerNotification(exception, PTR_TO_CORDB_ADDRESS(g_pMSCorEE))) + if (IsEventDebuggerNotification(exception, PTR_TO_CORDB_ADDRESS(g_hThisInst))) { return true; } @@ -12363,7 +12363,7 @@ void Debugger::GetAndSendTransitionStubInfo(CORDB_ADDRESS_TYPE *stubAddress) // If its not a stub, then maybe its an address in mscoree? if (result == false) { - result = (IsIPInModule(g_pMSCorEE, (PCODE)stubAddress) == TRUE); + result = (IsIPInModule(g_hThisInst, (PCODE)stubAddress) == TRUE); } // This is a synchronous event (reply required) diff --git a/src/coreclr/src/debug/ee/rcthread.cpp b/src/coreclr/src/debug/ee/rcthread.cpp index 87111404374a5f..85186e080034fa 100644 --- a/src/coreclr/src/debug/ee/rcthread.cpp +++ b/src/coreclr/src/debug/ee/rcthread.cpp @@ -17,7 +17,6 @@ #include "securitywrapper.h" #endif #include -#include #include "eemessagebox.h" diff --git a/src/coreclr/src/debug/inc/common.h b/src/coreclr/src/debug/inc/common.h index 034d9bb241022e..e31ac3aac6c371 100644 --- a/src/coreclr/src/debug/inc/common.h +++ b/src/coreclr/src/debug/inc/common.h @@ -205,10 +205,6 @@ HRESULT FindNativeInfoInILVariableArray(DWORD dwIndex, unsigned int nativeInfoCount, ICorDebugInfo::NativeVarInfo *nativeInfo); - -#define VALIDATE_HEAP -//HeapValidate(GetProcessHeap(), 0, NULL); - // struct DebuggerILToNativeMap: Holds the IL to Native offset map // Great pains are taken to ensure that this each entry corresponds to the // first IL instruction in a source line. It isn't actually a mapping diff --git a/src/coreclr/src/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/src/dlls/mscoree/coreclr/CMakeLists.txt index e86e91f6a69e88..0517bb50df3218 100644 --- a/src/coreclr/src/dlls/mscoree/coreclr/CMakeLists.txt +++ b/src/coreclr/src/dlls/mscoree/coreclr/CMakeLists.txt @@ -57,6 +57,10 @@ else(CLR_CMAKE_HOST_WIN32) set(EXPORTS_LINKER_OPTION -Wl,-exported_symbols_list,${EXPORTS_FILE}) endif(CLR_CMAKE_TARGET_DARWIN) + if(CLR_CMAKE_TARGET_ANDROID AND CLR_CMAKE_HOST_ARCH_ARM) + set(EXPORTS_LINKER_OPTION "${EXPORTS_LINKER_OPTION} -Wl,--no-warn-shared-textrel") + endif() + endif (CLR_CMAKE_HOST_WIN32) add_definitions(-DFX_VER_INTERNALNAME_STR=CoreCLR.dll) diff --git a/src/coreclr/src/dlls/mscoree/mscoree.cpp b/src/coreclr/src/dlls/mscoree/mscoree.cpp index 2a8c7875b87c34..d87d9bebc0ca02 100644 --- a/src/coreclr/src/dlls/mscoree/mscoree.cpp +++ b/src/coreclr/src/dlls/mscoree/mscoree.cpp @@ -20,15 +20,15 @@ #include +// Globals +extern HINSTANCE g_hThisInst; + // Locals. BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error. HINSTANCE hInst, // Instance handle of the loaded module. DWORD dwReason, // Reason for loading. LPVOID lpReserved); // Unused. -// Globals. -HINSTANCE g_hThisInst; // This library. - #ifndef CROSSGEN_COMPILE //***************************************************************************** // Handle lifetime of loaded library. @@ -36,8 +36,6 @@ HINSTANCE g_hThisInst; // This library. #include -extern "C" IExecutionEngine* IEE(); - #ifdef TARGET_WINDOWS #include // for __security_init_cookie() @@ -62,15 +60,11 @@ extern "C" BOOL WINAPI CoreDllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpRe // Initialization" check and makes it pass. __security_init_cookie(); - // It's critical that we invoke InitUtilCode() before the CRT initializes. + // It's critical that we initialize g_hmodCoreCLR before the CRT initializes. // We have a lot of global ctors that will break if we let the CRT initialize without // this step having been done. - CoreClrCallbacks cccallbacks; - cccallbacks.m_hmodCoreCLR = (HINSTANCE)hInstance; - cccallbacks.m_pfnIEE = IEE; - cccallbacks.m_pfnGetCORSystemDirectory = GetCORSystemDirectoryInternaL; - InitUtilcode(cccallbacks); + g_hmodCoreCLR = (HINSTANCE)hInstance; if (!(result = _CRT_INIT(hInstance, dwReason, lpReserved))) { @@ -115,15 +109,7 @@ BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved) case DLL_PROCESS_ATTACH: { #ifndef TARGET_WINDOWS - // It's critical that we invoke InitUtilCode() before the CRT initializes. - // We have a lot of global ctors that will break if we let the CRT initialize without - // this step having been done. - - CoreClrCallbacks cccallbacks; - cccallbacks.m_hmodCoreCLR = (HINSTANCE)hInstance; - cccallbacks.m_pfnIEE = IEE; - cccallbacks.m_pfnGetCORSystemDirectory = GetCORSystemDirectoryInternaL; - InitUtilcode(cccallbacks); + g_hmodCoreCLR = (HINSTANCE)hInstance; #endif // Save the module handle. diff --git a/src/coreclr/src/dlls/mscorpe/ceefilegenwriter.cpp b/src/coreclr/src/dlls/mscorpe/ceefilegenwriter.cpp index 8c18573c1b518e..1de4e817eab78a 100644 --- a/src/coreclr/src/dlls/mscorpe/ceefilegenwriter.cpp +++ b/src/coreclr/src/dlls/mscorpe/ceefilegenwriter.cpp @@ -17,10 +17,6 @@ #include #include -// Globals. -HINSTANCE g_hThisInst; // This library. - - #ifdef EMIT_FIXUPS // Emitted PEFIXUP structure looks like this @@ -941,178 +937,11 @@ HRESULT CeeFileGenWriter::emitExeMain() return S_OK; } // HRESULT CeeFileGenWriter::emitExeMain() - -HRESULT GetClrSystemDirectory(SString& pbuffer) -{ - HRESULT hr = S_OK; - - - PathString pPath; - DWORD dwPath; - - _ASSERTE (g_hThisInst); - - dwPath = WszGetModuleFileName(g_hThisInst, pPath); - if(dwPath == 0) - { - hr = HRESULT_FROM_GetLastErrorNA(); - return (hr); - } - - return CopySystemDirectory(pPath, pbuffer); -} - #ifndef TARGET_UNIX -BOOL RunProcess(LPCWSTR tempResObj, LPCWSTR pszFilename, DWORD* pdwExitCode, PEWriter &pewriter) -{ - BOOL fSuccess = FALSE; - - PROCESS_INFORMATION pi; - - PathString wszSystemDir; - if (FAILED(GetClrSystemDirectory(wszSystemDir))) - return FALSE; - - const WCHAR* wzMachine; - if(pewriter.isIA64()) - wzMachine = L"IA64"; - else if(pewriter.isAMD64()) - wzMachine = L"AMD64"; - else if(pewriter.isARM()) - wzMachine = L"ARM"; - else - wzMachine = L"IX86"; - - // Res file, so convert it - StackSString ssCmdLine; - - LPWSTR ext = PathFindExtension(pszFilename); - if(*ext == NULL) - { - ssCmdLine.Printf(L"%scvtres.exe /NOLOGO /READONLY /MACHINE:%s \"/OUT:%s\" \"%s.\"", - wszSystemDir.GetUnicode(), - wzMachine, - tempResObj, - pszFilename); - } - else - { - ssCmdLine.Printf(L"%scvtres.exe /NOLOGO /READONLY /MACHINE:%s \"/OUT:%s\" \"%s\"", - wszSystemDir.GetUnicode(), - wzMachine, - tempResObj, - pszFilename); - } - - STARTUPINFOW start; - ZeroMemory(&start, sizeof(start)); - start.cb = sizeof(start); - start.dwFlags = STARTF_USESHOWWINDOW; - start.wShowWindow = SW_HIDE; - - fSuccess = WszCreateProcess( - NULL, - ssCmdLine.GetUnicode(), - NULL, - NULL, - true, - 0, - 0, - NULL, - &start, - &pi); - - // If process runs, wait for it to finish - if (fSuccess) { - WaitForSingleObject(pi.hProcess, INFINITE); - - GetExitCodeProcess(pi.hProcess, pdwExitCode); - - CloseHandle(pi.hProcess); - - CloseHandle(pi.hThread); - } - return fSuccess; -} // BOOL RunProcess() - -// Ensure that pszFilename is an object file (not just a binary resource) -// If we convert, then return obj filename in pszTempFilename -HRESULT ConvertResource(const WCHAR * pszFilename, __in_ecount(cchTempFilename) WCHAR *pszTempFilename, size_t cchTempFilename, PEWriter &pewriter) -{ - HANDLE hFile = WszCreateFile(pszFilename, GENERIC_READ, - FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - -// failure - if (!hFile || (hFile == INVALID_HANDLE_VALUE)) - { - //dbprintf("Can't find resource files:%S\n", pszFilename); - return HRESULT_FROM_GetLastError(); - } - -// Read first 4 bytes. If they're all 0, we have a win32 .res file which must be -// converted. (So call CvtRes.exe). Else it's an obj file. - - DWORD dwCount = -1; - DWORD dwData = -1; - - BOOL fRet = ReadFile(hFile, - &dwData, - 4, - &dwCount, - NULL - ); - - CloseHandle(hFile); - - if (!fRet) { - //dbprintf("Invalid resource file:%S\n", pszFilename); - return HRESULT_FROM_GetLastError(); - } - - if (dwData != 0) - { - return S_OK; - } - - PathString tempResObj; - PathString tempResPath; - - // Create the temp file where the temp path is at rather than where the application is at. - if (!WszGetTempPath( tempResPath)) - { - return HRESULT_FROM_GetLastError(); - } - - if (!WszGetTempFileName(tempResPath, L"RES", 0, tempResObj)) - { - //dbprintf("GetTempFileName failed\n"); - return HRESULT_FROM_GetLastError(); - } - - DWORD dwExitCode; - fRet = RunProcess(tempResObj, pszFilename, &dwExitCode, pewriter); - - if (!fRet) - { // Couldn't run cvtres.exe - return PostError(CEE_E_CVTRES_NOT_FOUND); - } - else if (dwExitCode != 0) - { // CvtRes.exe ran, but failed - return HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND); - } - else - { // Conversion succesful, so return filename. - wcscpy_s(pszTempFilename, cchTempFilename, tempResObj); - } - - return S_OK; -} // HRESULT ConvertResource() - - // This function reads a resource file and emits it into the generated PE file. // 1. We can only link resources in obj format. Must convert from .res to .obj -// with CvtRes.exe. +// with CvtRes.exe. See https://github.com/dotnet/runtime/issues/11412. // 2. Must touch up all COFF relocs from .rsrc$01 (resource header) to .rsrc$02 // (resource raw data) HRESULT CeeFileGenWriter::emitResourceSection() @@ -1120,21 +949,7 @@ HRESULT CeeFileGenWriter::emitResourceSection() if (m_resourceFileName == NULL) return S_OK; - // Make sure szResFileName is an obj, not just a .res; change name if we convert - WCHAR szTempFileName[MAX_PATH+1]; - szTempFileName[0] = L'\0'; - HRESULT hr = ConvertResource(m_resourceFileName, szTempFileName, - MAX_PATH+1, getPEWriter()); - if (FAILED(hr)) return hr; - - // Filename may change (if we convert .res to .obj), so have floating pointer - const WCHAR* szResFileName; - if (*szTempFileName) - szResFileName = szTempFileName; - else - szResFileName = m_resourceFileName; - - _ASSERTE(szResFileName); + const WCHAR* szResFileName = m_resourceFileName; // read the resource file and spit it out in the .rsrc section @@ -1142,7 +957,7 @@ HRESULT CeeFileGenWriter::emitResourceSection() HANDLE hMap = NULL; IMAGE_FILE_HEADER *hMod = NULL; - hr = S_OK; + HRESULT hr = S_OK; struct Param { @@ -1436,9 +1251,6 @@ lDone: ; CloseHandle(hMap); if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); - if (szResFileName == szTempFileName) - // delete temporary file if we created one - WszDeleteFile(szResFileName); return hr; } // HRESULT CeeFileGenWriter::emitResourceSection() @@ -1981,34 +1793,3 @@ HRESULT CeeFileGenWriter::TestEmitFixups() } #endif // TEST_EMIT_FIXUPS #endif // EMIT_FIXUPS - -#ifndef FEATURE_MERGE_JIT_AND_ENGINE - -//***************************************************************************** -// Handle lifetime of loaded library. -//***************************************************************************** -extern "C" -BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved) -{ - switch (dwReason) - { - case DLL_PROCESS_ATTACH: - { // Save the module handle. - g_hThisInst = (HINSTANCE)hInstance; - DisableThreadLibraryCalls((HMODULE)hInstance); - } - break; - case DLL_PROCESS_DETACH: - break; - } - - return (true); -} // BOOL WINAPI DllMain() - - -HINSTANCE GetModuleInst() -{ - return (g_hThisInst); -} // HINSTANCE GetModuleInst() - -#endif //FEATURE_MERGE_JIT_AND_ENGINE diff --git a/src/coreclr/src/gc/gc.cpp b/src/coreclr/src/gc/gc.cpp index e547defba10736..e54a993d6fca88 100644 --- a/src/coreclr/src/gc/gc.cpp +++ b/src/coreclr/src/gc/gc.cpp @@ -12198,7 +12198,7 @@ void gc_heap::adjust_limit_clr (uint8_t* start, size_t limit_size, size_t size, uint8_t* obj_start = acontext->alloc_ptr; assert(start >= obj_start); uint8_t* obj_end = obj_start + size - plug_skew; - assert(obj_end > clear_start); + assert(obj_end >= clear_start); // if clearing at the object start, clear the syncblock. if(obj_start == start) @@ -37204,7 +37204,9 @@ GCHeap::Alloc(gc_alloc_context* context, size_t size, uint32_t flags REQD_ALIGN_ #endif //_PREFAST_ #endif //MULTIPLE_HEAPS - if (size >= loh_size_threshold || (flags & GC_ALLOC_LARGE_OBJECT_HEAP)) + assert(size < loh_size_threshold || (flags & GC_ALLOC_LARGE_OBJECT_HEAP)); + + if (flags & GC_ALLOC_USER_OLD_HEAP) { // The LOH always guarantees at least 8-byte alignment, regardless of platform. Moreover it doesn't // support mis-aligned object headers so we can't support biased headers. Luckily for us @@ -37213,7 +37215,8 @@ GCHeap::Alloc(gc_alloc_context* context, size_t size, uint32_t flags REQD_ALIGN_ ASSERT((flags & GC_ALLOC_ALIGN8_BIAS) == 0); ASSERT(65536 < loh_size_threshold); - newAlloc = (Object*) hp->allocate_uoh_object (size + ComputeMaxStructAlignPadLarge(requiredAlignment), flags, loh_generation, acontext->alloc_bytes_uoh); + int gen_num = (flags & GC_ALLOC_PINNED_OBJECT_HEAP) ? poh_generation : loh_generation; + newAlloc = (Object*) hp->allocate_uoh_object (size + ComputeMaxStructAlignPadLarge(requiredAlignment), flags, gen_num, acontext->alloc_bytes_uoh); ASSERT(((size_t)newAlloc & 7) == 0); #ifdef FEATURE_STRUCTALIGN diff --git a/src/coreclr/src/gc/gcinterface.h b/src/coreclr/src/gc/gcinterface.h index cd78561af31dc6..de6456d3924731 100644 --- a/src/coreclr/src/gc/gcinterface.h +++ b/src/coreclr/src/gc/gcinterface.h @@ -890,7 +890,7 @@ void updateGCShadow(Object** ptr, Object* val); #define GC_CALL_INTERIOR 0x1 #define GC_CALL_PINNED 0x2 -//flags for IGCHeapAlloc(...) +// keep in sync with GC_ALLOC_FLAGS in GC.cs enum GC_ALLOC_FLAGS { GC_ALLOC_NO_FLAGS = 0, @@ -901,6 +901,7 @@ enum GC_ALLOC_FLAGS GC_ALLOC_ZEROING_OPTIONAL = 16, GC_ALLOC_LARGE_OBJECT_HEAP = 32, GC_ALLOC_PINNED_OBJECT_HEAP = 64, + GC_ALLOC_USER_OLD_HEAP = GC_ALLOC_LARGE_OBJECT_HEAP | GC_ALLOC_PINNED_OBJECT_HEAP, }; inline GC_ALLOC_FLAGS operator|(GC_ALLOC_FLAGS a, GC_ALLOC_FLAGS b) diff --git a/src/coreclr/src/gc/unix/gcenv.unix.cpp b/src/coreclr/src/gc/unix/gcenv.unix.cpp index f32308c90106c8..855f2da02a9822 100644 --- a/src/coreclr/src/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/src/gc/unix/gcenv.unix.cpp @@ -25,6 +25,8 @@ #undef min #undef max +#include + #if HAVE_SYS_TIME_H #include #else diff --git a/src/coreclr/src/inc/CrstTypes.def b/src/coreclr/src/inc/CrstTypes.def index 5bbf1b2d5198eb..06f900a79be900 100644 --- a/src/coreclr/src/inc/CrstTypes.def +++ b/src/coreclr/src/inc/CrstTypes.def @@ -351,6 +351,10 @@ End Crst JitGenericHandleCache End +Crst JitPatchpoint + AcquiredBefore LoaderHeap +End + Crst JitPerf Unordered End diff --git a/src/coreclr/src/inc/MSCOREE.IDL b/src/coreclr/src/inc/MSCOREE.IDL index bcf5b588b6fb6d..8a19345f86c163 100644 --- a/src/coreclr/src/inc/MSCOREE.IDL +++ b/src/coreclr/src/inc/MSCOREE.IDL @@ -10,11 +10,6 @@ ** ** **************************************************************************************/ -cpp_quote("#define DECLARE_DEPRECATED ") -cpp_quote("#define DEPRECATED_CLR_STDAPI STDAPI") - -cpp_quote("") - // // Interface descriptions // @@ -301,7 +296,3 @@ interface ICLRRuntimeHost4 : ICLRRuntimeHost2 [in] BOOL fWaitUntilDone, [out] int *pLatchedExitCode); }; - -cpp_quote("#undef DEPRECATED_CLR_STDAPI") -cpp_quote("#undef DECLARE_DEPRECATED") -cpp_quote("#undef DEPRECATED_CLR_API_MESG") diff --git a/src/coreclr/src/inc/clrconfigvalues.h b/src/coreclr/src/inc/clrconfigvalues.h index d4ec91f59f95d2..175a376b18f575 100644 --- a/src/coreclr/src/inc/clrconfigvalues.h +++ b/src/coreclr/src/inc/clrconfigvalues.h @@ -644,6 +644,16 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_DeleteCallCountingStubsAfter, W("TC_DeleteC #endif #endif +/// +/// On-Stack Replacement +/// +#ifdef FEATURE_ON_STACK_REPLACEMENT +RETAIL_CONFIG_DWORD_INFO(INTERNAL_OSR_CounterBump, W("OSR_CounterBump"), 1000, "Counter reload value when a patchpoint is hit") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_OSR_HitLimit, W("OSR_HitLimit"), 10, "Number of times a patchpoint must call back to trigger an OSR transition") +CONFIG_DWORD_INFO(INTERNAL_OSR_LowId, W("OSR_LowId"), (DWORD)-1, "Low end of enabled patchpoint range (inclusive)"); +CONFIG_DWORD_INFO(INTERNAL_OSR_HighId, W("OSR_HighId"), 10000000, "High end of enabled patchpoint range (inclusive)"); +#endif + /// /// Entry point slot backpatch /// diff --git a/src/coreclr/src/inc/clrhost.h b/src/coreclr/src/inc/clrhost.h index 1292446b2926ee..e43d6ebb83aefc 100644 --- a/src/coreclr/src/inc/clrhost.h +++ b/src/coreclr/src/inc/clrhost.h @@ -56,20 +56,16 @@ #endif // _DEBUG -IExecutionEngine *GetExecutionEngine(); -IEEMemoryManager *GetEEMemoryManager(); LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength); BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); -LPVOID ClrDebugAlloc (size_t size, LPCSTR pszFile, int iLineNo); HANDLE ClrGetProcessHeap(); HANDLE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); BOOL ClrHeapDestroy(HANDLE hHeap); LPVOID ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, S_SIZE_T dwBytes); BOOL ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); -BOOL ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); HANDLE ClrGetProcessExecutableHeap(); @@ -78,8 +74,8 @@ extern int RFS_HashStack(); #endif #ifndef SELF_NO_HOST -LPVOID EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes); -BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem); +LPVOID ClrHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes); +BOOL ClrHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem); #endif inline LPVOID ClrAllocInProcessHeap(DWORD dwFlags, S_SIZE_T dwBytes) @@ -91,7 +87,7 @@ inline LPVOID ClrAllocInProcessHeap(DWORD dwFlags, S_SIZE_T dwBytes) } #ifndef SELF_NO_HOST - return EEHeapAllocInProcessHeap(dwFlags, dwBytes.Value()); + return ClrHeapAllocInProcessHeap(dwFlags, dwBytes.Value()); #else #undef HeapAlloc #undef GetProcessHeap @@ -108,7 +104,7 @@ inline BOOL ClrFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem) { STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY; #ifndef SELF_NO_HOST - return EEHeapFreeInProcessHeap(dwFlags, lpMem); + return ClrHeapFreeInProcessHeap(dwFlags, lpMem); #else #undef HeapFree #undef GetProcessHeap @@ -128,29 +124,10 @@ inline BOOL ClrFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem) // critical section api CRITSEC_COOKIE ClrCreateCriticalSection(CrstType type, CrstFlags flags); -HRESULT ClrDeleteCriticalSection(CRITSEC_COOKIE cookie); +void ClrDeleteCriticalSection(CRITSEC_COOKIE cookie); void ClrEnterCriticalSection(CRITSEC_COOKIE cookie); void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie); -// event api -EVENT_COOKIE ClrCreateAutoEvent(BOOL bInitialState); -EVENT_COOKIE ClrCreateManualEvent(BOOL bInitialState); -void ClrCloseEvent(EVENT_COOKIE event); -BOOL ClrSetEvent(EVENT_COOKIE event); -BOOL ClrResetEvent(EVENT_COOKIE event); -DWORD ClrWaitEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable); - -// semaphore api -SEMAPHORE_COOKIE ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax); -void ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore); -BOOL ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount); -DWORD ClrWaitSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable); - -// mutex api -MUTEX_COOKIE ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName); -void ClrCloseMutex(MUTEX_COOKIE mutex); -BOOL ClrReleaseMutex(MUTEX_COOKIE mutex); -DWORD ClrWaitForMutex(MUTEX_COOKIE mutex,DWORD dwMilliseconds,BOOL bAlertable); DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable); // Rather than use the above APIs directly, it is recommended that holder classes @@ -163,94 +140,6 @@ typedef Holder, VoidClrDeleteCriticalSection, NULL> CRITSEC_AllocationHolder; -class Event { -public: - Event () - : m_event(NULL) - {STATIC_CONTRACT_LEAF;} - ~Event () - { - STATIC_CONTRACT_WRAPPER; - CloseEvent(); - } - - void CreateAutoEvent(BOOL bInitialState) - { - STATIC_CONTRACT_WRAPPER; - m_event = ClrCreateAutoEvent(bInitialState); - } - void CreateManualEvent(BOOL bInitialState) - { - STATIC_CONTRACT_WRAPPER; - m_event = ClrCreateManualEvent(bInitialState); - } - void CloseEvent() - { - STATIC_CONTRACT_WRAPPER; - if (m_event != NULL) - ClrCloseEvent(m_event); - m_event = NULL; - } - - BOOL Set() - { - STATIC_CONTRACT_WRAPPER; - return ClrSetEvent(m_event); - } - BOOL Reset() - { - STATIC_CONTRACT_WRAPPER; - return ClrResetEvent(m_event); - } - DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable) - { - STATIC_CONTRACT_WRAPPER; - return ClrWaitEvent(m_event, dwMilliseconds, bAlertable); - } - -private: - EVENT_COOKIE m_event; -}; - -class Semaphore { -public: - Semaphore () - : m_semaphore(NULL) - {STATIC_CONTRACT_LEAF;} - ~Semaphore () - { - STATIC_CONTRACT_WRAPPER; - Close(); - } - - void Create(DWORD dwInitial, DWORD dwMax) - { - STATIC_CONTRACT_WRAPPER; - m_semaphore = ClrCreateSemaphore(dwInitial, dwMax); - } - void Close() - { - STATIC_CONTRACT_WRAPPER; - if (m_semaphore != NULL) - ClrCloseSemaphore(m_semaphore); - m_semaphore = NULL; - } - - BOOL Release(LONG lReleaseCount, LONG* lpPreviousCount) - { - STATIC_CONTRACT_WRAPPER; - return ClrReleaseSemaphore(m_semaphore, lReleaseCount, lpPreviousCount); - } - DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable) - { - STATIC_CONTRACT_WRAPPER; - return ClrWaitSemaphore(m_semaphore, dwMilliseconds, bAlertable); - } - -private: - SEMAPHORE_COOKIE m_semaphore; -}; - HMODULE GetCLRModule (); extern thread_local int t_CantAllocCount; diff --git a/src/coreclr/src/inc/clrinternal.idl b/src/coreclr/src/inc/clrinternal.idl index 19fc7081184c9a..27a3c0a4536119 100644 --- a/src/coreclr/src/inc/clrinternal.idl +++ b/src/coreclr/src/inc/clrinternal.idl @@ -16,45 +16,6 @@ import "unknwn.idl"; // import mscoree.idl for BucketParameters definition import "mscoree.idl"; - - -cpp_quote("#if 0") - -typedef struct _OSVERSIONINFOA { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - CHAR szCSDVersion[ 128 ]; // Maintenance string for PSS usage -} OSVERSIONINFOA, *POSVERSIONINFOA, *LPOSVERSIONINFOA; - -typedef struct _OSVERSIONINFOW { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - WCHAR szCSDVersion[ 128 ]; // Maintenance string for PSS usage -} OSVERSIONINFOW, *POSVERSIONINFOW, *LPOSVERSIONINFOW, RTL_OSVERSIONINFOW, *PRTL_OSVERSIONINFOW; -#ifdef UNICODE -typedef OSVERSIONINFOW OSVERSIONINFO; -typedef POSVERSIONINFOW POSVERSIONINFO; -typedef LPOSVERSIONINFOW LPOSVERSIONINFO; -#else -typedef OSVERSIONINFOA OSVERSIONINFO; -typedef POSVERSIONINFOA POSVERSIONINFO; -typedef LPOSVERSIONINFOA LPOSVERSIONINFO; -#endif // UNICODE - -cpp_quote("#endif") - -// IID IExecutionEngine : uuid(7AF02DAC-2A33-494b-A09F-25E00A93C6F8) -cpp_quote("EXTERN_GUID(IID_IExecutionEngine, 0x7AF02DAC, 0x2A33, 0x494b, 0xA0, 0x9F, 0x25, 0xE0, 0x0A, 0x93, 0xC6, 0xF8);") - -// IID IEEMemoryManager : uuid{17713B61-B59F-4e13-BAAF-91623DC8ADC0} -cpp_quote("EXTERN_GUID(IID_IEEMemoryManager, 0x17713b61, 0xb59f, 0x4e13, 0xba, 0xaf, 0x91, 0x62, 0x3d, 0xc8, 0xad, 0xc0);") - // This ID is embedded in the CLRDEBUGINFO resource so that the shim can differentiate dlls which happen to be named // clr.dll from official Microsoft clr.dll implementations. This is not intended to authenticate a CLR in a strong // security sense but short of deliberate 3rd party spoofing it should provide a good identity. @@ -92,9 +53,6 @@ cpp_quote("EXTERN_GUID(IID_IPrivateManagedExceptionReporting, 0xad76a023, 0x332d // Interface for exposing services from the EE to other DLLs of the CLR. //***************************************************************************** typedef void * CRITSEC_COOKIE; -typedef void * EVENT_COOKIE; -typedef void * SEMAPHORE_COOKIE; -typedef void * MUTEX_COOKIE; typedef enum { CRST_DEFAULT = 0x0, @@ -116,145 +74,6 @@ typedef enum { // this option will assert it in debug mode. } CrstFlags; -// Callback function for cleaning up TLS -typedef VOID (__stdcall *PTLS_CALLBACK_FUNCTION)(PVOID); - - -[ - uuid(7AF02DAC-2A33-494b-A09F-25E00A93C6F8), - helpstring("CLR Coordination Interface"), - pointer_default(unique), - local -] -interface IExecutionEngine : IUnknown -{ - // Critical Sections are sometimes exposed to the host and therefore need to be - // reflected from all CLR DLLs to the EE. - // - // In addition, we always monitor interactions between the lock & the GC, based - // on the GC mode in which the lock is acquired and we restrict what operations - // are permitted while holding the lock based on this. - // - // Finally, we we rank all our locks to prevent deadlock across all the DLLs of - // the CLR. This is the level argument to CreateLock. - // - // All usage of these locks must be exception-safe. To achieve this, we suggest - // using Holders (see holder.h & crst.h). In fact, within the EE code cannot - // hold locks except by using exception-safe holders. - - CRITSEC_COOKIE CreateLock([in] LPCSTR szTag, [in] LPCSTR level, [in] CrstFlags flags); - - void DestroyLock([in] CRITSEC_COOKIE lock); - - void AcquireLock([in] CRITSEC_COOKIE lock); - - void ReleaseLock([in] CRITSEC_COOKIE lock); - - EVENT_COOKIE CreateAutoEvent([in] BOOL bInitialState); - EVENT_COOKIE CreateManualEvent([in] BOOL bInitialState); - void CloseEvent([in] EVENT_COOKIE event); - BOOL ClrSetEvent([in] EVENT_COOKIE event); - BOOL ClrResetEvent([in] EVENT_COOKIE event); - DWORD WaitForEvent([in] EVENT_COOKIE event, [in] DWORD dwMilliseconds, [in] BOOL bAlertable); - DWORD WaitForSingleObject([in] HANDLE handle, [in] DWORD dwMilliseconds); - - // OS header file defines CreateSemaphore. - SEMAPHORE_COOKIE ClrCreateSemaphore([in] DWORD dwInitial, [in] DWORD dwMax); - void ClrCloseSemaphore([in] SEMAPHORE_COOKIE semaphore); - DWORD ClrWaitForSemaphore([in] SEMAPHORE_COOKIE semaphore, [in] DWORD dwMilliseconds, [in] BOOL bAlertable); - BOOL ClrReleaseSemaphore([in] SEMAPHORE_COOKIE semaphore, [in] LONG lReleaseCount, [in] LONG *lpPreviousCount); - - MUTEX_COOKIE ClrCreateMutex([in]LPSECURITY_ATTRIBUTES lpMutexAttributes, [in]BOOL bInitialOwner, [in]LPCTSTR lpName); - DWORD ClrWaitForMutex([in] MUTEX_COOKIE mutex, [in] DWORD dwMilliseconds, [in] BOOL bAlertable); - BOOL ClrReleaseMutex([in] MUTEX_COOKIE mutex); - void ClrCloseMutex([in] MUTEX_COOKIE mutex); - - DWORD ClrSleepEx([in] DWORD dwMilliseconds, [in] BOOL bAlertable); - - BOOL ClrAllocationDisallowed(); - - void GetLastThrownObjectExceptionFromThread([out] void **ppvException); - -}; // interface IExecutionEngine - - -//***************************************************************************** -// Interface for exposing memory services from the EE to other DLLs of the CLR. -//***************************************************************************** - -cpp_quote("#if !defined(_WINNT_) && !defined(_NTMMAPI_)") -typedef void* PMEMORY_BASIC_INFORMATION; -cpp_quote("#endif") - - -[ - uuid(17713B61-B59F-4e13-BAAF-91623DC8ADC0), - helpstring("CLR Memory Manager Interface"), - pointer_default(unique), - local -] -interface IEEMemoryManager : IUnknown -{ - LPVOID ClrVirtualAlloc( - [in] LPVOID lpAddress, // region to reserve or commit - [in] SIZE_T dwSize, // size of region - [in] DWORD flAllocationType, // type of allocation - [in] DWORD flProtect // type of access protection - ); - - BOOL ClrVirtualFree( - [in] LPVOID lpAddress, // address of region - [in] SIZE_T dwSize, // size of region - [in] DWORD dwFreeType // operation type - ); - - SIZE_T ClrVirtualQuery( - [in] const void* lpAddress, // address of region - [in] PMEMORY_BASIC_INFORMATION lpBuffer, // information buffer - [in] SIZE_T dwLength // size of buffer - ); - - BOOL ClrVirtualProtect( - [in] LPVOID lpAddress, // region of committed pages - [in] SIZE_T dwSize, // size of the region - [in] DWORD flNewProtect, // desired access protection - [in] DWORD* lpflOldProtect // old protection - ); - - HANDLE ClrGetProcessHeap(); - - HANDLE ClrHeapCreate( - [in] DWORD flOptions, // heap allocation attributes - [in] SIZE_T dwInitialSize, // initial heap size - [in] SIZE_T dwMaximumSize // maximum heap size - ); - - BOOL ClrHeapDestroy( - [in] HANDLE hHeap // handle to heap - ); - - LPVOID ClrHeapAlloc( - [in] HANDLE hHeap, // handle to private heap block - [in] DWORD dwFlags, // heap allocation control - [in] SIZE_T dwBytes // number of bytes to allocate - ); - - BOOL ClrHeapFree( - [in] HANDLE hHeap, // handle to heap - [in] DWORD dwFlags, // heap free options - [in] LPVOID lpMem // pointer to memory - ); - - BOOL ClrHeapValidate( - [in] HANDLE hHeap, // handle to heap - [in] DWORD dwFlags, // heap access options - [in] const void* lpMem // optional pointer to memory block - ); - - HANDLE ClrGetProcessExecutableHeap(); - -}; // interface IEEMemoryManager - //******************************************************************************************** // Interface for exposing GetBucketParametersForCurrentException to Watson testing harness. //******************************************************************************************** @@ -268,5 +87,3 @@ interface IPrivateManagedExceptionReporting : IUnknown { HRESULT GetBucketParametersForCurrentException([out]BucketParameters *pParams); } - - diff --git a/src/coreclr/src/inc/corinfo.h b/src/coreclr/src/inc/corinfo.h index 0fa5edbac36cb7..900de9c32f5e01 100644 --- a/src/coreclr/src/inc/corinfo.h +++ b/src/coreclr/src/inc/corinfo.h @@ -631,6 +631,8 @@ enum CorInfoHelpFunc CORINFO_HELP_STACK_PROBE, // Probes each page of the allocated stack frame + CORINFO_HELP_PATCHPOINT, // Notify runtime that code has reached a patchpoint + CORINFO_HELP_COUNT, }; @@ -1084,6 +1086,11 @@ inline bool dontInline(CorInfoInline val) { return(val < 0); } +// Patchpoint info is passed back and forth across the interface +// but is opaque. + +struct PatchpointInfo; + // Cookie types consumed by the code generator (these are opaque values // not inspected by the code generator): @@ -2169,6 +2176,16 @@ class ICorStaticInfo GSCookie ** ppCookieVal // OUT ) = 0; + // Provide patchpoint info for the method currently being jitted. + virtual void setPatchpointInfo( + PatchpointInfo* patchpointInfo + ) = 0; + + // Get patchpoint info and il offset for the method currently being jitted. + virtual PatchpointInfo* getOSRInfo( + unsigned *ilOffset // [OUT] il offset of OSR entry point + ) = 0; + /**********************************************************************************/ // // ICorModuleInfo diff --git a/src/coreclr/src/inc/corinfoinstructionset.h b/src/coreclr/src/inc/corinfoinstructionset.h new file mode 100644 index 00000000000000..d43d743134f449 --- /dev/null +++ b/src/coreclr/src/inc/corinfoinstructionset.h @@ -0,0 +1,276 @@ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// FROM /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +// using /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat + +#ifndef CORINFOINSTRUCTIONSET_H +#define CORINFOINSTRUCTIONSET_H + +enum CORINFO_InstructionSet +{ + InstructionSet_ILLEGAL = 0, + InstructionSet_NONE = 63, +#ifdef TARGET_ARM64 + InstructionSet_ArmBase=1, + InstructionSet_ArmBase_Arm64=2, + InstructionSet_AdvSimd=3, + InstructionSet_AdvSimd_Arm64=4, + InstructionSet_Aes=5, + InstructionSet_Crc32=6, + InstructionSet_Crc32_Arm64=7, + InstructionSet_Sha1=8, + InstructionSet_Sha256=9, + InstructionSet_Atomics=10, + InstructionSet_Vector64=11, + InstructionSet_Vector128=12, +#endif // TARGET_ARM64 +#ifdef TARGET_AMD64 + InstructionSet_SSE=1, + InstructionSet_SSE2=2, + InstructionSet_SSE3=3, + InstructionSet_SSSE3=4, + InstructionSet_SSE41=5, + InstructionSet_SSE42=6, + InstructionSet_AVX=7, + InstructionSet_AVX2=8, + InstructionSet_AES=9, + InstructionSet_BMI1=10, + InstructionSet_BMI2=11, + InstructionSet_FMA=12, + InstructionSet_LZCNT=13, + InstructionSet_PCLMULQDQ=14, + InstructionSet_POPCNT=15, + InstructionSet_Vector128=16, + InstructionSet_Vector256=17, + InstructionSet_BMI1_X64=18, + InstructionSet_BMI2_X64=19, + InstructionSet_LZCNT_X64=20, + InstructionSet_POPCNT_X64=21, + InstructionSet_SSE_X64=22, + InstructionSet_SSE2_X64=23, + InstructionSet_SSE41_X64=24, + InstructionSet_SSE42_X64=25, +#endif // TARGET_AMD64 +#ifdef TARGET_X86 + InstructionSet_SSE=1, + InstructionSet_SSE2=2, + InstructionSet_SSE3=3, + InstructionSet_SSSE3=4, + InstructionSet_SSE41=5, + InstructionSet_SSE42=6, + InstructionSet_AVX=7, + InstructionSet_AVX2=8, + InstructionSet_AES=9, + InstructionSet_BMI1=10, + InstructionSet_BMI2=11, + InstructionSet_FMA=12, + InstructionSet_LZCNT=13, + InstructionSet_PCLMULQDQ=14, + InstructionSet_POPCNT=15, + InstructionSet_Vector128=16, + InstructionSet_Vector256=17, + InstructionSet_BMI1_X64=18, + InstructionSet_BMI2_X64=19, + InstructionSet_LZCNT_X64=20, + InstructionSet_POPCNT_X64=21, + InstructionSet_SSE_X64=22, + InstructionSet_SSE2_X64=23, + InstructionSet_SSE41_X64=24, + InstructionSet_SSE42_X64=25, +#endif // TARGET_X86 + +}; + +struct CORINFO_InstructionSetFlags +{ +private: + uint64_t _flags = 0; +public: + void AddInstructionSet(CORINFO_InstructionSet instructionSet) + { + _flags = _flags | (((uint64_t)1) << instructionSet); + } + + void RemoveInstructionSet(CORINFO_InstructionSet instructionSet) + { + _flags = _flags & ~(((uint64_t)1) << instructionSet); + } + + bool HasInstructionSet(CORINFO_InstructionSet instructionSet) const + { + return _flags & (((uint64_t)1) << instructionSet); + } + + bool Equals(CORINFO_InstructionSetFlags other) const + { + return _flags == other._flags; + } + + void Add(CORINFO_InstructionSetFlags other) + { + _flags |= other._flags; + } + + bool IsEmpty() const + { + return _flags == 0; + } + + void Reset() + { + _flags = 0; + } + + void Set64BitInstructionSetVariants() + { +#ifdef TARGET_ARM64 + if (HasInstructionSet(InstructionSet_ArmBase)) + AddInstructionSet(InstructionSet_ArmBase_Arm64); + if (HasInstructionSet(InstructionSet_AdvSimd)) + AddInstructionSet(InstructionSet_AdvSimd_Arm64); + if (HasInstructionSet(InstructionSet_Crc32)) + AddInstructionSet(InstructionSet_Crc32_Arm64); +#endif // TARGET_ARM64 +#ifdef TARGET_AMD64 + if (HasInstructionSet(InstructionSet_SSE)) + AddInstructionSet(InstructionSet_SSE_X64); + if (HasInstructionSet(InstructionSet_SSE2)) + AddInstructionSet(InstructionSet_SSE2_X64); + if (HasInstructionSet(InstructionSet_SSE41)) + AddInstructionSet(InstructionSet_SSE41_X64); + if (HasInstructionSet(InstructionSet_SSE42)) + AddInstructionSet(InstructionSet_SSE42_X64); + if (HasInstructionSet(InstructionSet_BMI1)) + AddInstructionSet(InstructionSet_BMI1_X64); + if (HasInstructionSet(InstructionSet_BMI2)) + AddInstructionSet(InstructionSet_BMI2_X64); + if (HasInstructionSet(InstructionSet_LZCNT)) + AddInstructionSet(InstructionSet_LZCNT_X64); + if (HasInstructionSet(InstructionSet_POPCNT)) + AddInstructionSet(InstructionSet_POPCNT_X64); +#endif // TARGET_AMD64 +#ifdef TARGET_X86 +#endif // TARGET_X86 + + } + + uint64_t GetFlagsRaw() + { + return _flags; + } + + void SetFromFlagsRaw(uint64_t flags) + { + _flags = flags; + } +}; + +inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_InstructionSetFlags input) +{ + CORINFO_InstructionSetFlags oldflags = input; + CORINFO_InstructionSetFlags resultflags = input; + do + { + oldflags = resultflags; +#ifdef TARGET_ARM64 + if (resultflags.HasInstructionSet(InstructionSet_ArmBase) && !resultflags.HasInstructionSet(InstructionSet_ArmBase_Arm64)) + resultflags.RemoveInstructionSet(InstructionSet_ArmBase); + if (resultflags.HasInstructionSet(InstructionSet_AdvSimd) && !resultflags.HasInstructionSet(InstructionSet_AdvSimd_Arm64)) + resultflags.RemoveInstructionSet(InstructionSet_AdvSimd); + if (resultflags.HasInstructionSet(InstructionSet_Crc32) && !resultflags.HasInstructionSet(InstructionSet_Crc32_Arm64)) + resultflags.RemoveInstructionSet(InstructionSet_Crc32); + if (resultflags.HasInstructionSet(InstructionSet_AdvSimd) && !resultflags.HasInstructionSet(InstructionSet_ArmBase)) + resultflags.RemoveInstructionSet(InstructionSet_AdvSimd); + if (resultflags.HasInstructionSet(InstructionSet_Aes) && !resultflags.HasInstructionSet(InstructionSet_ArmBase)) + resultflags.RemoveInstructionSet(InstructionSet_Aes); + if (resultflags.HasInstructionSet(InstructionSet_Crc32) && !resultflags.HasInstructionSet(InstructionSet_ArmBase)) + resultflags.RemoveInstructionSet(InstructionSet_Crc32); + if (resultflags.HasInstructionSet(InstructionSet_Sha1) && !resultflags.HasInstructionSet(InstructionSet_ArmBase)) + resultflags.RemoveInstructionSet(InstructionSet_Sha1); + if (resultflags.HasInstructionSet(InstructionSet_Sha256) && !resultflags.HasInstructionSet(InstructionSet_ArmBase)) + resultflags.RemoveInstructionSet(InstructionSet_Sha256); +#endif // TARGET_ARM64 +#ifdef TARGET_AMD64 + if (resultflags.HasInstructionSet(InstructionSet_SSE) && !resultflags.HasInstructionSet(InstructionSet_SSE_X64)) + resultflags.RemoveInstructionSet(InstructionSet_SSE); + if (resultflags.HasInstructionSet(InstructionSet_SSE2) && !resultflags.HasInstructionSet(InstructionSet_SSE2_X64)) + resultflags.RemoveInstructionSet(InstructionSet_SSE2); + if (resultflags.HasInstructionSet(InstructionSet_SSE41) && !resultflags.HasInstructionSet(InstructionSet_SSE41_X64)) + resultflags.RemoveInstructionSet(InstructionSet_SSE41); + if (resultflags.HasInstructionSet(InstructionSet_SSE42) && !resultflags.HasInstructionSet(InstructionSet_SSE42_X64)) + resultflags.RemoveInstructionSet(InstructionSet_SSE42); + if (resultflags.HasInstructionSet(InstructionSet_BMI1) && !resultflags.HasInstructionSet(InstructionSet_BMI1_X64)) + resultflags.RemoveInstructionSet(InstructionSet_BMI1); + if (resultflags.HasInstructionSet(InstructionSet_BMI2) && !resultflags.HasInstructionSet(InstructionSet_BMI2_X64)) + resultflags.RemoveInstructionSet(InstructionSet_BMI2); + if (resultflags.HasInstructionSet(InstructionSet_LZCNT) && !resultflags.HasInstructionSet(InstructionSet_LZCNT_X64)) + resultflags.RemoveInstructionSet(InstructionSet_LZCNT); + if (resultflags.HasInstructionSet(InstructionSet_POPCNT) && !resultflags.HasInstructionSet(InstructionSet_POPCNT_X64)) + resultflags.RemoveInstructionSet(InstructionSet_POPCNT); + if (resultflags.HasInstructionSet(InstructionSet_SSE2) && !resultflags.HasInstructionSet(InstructionSet_SSE)) + resultflags.RemoveInstructionSet(InstructionSet_SSE2); + if (resultflags.HasInstructionSet(InstructionSet_SSE3) && !resultflags.HasInstructionSet(InstructionSet_SSE2)) + resultflags.RemoveInstructionSet(InstructionSet_SSE3); + if (resultflags.HasInstructionSet(InstructionSet_SSSE3) && !resultflags.HasInstructionSet(InstructionSet_SSE3)) + resultflags.RemoveInstructionSet(InstructionSet_SSSE3); + if (resultflags.HasInstructionSet(InstructionSet_SSE41) && !resultflags.HasInstructionSet(InstructionSet_SSSE3)) + resultflags.RemoveInstructionSet(InstructionSet_SSE41); + if (resultflags.HasInstructionSet(InstructionSet_SSE42) && !resultflags.HasInstructionSet(InstructionSet_SSE41)) + resultflags.RemoveInstructionSet(InstructionSet_SSE42); + if (resultflags.HasInstructionSet(InstructionSet_AVX) && !resultflags.HasInstructionSet(InstructionSet_SSE42)) + resultflags.RemoveInstructionSet(InstructionSet_AVX); + if (resultflags.HasInstructionSet(InstructionSet_AVX2) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_AVX2); + if (resultflags.HasInstructionSet(InstructionSet_AES) && !resultflags.HasInstructionSet(InstructionSet_SSE2)) + resultflags.RemoveInstructionSet(InstructionSet_AES); + if (resultflags.HasInstructionSet(InstructionSet_BMI1) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_BMI1); + if (resultflags.HasInstructionSet(InstructionSet_BMI2) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_BMI2); + if (resultflags.HasInstructionSet(InstructionSet_FMA) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_FMA); + if (resultflags.HasInstructionSet(InstructionSet_PCLMULQDQ) && !resultflags.HasInstructionSet(InstructionSet_SSE2)) + resultflags.RemoveInstructionSet(InstructionSet_PCLMULQDQ); + if (resultflags.HasInstructionSet(InstructionSet_POPCNT) && !resultflags.HasInstructionSet(InstructionSet_SSE42)) + resultflags.RemoveInstructionSet(InstructionSet_POPCNT); +#endif // TARGET_AMD64 +#ifdef TARGET_X86 + if (resultflags.HasInstructionSet(InstructionSet_SSE2) && !resultflags.HasInstructionSet(InstructionSet_SSE)) + resultflags.RemoveInstructionSet(InstructionSet_SSE2); + if (resultflags.HasInstructionSet(InstructionSet_SSE3) && !resultflags.HasInstructionSet(InstructionSet_SSE2)) + resultflags.RemoveInstructionSet(InstructionSet_SSE3); + if (resultflags.HasInstructionSet(InstructionSet_SSSE3) && !resultflags.HasInstructionSet(InstructionSet_SSE3)) + resultflags.RemoveInstructionSet(InstructionSet_SSSE3); + if (resultflags.HasInstructionSet(InstructionSet_SSE41) && !resultflags.HasInstructionSet(InstructionSet_SSSE3)) + resultflags.RemoveInstructionSet(InstructionSet_SSE41); + if (resultflags.HasInstructionSet(InstructionSet_SSE42) && !resultflags.HasInstructionSet(InstructionSet_SSE41)) + resultflags.RemoveInstructionSet(InstructionSet_SSE42); + if (resultflags.HasInstructionSet(InstructionSet_AVX) && !resultflags.HasInstructionSet(InstructionSet_SSE42)) + resultflags.RemoveInstructionSet(InstructionSet_AVX); + if (resultflags.HasInstructionSet(InstructionSet_AVX2) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_AVX2); + if (resultflags.HasInstructionSet(InstructionSet_AES) && !resultflags.HasInstructionSet(InstructionSet_SSE2)) + resultflags.RemoveInstructionSet(InstructionSet_AES); + if (resultflags.HasInstructionSet(InstructionSet_BMI1) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_BMI1); + if (resultflags.HasInstructionSet(InstructionSet_BMI2) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_BMI2); + if (resultflags.HasInstructionSet(InstructionSet_FMA) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_FMA); + if (resultflags.HasInstructionSet(InstructionSet_PCLMULQDQ) && !resultflags.HasInstructionSet(InstructionSet_SSE2)) + resultflags.RemoveInstructionSet(InstructionSet_PCLMULQDQ); + if (resultflags.HasInstructionSet(InstructionSet_POPCNT) && !resultflags.HasInstructionSet(InstructionSet_SSE42)) + resultflags.RemoveInstructionSet(InstructionSet_POPCNT); +#endif // TARGET_X86 + + } while (!oldflags.Equals(resultflags)); + return resultflags; +} + + + +#endif // CORINFOINSTRUCTIONSET_H diff --git a/src/coreclr/src/inc/corjit.h b/src/coreclr/src/inc/corjit.h index 47b6858238415d..857fa5bc2e1155 100644 --- a/src/coreclr/src/inc/corjit.h +++ b/src/coreclr/src/inc/corjit.h @@ -89,7 +89,6 @@ extern "C" void __stdcall jitStartup(ICorJitHost* host); class ICorJitCompiler; class ICorJitInfo; -struct IEEMemoryManager; extern "C" ICorJitCompiler* __stdcall getJit(); diff --git a/src/coreclr/src/inc/corjitflags.h b/src/coreclr/src/inc/corjitflags.h index 1982e0c7b93f64..eac6f9277909da 100644 --- a/src/coreclr/src/inc/corjitflags.h +++ b/src/coreclr/src/inc/corjitflags.h @@ -17,6 +17,8 @@ #ifndef _COR_JIT_FLAGS_H_ #define _COR_JIT_FLAGS_H_ +#include "corinfoinstructionset.h" + class CORJIT_FLAGS { public: @@ -40,7 +42,6 @@ class CORJIT_FLAGS CORJIT_FLAG_TARGET_P4 = 9, CORJIT_FLAG_USE_FCOMI = 10, // Generated code may use fcomi(p) instruction CORJIT_FLAG_USE_CMOV = 11, // Generated code may use cmov instruction - CORJIT_FLAG_USE_SSE2 = 12, // Generated code may use SSE-2 instructions #else // !defined(TARGET_X86) @@ -52,21 +53,12 @@ class CORJIT_FLAGS #endif // !defined(TARGET_X86) - CORJIT_FLAG_UNUSED6 = 13, - - #if defined(TARGET_X86) || defined(TARGET_AMD64) - - CORJIT_FLAG_USE_AVX = 14, - CORJIT_FLAG_USE_AVX2 = 15, - CORJIT_FLAG_USE_AVX_512 = 16, - - #else // !defined(TARGET_X86) && !defined(TARGET_AMD64) + CORJIT_FLAG_OSR = 13, // Generate alternate method for On Stack Replacement CORJIT_FLAG_UNUSED7 = 14, CORJIT_FLAG_UNUSED8 = 15, CORJIT_FLAG_UNUSED9 = 16, - #endif // !defined(TARGET_X86) && !defined(TARGET_AMD64) #if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64) CORJIT_FLAG_FEATURE_SIMD = 17, @@ -106,57 +98,6 @@ class CORJIT_FLAGS CORJIT_FLAG_NO_INLINING = 42, // JIT should not inline any called method into this method -#if defined(TARGET_ARM64) - - CORJIT_FLAG_HAS_ARM64_AES = 43, // ID_AA64ISAR0_EL1.AES is 1 or better - CORJIT_FLAG_HAS_ARM64_ATOMICS = 44, // ID_AA64ISAR0_EL1.Atomic is 2 or better - CORJIT_FLAG_HAS_ARM64_CRC32 = 45, // ID_AA64ISAR0_EL1.CRC32 is 1 or better - CORJIT_FLAG_HAS_ARM64_DCPOP = 46, // ID_AA64ISAR1_EL1.DPB is 1 or better - CORJIT_FLAG_HAS_ARM64_DP = 47, // ID_AA64ISAR0_EL1.DP is 1 or better - CORJIT_FLAG_HAS_ARM64_FCMA = 48, // ID_AA64ISAR1_EL1.FCMA is 1 or better - CORJIT_FLAG_HAS_ARM64_FP = 49, // ID_AA64PFR0_EL1.FP is 0 or better - CORJIT_FLAG_HAS_ARM64_FP16 = 50, // ID_AA64PFR0_EL1.FP is 1 or better - CORJIT_FLAG_HAS_ARM64_JSCVT = 51, // ID_AA64ISAR1_EL1.JSCVT is 1 or better - CORJIT_FLAG_HAS_ARM64_LRCPC = 52, // ID_AA64ISAR1_EL1.LRCPC is 1 or better - CORJIT_FLAG_HAS_ARM64_PMULL = 53, // ID_AA64ISAR0_EL1.AES is 2 or better - CORJIT_FLAG_HAS_ARM64_SHA1 = 54, // ID_AA64ISAR0_EL1.SHA1 is 1 or better - CORJIT_FLAG_HAS_ARM64_SHA256 = 55, // ID_AA64ISAR0_EL1.SHA2 is 1 or better - CORJIT_FLAG_HAS_ARM64_SHA512 = 56, // ID_AA64ISAR0_EL1.SHA2 is 2 or better - CORJIT_FLAG_HAS_ARM64_SHA3 = 57, // ID_AA64ISAR0_EL1.SHA3 is 1 or better - CORJIT_FLAG_HAS_ARM64_ADVSIMD = 58, // ID_AA64PFR0_EL1.AdvSIMD is 0 or better - CORJIT_FLAG_HAS_ARM64_ADVSIMD_V81 = 59, // ID_AA64ISAR0_EL1.RDM is 1 or better - CORJIT_FLAG_HAS_ARM64_ADVSIMD_FP16 = 60, // ID_AA64PFR0_EL1.AdvSIMD is 1 or better - CORJIT_FLAG_HAS_ARM64_SM3 = 61, // ID_AA64ISAR0_EL1.SM3 is 1 or better - CORJIT_FLAG_HAS_ARM64_SM4 = 62, // ID_AA64ISAR0_EL1.SM4 is 1 or better - CORJIT_FLAG_HAS_ARM64_SVE = 63 // ID_AA64PFR0_EL1.SVE is 1 or better - -#elif defined(TARGET_X86) || defined(TARGET_AMD64) - - CORJIT_FLAG_USE_SSE3 = 43, - CORJIT_FLAG_USE_SSSE3 = 44, - CORJIT_FLAG_USE_SSE41 = 45, - CORJIT_FLAG_USE_SSE42 = 46, - CORJIT_FLAG_USE_AES = 47, - CORJIT_FLAG_USE_BMI1 = 48, - CORJIT_FLAG_USE_BMI2 = 49, - CORJIT_FLAG_USE_FMA = 50, - CORJIT_FLAG_USE_LZCNT = 51, - CORJIT_FLAG_USE_PCLMULQDQ = 52, - CORJIT_FLAG_USE_POPCNT = 53, - CORJIT_FLAG_UNUSED23 = 54, - CORJIT_FLAG_UNUSED24 = 55, - CORJIT_FLAG_UNUSED25 = 56, - CORJIT_FLAG_UNUSED26 = 57, - CORJIT_FLAG_UNUSED27 = 58, - CORJIT_FLAG_UNUSED28 = 59, - CORJIT_FLAG_UNUSED29 = 60, - CORJIT_FLAG_UNUSED30 = 61, - CORJIT_FLAG_UNUSED31 = 62, - CORJIT_FLAG_UNUSED32 = 63 - - -#else // !defined(TARGET_ARM64) &&!defined(TARGET_X86) && !defined(TARGET_AMD64) - CORJIT_FLAG_UNUSED12 = 43, CORJIT_FLAG_UNUSED13 = 44, CORJIT_FLAG_UNUSED14 = 45, @@ -178,8 +119,6 @@ class CORJIT_FLAGS CORJIT_FLAG_UNUSED30 = 61, CORJIT_FLAG_UNUSED31 = 62, CORJIT_FLAG_UNUSED32 = 63 - -#endif // !defined(TARGET_ARM64) &&!defined(TARGET_X86) && !defined(TARGET_AMD64) }; CORJIT_FLAGS() @@ -198,11 +137,28 @@ class CORJIT_FLAGS CORJIT_FLAGS(const CORJIT_FLAGS& other) { corJitFlags = other.corJitFlags; + instructionSetFlags = other.instructionSetFlags; } void Reset() { corJitFlags = 0; + instructionSetFlags.Reset(); + } + + void Set(CORINFO_InstructionSet instructionSet) + { + instructionSetFlags.AddInstructionSet(instructionSet); + } + + void Clear(CORINFO_InstructionSet instructionSet) + { + instructionSetFlags.RemoveInstructionSet(instructionSet); + } + + void Set64BitInstructionSetVariants() + { + instructionSetFlags.Set64BitInstructionSetVariants(); } void Set(CorJitFlag flag) @@ -223,16 +179,17 @@ class CORJIT_FLAGS void Add(const CORJIT_FLAGS& other) { corJitFlags |= other.corJitFlags; + instructionSetFlags.Add(other.instructionSetFlags); } - void Remove(const CORJIT_FLAGS& other) + bool IsEmpty() const { - corJitFlags &= ~other.corJitFlags; + return corJitFlags == 0 && instructionSetFlags.IsEmpty(); } - bool IsEmpty() const + void EnsureValidInstructionSetSupport() { - return corJitFlags == 0; + instructionSetFlags = EnsureInstructionSetFlagsAreValid(instructionSetFlags); } // DO NOT USE THIS FUNCTION! (except in very restricted special cases) @@ -241,9 +198,16 @@ class CORJIT_FLAGS return corJitFlags; } + // DO NOT USE THIS FUNCTION! (except in very restricted special cases) + unsigned __int64 GetInstructionSetFlagsRaw() + { + return instructionSetFlags.GetFlagsRaw(); + } + private: unsigned __int64 corJitFlags; + CORINFO_InstructionSetFlags instructionSetFlags; }; diff --git a/src/coreclr/src/inc/crsttypes.h b/src/coreclr/src/inc/crsttypes.h index 3638826f769d32..98d24c2efafcae 100644 --- a/src/coreclr/src/inc/crsttypes.h +++ b/src/coreclr/src/inc/crsttypes.h @@ -89,88 +89,89 @@ enum CrstType CrstJit = 70, CrstJitGenericHandleCache = 71, CrstJitInlineTrackingMap = 72, - CrstJitPerf = 73, - CrstJumpStubCache = 74, - CrstLeafLock = 75, - CrstListLock = 76, - CrstLoaderAllocator = 77, - CrstLoaderAllocatorReferences = 78, - CrstLoaderHeap = 79, - CrstMda = 80, - CrstMetadataTracker = 81, - CrstMethodDescBackpatchInfoTracker = 82, - CrstModIntPairList = 83, - CrstModule = 84, - CrstModuleFixup = 85, - CrstModuleLookupTable = 86, - CrstMulticoreJitHash = 87, - CrstMulticoreJitManager = 88, - CrstMUThunkHash = 89, - CrstNativeBinderInit = 90, - CrstNativeImageCache = 91, - CrstNativeImageEagerFixups = 92, - CrstNls = 93, - CrstNotifyGdb = 94, - CrstObjectList = 95, - CrstOnEventManager = 96, - CrstPatchEntryPoint = 97, - CrstPEImage = 98, - CrstPEImagePDBStream = 99, - CrstPendingTypeLoadEntry = 100, - CrstPinHandle = 101, - CrstPinnedByrefValidation = 102, - CrstProfilerGCRefDataFreeList = 103, - CrstProfilingAPIStatus = 104, - CrstPublisherCertificate = 105, - CrstRCWCache = 106, - CrstRCWCleanupList = 107, - CrstRCWRefCache = 108, - CrstReadyToRunEntryPointToMethodDescMap = 109, - CrstReDacl = 110, - CrstReflection = 111, - CrstReJITGlobalRequest = 112, - CrstRemoting = 113, - CrstRetThunkCache = 114, - CrstRWLock = 115, - CrstSavedExceptionInfo = 116, - CrstSaveModuleProfileData = 117, - CrstSecurityStackwalkCache = 118, - CrstSharedAssemblyCreate = 119, - CrstSigConvert = 120, - CrstSingleUseLock = 121, - CrstSpecialStatics = 122, - CrstSqmManager = 123, - CrstStackSampler = 124, - CrstStressLog = 125, - CrstStrongName = 126, - CrstStubCache = 127, - CrstStubDispatchCache = 128, - CrstStubUnwindInfoHeapSegments = 129, - CrstSyncBlockCache = 130, - CrstSyncHashLock = 131, - CrstSystemBaseDomain = 132, - CrstSystemDomain = 133, - CrstSystemDomainDelayedUnloadList = 134, - CrstThreadIdDispenser = 135, - CrstThreadpoolEventCache = 136, - CrstThreadpoolTimerQueue = 137, - CrstThreadpoolWaitThreads = 138, - CrstThreadpoolWorker = 139, - CrstThreadStaticDataHashTable = 140, - CrstThreadStore = 141, - CrstTieredCompilation = 142, - CrstTPMethodTable = 143, - CrstTypeEquivalenceMap = 144, - CrstTypeIDMap = 145, - CrstUMEntryThunkCache = 146, - CrstUMThunkHash = 147, - CrstUniqueStack = 148, - CrstUnresolvedClassLock = 149, - CrstUnwindInfoTableLock = 150, - CrstVSDIndirectionCellLock = 151, - CrstWinRTFactoryCache = 152, - CrstWrapperTemplate = 153, - kNumberOfCrstTypes = 154 + CrstJitPatchpoint = 73, + CrstJitPerf = 74, + CrstJumpStubCache = 75, + CrstLeafLock = 76, + CrstListLock = 77, + CrstLoaderAllocator = 78, + CrstLoaderAllocatorReferences = 79, + CrstLoaderHeap = 80, + CrstMda = 81, + CrstMetadataTracker = 82, + CrstMethodDescBackpatchInfoTracker = 83, + CrstModIntPairList = 84, + CrstModule = 85, + CrstModuleFixup = 86, + CrstModuleLookupTable = 87, + CrstMulticoreJitHash = 88, + CrstMulticoreJitManager = 89, + CrstMUThunkHash = 90, + CrstNativeBinderInit = 91, + CrstNativeImageCache = 92, + CrstNativeImageEagerFixups = 93, + CrstNls = 94, + CrstNotifyGdb = 95, + CrstObjectList = 96, + CrstOnEventManager = 97, + CrstPatchEntryPoint = 98, + CrstPEImage = 99, + CrstPEImagePDBStream = 100, + CrstPendingTypeLoadEntry = 101, + CrstPinHandle = 102, + CrstPinnedByrefValidation = 103, + CrstProfilerGCRefDataFreeList = 104, + CrstProfilingAPIStatus = 105, + CrstPublisherCertificate = 106, + CrstRCWCache = 107, + CrstRCWCleanupList = 108, + CrstRCWRefCache = 109, + CrstReadyToRunEntryPointToMethodDescMap = 110, + CrstReDacl = 111, + CrstReflection = 112, + CrstReJITGlobalRequest = 113, + CrstRemoting = 114, + CrstRetThunkCache = 115, + CrstRWLock = 116, + CrstSavedExceptionInfo = 117, + CrstSaveModuleProfileData = 118, + CrstSecurityStackwalkCache = 119, + CrstSharedAssemblyCreate = 120, + CrstSigConvert = 121, + CrstSingleUseLock = 122, + CrstSpecialStatics = 123, + CrstSqmManager = 124, + CrstStackSampler = 125, + CrstStressLog = 126, + CrstStrongName = 127, + CrstStubCache = 128, + CrstStubDispatchCache = 129, + CrstStubUnwindInfoHeapSegments = 130, + CrstSyncBlockCache = 131, + CrstSyncHashLock = 132, + CrstSystemBaseDomain = 133, + CrstSystemDomain = 134, + CrstSystemDomainDelayedUnloadList = 135, + CrstThreadIdDispenser = 136, + CrstThreadpoolEventCache = 137, + CrstThreadpoolTimerQueue = 138, + CrstThreadpoolWaitThreads = 139, + CrstThreadpoolWorker = 140, + CrstThreadStaticDataHashTable = 141, + CrstThreadStore = 142, + CrstTieredCompilation = 143, + CrstTPMethodTable = 144, + CrstTypeEquivalenceMap = 145, + CrstTypeIDMap = 146, + CrstUMEntryThunkCache = 147, + CrstUMThunkHash = 148, + CrstUniqueStack = 149, + CrstUnresolvedClassLock = 150, + CrstUnwindInfoTableLock = 151, + CrstVSDIndirectionCellLock = 152, + CrstWinRTFactoryCache = 153, + CrstWrapperTemplate = 154, + kNumberOfCrstTypes = 155 }; #endif // __CRST_TYPES_INCLUDED @@ -254,6 +255,7 @@ int g_rgCrstLevelMap[] = 8, // CrstJit 0, // CrstJitGenericHandleCache 16, // CrstJitInlineTrackingMap + 3, // CrstJitPatchpoint -1, // CrstJitPerf 6, // CrstJumpStubCache 0, // CrstLeafLock @@ -413,6 +415,7 @@ LPCSTR g_rgCrstNameMap[] = "CrstJit", "CrstJitGenericHandleCache", "CrstJitInlineTrackingMap", + "CrstJitPatchpoint", "CrstJitPerf", "CrstJumpStubCache", "CrstLeafLock", diff --git a/src/coreclr/src/inc/eventtracebase.h b/src/coreclr/src/inc/eventtracebase.h index cde996a92185e2..a02d8f5fbda696 100644 --- a/src/coreclr/src/inc/eventtracebase.h +++ b/src/coreclr/src/inc/eventtracebase.h @@ -242,7 +242,7 @@ extern UINT32 g_nClrInstanceId; #endif // defined(HOST_UNIX) && (defined(FEATURE_EVENT_TRACE) || defined(FEATURE_EVENTSOURCE_XPLAT)) -#if defined(FEATURE_PERFTRACING) +#if defined(FEATURE_PERFTRACING) || defined(FEATURE_EVENTSOURCE_XPLAT) /***************************************/ /* Tracing levels supported by CLR ETW */ @@ -397,7 +397,7 @@ class XplatEventLoggerConfiguration NewArrayHolder _argument; bool _isValid; }; -#endif // FEATURE_PERFTRACING +#endif // defined(FEATURE_PERFTRACING) || defined(FEATURE_EVENTSOURCE_XPLAT) #if defined(HOST_UNIX) && (defined(FEATURE_EVENT_TRACE) || defined(FEATURE_EVENTSOURCE_XPLAT)) diff --git a/src/coreclr/src/inc/jithelpers.h b/src/coreclr/src/inc/jithelpers.h index 8e92cbd410514f..cc726a9046414f 100644 --- a/src/coreclr/src/inc/jithelpers.h +++ b/src/coreclr/src/inc/jithelpers.h @@ -357,6 +357,8 @@ JITHELPER(CORINFO_HELP_STACK_PROBE, NULL, CORINFO_HELP_SIG_UNDEF) #endif + JITHELPER(CORINFO_HELP_PATCHPOINT, JIT_Patchpoint, CORINFO_HELP_SIG_REG_ONLY) + #undef JITHELPER #undef DYNAMICJITHELPER #undef JITHELPER diff --git a/src/coreclr/src/inc/patchpointinfo.h b/src/coreclr/src/inc/patchpointinfo.h new file mode 100644 index 00000000000000..135ad0135a5496 --- /dev/null +++ b/src/coreclr/src/inc/patchpointinfo.h @@ -0,0 +1,145 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// -------------------------------------------------------------------------------- +// patchpointinfo.h +// -------------------------------------------------------------------------------- + +#include + +#ifndef _PATCHPOINTINFO_H_ +#define _PATCHPOINTINFO_H_ + +// -------------------------------------------------------------------------------- +// Describes information needed to make an OSR transition +// - location of Il-visible locals and other important state on the +// original (Tier0) method frame +// - total size of the original frame, and SP-FP delta +// +// Currently the patchpoint info is independent of the IL offset of the patchpoint. +// +// This data is produced when jitting a Tier0 method with OSR enabled, and consumed +// by the Tier1/OSR jit request. +// +struct PatchpointInfo +{ + // Determine how much storage is needed to hold this info + static unsigned ComputeSize(unsigned localCount) + { + unsigned baseSize = sizeof(PatchpointInfo); + unsigned variableSize = localCount * sizeof(int); + unsigned totalSize = baseSize + variableSize; + return totalSize; + } + + // Initialize + void Initialize(unsigned localCount, int fpToSpDelta) + { + m_fpToSpDelta = fpToSpDelta; + m_numberOfLocals = localCount; + m_genericContextArgOffset = -1; + m_keptAliveThisOffset = -1; + m_securityCookieOffset = -1; + } + + // Total size of this patchpoint info record, in bytes + unsigned PatchpointInfoSize() const + { + return ComputeSize(m_numberOfLocals); + } + + // FP to SP delta of the original method + int FpToSpDelta() const + { + return m_fpToSpDelta; + } + + // Number of locals in the original method (including special locals) + unsigned NumberOfLocals() const + { + return m_numberOfLocals; + } + + // Original method caller SP offset for generic context arg + int GenericContextArgOffset() const + { + return m_genericContextArgOffset; + } + + void SetGenericContextArgOffset(int offset) + { + m_genericContextArgOffset = offset; + } + + // Original method FP relative offset for kept-alive this + int KeptAliveThisOffset() const + { + return m_keptAliveThisOffset; + } + + bool HasKeptAliveThis() const + { + return m_keptAliveThisOffset != -1; + } + + void SetKeptAliveThisOffset(int offset) + { + m_keptAliveThisOffset = offset; + } + + // Original method FP relative offset for security cookie + int SecurityCookieOffset() const + { + return m_securityCookieOffset; + } + + bool HasSecurityCookie() const + { + return m_securityCookieOffset != -1; + } + + void SetSecurityCookieOffset(int offset) + { + m_securityCookieOffset = offset; + } + + // True if this local was address exposed in the original method + bool IsExposed(unsigned localNum) const + { + return ((m_offsetAndExposureData[localNum] & EXPOSURE_MASK) != 0); + } + + void SetIsExposed(unsigned localNum) + { + m_offsetAndExposureData[localNum] |= EXPOSURE_MASK; + } + + // FP relative offset of this local in the original method + int Offset(unsigned localNum) const + { + return (m_offsetAndExposureData[localNum] & ~EXPOSURE_MASK); + } + + void SetOffset(unsigned localNum, int offset) + { + m_offsetAndExposureData[localNum] = offset; + } + +private: + enum + { + EXPOSURE_MASK = 0x1 + }; + + unsigned m_numberOfLocals; + int m_fpToSpDelta; + int m_genericContextArgOffset; + int m_keptAliveThisOffset; + int m_securityCookieOffset; + int m_offsetAndExposureData[]; +}; + +typedef DPTR(struct PatchpointInfo) PTR_PatchpointInfo; + +#endif // _PATCHPOINTINFO_H_ diff --git a/src/coreclr/src/inc/readytoruninstructionset.h b/src/coreclr/src/inc/readytoruninstructionset.h new file mode 100644 index 00000000000000..6e6f2549f90440 --- /dev/null +++ b/src/coreclr/src/inc/readytoruninstructionset.h @@ -0,0 +1,38 @@ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// FROM /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +// using /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat + +#ifndef READYTORUNINSTRUCTIONSET_H +#define READYTORUNINSTRUCTIONSET_H +enum ReadyToRunInstructionSet +{ + READYTORUN_INSTRUCTION_Sse=1, + READYTORUN_INSTRUCTION_Sse2=2, + READYTORUN_INSTRUCTION_Sse3=3, + READYTORUN_INSTRUCTION_Ssse3=4, + READYTORUN_INSTRUCTION_Sse41=5, + READYTORUN_INSTRUCTION_Sse42=6, + READYTORUN_INSTRUCTION_Avx=7, + READYTORUN_INSTRUCTION_Avx2=8, + READYTORUN_INSTRUCTION_Aes=9, + READYTORUN_INSTRUCTION_Bmi1=10, + READYTORUN_INSTRUCTION_Bmi2=11, + READYTORUN_INSTRUCTION_Fma=12, + READYTORUN_INSTRUCTION_Lzcnt=13, + READYTORUN_INSTRUCTION_Pclmulqdq=14, + READYTORUN_INSTRUCTION_Popcnt=15, + READYTORUN_INSTRUCTION_ArmBase=16, + READYTORUN_INSTRUCTION_AdvSimd=17, + READYTORUN_INSTRUCTION_Crc32=18, + READYTORUN_INSTRUCTION_Sha1=19, + READYTORUN_INSTRUCTION_Sha256=20, + READYTORUN_INSTRUCTION_Atomics=21, + +}; + +#endif // READYTORUNINSTRUCTIONSET_H diff --git a/src/coreclr/src/inc/slist.h b/src/coreclr/src/inc/slist.h index f5d03126f9f9bd..87dec1dcd0bb5a 100644 --- a/src/coreclr/src/inc/slist.h +++ b/src/coreclr/src/inc/slist.h @@ -274,7 +274,7 @@ class SList SLink *ret = SLink::FindAndRemove(m_pHead, GetLink(pObj), &prior); if (ret == m_pTail) - m_pTail = prior; + m_pTail = PTR_SLink(prior); return GetObject(ret); } diff --git a/src/coreclr/src/inc/utilcode.h b/src/coreclr/src/inc/utilcode.h index 45b5c4c59607cd..9283af18d62d1c 100644 --- a/src/coreclr/src/inc/utilcode.h +++ b/src/coreclr/src/inc/utilcode.h @@ -4713,50 +4713,7 @@ typedef HMODULE HMODULE_TGT; BOOL IsIPInModule(HMODULE_TGT hModule, PCODE ip); -//---------------------------------------------------------------------------------------- -// The runtime invokes InitUtilcode() in its dllmain and passes along all of the critical -// callback pointers. For the desktop CLR, all DLLs loaded by the runtime must also call -// InitUtilcode with the same callbacks as the runtime used. To achieve this, the runtime -// calls a special initialization routine exposed by the loaded module with the callbacks, -// which in turn calls InitUtilcode. -// -// This structure collects all of the critical callback info passed in InitUtilcode(). -//---------------------------------------------------------------------------------------- -struct CoreClrCallbacks -{ - typedef IExecutionEngine* (* pfnIEE_t)(); - typedef HRESULT (* pfnGetCORSystemDirectory_t)(SString& pbuffer); - - HINSTANCE m_hmodCoreCLR; - pfnIEE_t m_pfnIEE; - pfnGetCORSystemDirectory_t m_pfnGetCORSystemDirectory; -}; - - -// For DAC, we include this functionality only when EH SxS is enabled. - -//---------------------------------------------------------------------------------------- -// CoreCLR must invoke this before CRT initialization to ensure utilcode has all the callback -// pointers it needs. -//---------------------------------------------------------------------------------------- -VOID InitUtilcode(const CoreClrCallbacks &cccallbacks); -CoreClrCallbacks const & GetClrCallbacks(); - -//---------------------------------------------------------------------------------------- -// Stuff below is for utilcode.lib eyes only. -//---------------------------------------------------------------------------------------- - -// Stores callback pointers provided by InitUtilcode(). -extern CoreClrCallbacks g_CoreClrCallbacks; - -// Throws up a helpful dialog if InitUtilcode() wasn't called. -#ifdef _DEBUG -void OnUninitializedCoreClrCallbacks(); -#define VALIDATECORECLRCALLBACKS() if (g_CoreClrCallbacks.m_hmodCoreCLR == NULL) OnUninitializedCoreClrCallbacks() -#else //_DEBUG -#define VALIDATECORECLRCALLBACKS() -#endif //_DEBUG - +extern HINSTANCE g_hmodCoreCLR; #ifdef FEATURE_CORRUPTING_EXCEPTIONS diff --git a/src/coreclr/src/inc/utsem.h b/src/coreclr/src/inc/utsem.h index b24871d2325d78..0cacfcd940f6e7 100644 --- a/src/coreclr/src/inc/utsem.h +++ b/src/coreclr/src/inc/utsem.h @@ -46,18 +46,9 @@ class UTSemReadWrite #endif //_DEBUG private: - Semaphore * GetReadWaiterSemaphore() - { - return m_pReadWaiterSemaphore; - } - Event * GetWriteWaiterEvent() - { - return m_pWriteWaiterEvent; - } - Volatile m_dwFlag; // internal state, see implementation - Semaphore * m_pReadWaiterSemaphore; // semaphore for awakening read waiters - Event * m_pWriteWaiterEvent; // event for awakening write waiters + HANDLE m_hReadWaiterSemaphore; // semaphore for awakening read waiters + HANDLE m_hWriteWaiterEvent; // event for awakening write waiters }; // class UTSemReadWrite #endif // __UTSEM_H__ diff --git a/src/coreclr/src/jit/CMakeLists.txt b/src/coreclr/src/jit/CMakeLists.txt index 2f4a3f201623de..5be8e3f96dab3e 100644 --- a/src/coreclr/src/jit/CMakeLists.txt +++ b/src/coreclr/src/jit/CMakeLists.txt @@ -67,6 +67,7 @@ set( JIT_SOURCES objectalloc.cpp optcse.cpp optimizer.cpp + patchpoint.cpp phase.cpp rangecheck.cpp rationalize.cpp diff --git a/src/coreclr/src/jit/block.cpp b/src/coreclr/src/jit/block.cpp index 01058ba2ab9f7b..fe186a3544102e 100644 --- a/src/coreclr/src/jit/block.cpp +++ b/src/coreclr/src/jit/block.cpp @@ -344,6 +344,14 @@ void BasicBlock::dspFlags() { printf("bwd "); } + if (bbFlags & BBF_BACKWARD_JUMP_TARGET) + { + printf("bwd-target "); + } + if (bbFlags & BBF_PATCHPOINT) + { + printf("ppoint "); + } if (bbFlags & BBF_RETLESS_CALL) { printf("retless "); diff --git a/src/coreclr/src/jit/block.h b/src/coreclr/src/jit/block.h index 15897374c565d8..94adae39c50345 100644 --- a/src/coreclr/src/jit/block.h +++ b/src/coreclr/src/jit/block.h @@ -440,14 +440,15 @@ struct BasicBlock : private LIR::Range // BBJ_CALLFINALLY block, as well as, on x86, the final step block out of a // finally. -#define BBF_CLONED_FINALLY_BEGIN 0x100000000 // First block of a cloned finally region -#define BBF_CLONED_FINALLY_END 0x200000000 // Last block of a cloned finally region -#define BBF_HAS_CALL 0x400000000 // BB contains a call +#define BBF_CLONED_FINALLY_BEGIN 0x100000000 // First block of a cloned finally region +#define BBF_CLONED_FINALLY_END 0x200000000 // Last block of a cloned finally region +#define BBF_HAS_CALL 0x400000000 // BB contains a call +#define BBF_DOMINATED_BY_EXCEPTIONAL_ENTRY 0x800000000 // Block is dominated by exceptional entry. +#define BBF_BACKWARD_JUMP_TARGET 0x1000000000 // Block is a target of a backward jump +#define BBF_PATCHPOINT 0x2000000000 // Block is a patchpoint // clang-format on -#define BBF_DOMINATED_BY_EXCEPTIONAL_ENTRY 0x800000000 // Block is dominated by exceptional entry. - // Flags that relate blocks to loop structure. #define BBF_LOOP_FLAGS (BBF_LOOP_PREHEADER | BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1) diff --git a/src/coreclr/src/jit/codegenarm64.cpp b/src/coreclr/src/jit/codegenarm64.cpp index 4970dbd6261d39..675fca49de84dd 100644 --- a/src/coreclr/src/jit/codegenarm64.cpp +++ b/src/coreclr/src/jit/codegenarm64.cpp @@ -5230,7 +5230,7 @@ void CodeGen::genArm64EmitterUnitTests() #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // - // Loads to /Stores from one, two, three, or four SIMD&FP registers + // Loads to and Stores from one, two, three, or four SIMD&FP registers // genDefineTempLabel(genCreateTempLabel()); @@ -5413,7 +5413,7 @@ void CodeGen::genArm64EmitterUnitTests() #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // - // Loads to /Stores from one, two, three, or four SIMD&FP registers + // Loads to and Stores from one, two, three, or four SIMD&FP registers // genDefineTempLabel(genCreateTempLabel()); @@ -5596,7 +5596,7 @@ void CodeGen::genArm64EmitterUnitTests() #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // - // Loads to /Stores from one, two, three, or four SIMD&FP registers + // Loads to and Stores from one, two, three, or four SIMD&FP registers // genDefineTempLabel(genCreateTempLabel()); @@ -5779,7 +5779,7 @@ void CodeGen::genArm64EmitterUnitTests() #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // - // Loads to /Stores from one, two, three, or four SIMD&FP registers + // Loads to and Stores from one, two, three, or four SIMD&FP registers // genDefineTempLabel(genCreateTempLabel()); @@ -5836,7 +5836,7 @@ void CodeGen::genArm64EmitterUnitTests() #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // - // Loads to /Stores from one, two, three, or four SIMD&FP registers + // Loads to and Stores from one, two, three, or four SIMD&FP registers // genDefineTempLabel(genCreateTempLabel()); @@ -5893,7 +5893,7 @@ void CodeGen::genArm64EmitterUnitTests() #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // - // Loads to /Stores from one, two, three, or four SIMD&FP registers + // Loads to and Stores from one, two, three, or four SIMD&FP registers // genDefineTempLabel(genCreateTempLabel()); diff --git a/src/coreclr/src/jit/codegencommon.cpp b/src/coreclr/src/jit/codegencommon.cpp index 59de2fdd84214d..b9825d2ec9850b 100644 --- a/src/coreclr/src/jit/codegencommon.cpp +++ b/src/coreclr/src/jit/codegencommon.cpp @@ -28,6 +28,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "gcinfoencoder.h" #endif +#include "patchpointinfo.h" + /*****************************************************************************/ const BYTE genTypeSizes[] = { @@ -2152,6 +2154,11 @@ void CodeGen::genGenerateMachineCode() printf("; ReadyToRun compilation\n"); } + if (compiler->opts.IsOSR()) + { + printf("; OSR variant for entry point 0x%x\n", compiler->info.compILEntry); + } + if ((compiler->opts.compFlags & CLFLG_MAXOPT) == CLFLG_MAXOPT) { printf("; optimized code\n"); @@ -4488,6 +4495,12 @@ void CodeGen::genEnregisterIncomingStackArgs() } #endif + // OSR handles this specially + if (compiler->opts.IsOSR()) + { + return; + } + assert(compiler->compGeneratingProlog); unsigned varNum = 0; @@ -4588,6 +4601,20 @@ void CodeGen::genCheckUseBlockInit() continue; } + // Initialization of OSR locals must be handled specially + if (compiler->lvaIsOSRLocal(varNum)) + { + varDsc->lvMustInit = 0; + continue; + } + + // Likewise, initialization of the GS cookie is handled specially for OSR. + // Could do this for non-OSR too.. (likewise for the dummy) + if (compiler->opts.IsOSR() && varNum == compiler->lvaGSSecurityCookie) + { + continue; + } + if (!varDsc->lvIsInReg() && !varDsc->lvOnFrame) { noway_assert(varDsc->lvRefCnt() == 0); @@ -6629,6 +6656,127 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, inst_ST_RV(ins_Store(TYP_I_IMPL), tempThis, 0, genGetZeroReg(initReg, pInitRegZeroed), TYP_I_IMPL); } } + + // Initialize args and locals for OSR. Note this may include promoted fields. + if (compiler->opts.IsOSR()) + { + PatchpointInfo* patchpointInfo = compiler->info.compPatchpointInfo; + + // basic sanity checks (make sure we're OSRing the right method) + assert(patchpointInfo->NumberOfLocals() == compiler->info.compLocalsCount); + + const int originalFrameSize = patchpointInfo->FpToSpDelta(); + const unsigned patchpointInfoLen = patchpointInfo->NumberOfLocals(); + + for (unsigned varNum = 0; varNum < compiler->lvaCount; varNum++) + { + if (!compiler->lvaIsOSRLocal(varNum)) + { + continue; + } + + LclVarDsc* const varDsc = compiler->lvaGetDesc(varNum); + + if (!varDsc->lvIsInReg()) + { + JITDUMP("---OSR--- V%02u in memory\n", varNum); + continue; + } + + if (!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex)) + { + JITDUMP("---OSR--- V%02u (reg) not live at entry\n", varNum); + continue; + } + + int fieldOffset = 0; + unsigned lclNum = varNum; + + if (varDsc->lvIsStructField) + { + lclNum = varDsc->lvParentLcl; + assert(lclNum < patchpointInfoLen); + + fieldOffset = varDsc->lvFldOffset; + JITDUMP("---OSR--- V%02u is promoted field of V%02u at offset %d\n", varNum, lclNum, fieldOffset); + } + + // Note we are always reading from the original frame here + const var_types lclTyp = genActualType(varDsc->lvType); + const emitAttr size = emitTypeSize(lclTyp); + const int stkOffs = patchpointInfo->Offset(lclNum) + fieldOffset; + + // Original frames always use frame pointers, so + // stkOffs is the original frame-relative offset + // to the variable. + // + // We need to determine the stack or frame-pointer relative + // offset for this variable in the current frame. + // + // If current frame does not use a frame pointer, we need to + // add the SP-to-FP delta of this frame and the SP-to-FP delta + // of the original frame; that translates from this frame's + // stack pointer the old frame frame pointer. + // + // We then add the original frame's frame-pointer relative + // offset (note this offset is usually negative -- the stack + // grows down, so locals are below the frame pointer). + // + // /-----original frame-----/ + // / return address / + // / saved RBP --+ / <--- Original frame ptr --+ + // / ... | / | + // / ... (stkOffs) / | + // / ... | / | + // / variable --+ / | + // / ... / (original frame sp-fp delta) + // / ... / | + // /-----OSR frame ---------/ | + // / pseudo return address / --+ + // / ... / | + // / ... / (this frame sp-fp delta) + // / ... / | + // /------------------------/ <--- Stack ptr --+ + // + // If the current frame is using a frame pointer, we need to + // add the SP-to-FP delta of/ the original frame and then add + // the original frame's frame-pointer relative offset. + // + // /-----original frame-----/ + // / return address / + // / saved RBP --+ / <--- Original frame ptr --+ + // / ... | / | + // / ... (stkOffs) / | + // / ... | / | + // / variable --+ / | + // / ... / (original frame sp-fp delta) + // / ... / | + // /-----OSR frame ---------/ | + // / pseudo return address / --+ + // / saved RBP / <--- Frame ptr --+ + // / ... / + // / ... / + // / ... / + // /------------------------/ + + int offset = originalFrameSize + stkOffs; + + if (isFramePointerUsed()) + { + // also adjust for saved RPB on this frame + offset += TARGET_POINTER_SIZE; + } + else + { + offset += genSPtoFPdelta(); + } + + JITDUMP("---OSR--- V%02u (reg) old rbp offset %d old frame %d this frame sp-fp %d new offset %d (%02xH)\n", + varNum, stkOffs, originalFrameSize, genSPtoFPdelta(), offset, offset); + + GetEmitter()->emitIns_R_AR(ins_Load(lclTyp), size, varDsc->GetRegNum(), genFramePointerReg(), offset); + } + } } /*----------------------------------------------------------------------------- @@ -6642,6 +6790,12 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, void CodeGen::genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed) { + // For OSR the original method has set this up for us. + if (compiler->opts.IsOSR()) + { + return; + } + assert(compiler->compGeneratingProlog); bool reportArg = compiler->lvaReportParamTypeArg(); @@ -7296,6 +7450,19 @@ void CodeGen::genFnProlog() psiBegProlog(); } +#if defined(TARGET_XARCH) + // For OSR there is a "phantom prolog" to account for the actions taken + // in the original frame that impact RBP and RSP on entry to the OSR method. + if (compiler->opts.IsOSR()) + { + PatchpointInfo* patchpointInfo = compiler->info.compPatchpointInfo; + const int originalFrameSize = patchpointInfo->FpToSpDelta(); + + compiler->unwindPush(REG_FPBASE); + compiler->unwindAllocStack(originalFrameSize); + } +#endif + #ifdef DEBUG if (compiler->compJitHaltMethod()) @@ -7487,7 +7654,8 @@ void CodeGen::genFnProlog() } } - assert((genInitStkLclCnt > 0) == hasUntrLcl); + // TODO-Cleanup: Add suitable assert for the OSR case. + assert(compiler->opts.IsOSR() || ((genInitStkLclCnt > 0) == hasUntrLcl)); #ifdef DEBUG if (verbose) @@ -7593,7 +7761,9 @@ void CodeGen::genFnProlog() // This way, the varargs iterator will be able to retrieve the // call arguments properly since both the arg regs and the stack allocated // args will be contiguous. - if (compiler->info.compIsVarArgs) + // + // OSR methods can skip this, as the setup is done by the orignal method. + if (compiler->info.compIsVarArgs && !compiler->opts.IsOSR()) { GetEmitter()->spillIntArgRegsToShadowSlots(); } @@ -7801,7 +7971,11 @@ void CodeGen::genFnProlog() #ifdef PROFILING_SUPPORTED // Insert a function entry callback for profiling, if requested. - genProfilingEnterCallback(initReg, &initRegZeroed); + // OSR methods aren't called, so don't have enter hooks. + if (!compiler->opts.IsOSR()) + { + genProfilingEnterCallback(initReg, &initRegZeroed); + } #endif // PROFILING_SUPPORTED @@ -7840,37 +8014,43 @@ void CodeGen::genFnProlog() // Update the arg initial register locations. compiler->lvaUpdateArgsWithInitialReg(); - FOREACH_REGISTER_FILE(regState) + // Home incoming arguments and generate any required inits. + // OSR handles this by moving the values from the original frame. + // + if (!compiler->opts.IsOSR()) { - if (regState->rsCalleeRegArgMaskLiveIn) + FOREACH_REGISTER_FILE(regState) { - // If we need an extra register to shuffle around the incoming registers - // we will use xtraReg (initReg) and set the xtraRegClobbered flag, - // if we don't need to use the xtraReg then this flag will stay false - // - regNumber xtraReg; - bool xtraRegClobbered = false; - - if (genRegMask(initReg) & RBM_ARG_REGS) - { - xtraReg = initReg; - } - else + if (regState->rsCalleeRegArgMaskLiveIn) { - xtraReg = REG_SCRATCH; - initRegZeroed = false; - } + // If we need an extra register to shuffle around the incoming registers + // we will use xtraReg (initReg) and set the xtraRegClobbered flag, + // if we don't need to use the xtraReg then this flag will stay false + // + regNumber xtraReg; + bool xtraRegClobbered = false; - genFnPrologCalleeRegArgs(xtraReg, &xtraRegClobbered, regState); + if (genRegMask(initReg) & RBM_ARG_REGS) + { + xtraReg = initReg; + } + else + { + xtraReg = REG_SCRATCH; + initRegZeroed = false; + } - if (xtraRegClobbered) - { - initRegZeroed = false; + genFnPrologCalleeRegArgs(xtraReg, &xtraRegClobbered, regState); + + if (xtraRegClobbered) + { + initRegZeroed = false; + } } } } - // Home the incoming arguments + // Home the incoming arguments. genEnregisterIncomingStackArgs(); /* Initialize any must-init registers variables now */ @@ -8440,6 +8620,24 @@ void CodeGen::genFnEpilog(BasicBlock* block) } genPopCalleeSavedRegisters(); + + // Extra OSR adjust to get to where RBP was saved by the original frame, and + // restore RBP. + // + // Note the other callee saves made in that frame are dead, the OSR method + // will save and restore what it needs. + if (compiler->opts.IsOSR()) + { + PatchpointInfo* patchpointInfo = compiler->info.compPatchpointInfo; + const int originalFrameSize = patchpointInfo->FpToSpDelta(); + + // Use add since we know the SP-to-FP delta of the original method. + // + // If we ever allow the original method to have localloc this will + // need to change. + inst_RV_IV(INS_add, REG_SPBASE, originalFrameSize, EA_PTRSIZE); + inst_RV(INS_pop, REG_EBP, TYP_I_IMPL); + } } else { @@ -8471,9 +8669,11 @@ void CodeGen::genFnEpilog(BasicBlock* block) if (compiler->compLocallocUsed) { + // OSR not yet ready for localloc + assert(!compiler->opts.IsOSR()); + // ESP may be variable if a localloc was actually executed. Reset it. // lea esp, [ebp - compiler->compCalleeRegsPushed * REGSIZE_BYTES] - needLea = true; } else if (!regSet.rsRegsModified(RBM_CALLEE_SAVED)) @@ -8543,10 +8743,26 @@ void CodeGen::genFnEpilog(BasicBlock* block) // // Pop the callee-saved registers (if any) // - genPopCalleeSavedRegisters(); #ifdef TARGET_AMD64 + // Extra OSR adjust to get to where RBP was saved by the original frame. + // + // Note the other callee saves made in that frame are dead, the current method + // will save and restore what it needs. + if (compiler->opts.IsOSR()) + { + PatchpointInfo* patchpointInfo = compiler->info.compPatchpointInfo; + const int originalFrameSize = patchpointInfo->FpToSpDelta(); + + // Use add since we know the SP-to-FP delta of the original method. + // We also need to skip over the slot where we pushed RBP. + // + // If we ever allow the original method to have localloc this will + // need to change. + inst_RV_IV(INS_add, REG_SPBASE, originalFrameSize + TARGET_POINTER_SIZE, EA_PTRSIZE); + } + assert(!needMovEspEbp); // "mov esp, ebp" is not allowed in AMD64 epilogs #else // !TARGET_AMD64 if (needMovEspEbp) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index 0ac2545a9ae6ae..d319979cb8884e 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -22,6 +22,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "lower.h" #include "gcinfo.h" #include "gcinfoencoder.h" +#include "patchpointinfo.h" /***************************************************************************** * @@ -69,6 +70,12 @@ void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed) return; } + if (compiler->opts.IsOSR() && compiler->info.compPatchpointInfo->HasSecurityCookie()) + { + // Security cookie is on original frame and was initialized there. + return; + } + if (compiler->gsGlobalSecurityCookieAddr == nullptr) { noway_assert(compiler->gsGlobalSecurityCookieVal != 0); diff --git a/src/coreclr/src/jit/compiler.cpp b/src/coreclr/src/jit/compiler.cpp index efa4d187da4e50..3a3e961b34c4c4 100644 --- a/src/coreclr/src/jit/compiler.cpp +++ b/src/coreclr/src/jit/compiler.cpp @@ -22,6 +22,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "lower.h" #include "stacklevelsetter.h" #include "jittelemetry.h" +#include "patchpointinfo.h" #if defined(DEBUG) // Column settings for COMPlus_JitDumpIR. We could(should) make these programmable. @@ -2192,250 +2193,179 @@ void Compiler::compSetProcessor() #endif // TARGET_X86 -// Instruction set flags for Intel hardware intrinsics + CORINFO_InstructionSetFlags instructionSetFlags = jitFlags.GetInstructionSetFlags(); + #ifdef TARGET_XARCH + // Instruction set flags for Intel hardware intrinsics opts.compSupportsISA = 0; if (JitConfig.EnableHWIntrinsic()) { // Dummy ISAs for simplifying the JIT code - opts.setSupportedISA(InstructionSet_Vector128); - opts.setSupportedISA(InstructionSet_Vector256); - } - - if (JitConfig.EnableSSE()) - { - opts.setSupportedISA(InstructionSet_SSE); -#ifdef TARGET_AMD64 - opts.setSupportedISA(InstructionSet_SSE_X64); -#endif // TARGET_AMD64 - - if (JitConfig.EnableSSE2()) - { - opts.setSupportedISA(InstructionSet_SSE2); -#ifdef TARGET_AMD64 - opts.setSupportedISA(InstructionSet_SSE2_X64); -#endif // TARGET_AMD64 - - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AES) && JitConfig.EnableAES()) - { - opts.setSupportedISA(InstructionSet_AES); - } - - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_PCLMULQDQ) && JitConfig.EnablePCLMULQDQ()) - { - opts.setSupportedISA(InstructionSet_PCLMULQDQ); - } - - // We need to additionaly check that COMPlus_EnableSSE3_4 is set, as that - // is a prexisting config flag that controls the SSE3+ ISAs - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE3) && JitConfig.EnableSSE3() && JitConfig.EnableSSE3_4()) - { - opts.setSupportedISA(InstructionSet_SSE3); - - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSSE3) && JitConfig.EnableSSSE3()) - { - opts.setSupportedISA(InstructionSet_SSSE3); - - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE41) && JitConfig.EnableSSE41()) - { - opts.setSupportedISA(InstructionSet_SSE41); -#ifdef TARGET_AMD64 - opts.setSupportedISA(InstructionSet_SSE41_X64); -#endif // TARGET_AMD64 - - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE42) && JitConfig.EnableSSE42()) - { - opts.setSupportedISA(InstructionSet_SSE42); -#ifdef TARGET_AMD64 - opts.setSupportedISA(InstructionSet_SSE42_X64); -#endif // TARGET_AMD64 - - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_POPCNT) && JitConfig.EnablePOPCNT()) - { - opts.setSupportedISA(InstructionSet_POPCNT); -#ifdef TARGET_AMD64 - opts.setSupportedISA(InstructionSet_POPCNT_X64); -#endif // TARGET_AMD64 - } - - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX) && JitConfig.EnableAVX()) - { - opts.setSupportedISA(InstructionSet_AVX); - - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_FMA) && JitConfig.EnableFMA()) - { - opts.setSupportedISA(InstructionSet_FMA); - } - - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2) && JitConfig.EnableAVX2()) - { - opts.setSupportedISA(InstructionSet_AVX2); - } - } - } - } - } - } - } + instructionSetFlags.AddInstructionSet(InstructionSet_Vector128); + instructionSetFlags.AddInstructionSet(InstructionSet_Vector256); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_LZCNT) && JitConfig.EnableLZCNT()) + if (!JitConfig.EnableSSE()) { - opts.setSupportedISA(InstructionSet_LZCNT); + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSE); #ifdef TARGET_AMD64 - opts.setSupportedISA(InstructionSet_LZCNT_X64); -#endif // TARGET_AMD64 - } - - // We currently need to also check that AVX is supported as that controls the support for the VEX encoding - // in the emitter. - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_BMI1) && JitConfig.EnableBMI1() && compSupports(InstructionSet_AVX)) - { - opts.setSupportedISA(InstructionSet_BMI1); -#ifdef TARGET_AMD64 - opts.setSupportedISA(InstructionSet_BMI1_X64); -#endif // TARGET_AMD64 + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSE_X64); +#endif } - // We currently need to also check that AVX is supported as that controls the support for the VEX encoding - // in the emitter. - if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_BMI2) && JitConfig.EnableBMI2() && compSupports(InstructionSet_AVX)) + if (!JitConfig.EnableSSE2()) { - opts.setSupportedISA(InstructionSet_BMI2); + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSE2); #ifdef TARGET_AMD64 - opts.setSupportedISA(InstructionSet_BMI2_X64); -#endif // TARGET_AMD64 - } - - if (!compIsForInlining()) - { - if (canUseVexEncoding()) - { - codeGen->GetEmitter()->SetUseVEXEncoding(true); - // Assume each JITted method does not contain AVX instruction at first - codeGen->GetEmitter()->SetContainsAVX(false); - codeGen->GetEmitter()->SetContains256bitAVX(false); - } + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSE2_X64); +#endif } -#endif // TARGET_XARCH -#if defined(TARGET_ARM64) - if (JitConfig.EnableHWIntrinsic()) + if (!JitConfig.EnableAES()) { - // Dummy ISAs for simplifying the JIT code - opts.setSupportedISA(InstructionSet_ArmBase); - opts.setSupportedISA(InstructionSet_ArmBase_Arm64); - opts.setSupportedISA(InstructionSet_Vector64); - opts.setSupportedISA(InstructionSet_Vector128); + instructionSetFlags.RemoveInstructionSet(InstructionSet_AES); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_AES) && JitConfig.EnableArm64Aes()) + if (!JitConfig.EnablePCLMULQDQ()) { - opts.setSupportedISA(InstructionSet_Aes); + instructionSetFlags.RemoveInstructionSet(InstructionSet_PCLMULQDQ); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_ATOMICS) && JitConfig.EnableArm64Atomics()) + // We need to additionaly check that COMPlus_EnableSSE3_4 is set, as that + // is a prexisting config flag that controls the SSE3+ ISAs + if (!JitConfig.EnableSSE3() || !JitConfig.EnableSSE3_4()) { - opts.setSupportedISA(InstructionSet_Atomics); + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSE3); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_CRC32) && JitConfig.EnableArm64Crc32()) + if (!JitConfig.EnableSSSE3()) { - opts.setSupportedISA(InstructionSet_Crc32); + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSSE3); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_DCPOP) && JitConfig.EnableArm64Dcpop()) + if (!JitConfig.EnableSSE41()) { - opts.setSupportedISA(InstructionSet_Dcpop); + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSE41); +#ifdef TARGET_AMD64 + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSE41_X64); +#endif } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_DP) && JitConfig.EnableArm64Dp()) + if (!JitConfig.EnableSSE42()) { - opts.setSupportedISA(InstructionSet_Dp); + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSE42); +#ifdef TARGET_AMD64 + instructionSetFlags.RemoveInstructionSet(InstructionSet_SSE42_X64); +#endif } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_FCMA) && JitConfig.EnableArm64Fcma()) + if (!JitConfig.EnablePOPCNT()) { - opts.setSupportedISA(InstructionSet_Fcma); + instructionSetFlags.RemoveInstructionSet(InstructionSet_POPCNT); +#ifdef TARGET_AMD64 + instructionSetFlags.RemoveInstructionSet(InstructionSet_POPCNT_X64); +#endif } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_FP) && JitConfig.EnableArm64Fp()) + if (!JitConfig.EnableAVX()) { - opts.setSupportedISA(InstructionSet_Fp); + instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_FP16) && JitConfig.EnableArm64Fp16()) + if (!JitConfig.EnableFMA()) { - opts.setSupportedISA(InstructionSet_Fp16); + instructionSetFlags.RemoveInstructionSet(InstructionSet_FMA); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_JSCVT) && JitConfig.EnableArm64Jscvt()) + if (!JitConfig.EnableAVX2()) { - opts.setSupportedISA(InstructionSet_Jscvt); + instructionSetFlags.RemoveInstructionSet(InstructionSet_AVX2); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_LRCPC) && JitConfig.EnableArm64Lrcpc()) + if (!JitConfig.EnableLZCNT()) { - opts.setSupportedISA(InstructionSet_Lrcpc); + instructionSetFlags.RemoveInstructionSet(InstructionSet_LZCNT); +#ifdef TARGET_AMD64 + instructionSetFlags.RemoveInstructionSet(InstructionSet_LZCNT_X64); +#endif // TARGET_AMD64 } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_PMULL) && JitConfig.EnableArm64Pmull()) + if (!JitConfig.EnableBMI1()) { - opts.setSupportedISA(InstructionSet_Pmull); + instructionSetFlags.RemoveInstructionSet(InstructionSet_BMI1); +#ifdef TARGET_AMD64 + instructionSetFlags.RemoveInstructionSet(InstructionSet_BMI1_X64); +#endif // TARGET_AMD64 } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_SHA1) && JitConfig.EnableArm64Sha1()) + if (!JitConfig.EnableBMI2()) { - opts.setSupportedISA(InstructionSet_Sha1); + instructionSetFlags.RemoveInstructionSet(InstructionSet_BMI2); +#ifdef TARGET_AMD64 + instructionSetFlags.RemoveInstructionSet(InstructionSet_BMI2_X64); +#endif // TARGET_AMD64 } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_SHA256) && JitConfig.EnableArm64Sha256()) +#endif // TARGET_XARCH +#if defined(TARGET_ARM64) + if (JitConfig.EnableHWIntrinsic()) { - opts.setSupportedISA(InstructionSet_Sha256); + // Dummy ISAs for simplifying the JIT code + instructionSetFlags.AddInstructionSet(InstructionSet_ArmBase); + instructionSetFlags.AddInstructionSet(InstructionSet_ArmBase_Arm64); + instructionSetFlags.AddInstructionSet(InstructionSet_Vector64); + instructionSetFlags.AddInstructionSet(InstructionSet_Vector128); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_SHA512) && JitConfig.EnableArm64Sha512()) + if (!JitConfig.EnableArm64Aes()) { - opts.setSupportedISA(InstructionSet_Sha512); + instructionSetFlags.RemoveInstructionSet(InstructionSet_Aes); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_SHA3) && JitConfig.EnableArm64Sha3()) + if (!JitConfig.EnableArm64Atomics()) { - opts.setSupportedISA(InstructionSet_Sha3); + instructionSetFlags.RemoveInstructionSet(InstructionSet_Atomics); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_ADVSIMD) && JitConfig.EnableArm64AdvSimd()) + if (!JitConfig.EnableArm64Crc32()) { - opts.setSupportedISA(InstructionSet_AdvSimd); - opts.setSupportedISA(InstructionSet_AdvSimd_Arm64); + instructionSetFlags.RemoveInstructionSet(InstructionSet_Crc32); + instructionSetFlags.RemoveInstructionSet(InstructionSet_Crc32_Arm64); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_ADVSIMD_V81) && JitConfig.EnableArm64AdvSimd_v81()) + if (!JitConfig.EnableArm64Sha1()) { - opts.setSupportedISA(InstructionSet_AdvSimd_v81); + instructionSetFlags.RemoveInstructionSet(InstructionSet_Sha1); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_ADVSIMD_FP16) && JitConfig.EnableArm64AdvSimd_Fp16()) + if (!JitConfig.EnableArm64Sha256()) { - opts.setSupportedISA(InstructionSet_AdvSimd_Fp16); + instructionSetFlags.RemoveInstructionSet(InstructionSet_Sha256); } - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_SM3) && JitConfig.EnableArm64Sm3()) + if (!JitConfig.EnableArm64AdvSimd()) { - opts.setSupportedISA(InstructionSet_Sm3); + instructionSetFlags.RemoveInstructionSet(InstructionSet_AdvSimd); + instructionSetFlags.RemoveInstructionSet(InstructionSet_AdvSimd_Arm64); } +#endif - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_SM4) && JitConfig.EnableArm64Sm4()) - { - opts.setSupportedISA(InstructionSet_Sm4); - } + instructionSetFlags = EnsureInstructionSetFlagsAreValid(instructionSetFlags); + opts.setSupportedISAs(jitFlags.GetInstructionSetFlags()); - if (jitFlags.IsSet(JitFlags::JIT_FLAG_HAS_ARM64_SVE) && JitConfig.EnableArm64Sve()) +#ifdef TARGET_XARCH + if (!compIsForInlining()) { - opts.setSupportedISA(InstructionSet_Sve); + if (canUseVexEncoding()) + { + codeGen->GetEmitter()->SetUseVEXEncoding(true); + // Assume each JITted method does not contain AVX instruction at first + codeGen->GetEmitter()->SetContainsAVX(false); + codeGen->GetEmitter()->SetContains256bitAVX(false); + } } -#endif +#endif // TARGET_XARCH } #ifdef PROFILING_SUPPORTED @@ -3228,6 +3158,11 @@ void Compiler::compInitOptions(JitFlags* jitFlags) printf("OPTIONS: Tier-1/FullOpts compilation, switched to MinOpts\n"); } + if (jitFlags->IsSet(JitFlags::JIT_FLAG_OSR)) + { + printf("OPTIONS: OSR variant with entry point 0x%x\n", info.compILEntry); + } + printf("OPTIONS: compCodeOpt = %s\n", (opts.compCodeOpt == BLENDED_CODE) ? "BLENDED_CODE" @@ -4278,6 +4213,10 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags // DoPhase(this, PHASE_INDXCALL, &Compiler::fgTransformIndirectCalls); + // Expand any patchpoints + // + DoPhase(this, PHASE_PATCHPOINTS, &Compiler::fgTransformPatchpoints); + // PostImportPhase: cleanup inlinees // auto postImportPhase = [this]() { @@ -4925,6 +4864,9 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags } #endif + // Generate PatchpointInfo + generatePatchpointInfo(); + RecordStateAtEndOfCompilation(); #ifdef FEATURE_TRACELOGGING @@ -4952,6 +4894,86 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags #endif // FUNC_INFO_LOGGING } +//------------------------------------------------------------------------ +// generatePatchpointInfo: allocate and fill in patchpoint info data, +// and report it to the VM +// +void Compiler::generatePatchpointInfo() +{ + if (!doesMethodHavePatchpoints()) + { + // Nothing to report + return; + } + + // Patchpoints are only found in Tier0 code, which is unoptimized, and so + // should always have frame pointer. + assert(codeGen->isFramePointerUsed()); + + // Allocate patchpoint info storage from runtime, and fill in initial bits of data. + const unsigned patchpointInfoSize = PatchpointInfo::ComputeSize(info.compLocalsCount); + PatchpointInfo* const patchpointInfo = (PatchpointInfo*)info.compCompHnd->allocateArray(patchpointInfoSize); + + // The +TARGET_POINTER_SIZE here is to account for the extra slot the runtime + // creates when it simulates calling the OSR method (the "pseudo return address" slot). + patchpointInfo->Initialize(info.compLocalsCount, codeGen->genSPtoFPdelta() + TARGET_POINTER_SIZE); + + JITDUMP("--OSR--- FP-SP delta is %d\n", patchpointInfo->FpToSpDelta()); + + // We record offsets for all the "locals" here. Could restrict + // this to just the IL locals with some extra logic, and save a bit of space, + // but would need to adjust all consumers, too. + for (unsigned lclNum = 0; lclNum < info.compLocalsCount; lclNum++) + { + LclVarDsc* const varDsc = lvaGetDesc(lclNum); + + // We expect all these to have stack homes, and be FP relative + assert(varDsc->lvOnFrame); + assert(varDsc->lvFramePointerBased); + + // Record FramePtr relative offset (no localloc yet) + patchpointInfo->SetOffset(lclNum, varDsc->lvStkOffs); + + // Note if IL stream contained an address-of that potentially leads to exposure. + // This bit of IL may be skipped by OSR partial importation. + if (varDsc->lvHasLdAddrOp) + { + patchpointInfo->SetIsExposed(lclNum); + } + + JITDUMP("--OSR-- V%02u is at offset %d%s\n", lclNum, patchpointInfo->Offset(lclNum), + patchpointInfo->IsExposed(lclNum) ? " (exposed)" : ""); + } + + // Special offsets + + if (lvaReportParamTypeArg() || lvaKeepAliveAndReportThis()) + { + const int offset = lvaToCallerSPRelativeOffset(lvaCachedGenericContextArgOffset(), true); + patchpointInfo->SetGenericContextArgOffset(offset); + JITDUMP("--OSR-- cached generic context offset is CallerSP %d\n", patchpointInfo->GenericContextArgOffset()); + } + + if (lvaKeepAliveAndReportThis()) + { + const int offset = lvaCachedGenericContextArgOffset(); + patchpointInfo->SetKeptAliveThisOffset(offset); + JITDUMP("--OSR-- kept-alive this offset is FP %d\n", patchpointInfo->KeptAliveThisOffset()); + } + + if (compGSReorderStackLayout) + { + assert(lvaGSSecurityCookie != BAD_VAR_NUM); + LclVarDsc* const varDsc = lvaGetDesc(lvaGSSecurityCookie); + patchpointInfo->SetSecurityCookieOffset(varDsc->lvStkOffs); + JITDUMP("--OSR-- security cookie V%02u offset is FP %d\n", lvaGSSecurityCookie, + patchpointInfo->SecurityCookieOffset()); + } + + // Register this with the runtime. + info.compCompHnd->setPatchpointInfo(patchpointInfo); +} + //------------------------------------------------------------------------ // ResetOptAnnotations: Clear annotations produced during global optimizations. // @@ -5208,6 +5230,19 @@ int Compiler::compCompile(CORINFO_METHOD_HANDLE methodHnd, info.compMethodHnd = methodHnd; info.compMethodInfo = methodInfo; + if (compIsForInlining()) + { + compileFlags->Clear(JitFlags::JIT_FLAG_OSR); + info.compILEntry = 0; + info.compPatchpointInfo = nullptr; + } + else if (compileFlags->IsSet(JitFlags::JIT_FLAG_OSR)) + { + // Fetch OSR info from the runtime + info.compPatchpointInfo = info.compCompHnd->getOSRInfo(&info.compILEntry); + assert(info.compPatchpointInfo != nullptr); + } + virtualStubParamInfo = new (this, CMK_Unknown) VirtualStubParamInfo(IsTargetAbi(CORINFO_CORERT_ABI)); // compMatchedVM is set to true if both CPU/ABI and OS are matching the execution engine requirements @@ -5248,28 +5283,11 @@ int Compiler::compCompile(CORINFO_METHOD_HANDLE methodHnd, // target default. Currently this is disabling all ARM64 architecture features except FP and SIMD, but this // should be altered to possibly enable all of them, when they are known to all work. - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_AES); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_ATOMICS); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_CRC32); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_DCPOP); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_DP); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_FCMA); - compileFlags->Set(JitFlags::JIT_FLAG_HAS_ARM64_FP); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_FP16); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_JSCVT); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_LRCPC); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_PMULL); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_SHA1); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_SHA256); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_SHA512); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_SHA3); - compileFlags->Set(JitFlags::JIT_FLAG_HAS_ARM64_ADVSIMD); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_ADVSIMD_V81); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_ADVSIMD_FP16); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_SM3); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_SM4); - compileFlags->Clear(JitFlags::JIT_FLAG_HAS_ARM64_SVE); - + CORINFO_InstructionSetFlags defaultArm64Flags; + defaultArm64Flags.AddInstructionSet(InstructionSet_ArmBase); + defaultArm64Flags.AddInstructionSet(InstructionSet_AdvSimd); + defaultArm64Flags.Set64BitInstructionSetVariants(); + compileFlags->SetInstructionSetFlags(defaultArm64Flags); #endif // defined(TARGET_ARM64) } @@ -6021,9 +6039,9 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, #ifdef DEBUG if ((JitConfig.DumpJittedMethods() == 1) && !compIsForInlining()) { - printf("Compiling %4d %s::%s, IL size = %u, hash=0x%08x %s%s\n", Compiler::jitTotalMethodCompiled, + printf("Compiling %4d %s::%s, IL size = %u, hash=0x%08x %s%s%s\n", Compiler::jitTotalMethodCompiled, info.compClassName, info.compMethodName, info.compILCodeSize, info.compMethodHash(), - compGetTieringName(), compGetStressMessage()); + compGetTieringName(), opts.IsOSR() ? " OSR" : "", compGetStressMessage()); } if (compIsForInlining()) { @@ -9185,3 +9203,36 @@ bool Compiler::killGCRefs(GenTree* tree) return false; } + +//------------------------------------------------------------------------ +// lvaIsOSRLocal: check if this local var is one that requires special +// treatment for OSR compilations. +// +// Arguments: +// varNum - variable of interest +// +// Return Value: +// true - this is an OSR compile and this local requires special treatment +// false - not an OSR compile, or not an interesting local for OSR + +bool Compiler::lvaIsOSRLocal(unsigned varNum) +{ + if (!opts.IsOSR()) + { + return false; + } + + if (varNum < info.compLocalsCount) + { + return true; + } + + LclVarDsc* varDsc = lvaGetDesc(varNum); + + if (varDsc->lvIsStructField) + { + return (varDsc->lvParentLcl < info.compLocalsCount); + } + + return false; +} diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index 0beb639a7e9c9f..3ddb0cddd5d885 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -2406,6 +2406,8 @@ class Compiler EHblkDsc* ehInitTryBlockRange(BasicBlock* blk, BasicBlock** tryBeg, BasicBlock** tryLast); + void fgSetTryBeg(EHblkDsc* handlerTab, BasicBlock* newTryBeg); + void fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast); void fgSetHndEnd(EHblkDsc* handlerTab, BasicBlock* newHndLast); @@ -2888,7 +2890,9 @@ class Compiler void gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut); int gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining); char* gtGetLclVarName(unsigned lclNum); - void gtDispLclVar(unsigned varNum, bool padForBiggestDisp = true); + void gtDispLclVar(unsigned lclNum, bool padForBiggestDisp = true); + void gtDispLclVarStructType(unsigned lclNum); + void gtDispClassLayout(ClassLayout* layout, var_types type); void gtDispStmt(Statement* stmt, const char* msg = nullptr); void gtDispBlockStmts(BasicBlock* block); void gtGetArgMsg(GenTreeCall* call, GenTree* arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength); @@ -3207,6 +3211,10 @@ class Compiler int lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased); int lvaGetInitialSPRelativeOffset(unsigned varNum); + // True if this is an OSR compilation and this local is potentially + // located on the original method stack frame. + bool lvaIsOSRLocal(unsigned varNum); + //------------------------ For splitting types ---------------------------- void lvaInitTypeRef(); @@ -3529,8 +3537,7 @@ class Compiler public: void impInit(); - - void impImport(BasicBlock* method); + void impImport(); CORINFO_CLASS_HANDLE impGetRefAnyClass(); CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle(); @@ -3671,7 +3678,7 @@ class Compiler bool mustExpand); protected: - bool compSupportsHWIntrinsic(InstructionSet isa); + bool compSupportsHWIntrinsic(CORINFO_InstructionSet isa); GenTree* impSpecialIntrinsic(NamedIntrinsic intrinsic, CORINFO_CLASS_HANDLE clsHnd, @@ -4146,6 +4153,7 @@ class Compiler BasicBlock* fgFirstBB; // Beginning of the basic block list BasicBlock* fgLastBB; // End of the basic block list BasicBlock* fgFirstColdBlock; // First block to be placed in the cold section + BasicBlock* fgEntryBB; // For OSR, the original method's entry point #if defined(FEATURE_EH_FUNCLETS) BasicBlock* fgFirstFuncletBB; // First block of outlined funclets (to allow block insertion before the funclets) #endif @@ -4359,6 +4367,8 @@ class Compiler void fgTransformIndirectCalls(); + void fgTransformPatchpoints(); + void fgInline(); void fgRemoveEmptyTry(); @@ -5268,11 +5278,10 @@ class Compiler public: void fgInsertStmtAtEnd(BasicBlock* block, Statement* stmt); Statement* fgNewStmtAtEnd(BasicBlock* block, GenTree* tree); + Statement* fgNewStmtNearEnd(BasicBlock* block, GenTree* tree); private: void fgInsertStmtNearEnd(BasicBlock* block, Statement* stmt); - Statement* fgNewStmtNearEnd(BasicBlock* block, GenTree* tree); - void fgInsertStmtAtBeg(BasicBlock* block, Statement* stmt); Statement* fgNewStmtAtBeg(BasicBlock* block, GenTree* tree); @@ -6370,6 +6379,7 @@ class Compiler #define OMF_HAS_OBJSTACKALLOC 0x00000040 // Method contains an object allocated on the stack. #define OMF_HAS_GUARDEDDEVIRT 0x00000080 // Method contains guarded devirtualization candidate #define OMF_HAS_EXPRUNTIMELOOKUP 0x00000100 // Method contains a runtime lookup to an expandable dictionary. +#define OMF_HAS_PATCHPOINT 0x00000200 // Method contains patchpoints bool doesMethodHaveFatPointer() { @@ -6426,6 +6436,16 @@ class Compiler void addExpRuntimeLookupCandidate(GenTreeCall* call); + bool doesMethodHavePatchpoints() + { + return (optMethodFlags & OMF_HAS_PATCHPOINT) != 0; + } + + void setMethodHasPatchpoint() + { + optMethodFlags |= OMF_HAS_PATCHPOINT; + } + unsigned optMethodFlags; bool doesMethodHaveNoReturnCalls() @@ -8274,7 +8294,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX return false; } - bool compSupports(InstructionSet isa) const + bool compSupports(CORINFO_InstructionSet isa) const { #if defined(TARGET_XARCH) || defined(TARGET_ARM64) return (opts.compSupportsISA & (1ULL << isa)) != 0; @@ -8383,11 +8403,13 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #if defined(TARGET_XARCH) || defined(TARGET_ARM64) uint64_t compSupportsISA; - void setSupportedISA(InstructionSet isa) +#endif + void setSupportedISAs(CORINFO_InstructionSetFlags isas) { - compSupportsISA |= 1ULL << isa; - } +#if defined(TARGET_XARCH) || defined(TARGET_ARM64) + compSupportsISA = isas.GetFlagsRaw(); #endif + } unsigned compFlags; // method attributes unsigned instrCount; @@ -8469,6 +8491,18 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX } #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + bool IsOSR() const + { + return jitFlags->IsSet(JitFlags::JIT_FLAG_OSR); + } +#else + bool IsOSR() const + { + return false; + } +#endif + // true if we should use the PINVOKE_{BEGIN,END} helpers instead of generating // PInvoke transitions inline (e.g. when targeting CoreRT). bool ShouldUsePInvokeHelpers() @@ -8809,11 +8843,13 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // The following holds the class attributes for the method we're compiling. unsigned compClassAttr; - const BYTE* compCode; - IL_OFFSET compILCodeSize; // The IL code size - IL_OFFSET compILImportSize; // Estimated amount of IL actually imported - UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This - // is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if: + const BYTE* compCode; + IL_OFFSET compILCodeSize; // The IL code size + IL_OFFSET compILImportSize; // Estimated amount of IL actually imported + IL_OFFSET compILEntry; // The IL entry point (normally 0) + PatchpointInfo* compPatchpointInfo; // Patchpoint data for OSR (normally nullptr) + UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This + // is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if: // (1) the code is not hot/cold split, and we issued less code than we expected, or // (2) the code is hot/cold split, and we issued less code than we expected // in the cold section (the hot section will always be padded out to compTotalHotCodeSize). @@ -9097,6 +9133,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ArenaAllocator* compGetArenaAllocator(); + void generatePatchpointInfo(); + #if MEASURE_MEM_ALLOC static bool s_dspMemStats; // Display per-phase memory statistics for every function #endif // MEASURE_MEM_ALLOC diff --git a/src/coreclr/src/jit/compphases.h b/src/coreclr/src/jit/compphases.h index f9e0684dad6871..cf0463c5f6e948 100644 --- a/src/coreclr/src/jit/compphases.h +++ b/src/coreclr/src/jit/compphases.h @@ -27,6 +27,7 @@ CompPhaseNameMacro(PHASE_PRE_IMPORT, "Pre-import", "PRE-IMP", false, -1, false) CompPhaseNameMacro(PHASE_IMPORTATION, "Importation", "IMPORT", false, -1, true) CompPhaseNameMacro(PHASE_INDXCALL, "Indirect call transform", "INDXCALL", false, -1, true) +CompPhaseNameMacro(PHASE_PATCHPOINTS, "Expand patchpoints", "PPOINT", false, -1, true) CompPhaseNameMacro(PHASE_POST_IMPORT, "Post-import", "POST-IMP", false, -1, false) CompPhaseNameMacro(PHASE_IBCINSTR, "IBC instrumentation", "IBCINSTR", false, -1, false) CompPhaseNameMacro(PHASE_MORPH_INIT, "Morph - Init", "MOR-INIT" ,false, -1, false) diff --git a/src/coreclr/src/jit/ee_il_dll.cpp b/src/coreclr/src/jit/ee_il_dll.cpp index 4ac4c24dfde058..78d3d8e59274aa 100644 --- a/src/coreclr/src/jit/ee_il_dll.cpp +++ b/src/coreclr/src/jit/ee_il_dll.cpp @@ -340,7 +340,7 @@ unsigned CILJit::getMaxIntrinsicSIMDVectorLength(CORJIT_FLAGS cpuCompileFlags) #ifdef FEATURE_SIMD #if defined(TARGET_XARCH) if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_FEATURE_SIMD) && - jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2)) + jitFlags.GetInstructionSetFlags().HasInstructionSet(InstructionSet_AVX2)) { // Since the ISAs can be disabled individually and since they are hierarchical in nature (that is // disabling SSE also disables SSE2 through AVX2), we need to check each ISA in the hierarchy to diff --git a/src/coreclr/src/jit/emitarm64.cpp b/src/coreclr/src/jit/emitarm64.cpp index e31a9ab43b5bc4..2ce9ed6f3cddfb 100644 --- a/src/coreclr/src/jit/emitarm64.cpp +++ b/src/coreclr/src/jit/emitarm64.cpp @@ -229,8 +229,8 @@ void emitter::emitInsSanityCheck(instrDesc* id) case IF_LS_2D: // LS_2D .Q.............. ....ssnnnnnttttt Vt Rn case IF_LS_2E: // LS_2E .Q.............. ....ssnnnnnttttt Vt Rn - case IF_LS_2F: // LS_2F .Q.............. ...Sssnnnnnttttt Vt[] Rn - case IF_LS_2G: // LS_2G .Q.............. ...Sssnnnnnttttt Vt[] Rn + case IF_LS_2F: // LS_2F .Q.............. xx.Sssnnnnnttttt Vt[] Rn + case IF_LS_2G: // LS_2G .Q.............. xx.Sssnnnnnttttt Vt[] Rn assert(isVectorRegister(id->idReg1())); assert(isIntegerRegister(id->idReg2())); // SP if (insOptsAnyArrangement(id->idInsOpt())) @@ -959,8 +959,8 @@ bool emitter::emitInsMayWriteToGCReg(instrDesc* id) case IF_LS_2C: // LS_2C .X.......X.iiiii iiiiP.nnnnnttttt Rt Rn imm(-256..+255) pre/post inc case IF_LS_2D: // LS_2D .Q.............. ....ssnnnnnttttt Vt Rn case IF_LS_2E: // LS_2E .Q.............. ....ssnnnnnttttt Vt Rn - case IF_LS_2F: // LS_2F .Q.............. ...Sssnnnnnttttt Vt[] Rn - case IF_LS_2G: // LS_2G .Q.............. ...Sssnnnnnttttt Vt[] Rn + case IF_LS_2F: // LS_2F .Q.............. xx.Sssnnnnnttttt Vt[] Rn + case IF_LS_2G: // LS_2G .Q.............. xx.Sssnnnnnttttt Vt[] Rn case IF_LS_3A: // LS_3A .X.......X.mmmmm xxxS..nnnnnttttt Rt Rn Rm ext(Rm) LSL {} case IF_LS_3B: // LS_3B X............... .aaaaannnnnttttt Rt Ra Rn case IF_LS_3C: // LS_3C X.........iiiiii iaaaaannnnnttttt Rt Ra Rn imm(im7,sh) @@ -9762,8 +9762,8 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) dst += emitOutput_Instr(dst, code); break; - case IF_LS_2F: // LS_2F .Q.............. ...Sssnnnnnttttt Vt[] Rn - case IF_LS_2G: // LS_2G .Q.............. ...Sssnnnnnttttt Vt[] Rn + case IF_LS_2F: // LS_2F .Q.............. xx.Sssnnnnnttttt Vt[] Rn + case IF_LS_2G: // LS_2G .Q.............. xx.Sssnnnnnttttt Vt[] Rn elemsize = id->idOpSize(); index = id->idSmallCns(); code = emitInsCode(ins, fmt); @@ -11645,8 +11645,8 @@ void emitter::emitDispIns( } break; - case IF_LS_2F: // LS_2F .Q.............. ...Sssnnnnnttttt Vt[] Rn - case IF_LS_2G: // LS_2G .Q.............. ...Sssnnnnnttttt Vt[] Rn + case IF_LS_2F: // LS_2F .Q.............. xx.Sssnnnnnttttt Vt[] Rn + case IF_LS_2G: // LS_2G .Q.............. xx.Sssnnnnnttttt Vt[] Rn registerListSize = insGetLoadStoreRegisterListSize(id->idIns()); elemsize = id->idOpSize(); emitDispVectorElemList(id->idReg1(), registerListSize, elemsize, id->idSmallCns(), true); diff --git a/src/coreclr/src/jit/emitfmtsarm64.h b/src/coreclr/src/jit/emitfmtsarm64.h index c0fd69edc05e59..401302695bb7ad 100644 --- a/src/coreclr/src/jit/emitfmtsarm64.h +++ b/src/coreclr/src/jit/emitfmtsarm64.h @@ -138,8 +138,8 @@ IF_DEF(LS_2D, IS_NONE, NONE) // LS_2D .Q.............. ....ssnnnnnttttt V // Load single structure and replicate base register IF_DEF(LS_2E, IS_NONE, NONE) // LS_2E .Q.............. ....ssnnnnnttttt Vt Rn Load/Store multiple structures post-indexed by an immediate // Load single structure and replicate post-indexed by an immediate -IF_DEF(LS_2F, IS_NONE, NONE) // LS_2F .Q.............. ...Sssnnnnnttttt Vt[] Rn Load/Store single structure base register -IF_DEF(LS_2G, IS_NONE, NONE) // LS_2G .Q.............. ...Sssnnnnnttttt Vt[] Rn Load/Store single structure post-indexed by an immediate +IF_DEF(LS_2F, IS_NONE, NONE) // LS_2F .Q.............. xx.Sssnnnnnttttt Vt[] Rn Load/Store single structure base register +IF_DEF(LS_2G, IS_NONE, NONE) // LS_2G .Q.............. xx.Sssnnnnnttttt Vt[] Rn Load/Store single structure post-indexed by an immediate IF_DEF(LS_3A, IS_NONE, NONE) // LS_3A .X.......X.mmmmm xxxS..nnnnnttttt Rt Rn Rm ext(Rm) LSL {} IF_DEF(LS_3B, IS_NONE, NONE) // LS_3B X............... .aaaaannnnnddddd Rd Ra Rn IF_DEF(LS_3C, IS_NONE, NONE) // LS_3C X.........iiiiii iaaaaannnnnddddd Rd Ra Rn imm(im7,sh) diff --git a/src/coreclr/src/jit/emitxarch.cpp b/src/coreclr/src/jit/emitxarch.cpp index f347c94d417642..bceab19a8f9804 100644 --- a/src/coreclr/src/jit/emitxarch.cpp +++ b/src/coreclr/src/jit/emitxarch.cpp @@ -1982,9 +1982,11 @@ inline UNATIVE_OFFSET emitter::emitInsSizeSV(code_t code, int var, int dsp) LclVarDsc* varDsc = emitComp->lvaTable + var; bool isRegPassedArg = varDsc->lvIsParam && varDsc->lvIsRegArg; // Register passed args could have a stack offset of 0. - noway_assert((int)offs < 0 || isRegPassedArg); + noway_assert((int)offs < 0 || isRegPassedArg || emitComp->opts.IsOSR()); #else // !UNIX_AMD64_ABI - noway_assert((int)offs < 0); + + // OSR transitioning to RBP frame currently can have mid-frame FP + noway_assert(((int)offs < 0) || emitComp->opts.IsOSR()); #endif // !UNIX_AMD64_ABI } diff --git a/src/coreclr/src/jit/flowgraph.cpp b/src/coreclr/src/jit/flowgraph.cpp index 63d80906cc6a8b..b7ccbcbda212dd 100644 --- a/src/coreclr/src/jit/flowgraph.cpp +++ b/src/coreclr/src/jit/flowgraph.cpp @@ -65,6 +65,7 @@ void Compiler::fgInit() fgFirstBB = nullptr; fgLastBB = nullptr; fgFirstColdBlock = nullptr; + fgEntryBB = nullptr; #if defined(FEATURE_EH_FUNCLETS) fgFirstFuncletBB = nullptr; @@ -4328,6 +4329,12 @@ bool Compiler::fgMayExplicitTailCall() return false; } + if (opts.IsReversePInvoke()) + { + // Reverse P/Invoke + return false; + } + #if !FEATURE_FIXED_OUT_ARGS if (info.compIsVarArgs) { @@ -5177,16 +5184,19 @@ void Compiler::fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, boo } } -/***************************************************************************** - * - * Finally link up the bbJumpDest of the blocks together - */ +//------------------------------------------------------------------------ +// fgMarkBackwardJump: mark blocks indicating there is a jump backwards in +// IL, from a higher to lower IL offset. +// +// Arguments: +// targetBlock -- target of the jump +// sourceBlock -- source of the jump -void Compiler::fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock) +void Compiler::fgMarkBackwardJump(BasicBlock* targetBlock, BasicBlock* sourceBlock) { - noway_assert(startBlock->bbNum <= endBlock->bbNum); + noway_assert(targetBlock->bbNum <= sourceBlock->bbNum); - for (BasicBlock* block = startBlock; block != endBlock->bbNext; block = block->bbNext) + for (BasicBlock* block = targetBlock; block != sourceBlock->bbNext; block = block->bbNext) { if ((block->bbFlags & BBF_BACKWARD_JUMP) == 0) { @@ -5194,6 +5204,8 @@ void Compiler::fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock) compHasBackwardJump = true; } } + + targetBlock->bbFlags |= BBF_BACKWARD_JUMP_TARGET; } /***************************************************************************** @@ -5983,6 +5995,28 @@ void Compiler::fgFindBasicBlocks() return; } + // If we are doing OSR, add an entry block that simply branches to the right IL offset. + if (opts.IsOSR()) + { + // Remember the original entry block in case this method is tail recursive. + fgEntryBB = fgLookupBB(0); + + // Find the OSR entry block. + assert(info.compILEntry >= 0); + BasicBlock* bbTarget = fgLookupBB(info.compILEntry); + + fgEnsureFirstBBisScratch(); + fgFirstBB->bbJumpKind = BBJ_ALWAYS; + fgFirstBB->bbJumpDest = bbTarget; + fgAddRefPred(bbTarget, fgFirstBB); + + JITDUMP("OSR: redirecting flow at entry via " FMT_BB " to " FMT_BB " (il offset 0x%x)\n", fgFirstBB->bbNum, + bbTarget->bbNum, info.compILEntry); + + // rebuild lookup table... should be able to avoid this by leaving room up front. + fgInitBBLookup(); + } + /* Mark all blocks within 'try' blocks as such */ if (info.compXcptnsCount == 0) @@ -6859,7 +6893,7 @@ unsigned Compiler::fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNestin void Compiler::fgImport() { - impImport(fgFirstBB); + impImport(); // Estimate how much of method IL was actually imported. // @@ -9693,118 +9727,238 @@ void Compiler::fgSimpleLowering() #endif } -/***************************************************************************** - * - * Find and remove any basic blocks that are useless (e.g. they have not been - * imported because they are not reachable, or they have been optimized away). - */ - +//------------------------------------------------------------------------ +// fgRemoveEmptyBlocks: clean up flow graph after importation +// +// Notes: +// +// Find and remove any basic blocks that are useless (e.g. they have not been +// imported because they are not reachable, or they have been optimized away). +// +// Remove try regions where no blocks in the try were imported. +// Update the end of try and handler regions where trailing blocks were not imported. +// Update the start of try regions that were partially imported (OSR) +// void Compiler::fgRemoveEmptyBlocks() { + JITDUMP("\n*************** In fgRemoveEmptyBlocks\n"); + BasicBlock* cur; BasicBlock* nxt; - /* If we remove any blocks, we'll have to do additional work */ - + // If we remove any blocks, we'll have to do additional work unsigned removedBlks = 0; for (cur = fgFirstBB; cur != nullptr; cur = nxt) { - /* Get hold of the next block (in case we delete 'cur') */ - + // Get hold of the next block (in case we delete 'cur') nxt = cur->bbNext; - /* Should this block be removed? */ - + // Should this block be removed? if (!(cur->bbFlags & BBF_IMPORTED)) { noway_assert(cur->isEmpty()); if (ehCanDeleteEmptyBlock(cur)) { - /* Mark the block as removed */ + JITDUMP(FMT_BB " was not imported, marking as removed (%d)\n", cur->bbNum, removedBlks); cur->bbFlags |= BBF_REMOVED; - - /* Remember that we've removed a block from the list */ - removedBlks++; -#ifdef DEBUG - if (verbose) - { - printf(FMT_BB " was not imported, marked as removed (%d)\n", cur->bbNum, removedBlks); - } -#endif // DEBUG - - /* Drop the block from the list */ - + // Drop the block from the list. + // + // We rely on the fact that this does not clear out + // cur->bbNext or cur->bbPrev in the code that + // follows. fgUnlinkBlock(cur); } else { - // We were prevented from deleting this block by EH normalization. Mark the block as imported. + // We were prevented from deleting this block by EH + // normalization. Mark the block as imported. cur->bbFlags |= BBF_IMPORTED; } } } - /* If no blocks were removed, we're done */ - + // If no blocks were removed, we're done if (removedBlks == 0) { return; } - /* Update all references in the exception handler table. - * Mark the new blocks as non-removable. - * - * We may have made the entire try block unreachable. - * Check for this case and remove the entry from the EH table. - */ - + // Update all references in the exception handler table. + // + // We may have made the entire try block unreachable. + // Check for this case and remove the entry from the EH table. + // + // For OSR, just the initial part of a try range may become + // unreachable; if so we need to shrink the try range down + // to the portion that was imported. unsigned XTnum; EHblkDsc* HBtab; - INDEBUG(unsigned delCnt = 0;) + unsigned delCnt = 0; + // Walk the EH regions from inner to outer for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++) { AGAIN: - /* If the beginning of the try block was not imported, we - * need to remove the entry from the EH table. */ + // If start of a try region was not imported, then we either + // need to trim the region extent, or remove the region + // entirely. + // + // In normal importation, it is not valid to jump into the + // middle of a try, so if the try entry was not imported, the + // entire try can be removed. + // + // In OSR importation the entry patchpoint may be in the + // middle of a try, and we need to determine how much of the + // try ended up getting imported. Because of backwards + // branches we may end up importing the entire try even though + // execution starts in the middle. + // + // Note it is common in both cases for the ends of trys (and + // associated handlers) to end up not getting imported, so if + // the try region is not removed, we always check if we need + // to trim the ends. + // if (HBtab->ebdTryBeg->bbFlags & BBF_REMOVED) { - noway_assert(!(HBtab->ebdTryBeg->bbFlags & BBF_IMPORTED)); -#ifdef DEBUG - if (verbose) + // Usual case is that the entire try can be removed. + bool removeTryRegion = true; + + if (opts.IsOSR()) { - printf("Beginning of try block (" FMT_BB ") not imported " - "- remove index #%u from the EH table\n", - HBtab->ebdTryBeg->bbNum, XTnum + delCnt); - } - delCnt++; -#endif // DEBUG + // For OSR we may need to trim the try region start. + // + // We rely on the fact that removed blocks have been snipped from + // the main block list, but that those removed blocks have kept + // their bbprev (and bbnext) links. + // + // Find the first unremoved block before the try entry block. + // + BasicBlock* const oldTryEntry = HBtab->ebdTryBeg; + BasicBlock* tryEntryPrev = oldTryEntry->bbPrev; + while ((tryEntryPrev != nullptr) && ((tryEntryPrev->bbFlags & BBF_REMOVED) != 0)) + { + tryEntryPrev = tryEntryPrev->bbPrev; + } - fgRemoveEHTableEntry(XTnum); + // Because we've added an unremovable scratch block as + // fgFirstBB, this backwards walk should always find + // some block. + assert(tryEntryPrev != nullptr); - if (XTnum < compHndBBtabCount) - { - // There are more entries left to process, so do more. Note that - // HBtab now points to the next entry, that we copied down to the - // current slot. XTnum also stays the same. - goto AGAIN; + // If there is a next block of this prev block, and that block is + // contained in the current try, we'd like to make that block + // the new start of the try, and keep the region. + BasicBlock* newTryEntry = tryEntryPrev->bbNext; + bool updateTryEntry = false; + + if ((newTryEntry != nullptr) && bbInTryRegions(XTnum, newTryEntry)) + { + // We want to trim the begin extent of the current try region to newTryEntry. + // + // This method is invoked after EH normalization, so we may need to ensure all + // try regions begin at blocks that are not the start or end of some other try. + // + // So, see if this block is already the start or end of some other EH region. + if (bbIsTryBeg(newTryEntry)) + { + // We've already end-trimmed the inner try. Do the same now for the + // current try, so it is easier to detect when they mutually protect. + // (we will call this again later, which is harmless). + fgSkipRmvdBlocks(HBtab); + + // If this try and the inner try form a "mutually protected try region" + // then we must continue to share the try entry block. + EHblkDsc* const HBinner = ehGetBlockTryDsc(newTryEntry); + assert(HBinner->ebdTryBeg == newTryEntry); + + if (HBtab->ebdTryLast != HBinner->ebdTryLast) + { + updateTryEntry = true; + } + } + // Also, a try and handler cannot start at the same block + else if (bbIsHandlerBeg(newTryEntry)) + { + updateTryEntry = true; + } + + if (updateTryEntry) + { + // We need to trim the current try to begin at a different block. Normally + // this would be problematic as we don't have enough context to redirect + // all the incoming edges, but we know oldTryEntry is unreachable. + // So there are no incoming edges to worry about. + // + assert(!tryEntryPrev->bbFallsThrough()); + + // What follows is similar to fgNewBBInRegion, but we can't call that + // here as the oldTryEntry is no longer in the main bb list. + newTryEntry = bbNewBasicBlock(BBJ_NONE); + newTryEntry->bbFlags |= (BBF_IMPORTED | BBF_INTERNAL); + + // Set the right EH region indices on this new block. + // + // Patchpoints currently cannot be inside handler regions, + // and so likewise the old and new try region entries. + assert(!oldTryEntry->hasHndIndex()); + newTryEntry->setTryIndex(XTnum); + newTryEntry->clearHndIndex(); + fgInsertBBafter(tryEntryPrev, newTryEntry); + + JITDUMP("OSR: changing start of try region #%u from " FMT_BB " to new " FMT_BB "\n", + XTnum + delCnt, oldTryEntry->bbNum, newTryEntry->bbNum); + } + else + { + // We can just trim the try to newTryEntry as it is not part of some inner try or handler. + JITDUMP("OSR: changing start of try region #%u from " FMT_BB " to " FMT_BB "\n", XTnum + delCnt, + oldTryEntry->bbNum, newTryEntry->bbNum); + } + + // Update the handler table + fgSetTryBeg(HBtab, newTryEntry); + + // Try entry blocks get specially marked and have special protection. + HBtab->ebdTryBeg->bbFlags |= BBF_DONT_REMOVE | BBF_TRY_BEG | BBF_HAS_LABEL; + + // We are keeping this try region + removeTryRegion = false; + } } - break; // no more entries (we deleted the last one), so exit the loop - } + if (removeTryRegion) + { + // In the dump, refer to the region by its original index. + JITDUMP("Try region #%u (" FMT_BB " -- " FMT_BB ") not imported, removing try from the EH table\n", + XTnum + delCnt, HBtab->ebdTryBeg->bbNum, HBtab->ebdTryLast->bbNum); -/* At this point we know we have a valid try block */ + delCnt++; -#ifdef DEBUG + fgRemoveEHTableEntry(XTnum); + + if (XTnum < compHndBBtabCount) + { + // There are more entries left to process, so do more. Note that + // HBtab now points to the next entry, that we copied down to the + // current slot. XTnum also stays the same. + goto AGAIN; + } + + // no more entries (we deleted the last one), so exit the loop + break; + } + } + + // If we get here, the try entry block was not removed. + // Check some invariants. assert(HBtab->ebdTryBeg->bbFlags & BBF_IMPORTED); assert(HBtab->ebdTryBeg->bbFlags & BBF_DONT_REMOVE); - assert(HBtab->ebdHndBeg->bbFlags & BBF_IMPORTED); assert(HBtab->ebdHndBeg->bbFlags & BBF_DONT_REMOVE); @@ -9813,10 +9967,10 @@ void Compiler::fgRemoveEmptyBlocks() assert(HBtab->ebdFilter->bbFlags & BBF_IMPORTED); assert(HBtab->ebdFilter->bbFlags & BBF_DONT_REMOVE); } -#endif // DEBUG + // Finally, do region end trimming -- update try and handler ends to reflect removed blocks. fgSkipRmvdBlocks(HBtab); - } /* end of the for loop over XTnum */ + } // Renumber the basic blocks JITDUMP("\nRenumbering the basic blocks for fgRemoveEmptyBlocks\n"); @@ -13222,6 +13376,10 @@ void Compiler::fgComputeCalledCount(BasicBlock::weight_t returnWeight) { fgFirstBB->bbFlags |= BBF_RUN_RARELY; } + else + { + fgFirstBB->bbFlags &= ~BBF_RUN_RARELY; + } } #if DEBUG @@ -20570,6 +20728,12 @@ bool BBPredsChecker::CheckEhTryDsc(BasicBlock* block, BasicBlock* blockPred, EHb return true; } + // For OSR, we allow the firstBB to branch to the middle of a try. + if (comp->opts.IsOSR() && (blockPred == comp->fgFirstBB)) + { + return true; + } + printf("Jump into the middle of try region: " FMT_BB " branches to " FMT_BB "\n", blockPred->bbNum, block->bbNum); assert(!"Jump into middle of try region"); return false; @@ -20752,6 +20916,7 @@ void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRef #endif // DEBUG fgDebugCheckBlockLinks(); + fgFirstBBisScratch(); if (fgBBcount > 10000 && expensiveDebugCheckLevel < 1) { diff --git a/src/coreclr/src/jit/gcencode.cpp b/src/coreclr/src/jit/gcencode.cpp index 5d05f969a1f48d..a346b9fd1ab258 100644 --- a/src/coreclr/src/jit/gcencode.cpp +++ b/src/coreclr/src/jit/gcencode.cpp @@ -22,6 +22,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #endif #include "gcinfotypes.h" +#include "patchpointinfo.h" ReturnKind GCTypeToReturnKind(CorInfoGCType gcType) { @@ -3888,20 +3889,43 @@ void GCInfo::gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSiz assert(false); } - gcInfoEncoderWithLog->SetGenericsInstContextStackSlot( - compiler->lvaToCallerSPRelativeOffset(compiler->lvaCachedGenericContextArgOffset(), - compiler->isFramePointerUsed()), - ctxtParamType); + int offset = 0; + + if (compiler->opts.IsOSR()) + { + PatchpointInfo* ppInfo = compiler->info.compPatchpointInfo; + offset = ppInfo->GenericContextArgOffset(); + assert(offset != -1); + } + else + { + offset = compiler->lvaToCallerSPRelativeOffset(compiler->lvaCachedGenericContextArgOffset(), + compiler->isFramePointerUsed()); + } + + gcInfoEncoderWithLog->SetGenericsInstContextStackSlot(offset, ctxtParamType); } // As discussed above, handle the case where the generics context is obtained via // the method table of "this". else if (compiler->lvaKeepAliveAndReportThis()) { assert(compiler->info.compThisArg != BAD_VAR_NUM); - gcInfoEncoderWithLog->SetGenericsInstContextStackSlot( - compiler->lvaToCallerSPRelativeOffset(compiler->lvaCachedGenericContextArgOffset(), - compiler->isFramePointerUsed()), - GENERIC_CONTEXTPARAM_THIS); + + int offset = 0; + + if (compiler->opts.IsOSR()) + { + PatchpointInfo* ppInfo = compiler->info.compPatchpointInfo; + offset = ppInfo->GenericContextArgOffset(); + assert(offset != -1); + } + else + { + offset = compiler->lvaToCallerSPRelativeOffset(compiler->lvaCachedGenericContextArgOffset(), + compiler->isFramePointerUsed()); + } + + gcInfoEncoderWithLog->SetGenericsInstContextStackSlot(offset, GENERIC_CONTEXTPARAM_THIS); } if (compiler->getNeedsGSSecurityCookie()) @@ -3909,12 +3933,27 @@ void GCInfo::gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSiz assert(compiler->lvaGSSecurityCookie != BAD_VAR_NUM); // The lv offset is FP-relative, and the using code expects caller-sp relative, so translate. + int offset = compiler->lvaGetCallerSPRelativeOffset(compiler->lvaGSSecurityCookie); + + if (compiler->opts.IsOSR()) + { + // The offset computed above already includes the OSR frame adjustment, plus the + // pop of the "pseudo return address" from the OSR frame. + // + // To get to caller-SP, we need to subtract off the original frame size and the + // pushed RA and RBP for that frame. But ppInfo's FpToSpDelta also accounts for the + // pseudo RA between the original method frame and the OSR frame. So the net adjustment + // is simply FpToSpDelta plus one register. + PatchpointInfo* ppInfo = compiler->info.compPatchpointInfo; + int adjustment = ppInfo->FpToSpDelta() + REGSIZE_BYTES; + offset -= adjustment; + JITDUMP("OSR cookie adjustment %d, final caller-SP offset %d\n", adjustment, offset); + } + // The code offset ranges assume that the GS Cookie slot is initialized in the prolog, and is valid // through the remainder of the method. We will not query for the GS Cookie while we're in an epilog, // so the question of where in the epilog it becomes invalid is moot. - gcInfoEncoderWithLog->SetGSCookieStackSlot(compiler->lvaGetCallerSPRelativeOffset( - compiler->lvaGSSecurityCookie), - prologSize, methodSize); + gcInfoEncoderWithLog->SetGSCookieStackSlot(offset, prologSize, methodSize); } else if (compiler->lvaReportParamTypeArg() || compiler->lvaKeepAliveAndReportThis()) { diff --git a/src/coreclr/src/jit/gentree.cpp b/src/coreclr/src/jit/gentree.cpp index d31a8709080d72..1f0d2e7bf3b02f 100644 --- a/src/coreclr/src/jit/gentree.cpp +++ b/src/coreclr/src/jit/gentree.cpp @@ -10040,18 +10040,7 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, __in __in_z _ if (layout != nullptr) { - if (layout->IsBlockLayout()) - { - printf("<%u>", layout->GetSize()); - } - else if (varTypeIsSIMD(tree->TypeGet())) - { - printf("<%s>", layout->GetClassName()); - } - else - { - printf("<%s, %u>", layout->GetClassName(), layout->GetSize()); - } + gtDispClassLayout(layout, tree->TypeGet()); } } @@ -10413,6 +10402,69 @@ void Compiler::gtDispLclVar(unsigned lclNum, bool padForBiggestDisp) } } +//------------------------------------------------------------------------ +// gtDispLclVarStructType: Print size and type information about a struct or lclBlk local variable. +// +// Arguments: +// lclNum - The local var id. +// +void Compiler::gtDispLclVarStructType(unsigned lclNum) +{ + LclVarDsc* varDsc = lvaGetDesc(lclNum); + var_types type = varDsc->TypeGet(); + if (type == TYP_STRUCT) + { + ClassLayout* layout = varDsc->GetLayout(); + assert(layout != nullptr); + gtDispClassLayout(layout, type); + } + else if (type == TYP_LCLBLK) + { +#if FEATURE_FIXED_OUT_ARGS + assert(lclNum == lvaOutgoingArgSpaceVar); + // Since lvaOutgoingArgSpaceSize is a PhasedVar we can't read it for Dumping until + // after we set it to something. + if (lvaOutgoingArgSpaceSize.HasFinalValue()) + { + // A PhasedVar can't be directly used as an arg to a variadic function + unsigned value = lvaOutgoingArgSpaceSize; + printf("<%u> ", value); + } + else + { + printf(" "); // The value hasn't yet been determined + } +#else + assert(!"Unknown size"); + NO_WAY("Target doesn't support TYP_LCLBLK"); +#endif // FEATURE_FIXED_OUT_ARGS + } +} + +//------------------------------------------------------------------------ +// gtDispClassLayout: Print size and type information about a layout. +// +// Arguments: +// layout - the layout; +// type - variable type, used to avoid printing size for SIMD nodes. +// +void Compiler::gtDispClassLayout(ClassLayout* layout, var_types type) +{ + assert(layout != nullptr); + if (layout->IsBlockLayout()) + { + printf("<%u>", layout->GetSize()); + } + else if (varTypeIsSIMD(type)) + { + printf("<%s>", layout->GetClassName()); + } + else + { + printf("<%s, %u>", layout->GetClassName(), layout->GetSize()); + } +} + /*****************************************************************************/ void Compiler::gtDispConst(GenTree* tree) { diff --git a/src/coreclr/src/jit/gschecks.cpp b/src/coreclr/src/jit/gschecks.cpp index cc1bb6fc58021e..e31998d3b5a429 100644 --- a/src/coreclr/src/jit/gschecks.cpp +++ b/src/coreclr/src/jit/gschecks.cpp @@ -24,7 +24,7 @@ void Compiler::gsGSChecksInitCookie() { var_types type = TYP_I_IMPL; - lvaGSSecurityCookie = lvaGrabTemp(false DEBUGARG("GSSecurityCookie")); + lvaGSSecurityCookie = lvaGrabTempWithImplicitUse(false DEBUGARG("GSSecurityCookie")); // Prevent cookie init/check from being optimized lvaSetVarAddrExposed(lvaGSSecurityCookie); diff --git a/src/coreclr/src/jit/hwintrinsic.cpp b/src/coreclr/src/jit/hwintrinsic.cpp index 0aef72951e3b90..4af653b766e6be 100644 --- a/src/coreclr/src/jit/hwintrinsic.cpp +++ b/src/coreclr/src/jit/hwintrinsic.cpp @@ -61,12 +61,11 @@ var_types Compiler::getBaseTypeFromArgIfNeeded(NamedIntrinsic intrinsic, { HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic); - if (category == HW_Category_MemoryStore || HWIntrinsicInfo::BaseTypeFromSecondArg(intrinsic) || - HWIntrinsicInfo::BaseTypeFromFirstArg(intrinsic)) + if (HWIntrinsicInfo::BaseTypeFromSecondArg(intrinsic) || HWIntrinsicInfo::BaseTypeFromFirstArg(intrinsic)) { CORINFO_ARG_LIST_HANDLE arg = sig->args; - if ((category == HW_Category_MemoryStore) || HWIntrinsicInfo::BaseTypeFromSecondArg(intrinsic)) + if (HWIntrinsicInfo::BaseTypeFromSecondArg(intrinsic)) { arg = info.compCompHnd->getArgNext(arg); } @@ -303,7 +302,7 @@ NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, const char* enclosingClassName) { // TODO-Throughput: replace sequential search by binary search - InstructionSet isa = lookupIsa(className, enclosingClassName); + CORINFO_InstructionSet isa = lookupIsa(className, enclosingClassName); if (isa == InstructionSet_ILLEGAL) { @@ -585,7 +584,7 @@ GenTree* Compiler::addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* immO // // Return Value: // true iff the given instruction set is supported in the current compilation. -bool Compiler::compSupportsHWIntrinsic(InstructionSet isa) +bool Compiler::compSupportsHWIntrinsic(CORINFO_InstructionSet isa) { return JitConfig.EnableHWIntrinsic() && (featureSIMD || HWIntrinsicInfo::isScalarIsa(isa)) && ( @@ -630,11 +629,11 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, CORINFO_SIG_INFO* sig, bool mustExpand) { - InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsic); - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic); - int numArgs = sig->numArgs; - var_types retType = JITtype2varType(sig->retType); - var_types baseType = TYP_UNKNOWN; + CORINFO_InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsic); + HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic); + int numArgs = sig->numArgs; + var_types retType = JITtype2varType(sig->retType); + var_types baseType = TYP_UNKNOWN; if ((retType == TYP_STRUCT) && featureSIMD) { diff --git a/src/coreclr/src/jit/hwintrinsic.h b/src/coreclr/src/jit/hwintrinsic.h index 2931c51813e1ed..b80dce7f1c0b00 100644 --- a/src/coreclr/src/jit/hwintrinsic.h +++ b/src/coreclr/src/jit/hwintrinsic.h @@ -113,15 +113,15 @@ enum HWIntrinsicFlag : unsigned int struct HWIntrinsicInfo { - NamedIntrinsic id; - const char* name; - InstructionSet isa; - int ival; - unsigned simdSize; - int numArgs; - instruction ins[10]; - HWIntrinsicCategory category; - HWIntrinsicFlag flags; + NamedIntrinsic id; + const char* name; + CORINFO_InstructionSet isa; + int ival; + unsigned simdSize; + int numArgs; + instruction ins[10]; + HWIntrinsicCategory category; + HWIntrinsicFlag flags; static const HWIntrinsicInfo& lookup(NamedIntrinsic id); @@ -129,7 +129,7 @@ struct HWIntrinsicInfo const char* className, const char* methodName, const char* enclosingClassName); - static InstructionSet lookupIsa(const char* className, const char* enclosingClassName); + static CORINFO_InstructionSet lookupIsa(const char* className, const char* enclosingClassName); static unsigned lookupSimdSize(Compiler* comp, NamedIntrinsic id, CORINFO_SIG_INFO* sig); static int lookupNumArgs(const GenTreeHWIntrinsic* node); @@ -138,8 +138,8 @@ struct HWIntrinsicInfo static bool isImmOp(NamedIntrinsic id, const GenTree* op); static bool isInImmRange(NamedIntrinsic id, int ival); - static bool isFullyImplementedIsa(InstructionSet isa); - static bool isScalarIsa(InstructionSet isa); + static bool isFullyImplementedIsa(CORINFO_InstructionSet isa); + static bool isScalarIsa(CORINFO_InstructionSet isa); #ifdef TARGET_XARCH static bool isAVX2GatherIntrinsic(NamedIntrinsic id); @@ -157,7 +157,7 @@ struct HWIntrinsicInfo return lookup(id).name; } - static InstructionSet lookupIsa(NamedIntrinsic id) + static CORINFO_InstructionSet lookupIsa(NamedIntrinsic id) { return lookup(id).isa; } diff --git a/src/coreclr/src/jit/hwintrinsicarm64.cpp b/src/coreclr/src/jit/hwintrinsicarm64.cpp index 1f7dde990cc7d7..7f494ab96582f5 100644 --- a/src/coreclr/src/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/src/jit/hwintrinsicarm64.cpp @@ -15,7 +15,7 @@ // // Return Value: // The 64-bit only InstructionSet associated with isa -static InstructionSet Arm64VersionOfIsa(InstructionSet isa) +static CORINFO_InstructionSet Arm64VersionOfIsa(CORINFO_InstructionSet isa) { switch (isa) { @@ -38,7 +38,7 @@ static InstructionSet Arm64VersionOfIsa(InstructionSet isa) // // Return Value: // The InstructionSet associated with className -static InstructionSet lookupInstructionSet(const char* className) +static CORINFO_InstructionSet lookupInstructionSet(const char* className) { assert(className != nullptr); @@ -99,7 +99,7 @@ static InstructionSet lookupInstructionSet(const char* className) // // Return Value: // The InstructionSet associated with className and enclosingClassName -InstructionSet HWIntrinsicInfo::lookupIsa(const char* className, const char* enclosingClassName) +CORINFO_InstructionSet HWIntrinsicInfo::lookupIsa(const char* className, const char* enclosingClassName) { assert(className != nullptr); @@ -153,7 +153,7 @@ bool HWIntrinsicInfo::isInImmRange(NamedIntrinsic id, int ival) // // Return Value: // true if isa is supported; otherwise, false -bool HWIntrinsicInfo::isFullyImplementedIsa(InstructionSet isa) +bool HWIntrinsicInfo::isFullyImplementedIsa(CORINFO_InstructionSet isa) { switch (isa) { @@ -188,7 +188,7 @@ bool HWIntrinsicInfo::isFullyImplementedIsa(InstructionSet isa) // // Return Value: // true if isa is scalar; otherwise, false -bool HWIntrinsicInfo::isScalarIsa(InstructionSet isa) +bool HWIntrinsicInfo::isScalarIsa(CORINFO_InstructionSet isa) { switch (isa) { diff --git a/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp index 178f760a11f4d8..6853b59712243d 100644 --- a/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp @@ -301,6 +301,10 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) GetEmitter()->emitIns_R_R_R_R(ins, emitSize, targetReg, op2Reg, op3Reg, op1Reg); break; + case NI_AdvSimd_Store: + GetEmitter()->emitIns_R_R(ins, emitSize, op2Reg, op1Reg, opt); + break; + default: unreached(); } diff --git a/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp index 1ba67be0bb2d9e..cb5160e5cb9373 100644 --- a/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp @@ -79,11 +79,11 @@ static bool genIsTableDrivenHWIntrinsic(NamedIntrinsic intrinsicId, HWIntrinsicC // void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { - NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; - InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsicId); - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); - int ival = HWIntrinsicInfo::lookupIval(intrinsicId); - int numArgs = HWIntrinsicInfo::lookupNumArgs(node); + NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + CORINFO_InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsicId); + HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); + int ival = HWIntrinsicInfo::lookupIval(intrinsicId); + int numArgs = HWIntrinsicInfo::lookupNumArgs(node); assert(HWIntrinsicInfo::RequiresCodegen(intrinsicId)); diff --git a/src/coreclr/src/jit/hwintrinsiclistarm64.h b/src/coreclr/src/jit/hwintrinsiclistarm64.h index 8be27939f4e13c..ac2a571b34e843 100644 --- a/src/coreclr/src/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/src/jit/hwintrinsiclistarm64.h @@ -97,6 +97,7 @@ HARDWARE_INTRINSIC(AdvSimd, Or, - HARDWARE_INTRINSIC(AdvSimd, OrNot, -1, -1, 2, {INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd, PopCount, -1, -1, 1, {INS_cnt, INS_cnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd, SqrtScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsqrt, INS_fsqrt}, HW_Category_SIMDScalar, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AdvSimd, Store, -1, -1, 2, {INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_UnfixedSIMDSize|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) HARDWARE_INTRINSIC(AdvSimd, Subtract, -1, -1, 2, {INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_fsub, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AdvSimd, SubtractScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sub, INS_sub, INS_fsub, INS_fsub}, HW_Category_SIMDScalar, HW_Flag_NoContainment) HARDWARE_INTRINSIC(AdvSimd, Xor, -1, -1, 2, {INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) diff --git a/src/coreclr/src/jit/hwintrinsiclistxarch.h b/src/coreclr/src/jit/hwintrinsiclistxarch.h index 9cb005b8a0f7d8..de3add9c696272 100644 --- a/src/coreclr/src/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/src/jit/hwintrinsiclistxarch.h @@ -155,13 +155,13 @@ HARDWARE_INTRINSIC(SSE_ReciprocalSqrtScalar, "ReciprocalS HARDWARE_INTRINSIC(SSE_Shuffle, "Shuffle", SSE, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shufps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(SSE_Sqrt, "Sqrt", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_SqrtScalar, "SqrtScalar", SSE, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_Store, "Store", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_StoreAligned, "StoreAligned", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movntps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_Store, "Store", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE_StoreAligned, "StoreAligned", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movntps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) HARDWARE_INTRINSIC(SSE_StoreFence, "StoreFence", SSE, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_StoreHigh, "StoreHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_StoreLow, "StoreLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_StoreScalar, "StoreScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE_StoreHigh, "StoreHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE_StoreLow, "StoreLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE_StoreScalar, "StoreScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) HARDWARE_INTRINSIC(SSE_Subtract, "Subtract", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE_SubtractScalar, "SubtractScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE_UnpackHigh, "UnpackHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpckhps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) @@ -245,7 +245,7 @@ HARDWARE_INTRINSIC(SSE2_LoadHigh, "LoadHigh", HARDWARE_INTRINSIC(SSE2_LoadLow, "LoadLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlpd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_LoadScalarVector128, "LoadScalarVector128", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_movd, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_LoadVector128, "LoadVector128", SSE2, -1, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_MaskMove, "MaskMove", SSE2, -1, 16, 3, {INS_maskmovdqu, INS_maskmovdqu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_MaskMove, "MaskMove", SSE2, -1, 16, 3, {INS_maskmovdqu, INS_maskmovdqu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) HARDWARE_INTRINSIC(SSE2_Max, "Max", SSE2, -1, 16, 2, {INS_invalid, INS_pmaxub, INS_pmaxsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(SSE2_MemoryFence, "MemoryFence", SSE2, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_MaxScalar, "MaxScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) @@ -272,13 +272,13 @@ HARDWARE_INTRINSIC(SSE2_ShuffleHigh, "ShuffleHigh HARDWARE_INTRINSIC(SSE2_ShuffleLow, "ShuffleLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_pshuflw, INS_pshuflw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(SSE2_Sqrt, "Sqrt", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_SqrtScalar, "SqrtScalar", SSE2, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_Store, "Store", SSE2, -1, 16, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_StoreAligned, "StoreAligned", SSE2, -1, 16, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE2, -1, 16, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_invalid, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_StoreHigh, "StoreHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_StoreLow, "StoreLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_StoreNonTemporal, "StoreNonTemporal", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movnti, INS_movnti, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(SSE2_StoreScalar, "StoreScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_Store, "Store", SSE2, -1, 16, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2_StoreAligned, "StoreAligned", SSE2, -1, 16, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE2, -1, 16, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_invalid, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2_StoreHigh, "StoreHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2_StoreLow, "StoreLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2_StoreNonTemporal, "StoreNonTemporal", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movnti, INS_movnti, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2_StoreScalar, "StoreScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) HARDWARE_INTRINSIC(SSE2_Subtract, "Subtract", SSE2, -1, 16, 2, {INS_psubb, INS_psubb, INS_psubw, INS_psubw, INS_psubd, INS_psubd, INS_psubq, INS_psubq, INS_invalid, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_SubtractSaturate, "SubtractSaturate", SSE2, -1, 16, 2, {INS_psubsb, INS_psubusb, INS_psubsw, INS_psubusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_SubtractScalar, "SubtractScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) @@ -297,7 +297,7 @@ HARDWARE_INTRINSIC(SSE2_X64_ConvertToUInt64, "ConvertToUI HARDWARE_INTRINSIC(SSE2_X64_ConvertScalarToVector128Double, "ConvertScalarToVector128Double", SSE2_X64, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2sd, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) HARDWARE_INTRINSIC(SSE2_X64_ConvertScalarToVector128Int64, "ConvertScalarToVector128Int64", SSE2_X64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(SSE2_X64_ConvertScalarToVector128UInt64, "ConvertScalarToVector128UInt64", SSE2_X64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(SSE2_X64_StoreNonTemporal, "StoreNonTemporal", SSE2_X64, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movnti, INS_movnti, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(SSE2_X64_StoreNonTemporal, "StoreNonTemporal", SSE2_X64, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movnti, INS_movnti, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags @@ -447,9 +447,9 @@ HARDWARE_INTRINSIC(AVX_RoundToPositiveInfinity, "RoundToPosi HARDWARE_INTRINSIC(AVX_RoundToZero, "RoundToZero", AVX, 11, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_Shuffle, "Shuffle", AVX, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shufps, INS_shufpd}, HW_Category_IMM, HW_Flag_NoRMWSemantics|HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(AVX_Sqrt, "Sqrt", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_Store, "Store", AVX, -1, 32, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_StoreAligned, "StoreAligned", AVX, -1, 32, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", AVX, -1, 32, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntps, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX_Store, "Store", AVX, -1, 32, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AVX_StoreAligned, "StoreAligned", AVX, -1, 32, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AVX_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", AVX, -1, 32, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntps, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) HARDWARE_INTRINSIC(AVX_Subtract, "Subtract", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX_TestC, "TestC", AVX, -1, 0, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(AVX_TestNotZAndNotC, "TestNotZAndNotC", AVX, -1, 0, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/src/jit/hwintrinsicxarch.cpp b/src/coreclr/src/jit/hwintrinsicxarch.cpp index 6aa59aa2bb7f68..80b341f1c90ecb 100644 --- a/src/coreclr/src/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/src/jit/hwintrinsicxarch.cpp @@ -15,7 +15,7 @@ // // Return Value: // The 64-bit only InstructionSet associated with isa -static InstructionSet X64VersionOfIsa(InstructionSet isa) +static CORINFO_InstructionSet X64VersionOfIsa(CORINFO_InstructionSet isa) { switch (isa) { @@ -48,7 +48,7 @@ static InstructionSet X64VersionOfIsa(InstructionSet isa) // // Return Value: // The InstructionSet associated with className -static InstructionSet lookupInstructionSet(const char* className) +static CORINFO_InstructionSet lookupInstructionSet(const char* className) { assert(className != nullptr); if (className[0] == 'A') @@ -147,7 +147,7 @@ static InstructionSet lookupInstructionSet(const char* className) // // Return Value: // The InstructionSet associated with className and enclosingClassName -InstructionSet HWIntrinsicInfo::lookupIsa(const char* className, const char* enclosingClassName) +CORINFO_InstructionSet HWIntrinsicInfo::lookupIsa(const char* className, const char* enclosingClassName) { assert(className != nullptr); @@ -253,7 +253,7 @@ bool HWIntrinsicInfo::isAVX2GatherIntrinsic(NamedIntrinsic id) // // Return Value: // true if isa is supported; otherwise, false -bool HWIntrinsicInfo::isFullyImplementedIsa(InstructionSet isa) +bool HWIntrinsicInfo::isFullyImplementedIsa(CORINFO_InstructionSet isa) { switch (isa) { @@ -302,7 +302,7 @@ bool HWIntrinsicInfo::isFullyImplementedIsa(InstructionSet isa) // // Return Value: // true if isa is scalar; otherwise, false -bool HWIntrinsicInfo::isScalarIsa(InstructionSet isa) +bool HWIntrinsicInfo::isScalarIsa(CORINFO_InstructionSet isa) { switch (isa) { diff --git a/src/coreclr/src/jit/importer.cpp b/src/coreclr/src/jit/importer.cpp index e553a179714f66..64470231697357 100644 --- a/src/coreclr/src/jit/importer.cpp +++ b/src/coreclr/src/jit/importer.cpp @@ -7349,11 +7349,18 @@ var_types Compiler::impImportCall(OPCODE opcode, // Also, popping arguments in a varargs function is more work and NYI // If we have a security object, we have to keep our frame around for callers // to see any imperative security. + // Reverse P/Invokes need a call to CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT + // at the end, so tailcalls should be disabled. if (info.compFlags & CORINFO_FLG_SYNCH) { canTailCall = false; szCanTailCallFailReason = "Caller is synchronized"; } + else if (opts.IsReversePInvoke()) + { + canTailCall = false; + szCanTailCallFailReason = "Caller is Reverse P/Invoke"; + } #if !FEATURE_FIXED_OUT_ARGS else if (info.compIsVarArgs) { @@ -8495,10 +8502,37 @@ var_types Compiler::impImportCall(OPCODE opcode, if ((tailCallFlags != 0) && canTailCall && gtIsRecursiveCall(methHnd)) { assert(verCurrentState.esStackDepth == 0); + BasicBlock* loopHead = nullptr; + if (opts.IsOSR()) + { + // We might not have been planning on importing the method + // entry block, but now we must. + + // We should have remembered the real method entry block. + assert(fgEntryBB != nullptr); + + JITDUMP("\nOSR: found tail recursive call in the method, scheduling " FMT_BB " for importation\n", + fgEntryBB->bbNum); + impImportBlockPending(fgEntryBB); + + // Note there is no explicit flow to this block yet, + // make sure it stays around until we actually try + // the optimization. + fgEntryBB->bbFlags |= BBF_DONT_REMOVE; + + loopHead = fgEntryBB; + } + else + { + // For normal jitting we'll branch back to the firstBB; this + // should already be imported. + loopHead = fgFirstBB; + } + JITDUMP("\nFound tail recursive call in the method. Mark " FMT_BB " to " FMT_BB " as having a backward branch.\n", - fgFirstBB->bbNum, compCurBB->bbNum); - fgMarkBackwardJump(fgFirstBB, compCurBB); + loopHead->bbNum, compCurBB->bbNum); + fgMarkBackwardJump(loopHead, compCurBB); } // Note: we assume that small return types are already normalized by the managed callee @@ -10510,6 +10544,35 @@ void Compiler::impImportBlockCode(BasicBlock* block) impBeginTreeList(); +#ifdef FEATURE_ON_STACK_REPLACEMENT + + // Are there any places in the method where we might add a patchpoint? + if (compHasBackwardJump) + { + // Are patchpoints enabled? + if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0) && (JitConfig.TC_OnStackReplacement() > 0)) + { + // We don't inline at Tier0, if we do, we may need rethink our approach. + // Could probably support inlines that don't introduce flow. + assert(!compIsForInlining()); + + // Is the start of this block a suitable patchpoint? + // Current strategy is blocks that are stack-empty and backwards branch targets + if (block->bbFlags & BBF_BACKWARD_JUMP_TARGET && (verCurrentState.esStackDepth == 0)) + { + block->bbFlags |= BBF_PATCHPOINT; + setMethodHasPatchpoint(); + } + } + } + else + { + // Should not see backward branch targets w/o backwards branches + assert((block->bbFlags & BBF_BACKWARD_JUMP_TARGET) == 0); + } + +#endif // FEATURE_ON_STACK_REPLACEMENT + /* Walk the opcodes that comprise the basic block */ const BYTE* codeAddr = info.compCode + block->bbCodeOffs; @@ -11429,6 +11492,11 @@ void Compiler::impImportBlockCode(BasicBlock* block) BADCODE("Jmp not allowed in protected region"); } + if (opts.IsReversePInvoke()) + { + BADCODE("Jmp not allowed in reverse P/Invoke"); + } + if (verCurrentState.esStackDepth != 0) { BADCODE("Stack must be empty after CEE_JMPs"); @@ -16734,10 +16802,13 @@ void Compiler::impVerifyEHBlock(BasicBlock* block, bool isTryStart) assert(HBtab->HasFaultHandler()); } } + } - /* Recursively process the handler block */ - BasicBlock* hndBegBB = HBtab->ebdHndBeg; + // Recursively process the handler block, if we haven't already done so. + BasicBlock* hndBegBB = HBtab->ebdHndBeg; + if (((hndBegBB->bbFlags & BBF_IMPORTED) == 0) && (impGetPendingBlockMember(hndBegBB) == 0)) + { // Construct the proper verification stack state // either empty or one that contains just // the Exception Object that we are dealing with @@ -16773,18 +16844,22 @@ void Compiler::impVerifyEHBlock(BasicBlock* block, bool isTryStart) // Queue up the handler for importing // impImportBlockPending(hndBegBB); + } - if (HBtab->HasFilter()) - { - /* @VERIFICATION : Ideally the end of filter state should get - propagated to the catch handler, this is an incompleteness, - but is not a security/compliance issue, since the only - interesting state is the 'thisInit' state. - */ + // Process the filter block, if we haven't already done so. + if (HBtab->HasFilter()) + { + /* @VERIFICATION : Ideally the end of filter state should get + propagated to the catch handler, this is an incompleteness, + but is not a security/compliance issue, since the only + interesting state is the 'thisInit' state. + */ - verCurrentState.esStackDepth = 0; + BasicBlock* filterBB = HBtab->ebdFilter; - BasicBlock* filterBB = HBtab->ebdFilter; + if (((filterBB->bbFlags & BBF_IMPORTED) == 0) && (impGetPendingBlockMember(filterBB) == 0)) + { + verCurrentState.esStackDepth = 0; // push catch arg the stack, spill to a temp if necessary // Note: can update HBtab->ebdFilter! @@ -16794,7 +16869,9 @@ void Compiler::impVerifyEHBlock(BasicBlock* block, bool isTryStart) impImportBlockPending(filterBB); } } - else if (verTrackObjCtorInitState && HBtab->HasFaultHandler()) + + // This seems redundant ....?? + if (verTrackObjCtorInitState && HBtab->HasFaultHandler()) { /* Recursively process the handler block */ @@ -17861,7 +17938,7 @@ void Compiler::impSpillCliqueSetMember(SpillCliqueDir predOrSucc, BasicBlock* bl * basic flowgraph has already been constructed and is passed in. */ -void Compiler::impImport(BasicBlock* method) +void Compiler::impImport() { #ifdef DEBUG if (verbose) @@ -17923,21 +18000,45 @@ void Compiler::impImport(BasicBlock* method) impPendingList = impPendingFree = nullptr; - /* Add the entry-point to the worker-list */ + // Skip leading internal blocks. + // These can arise from needing a leading scratch BB, from EH normalization, and from OSR entry redirects. + // + // We expect a linear flow to the first non-internal block. But not necessarily straght-line flow. + BasicBlock* entryBlock = fgFirstBB; - // Skip leading internal blocks. There can be one as a leading scratch BB, and more - // from EH normalization. - // NOTE: It might be possible to always just put fgFirstBB on the pending list, and let everything else just fall - // out. - for (; method->bbFlags & BBF_INTERNAL; method = method->bbNext) + while (entryBlock->bbFlags & BBF_INTERNAL) { - // Treat these as imported. - assert(method->bbJumpKind == BBJ_NONE); // We assume all the leading ones are fallthrough. - JITDUMP("Marking leading BBF_INTERNAL block " FMT_BB " as BBF_IMPORTED\n", method->bbNum); - method->bbFlags |= BBF_IMPORTED; + JITDUMP("Marking leading BBF_INTERNAL block " FMT_BB " as BBF_IMPORTED\n", entryBlock->bbNum); + entryBlock->bbFlags |= BBF_IMPORTED; + + if (entryBlock->bbJumpKind == BBJ_NONE) + { + entryBlock = entryBlock->bbNext; + } + else if (entryBlock->bbJumpKind == BBJ_ALWAYS) + { + // Only expected for OSR + assert(opts.IsOSR()); + entryBlock = entryBlock->bbJumpDest; + } + else + { + assert(!"unexpected bbJumpKind in entry sequence"); + } } - impImportBlockPending(method); + // Note for OSR we'd like to be able to verify this block must be + // stack empty, but won't know that until we've imported...so instead + // we'll BADCODE out if we mess up. + // + // (the concern here is that the runtime asks us to OSR a + // different IL version than the one that matched the method that + // triggered OSR). This should not happen but I might have the + // IL versioning stuff wrong. + // + // TODO: we also currently expect this block to be a join point, + // which we should verify over when we find jump targets. + impImportBlockPending(entryBlock); /* Import blocks in the worker-list until there are no more */ diff --git a/src/coreclr/src/jit/indirectcalltransformer.cpp b/src/coreclr/src/jit/indirectcalltransformer.cpp index caec347798031c..6aadc37683a963 100644 --- a/src/coreclr/src/jit/indirectcalltransformer.cpp +++ b/src/coreclr/src/jit/indirectcalltransformer.cpp @@ -681,11 +681,12 @@ class IndirectCallTransformer } //------------------------------------------------------------------------ - // CreateThen: create else block with direct call to method + // CreateThen: create then block with direct call to method // virtual void CreateThen() { thenBlock = CreateAndInsertBasicBlock(BBJ_ALWAYS, checkBlock); + thenBlock->bbFlags |= currBlock->bbFlags & BBF_SPLIT_GAINED; InlineCandidateInfo* inlineInfo = origCall->gtInlineCandidateInfo; CORINFO_CLASS_HANDLE clsHnd = inlineInfo->clsHandle; @@ -758,7 +759,8 @@ class IndirectCallTransformer // virtual void CreateElse() { - elseBlock = CreateAndInsertBasicBlock(BBJ_NONE, thenBlock); + elseBlock = CreateAndInsertBasicBlock(BBJ_NONE, thenBlock); + elseBlock->bbFlags |= currBlock->bbFlags & BBF_SPLIT_GAINED; GenTreeCall* call = origCall; Statement* newStmt = compiler->gtNewStmt(call); diff --git a/src/coreclr/src/jit/instr.h b/src/coreclr/src/jit/instr.h index 0de79a4cc1387f..26ba6eec4ac016 100644 --- a/src/coreclr/src/jit/instr.h +++ b/src/coreclr/src/jit/instr.h @@ -292,71 +292,6 @@ enum emitAttr : unsigned #define EmitSize(x) (EA_ATTR(genTypeSize(TypeGet(x)))) -enum InstructionSet -{ - InstructionSet_ILLEGAL = 0, -#ifdef TARGET_XARCH - InstructionSet_Vector128, - InstructionSet_Vector256, - // Start linear order SIMD instruction sets - // These ISAs have strictly generation to generation order. - InstructionSet_SSE, - InstructionSet_SSE2, - InstructionSet_SSE3, - InstructionSet_SSSE3, - InstructionSet_SSE41, - InstructionSet_SSE42, - InstructionSet_AVX, - InstructionSet_AVX2, - // End linear order SIMD instruction sets. - InstructionSet_AES, - InstructionSet_BMI1, - InstructionSet_BMI2, - InstructionSet_FMA, - InstructionSet_LZCNT, - InstructionSet_PCLMULQDQ, - InstructionSet_POPCNT, - InstructionSet_BMI1_X64, - InstructionSet_BMI2_X64, - InstructionSet_LZCNT_X64, - InstructionSet_POPCNT_X64, - InstructionSet_SSE_X64, - InstructionSet_SSE2_X64, - InstructionSet_SSE41_X64, - InstructionSet_SSE42_X64, -#elif defined(TARGET_ARM) - InstructionSet_NEON, -#elif defined(TARGET_ARM64) - InstructionSet_AdvSimd, // ID_AA64PFR0_EL1.AdvSIMD is 0 or better - InstructionSet_AdvSimd_Arm64, - InstructionSet_AdvSimd_Fp16, // ID_AA64PFR0_EL1.AdvSIMD is 1 or better - InstructionSet_AdvSimd_v81, // ID_AA64ISAR0_EL1.RDM is 1 or better - InstructionSet_Aes, // ID_AA64ISAR0_EL1.AES is 1 or better - InstructionSet_ArmBase, - InstructionSet_ArmBase_Arm64, - InstructionSet_Atomics, // ID_AA64ISAR0_EL1.Atomic is 2 or better - InstructionSet_Crc32, // ID_AA64ISAR0_EL1.CRC32 is 1 or better - InstructionSet_Crc32_Arm64, - InstructionSet_Dcpop, // ID_AA64ISAR1_EL1.DPB is 1 or better - InstructionSet_Dp, // ID_AA64ISAR0_EL1.DP is 1 or better - InstructionSet_Fcma, // ID_AA64ISAR1_EL1.FCMA is 1 or better - InstructionSet_Fp, // ID_AA64PFR0_EL1.FP is 0 or better - InstructionSet_Fp16, // ID_AA64PFR0_EL1.FP is 1 or better - InstructionSet_Jscvt, // ID_AA64ISAR1_EL1.JSCVT is 1 or better - InstructionSet_Lrcpc, // ID_AA64ISAR1_EL1.LRCPC is 1 or better - InstructionSet_Pmull, // ID_AA64ISAR0_EL1.AES is 2 or better - InstructionSet_Sha1, // ID_AA64ISAR0_EL1.SHA1 is 1 or better - InstructionSet_Sha256, // ID_AA64ISAR0_EL1.SHA2 is 1 or better - InstructionSet_Sha512, // ID_AA64ISAR0_EL1.SHA2 is 2 or better - InstructionSet_Sha3, // ID_AA64ISAR0_EL1.SHA3 is 1 or better - InstructionSet_Sm3, // ID_AA64ISAR0_EL1.SM3 is 1 or better - InstructionSet_Sm4, // ID_AA64ISAR0_EL1.SM4 is 1 or better - InstructionSet_Sve, // ID_AA64PFR0_EL1.SVE is 1 or better - InstructionSet_Vector64, - InstructionSet_Vector128, -#endif - InstructionSet_NONE // No instruction set is available indicating an invalid value -}; // clang-format on /*****************************************************************************/ diff --git a/src/coreclr/src/jit/instrsarm64.h b/src/coreclr/src/jit/instrsarm64.h index 6958660ac68a32..f41a70466dcac8 100644 --- a/src/coreclr/src/jit/instrsarm64.h +++ b/src/coreclr/src/jit/instrsarm64.h @@ -87,65 +87,81 @@ INST6(sub, "sub", 0, 0, IF_EN6A, 0x4B000000, 0x4B000000, 0x4B200000, // enum name FP LD/ST LS_2D LS_3F LS_2E LS_2F LS_3G LS_2G INST6(ld1, "ld1", 0, LD, IF_EN6B, 0x0C407000, 0x0CC07000, 0x0CDF7000, 0x0D400000, 0x0DC00000, 0x0DDF0000) + // C7.2.170 LD1 (multiple structures, one register variant) // ld1 {Vt},[Xn] LS_2D 0Q00110001000000 0111ssnnnnnttttt 0C40 7000 base register // ld1 {Vt},[Xn],Xm LS_3F 0Q001100110mmmmm 0111ssnnnnnttttt 0CC0 7000 post-indexed by a register // ld1 {Vt},[Xn],#imm LS_2E 0Q00110011011111 0111ssnnnnnttttt 0CDF 7000 post-indexed by an immediate + // C7.2.171 LD1 (single structure) // ld1 {Vt}[],[Xn] LS_2F 0Q00110101000000 xx0Sssnnnnnttttt 0D40 0000 base register // ld1 {Vt}[],[Xn],Xm LS_3G 0Q001101110mmmmm xx0Sssnnnnnttttt 0DC0 0000 post-indexed by a register // ld1 {Vt}[],[Xn],#imm LS_2G 0Q00110111011111 xx0Sssnnnnnttttt 0DDF 0000 post-indexed by an immediate INST6(ld2, "ld2", 0, LD, IF_EN6B, 0x0C408000, 0x0CC08000, 0x0CDF8000, 0x0D600000, 0x0DE00000, 0x0DFF0000) + // C7.2.173 LD2 (multiple structures) // ld2 {Vt,Vt2},[Xn] LS_2D 0Q00110001000000 1000ssnnnnnttttt 0C40 8000 base register // ld2 {Vt,Vt2},[Xn],Xm LS_3F 0Q001100110mmmmm 1000ssnnnnnttttt 0CC0 8000 post-indexed by a register // ld2 {Vt,Vt2},[Xn],#imm LS_2E 0Q001100110mmmmm 1000ssnnnnnttttt 0CDF 8000 post-indexed by an immediate + // C7.2.174 LD2 (single structure) // ld2 {Vt,Vt2}[],[Xn] LS_2F 0Q00110101100000 xx0Sssnnnnnttttt 0D60 0000 base register // ld2 {Vt,Vt2}[],[Xn],Xm LS_3G 0Q001101111mmmmm xx0Sssnnnnnttttt 0DE0 0000 post-indexed by a register // ld2 {Vt,Vt2}[],[Xn],#imm LS_2G 0Q00110111111111 xx0Sssnnnnnttttt 0DFF 0000 post-indexed by an immediate INST6(ld3, "ld3", 0, LD, IF_EN6B, 0x0C404000, 0x0CC04000, 0x0CDF4000, 0x0D402000, 0x0DC02000, 0x0DDF2000) + // C7.2.176 LD3 (multiple structures) // ld3 {Vt-Vt3},[Xn] LS_2D 0Q00110001000000 0100ssnnnnnttttt 0C40 4000 base register // ld3 {Vt-Vt3},[Xn],Xm LS_3F 0Q001100110mmmmm 0100ssnnnnnttttt 0CC0 4000 post-indexed by a register // ld3 {Vt-Vt3},[Xn],#imm LS_2E 0Q001100110mmmmm 0100ssnnnnnttttt 0CDF 4000 post-indexed by an immediate + // C7.2.177 LD3 (single structure) // ld3 {Vt-Vt3}[],[Xn] LS_2F 0Q00110101000000 xx1Sssnnnnnttttt 0D40 2000 base register // ld3 {Vt-Vt3}[],[Xn],Xm LS_3G 0Q001101110mmmmm xx1Sssnnnnnttttt 0DC0 2000 post-indexed by a register // ld3 {Vt-Vt3}[],[Xn],#imm LS_2G 0Q00110111011111 xx1Sssnnnnnttttt 0DDF 2000 post-indexed by an immediate INST6(ld4, "ld4", 0, LD, IF_EN6B, 0x0C400000, 0x0CC00000, 0x0CDF0000, 0x0D602000, 0x0DE02000, 0x0DFF2000) + // C7.2.179 LD4 (multiple structures) // ld4 {Vt-Vt4},[Xn] LS_2D 0Q00110001000000 0000ssnnnnnttttt 0C40 0000 base register // ld4 {Vt-Vt4},[Xn],Xm LS_3F 0Q001100110mmmmm 0000ssnnnnnttttt 0CC0 0000 post-indexed by a register // ld4 {Vt-Vt4},[Xn],#imm LS_2E 0Q00110011011111 0000ssnnnnnttttt 0CDF 0000 post-indexed by an immediate + // C7.2.180 LD4 (single structure) // ld4 {Vt-Vt4}[],[Xn] LS_2F 0Q00110101100000 xx1Sssnnnnnttttt 0D60 2000 base register // ld4 {Vt-Vt4}[],[Xn],Xm LS_3G 0Q001101111mmmmm xx1Sssnnnnnttttt 0DE0 2000 post-indexed by a register // ld4 {Vt-Vt4}[],[Xn],#imm LS_2G 0Q00110111111111 xx1Sssnnnnnttttt 0DFF 2000 post-indexed by an immediate INST6(st1, "st1", 0, LD, IF_EN6B, 0x0C007000, 0x0C807000, 0x0C9F7000, 0x0D000000, 0x0D800000, 0x0D9F0000) + // C7.2.313 ST1 (multiple structures, one register variant) // st1 {Vt},[Xn] LS_2D 0Q00110000000000 0111ssnnnnnttttt 0C00 7000 base register // st1 {Vt},[Xn],Xm LS_3F 0Q001100100mmmmm 0111ssnnnnnttttt 0C80 7000 post-indexed by a register // st1 {Vt},[Xn],#imm LS_2E 0Q00110010011111 0111ssnnnnnttttt 0C9F 7000 post-indexed by an immediate + // C7.2.314 ST1 (single structure) // st1 {Vt}[],[Xn] LS_2F 0Q00110100000000 xx0Sssnnnnnttttt 0D00 0000 base register // st1 {Vt}[],[Xn],Xm LS_3G 0Q001101100mmmmm xx0Sssnnnnnttttt 0D80 0000 post-indexed by a register // st1 {Vt}[],[Xn],#imm LS_2G 0Q00110110011111 xx0Sssnnnnnttttt 0D9F 0000 post-indexed by an immediate INST6(st2, "st2", 0, ST, IF_EN6B, 0x0C008000, 0x0C808000, 0x0C9F8000, 0x0D200000, 0x0DA00000, 0x0DBF0000) + // C7.2.315 ST2 (multiple structures) // st2 {Vt,Vt2},[Xn] LS_2D 0Q00110000000000 1000ssnnnnnttttt 0C00 8000 base register // st2 {Vt,Vt2},[Xn],Xm LS_3F 0Q001100100mmmmm 1000ssnnnnnttttt 0C80 8000 post-indexed by a register // st2 {Vt,Vt2},[Xn],#imm LS_2E 0Q00110010011111 1000ssnnnnnttttt 0C9F 8000 post-indexed by an immediate + // C7.2.316 ST2 (single structure) // st2 {Vt,Vt2}[],[Xn] LS_2F 0Q00110100100000 xx0Sssnnnnnttttt 0D20 0000 base register // st2 {Vt,Vt2}[],[Xn],Xm LS_3G 0Q001101101mmmmm xx0Sssnnnnnttttt 0DA0 0000 post-indexed by a register // st2 {Vt,Vt2}[],[Xn],#imm LS_2G 0Q00110110111111 xx0Sssnnnnnttttt 0DBF 0000 post-indexed by an immediate INST6(st3, "st3", 0, ST, IF_EN6B, 0x0C004000, 0x0C804000, 0x0C9F4000, 0x0D002000, 0x0D802000, 0x0D9F2000) + // C7.2.317 ST3 (multiple structures) // st3 {Vt-Vt3},[Xn] LS_2D 0Q00110000000000 0100ssnnnnnttttt 0C00 4000 base register // st3 {Vt-Vt3},[Xn],Xm LS_3F 0Q001100100mmmmm 0100ssnnnnnttttt 0C80 4000 post-indexed by a register // st3 {Vt-Vt3},[Xn],#imm LS_2E 0Q00110010011111 0100ssnnnnnttttt 0C9F 4000 post-indexed by an immediate + // C7.2.318 ST3 (single structure) // st3 {Vt-Vt3}[],[Xn] LS_2F 0Q00110100000000 xx1Sssnnnnnttttt 0D00 2000 base register // st3 {Vt-Vt3}[],[Xn],Xm LS_3G 0Q001101100mmmmm xx1Sssnnnnnttttt 0D80 2000 post-indexed by a register // st3 {Vt-Vt3}[],[Xn],#imm LS_2G 0Q00110110011111 xx1Sssnnnnnttttt 0D9F 2000 post-indexed by an immediate INST6(st4, "st4", 0, ST, IF_EN6B, 0x0C000000, 0x0C800000, 0x0C9F0000, 0x0D202000, 0x0DA02000, 0x0DBF2000) + // C7.2.319 ST4 (multiple structures) // st4 {Vt-Vt4},[Xn] LS_2D 0Q00110000000000 0000ssnnnnnttttt 0C00 0000 base register // st4 {Vt-Vt4},[Xn],Xm LS_3F 0Q001100100mmmmm 0000ssnnnnnttttt 0C80 0000 post-indexed by a register // st4 {Vt-Vt4},[Xn],#imm LS_2E 0Q00110010011111 0000ssnnnnnttttt 0C9F 0000 post-indexed by an immediate + // C7.2.320 ST4 (single structure) // st4 {Vt-Vt4}[],[Xn] LS_2F 0Q00110100100000 xx1Sssnnnnnttttt 0D20 2000 base register // st4 {Vt-Vt4}[],[Xn],Xm LS_3G 0Q001101101mmmmm xx1Sssnnnnnttttt 0DA0 2000 post-indexed by a register // st4 {Vt-Vt4}[],[Xn],#imm LS_2G 0Q00110110111111 xx1Sssnnnnnttttt 0DBF 2000 post-indexed by an immediate @@ -438,51 +454,61 @@ INST3(mvn, "mvn", 0, 0, IF_EN3I, 0x2A2003E0, 0x2A2003E0, 0x2E205800) // enum name FP LD/ST LS_2D LS_3F LS_2E INST3(ld1_2regs,"ld1", 0,LD, IF_EN3J, 0x0C40A000, 0x0CC0A000, 0x0CDFA000) + // C7.2.170 LD1 (multiple structures, two registers variant) // ld1 {Vt,Vt2},[Xn] LS_2D 0Q00110001000000 1010ssnnnnnttttt 0C40 A000 base register // ld1 {Vt,Vt2},[Xn],Xm LS_3F 0Q001100110mmmmm 1010ssnnnnnttttt 0CC0 A000 post-indexed by a register // ld1 {Vt,Vt2},[Xn],#imm LS_2E 0Q00110011011111 1010ssnnnnnttttt 0CDF A000 post-indexed by an immediate INST3(ld1_3regs,"ld1", 0,LD, IF_EN3J, 0x0C406000, 0x0CC06000, 0x0CDF6000) + // C7.2.170 LD1 (multiple structures, three registers variant) // ld1 {Vt-Vt3},[Xn] LS_2D 0Q00110001000000 0110ssnnnnnttttt 0C40 6000 base register // ld1 {Vt-Vt3},[Xn],Xm LS_3F 0Q001100110mmmmm 0110ssnnnnnttttt 0CC0 6000 post-indexed by a register // ld1 {Vt-Vt3},[Xn],#imm LS_2E 0Q00110011011111 0110ssnnnnnttttt 0CDF 6000 post-indexed by an immediate INST3(ld1_4regs,"ld1", 0,LD, IF_EN3J, 0x0C402000, 0x0CC02000, 0x0CDF2000) + // C7.2.170 LD1 (multiple structures, four registers variant) // ld1 {Vt-Vt4},[Xn] LS_2D 0Q00110001000000 0010ssnnnnnttttt 0C40 2000 base register // ld1 {Vt-Vt4},[Xn],Xm LS_3F 0Q001100110mmmmm 0010ssnnnnnttttt 0CC0 2000 post-indexed by a register // ld1 {Vt-Vt4},[Xn],#imm LS_2E 0Q00110011011111 0010ssnnnnnttttt 0CDF 2000 post-indexed by an immediate INST3(st1_2regs,"st1", 0,ST, IF_EN3J, 0x0C00A000, 0x0C80A000, 0x0C9FA000) + // C7.2.313 ST1 (multiple structures, two registers variant) // st1 {Vt,Vt2},[Xn] LS_2D 0Q00110000000000 1010ssnnnnnttttt 0C00 A000 base register // st1 {Vt,Vt2},[Xn],Xm LS_3F 0Q001100100mmmmm 1010ssnnnnnttttt 0C80 A000 post-indexed by a register // st1 {Vt,Vt2},[Xn],#imm LS_2E 0Q00110010011111 1010ssnnnnnttttt 0C9F A000 post-indexed by an immediate INST3(st1_3regs,"st1", 0,ST, IF_EN3J, 0x0C006000, 0x0C806000, 0x0C9F6000) + // C7.2.313 ST1 (multiple structures, three registers variant) // st1 {Vt-Vt3},[Xn] LS_2D 0Q00110000000000 0110ssnnnnnttttt 0C00 6000 base register // st1 {Vt-Vt3},[Xn],Xm LS_3F 0Q001100100mmmmm 0110XXnnnnnttttt 0C80 6000 post-indexed by a register // st1 {Vt-Vt3},[Xn],#imm LS_2E 0Q00110010011111 0110XXnnnnnttttt 0C9F 6000 post-indexed by an immediate INST3(st1_4regs,"st1", 0,ST, IF_EN3J, 0x0C002000, 0x0C802000, 0x0C9F2000) + // C7.2.313 ST1 (multiple structures, four registers variant) // st1 {Vt-Vt4},[Xn] LS_2D 0Q00110000000000 0010XXnnnnnttttt 0C00 2000 base register // st1 {Vt-Vt4},[Xn],Xm LS_3F 0Q001100100mmmmm 0010XXnnnnnttttt 0C80 2000 post-indexed by a register // st1 {Vt-Vt4},[Xn],#imm LS_2E 0Q00110010011111 0010XXnnnnnttttt 0C9F 2000 post-indexed by an immediate INST3(ld1r, "ld1r", 0,LD, IF_EN3J, 0x0D40C000, 0x0DC0C000, 0x0DDFC000) + // C7.2.172 LD1R // ld1r {Vt},[Xn] LS_2D 0Q00110101000000 1100ssnnnnnttttt 0D40 C000 base register // ld1r {Vt},[Xn],Xm LS_3F 0Q001101110mmmmm 1100ssnnnnnttttt 0DC0 C000 post-indexed by a register // ld1r {Vt},[Xn],#1 LS_2E 0Q00110111011111 1100ssnnnnnttttt 0DDF C000 post-indexed by an immediate INST3(ld2r, "ld2r", 0,LD, IF_EN3J, 0x0D60C000, 0x0DE0C000, 0x0DFFC000) + // C7.2.175 LD2R // ld2r {Vt,Vt2},[Xn] LS_2D 0Q00110101100000 1100ssnnnnnttttt 0D60 C000 base register // ld2r {Vt,Vt2},[Xn],Xm LS_3F 0Q001101111mmmmm 1100ssnnnnnttttt 0DE0 C000 post-indexed by a register // ld2r {Vt,Vt2},[Xn],#2 LS_2E 0Q00110111111111 1100ssnnnnnttttt 0DFF C000 post-indexed by an immediate INST3(ld3r, "ld3r", 0,LD, IF_EN3J, 0x0D40E000, 0x0DC0E000, 0x0DDFE000) + // C7.2.178 LD3R // ld3r {Vt-Vt3},[Xn] LS_2D 0Q00110101000000 1110ssnnnnnttttt 0D40 E000 base register // ld3r {Vt-Vt3},[Xn],Xm LS_3F 0Q001101110mmmmm 1110ssnnnnnttttt 0DC0 E000 post-indexed by a register // ld3r {Vt-Vt3},[Xn],#4 LS_2E 0Q00110111011111 1110ssnnnnnttttt 0DDF E000 post-indexed by an immediate INST3(ld4r, "ld4r", 0,LD, IF_EN3J, 0x0D60E000, 0x0DE0E000, 0x0DFFE000) + // C7.2.181 LD4R // ld4r {Vt-Vt4},[Xn] LS_2D 0Q00110101100000 1110ssnnnnnttttt 0D60 E000 base register // ld4r {Vt-Vt4},[Xn],Xm LS_3F 0Q001101111mmmmm 1110ssnnnnnttttt 0DE0 E000 post-indexed by a register // ld4r {Vt-Vt4},[Xn],#8 LS_2E 0Q00110111111111 1110ssnnnnnttttt 0DFF E000 post-indexed by an immediate diff --git a/src/coreclr/src/jit/jitconfigvalues.h b/src/coreclr/src/jit/jitconfigvalues.h index 70f65eb5ebf9d2..65b92b55ba1338 100644 --- a/src/coreclr/src/jit/jitconfigvalues.h +++ b/src/coreclr/src/jit/jitconfigvalues.h @@ -394,6 +394,11 @@ CONFIG_INTEGER(JitGuardedDevirtualizationGuessUniqueInterface, W("JitGuardedDevi CONFIG_INTEGER(JitGuardedDevirtualizationGuessBestClass, W("JitGuardedDevirtualizationGuessBestClass"), 1) #endif // DEBUG +// Enable insertion of patchpoints into Tier0 methods with loops. +CONFIG_INTEGER(TC_OnStackReplacement, W("TC_OnStackReplacement"), 0) +// Initial patchpoint counter value used by jitted code +CONFIG_INTEGER(TC_OnStackReplacement_InitialCounter, W("TC_OnStackReplacement_InitialCounter"), 1000) + #if defined(DEBUG) // JitFunctionFile: Name of a file that contains a list of functions. If the currently compiled function is in the // file, certain other JIT config variables will be active. If the currently compiled function is not in the file, diff --git a/src/coreclr/src/jit/jitee.h b/src/coreclr/src/jit/jitee.h index 4f9df37e92de8c..405ef9a7d74219 100644 --- a/src/coreclr/src/jit/jitee.h +++ b/src/coreclr/src/jit/jitee.h @@ -27,7 +27,6 @@ class JitFlags JIT_FLAG_TARGET_P4 = 9, JIT_FLAG_USE_FCOMI = 10, // Generated code may use fcomi(p) instruction JIT_FLAG_USE_CMOV = 11, // Generated code may use cmov instruction - JIT_FLAG_USE_SSE2 = 12, // Generated code may use SSE-2 instructions #else // !defined(TARGET_X86) @@ -39,22 +38,12 @@ class JitFlags #endif // !defined(TARGET_X86) - JIT_FLAG_UNUSED6 = 13, - - #if defined(TARGET_X86) || defined(TARGET_AMD64) - - JIT_FLAG_USE_AVX = 14, - JIT_FLAG_USE_AVX2 = 15, - JIT_FLAG_USE_AVX_512 = 16, - - #else // !defined(TARGET_X86) && !defined(TARGET_AMD64) + JIT_FLAG_OSR = 13, // Generate alternate version for On Stack Replacement JIT_FLAG_UNUSED7 = 14, JIT_FLAG_UNUSED8 = 15, JIT_FLAG_UNUSED9 = 16, - #endif // !defined(TARGET_X86) && !defined(TARGET_AMD64) - #if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64) JIT_FLAG_FEATURE_SIMD = 17, #else @@ -93,57 +82,6 @@ class JitFlags JIT_FLAG_NO_INLINING = 42, // JIT should not inline any called method into this method -#if defined(TARGET_ARM64) - - JIT_FLAG_HAS_ARM64_AES = 43, // ID_AA64ISAR0_EL1.AES is 1 or better - JIT_FLAG_HAS_ARM64_ATOMICS = 44, // ID_AA64ISAR0_EL1.Atomic is 2 or better - JIT_FLAG_HAS_ARM64_CRC32 = 45, // ID_AA64ISAR0_EL1.CRC32 is 1 or better - JIT_FLAG_HAS_ARM64_DCPOP = 46, // ID_AA64ISAR1_EL1.DPB is 1 or better - JIT_FLAG_HAS_ARM64_DP = 47, // ID_AA64ISAR0_EL1.DP is 1 or better - JIT_FLAG_HAS_ARM64_FCMA = 48, // ID_AA64ISAR1_EL1.FCMA is 1 or better - JIT_FLAG_HAS_ARM64_FP = 49, // ID_AA64PFR0_EL1.FP is 0 or better - JIT_FLAG_HAS_ARM64_FP16 = 50, // ID_AA64PFR0_EL1.FP is 1 or better - JIT_FLAG_HAS_ARM64_JSCVT = 51, // ID_AA64ISAR1_EL1.JSCVT is 1 or better - JIT_FLAG_HAS_ARM64_LRCPC = 52, // ID_AA64ISAR1_EL1.LRCPC is 1 or better - JIT_FLAG_HAS_ARM64_PMULL = 53, // ID_AA64ISAR0_EL1.AES is 2 or better - JIT_FLAG_HAS_ARM64_SHA1 = 54, // ID_AA64ISAR0_EL1.SHA1 is 1 or better - JIT_FLAG_HAS_ARM64_SHA256 = 55, // ID_AA64ISAR0_EL1.SHA2 is 1 or better - JIT_FLAG_HAS_ARM64_SHA512 = 56, // ID_AA64ISAR0_EL1.SHA2 is 2 or better - JIT_FLAG_HAS_ARM64_SHA3 = 57, // ID_AA64ISAR0_EL1.SHA3 is 1 or better - JIT_FLAG_HAS_ARM64_ADVSIMD = 58, // ID_AA64PFR0_EL1.AdvSIMD is 0 or better - JIT_FLAG_HAS_ARM64_ADVSIMD_V81 = 59, // ID_AA64ISAR0_EL1.RDM is 1 or better - JIT_FLAG_HAS_ARM64_ADVSIMD_FP16 = 60, // ID_AA64PFR0_EL1.AdvSIMD is 1 or better - JIT_FLAG_HAS_ARM64_SM3 = 61, // ID_AA64ISAR0_EL1.SM3 is 1 or better - JIT_FLAG_HAS_ARM64_SM4 = 62, // ID_AA64ISAR0_EL1.SM4 is 1 or better - JIT_FLAG_HAS_ARM64_SVE = 63 // ID_AA64PFR0_EL1.SVE is 1 or better - -#elif defined(TARGET_X86) || defined(TARGET_AMD64) - - JIT_FLAG_USE_SSE3 = 43, - JIT_FLAG_USE_SSSE3 = 44, - JIT_FLAG_USE_SSE41 = 45, - JIT_FLAG_USE_SSE42 = 46, - JIT_FLAG_USE_AES = 47, - JIT_FLAG_USE_BMI1 = 48, - JIT_FLAG_USE_BMI2 = 49, - JIT_FLAG_USE_FMA = 50, - JIT_FLAG_USE_LZCNT = 51, - JIT_FLAG_USE_PCLMULQDQ = 52, - JIT_FLAG_USE_POPCNT = 53, - JIT_FLAG_UNUSED23 = 54, - JIT_FLAG_UNUSED24 = 55, - JIT_FLAG_UNUSED25 = 56, - JIT_FLAG_UNUSED26 = 57, - JIT_FLAG_UNUSED27 = 58, - JIT_FLAG_UNUSED28 = 59, - JIT_FLAG_UNUSED29 = 60, - JIT_FLAG_UNUSED30 = 61, - JIT_FLAG_UNUSED31 = 62, - JIT_FLAG_UNUSED32 = 63 - - -#else // !defined(TARGET_ARM64) && !defined(TARGET_X86) && !defined(TARGET_AMD64) - JIT_FLAG_UNUSED12 = 43, JIT_FLAG_UNUSED13 = 44, JIT_FLAG_UNUSED14 = 45, @@ -166,8 +104,6 @@ class JitFlags JIT_FLAG_UNUSED31 = 62, JIT_FLAG_UNUSED32 = 63 -#endif // !defined(TARGET_ARM64) && !defined(TARGET_X86) && !defined(TARGET_AMD64) - }; // clang-format on @@ -187,29 +123,29 @@ class JitFlags m_jitFlags = 0; } - void Set(JitFlag flag) + CORINFO_InstructionSetFlags GetInstructionSetFlags() const { - m_jitFlags |= 1ULL << (unsigned __int64)flag; + return m_instructionSetFlags; } - void Clear(JitFlag flag) + void SetInstructionSetFlags(CORINFO_InstructionSetFlags instructionSetFlags) { - m_jitFlags &= ~(1ULL << (unsigned __int64)flag); + m_instructionSetFlags = instructionSetFlags; } - bool IsSet(JitFlag flag) const + void Set(JitFlag flag) { - return (m_jitFlags & (1ULL << (unsigned __int64)flag)) != 0; + m_jitFlags |= 1ULL << (unsigned __int64)flag; } - void Add(const JitFlags& other) + void Clear(JitFlag flag) { - m_jitFlags |= other.m_jitFlags; + m_jitFlags &= ~(1ULL << (unsigned __int64)flag); } - void Remove(const JitFlags& other) + bool IsSet(JitFlag flag) const { - m_jitFlags &= ~other.m_jitFlags; + return (m_jitFlags & (1ULL << (unsigned __int64)flag)) != 0; } bool IsEmpty() const @@ -222,8 +158,9 @@ class JitFlags // We don't want to have to check every one, so we assume it is exactly the same values as the JitFlag // values defined in this type. m_jitFlags = flags.GetFlagsRaw(); + m_instructionSetFlags.SetFromFlagsRaw(flags.GetInstructionSetFlagsRaw()); - C_ASSERT(sizeof(m_jitFlags) == sizeof(CORJIT_FLAGS)); + C_ASSERT(sizeof(JitFlags) == sizeof(CORJIT_FLAGS)); #define FLAGS_EQUAL(a, b) C_ASSERT((unsigned)(a) == (unsigned)(b)) @@ -242,15 +179,6 @@ class JitFlags FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_TARGET_P4, JIT_FLAG_TARGET_P4); FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_FCOMI, JIT_FLAG_USE_FCOMI); FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_CMOV, JIT_FLAG_USE_CMOV); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE2, JIT_FLAG_USE_SSE2); - -#endif - -#if defined(TARGET_X86) || defined(TARGET_AMD64) - - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX, JIT_FLAG_USE_AVX); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX2, JIT_FLAG_USE_AVX2); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX_512, JIT_FLAG_USE_AVX_512); #endif @@ -290,50 +218,10 @@ class JitFlags #endif // TARGET_ARM FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING, JIT_FLAG_NO_INLINING); - -#if defined(TARGET_ARM64) - - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_AES, JIT_FLAG_HAS_ARM64_AES); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ATOMICS, JIT_FLAG_HAS_ARM64_ATOMICS); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_CRC32, JIT_FLAG_HAS_ARM64_CRC32); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_DCPOP, JIT_FLAG_HAS_ARM64_DCPOP); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_DP, JIT_FLAG_HAS_ARM64_DP); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FCMA, JIT_FLAG_HAS_ARM64_FCMA); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FP, JIT_FLAG_HAS_ARM64_FP); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FP16, JIT_FLAG_HAS_ARM64_FP16); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_JSCVT, JIT_FLAG_HAS_ARM64_JSCVT); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_LRCPC, JIT_FLAG_HAS_ARM64_LRCPC); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_PMULL, JIT_FLAG_HAS_ARM64_PMULL); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA1, JIT_FLAG_HAS_ARM64_SHA1); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA256, JIT_FLAG_HAS_ARM64_SHA256); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA512, JIT_FLAG_HAS_ARM64_SHA512); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA3, JIT_FLAG_HAS_ARM64_SHA3); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD, JIT_FLAG_HAS_ARM64_ADVSIMD); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD_V81, JIT_FLAG_HAS_ARM64_ADVSIMD_V81); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD_FP16, JIT_FLAG_HAS_ARM64_ADVSIMD_FP16); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SM3, JIT_FLAG_HAS_ARM64_SM3); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SM4, JIT_FLAG_HAS_ARM64_SM4); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SVE, JIT_FLAG_HAS_ARM64_SVE); - -#elif defined(TARGET_X86) || defined(TARGET_AMD64) - - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE3, JIT_FLAG_USE_SSE3); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_SSSE3, JIT_FLAG_USE_SSSE3); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE41, JIT_FLAG_USE_SSE41); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE42, JIT_FLAG_USE_SSE42); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_AES, JIT_FLAG_USE_AES); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_BMI1, JIT_FLAG_USE_BMI1); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_BMI2, JIT_FLAG_USE_BMI2); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_FMA, JIT_FLAG_USE_FMA); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_LZCNT, JIT_FLAG_USE_LZCNT); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_PCLMULQDQ, JIT_FLAG_USE_PCLMULQDQ); - FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_POPCNT, JIT_FLAG_USE_POPCNT); - -#endif // TARGET_X86 || TARGET_AMD64 - #undef FLAGS_EQUAL } private: - unsigned __int64 m_jitFlags; + unsigned __int64 m_jitFlags; + CORINFO_InstructionSetFlags m_instructionSetFlags; }; diff --git a/src/coreclr/src/jit/jiteh.cpp b/src/coreclr/src/jit/jiteh.cpp index b17785c50b800f..4c9f39ebd6e68e 100644 --- a/src/coreclr/src/jit/jiteh.cpp +++ b/src/coreclr/src/jit/jiteh.cpp @@ -1212,6 +1212,25 @@ EHblkDsc* Compiler::ehInitTryBlockRange(BasicBlock* blk, BasicBlock** tryBeg, Ba return tryTab; } +/***************************************************************************** + * This method updates the value of ebdTryBeg + */ + +void Compiler::fgSetTryBeg(EHblkDsc* handlerTab, BasicBlock* newTryBeg) +{ + assert(newTryBeg != nullptr); + + // Check if we are going to change the existing value of endTryLast + // + if (handlerTab->ebdTryBeg != newTryBeg) + { + // Update the EH table with the newTryLast block + handlerTab->ebdTryBeg = newTryBeg; + + JITDUMP("EH#%u: New first block of try: " FMT_BB "\n", ehGetIndex(handlerTab), handlerTab->ebdTryBeg->bbNum); + } +} + /***************************************************************************** * This method updates the value of ebdTryLast. */ diff --git a/src/coreclr/src/jit/lclvars.cpp b/src/coreclr/src/jit/lclvars.cpp index f93062dff004c5..3806dcdf2b5582 100644 --- a/src/coreclr/src/jit/lclvars.cpp +++ b/src/coreclr/src/jit/lclvars.cpp @@ -21,6 +21,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "emit.h" #include "register_arg_convention.h" #include "jitstd/algorithm.h" +#include "patchpointinfo.h" /*****************************************************************************/ @@ -279,6 +280,17 @@ void Compiler::lvaInitTypeRef() CORINFO_CLASS_HANDLE clsHnd = info.compCompHnd->getArgClass(&info.compMethodInfo->locals, localsSig); lvaSetClass(varNum, clsHnd); } + + if (opts.IsOSR() && info.compPatchpointInfo->IsExposed(varNum)) + { + JITDUMP("-- V%02u is OSR exposed\n", varNum); + varDsc->lvHasLdAddrOp = 1; + + if (varDsc->lvType != TYP_STRUCT) + { + lvaSetVarAddrExposed(varNum); + } + } } if ( // If there already exist unsafe buffers, don't mark more structs as unsafe @@ -1028,6 +1040,14 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo) lvaSetVarAddrExposed(varDscInfo->varNum); #endif // !TARGET_X86 } + + if (opts.IsOSR() && info.compPatchpointInfo->IsExposed(varDscInfo->varNum)) + { + JITDUMP("-- V%02u is OSR exposed\n", varDscInfo->varNum); + varDsc->lvHasLdAddrOp = 1; + lvaSetVarAddrExposed(varDscInfo->varNum); + } + } // for each user arg #ifdef TARGET_ARM @@ -1830,6 +1850,13 @@ bool Compiler::StructPromotionHelper::CanPromoteStructVar(unsigned lclNum) return false; } + // TODO-CQ: enable promotion for OSR locals + if (compiler->lvaIsOSRLocal(lclNum)) + { + JITDUMP(" struct promotion of V%02u is disabled because it is an OSR local\n", lclNum); + return false; + } + CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle(); return CanPromoteStructType(typeHnd); } @@ -4781,6 +4808,13 @@ void Compiler::lvaFixVirtualFrameOffsets() assert(varDsc->lvFramePointerBased); // We always access it RBP-relative. assert(!varDsc->lvMustInit); // It is never "must init". varDsc->lvStkOffs = codeGen->genCallerSPtoInitialSPdelta() + lvaLclSize(lvaOutgoingArgSpaceVar); + + // With OSR the new frame RBP points at the base of the new frame, but the virtual offsets + // are from the base of the old frame. Adjust. + if (opts.IsOSR()) + { + varDsc->lvStkOffs -= info.compPatchpointInfo->FpToSpDelta(); + } } #endif @@ -4789,9 +4823,11 @@ void Compiler::lvaFixVirtualFrameOffsets() #ifdef TARGET_XARCH delta += REGSIZE_BYTES; // pushed PC (return address) for x86/x64 + JITDUMP("--- delta bump %d for RA\n", REGSIZE_BYTES); if (codeGen->doubleAlignOrFramePointerUsed()) { + JITDUMP("--- delta bump %d for FP\n", REGSIZE_BYTES); delta += REGSIZE_BYTES; // pushed EBP (frame pointer) } #endif @@ -4799,6 +4835,7 @@ void Compiler::lvaFixVirtualFrameOffsets() if (!codeGen->isFramePointerUsed()) { // pushed registers, return address, and padding + JITDUMP("--- delta bump %d for RSP frame\n", codeGen->genTotalFrameSize()); delta += codeGen->genTotalFrameSize(); } #if defined(TARGET_ARM) @@ -4811,10 +4848,21 @@ void Compiler::lvaFixVirtualFrameOffsets() else { // FP is used. + JITDUMP("--- delta bump %d for RBP frame\n", codeGen->genTotalFrameSize() - codeGen->genSPtoFPdelta()); delta += codeGen->genTotalFrameSize() - codeGen->genSPtoFPdelta(); } #endif // TARGET_AMD64 + // For OSR, update the delta to reflect the current policy that + // RBP points at the base of the new frame, and RSP is relative to that RBP. + if (opts.IsOSR()) + { + JITDUMP("--- delta bump %d for OSR\n", info.compPatchpointInfo->FpToSpDelta()); + delta += info.compPatchpointInfo->FpToSpDelta(); + } + + JITDUMP("--- virtual stack offset to actual stack offset delta is %d\n", delta); + unsigned lclNum; for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++) { @@ -4857,6 +4905,7 @@ void Compiler::lvaFixVirtualFrameOffsets() if (doAssignStkOffs) { + JITDUMP("-- V%02u was %d, now %d\n", lclNum, varDsc->lvStkOffs, varDsc->lvStkOffs + delta); varDsc->lvStkOffs += delta; #if DOUBLE_ALIGN @@ -4876,8 +4925,9 @@ void Compiler::lvaFixVirtualFrameOffsets() } #endif // On System V environments the stkOffs could be 0 for params passed in registers. - assert(codeGen->isFramePointerUsed() || - varDsc->lvStkOffs >= 0); // Only EBP relative references can have negative offsets + // + // For normal methods only EBP relative references can have negative offsets. + assert(codeGen->isFramePointerUsed() || varDsc->lvStkOffs >= 0); } } @@ -5593,7 +5643,9 @@ int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, */ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() { - int stkOffs = 0; + int stkOffs = 0; + int originalFrameStkOffs = 0; + int originalFrameSize = 0; // codeGen->isFramePointerUsed is set in regalloc phase. Initialize it to a guess for pre-regalloc layout. if (lvaDoneFrameLayout <= PRE_REGALLOC_FRAME_LAYOUT) { @@ -5632,6 +5684,15 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() lvaTable[lvaRetAddrVar].lvStkOffs = stkOffs; } + // If we are an OSR method, we "inherit" the frame of the original method, + // and the stack is already double aligned on entry (since the return adddress push + // and any special alignment push happened "before"). + if (opts.IsOSR()) + { + originalFrameSize = info.compPatchpointInfo->FpToSpDelta(); + originalFrameStkOffs = stkOffs; + stkOffs -= originalFrameSize; + } // TODO-AMD64-CQ: for X64 eventually this should be pushed with all the other // calleeregs. When you fix this, you'll also need to fix // the assert at the bottom of this method @@ -5714,10 +5775,16 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() // boundary we would have to use movups when offset turns out unaligned. Movaps is more // performant than movups. unsigned calleeFPRegsSavedSize = genCountBits(compCalleeFPRegsSavedMask) * XMM_REGSIZE_BYTES; - if (calleeFPRegsSavedSize > 0 && ((stkOffs % XMM_REGSIZE_BYTES) != 0)) + + // For OSR the alignment pad computation should not take the original frame into account. + // Original frame size includes the pseudo-saved RA and so is always = 8 mod 16. + const int offsetForAlign = -(stkOffs + originalFrameSize); + + if ((calleeFPRegsSavedSize > 0) && ((offsetForAlign % XMM_REGSIZE_BYTES) != 0)) { // Take care of alignment - int alignPad = (int)AlignmentPad((unsigned)-stkOffs, XMM_REGSIZE_BYTES); + int alignPad = (int)AlignmentPad((unsigned)offsetForAlign, XMM_REGSIZE_BYTES); + assert(alignPad != 0); stkOffs -= alignPad; lvaIncrementFrameSize(alignPad); } @@ -5800,7 +5867,19 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() } #endif // JIT32_GCENCODER - if (lvaReportParamTypeArg()) + // OSR methods use the original method slot for the cached kept alive this, + // so don't need to allocate a slot on the new frame. + if (opts.IsOSR()) + { + if (lvaKeepAliveAndReportThis()) + { + PatchpointInfo* ppInfo = info.compPatchpointInfo; + assert(ppInfo->HasKeptAliveThis()); + int originalOffset = ppInfo->KeptAliveThisOffset(); + lvaCachedGenericContextArgOffs = originalFrameStkOffs + originalOffset; + } + } + else if (lvaReportParamTypeArg()) { #ifdef JIT32_GCENCODER noway_assert(codeGen->isFramePointerUsed()); @@ -5844,7 +5923,11 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() if (compGSReorderStackLayout) { assert(getNeedsGSSecurityCookie()); - stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaGSSecurityCookie, lvaLclSize(lvaGSSecurityCookie), stkOffs); + + if (!opts.IsOSR() || !info.compPatchpointInfo->HasSecurityCookie()) + { + stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaGSSecurityCookie, lvaLclSize(lvaGSSecurityCookie), stkOffs); + } } /* @@ -5937,7 +6020,7 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() In other words, we will not calculate the "base" address of the struct local if the promotion type is PROMOTION_TYPE_FIELD_DEPENDENT. */ - if (lvaIsFieldOfDependentlyPromotedStruct(varDsc)) + if (!opts.IsOSR() && lvaIsFieldOfDependentlyPromotedStruct(varDsc)) { continue; } @@ -5958,6 +6041,29 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() allocateOnFrame = false; } + // For OSR args and locals, we use the slots on the original frame. + // + // Note we must do this even for "non frame" locals, as we sometimes + // will refer to their memory homes. + if (lvaIsOSRLocal(lclNum)) + { + // TODO-CQ: enable struct promotion for OSR locals; when that + // happens, figure out how to properly refer to the original + // frame slots for the promoted fields. + assert(!varDsc->lvIsStructField); + + // Add frampointer-relative offset of this OSR live local in the original frame + // to the offset of original frame in our new frame. + int originalOffset = info.compPatchpointInfo->Offset(lclNum); + int offset = originalFrameStkOffs + originalOffset; + + JITDUMP("---OSR--- V%02u (on old frame) old rbp offset %d old frame offset %d new virt offset %d\n", + lclNum, originalOffset, originalFrameStkOffs, offset); + + lvaTable[lclNum].lvStkOffs = offset; + continue; + } + /* Ignore variables that are not on the stack frame */ if (!allocateOnFrame) @@ -5979,7 +6085,21 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() } else if (lvaGSSecurityCookie == lclNum && getNeedsGSSecurityCookie()) { - continue; // This is allocated outside of this loop. + // Special case for OSR. If the original method had a cookie, + // we use its slot on the original frame. + if (opts.IsOSR() && info.compPatchpointInfo->HasSecurityCookie()) + { + int originalOffset = info.compPatchpointInfo->SecurityCookieOffset(); + int offset = originalFrameStkOffs + originalOffset; + + JITDUMP("---OSR--- V%02u (on old frame, security cookie) old rbp offset %d old frame offset %d new " + "virt offset %d\n", + lclNum, originalOffset, originalFrameStkOffs, offset); + + lvaTable[lclNum].lvStkOffs = offset; + } + + continue; } // These need to be located as the very first variables (highest memory address) @@ -6172,8 +6292,11 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() if (getNeedsGSSecurityCookie() && !compGSReorderStackLayout) { - // LOCALLOC used, but we have no unsafe buffer. Allocated cookie last, close to localloc buffer. - stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaGSSecurityCookie, lvaLclSize(lvaGSSecurityCookie), stkOffs); + if (!opts.IsOSR() || !info.compPatchpointInfo->HasSecurityCookie()) + { + // LOCALLOC used, but we have no unsafe buffer. Allocated cookie last, close to localloc buffer. + stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaGSSecurityCookie, lvaLclSize(lvaGSSecurityCookie), stkOffs); + } } if (tempsAllocated == false) @@ -6303,7 +6426,8 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() pushedCount += 1; // pushed PC (return address) #endif - noway_assert(compLclFrameSize == (unsigned)-(stkOffs + (pushedCount * (int)TARGET_POINTER_SIZE))); + noway_assert(compLclFrameSize + originalFrameSize == + (unsigned)-(stkOffs + (pushedCount * (int)TARGET_POINTER_SIZE))); } int Compiler::lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs) @@ -6751,7 +6875,7 @@ void Compiler::lvaDumpFrameLocation(unsigned lclNum) void Compiler::lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth) { - LclVarDsc* varDsc = lvaTable + lclNum; + LclVarDsc* varDsc = lvaGetDesc(lclNum); var_types type = varDsc->TypeGet(); if (curState == INITIAL_FRAME_LAYOUT) @@ -6760,30 +6884,7 @@ void Compiler::lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t r gtDispLclVar(lclNum); printf(" %7s ", varTypeName(type)); - if (genTypeSize(type) == 0) - { -#if FEATURE_FIXED_OUT_ARGS - if (lclNum == lvaOutgoingArgSpaceVar) - { - // Since lvaOutgoingArgSpaceSize is a PhasedVar we can't read it for Dumping until - // after we set it to something. - if (lvaOutgoingArgSpaceSize.HasFinalValue()) - { - // A PhasedVar can't be directly used as an arg to a variadic function - unsigned value = lvaOutgoingArgSpaceSize; - printf("(%2d) ", value); - } - else - { - printf("(na) "); // The value hasn't yet been determined - } - } - else -#endif // FEATURE_FIXED_OUT_ARGS - { - printf("(%2d) ", lvaLclSize(lclNum)); - } - } + gtDispLclVarStructType(lclNum); } else { @@ -7246,6 +7347,21 @@ int Compiler::lvaToCallerSPRelativeOffset(int offset, bool isFpBased) const { assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT); + // TODO-Cleanup + // + // This current should not be called for OSR as caller SP relative + // offsets computed below do not reflect the extra stack space + // taken up by the original method frame. + // + // We should make it work. + // + // Instead we record the needed offsets in the patchpoint info + // when doing the original method compile(see special offsets + // in generatePatchpointInfo) and consume those values in the OSR + // compile. If we fix this we may be able to reduce the size + // of the patchpoint info and have less special casing for these + // frame slots. + if (isFpBased) { offset += codeGen->genCallerSPtoFPdelta(); diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index 580f2b6f71fa22..3d6e3799914d3b 100644 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -1809,6 +1809,7 @@ void Lowering::LowerFastTailCall(GenTreeCall* call) // Most of these checks are already done by importer or fgMorphTailCall(). // This serves as a double sanity check. assert((comp->info.compFlags & CORINFO_FLG_SYNCH) == 0); // tail calls from synchronized methods + assert(!comp->opts.IsReversePInvoke()); // tail calls reverse pinvoke assert(!call->IsUnmanaged()); // tail calls to unamanaged methods assert(!comp->compLocallocUsed); // tail call from methods that also do localloc diff --git a/src/coreclr/src/jit/lsraarm64.cpp b/src/coreclr/src/jit/lsraarm64.cpp index 6a695a1185a0a0..b9de46de1910b8 100644 --- a/src/coreclr/src/jit/lsraarm64.cpp +++ b/src/coreclr/src/jit/lsraarm64.cpp @@ -994,11 +994,11 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) // int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) { - NamedIntrinsic intrinsicId = intrinsicTree->gtHWIntrinsicId; - var_types baseType = intrinsicTree->gtSIMDBaseType; - InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsicId); - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); - int numArgs = HWIntrinsicInfo::lookupNumArgs(intrinsicTree); + NamedIntrinsic intrinsicId = intrinsicTree->gtHWIntrinsicId; + var_types baseType = intrinsicTree->gtSIMDBaseType; + CORINFO_InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsicId); + HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); + int numArgs = HWIntrinsicInfo::lookupNumArgs(intrinsicTree); GenTree* op1 = intrinsicTree->gtGetOp1(); GenTree* op2 = intrinsicTree->gtGetOp2(); diff --git a/src/coreclr/src/jit/lsrabuild.cpp b/src/coreclr/src/jit/lsrabuild.cpp index c45aad77aec9d1..91ac9fdf32ba75 100644 --- a/src/coreclr/src/jit/lsrabuild.cpp +++ b/src/coreclr/src/jit/lsrabuild.cpp @@ -1732,15 +1732,7 @@ BasicBlock* getNonEmptyBlock(BasicBlock* block) { while (block != nullptr && block->GetFirstLIRNode() == nullptr) { - BasicBlock* nextBlock = block->bbNext; - // Note that here we use the version of NumSucc that does not take a compiler. - // That way this doesn't have to take a compiler, or be an instance method, e.g. of LinearScan. - // If we have an empty block, it must have jump type BBJ_NONE or BBJ_ALWAYS, in which - // case we don't need the version that takes a compiler. - assert(block->NumSucc() == 1 && ((block->bbJumpKind == BBJ_ALWAYS) || (block->bbJumpKind == BBJ_NONE))); - // sometimes the first block is empty and ends with an uncond branch - // assert( block->GetSucc(0) == nextBlock); - block = nextBlock; + block = block->GetUniqueSucc(); } assert(block != nullptr && block->GetFirstLIRNode() != nullptr); return block; @@ -1785,12 +1777,21 @@ void LinearScan::insertZeroInitRefPositions() Interval* interval = getIntervalForLocalVar(varIndex); if (compiler->info.compInitMem || varTypeIsGC(varDsc->TypeGet())) { + varDsc->lvMustInit = true; + + // OSR will handle init of locals and promoted fields thereof + if (compiler->lvaIsOSRLocal(compiler->lvaTrackedIndexToLclNum(varIndex))) + { + JITDUMP(" will be initialized by OSR\n"); + // setIntervalAsSpilled(interval); + varDsc->lvMustInit = false; + } + JITDUMP(" creating ZeroInit\n"); GenTree* firstNode = getNonEmptyBlock(compiler->fgFirstBB)->firstNode(); RefPosition* pos = newRefPosition(interval, MinLocation, RefTypeZeroInit, firstNode, allRegs(interval->registerType)); pos->setRegOptional(true); - varDsc->lvMustInit = true; } else { diff --git a/src/coreclr/src/jit/lsraxarch.cpp b/src/coreclr/src/jit/lsraxarch.cpp index 19c914e614d91b..2578cd7fbdc925 100644 --- a/src/coreclr/src/jit/lsraxarch.cpp +++ b/src/coreclr/src/jit/lsraxarch.cpp @@ -2286,11 +2286,11 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) // int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) { - NamedIntrinsic intrinsicId = intrinsicTree->gtHWIntrinsicId; - var_types baseType = intrinsicTree->gtSIMDBaseType; - InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsicId); - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); - int numArgs = HWIntrinsicInfo::lookupNumArgs(intrinsicTree); + NamedIntrinsic intrinsicId = intrinsicTree->gtHWIntrinsicId; + var_types baseType = intrinsicTree->gtSIMDBaseType; + CORINFO_InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsicId); + HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); + int numArgs = HWIntrinsicInfo::lookupNumArgs(intrinsicTree); // Set the AVX Flags if this instruction may use VEX encoding for SIMD operations. // Note that this may be true even if the ISA is not AVX (e.g. for platform-agnostic intrinsics diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index a8b134e7332e27..e3be6833e0d3cd 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -7538,18 +7538,16 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) { callType = TYP_I_IMPL; } - else if (howToReturnStruct == SPK_ByValueAsHfa) + else if (howToReturnStruct == SPK_ByValueAsHfa || varTypeIsSIMD(callType)) { callType = TYP_FLOAT; } - assert((callType != TYP_UNKNOWN) && (callType != TYP_STRUCT)); + assert((callType != TYP_UNKNOWN) && !varTypeIsStruct(callType)); } else { callType = origCallType; } - GenTree* zero = gtNewZeroConNode(callType); - result = fgMorphTree(zero); } else { @@ -8549,14 +8547,26 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa // Remove the call fgRemoveStmt(block, lastStmt); - // Set the loop edge. Ensure we have a scratch block and then target the - // next block. Loop detection needs to see a pred out of the loop, so - // mark the scratch block BBF_DONT_REMOVE to prevent empty block removal - // on it. - fgEnsureFirstBBisScratch(); - fgFirstBB->bbFlags |= BBF_DONT_REMOVE; + // Set the loop edge. + if (opts.IsOSR()) + { + // Todo: this may not look like a viable loop header. + // Might need the moral equivalent of a scratch BB. + block->bbJumpDest = fgEntryBB; + } + else + { + // Ensure we have a scratch block and then target the next + // block. Loop detection needs to see a pred out of the loop, + // so mark the scratch block BBF_DONT_REMOVE to prevent empty + // block removal on it. + fgEnsureFirstBBisScratch(); + fgFirstBB->bbFlags |= BBF_DONT_REMOVE; + block->bbJumpDest = fgFirstBB->bbNext; + } + + // Finish hooking things up. block->bbJumpKind = BBJ_ALWAYS; - block->bbJumpDest = fgFirstBB->bbNext; block->bbJumpDest->bbFlags |= BBF_JMP_TARGET; fgAddRefPred(block->bbJumpDest, block); block->bbFlags &= ~BBF_HAS_JMP; @@ -14114,6 +14124,13 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree) switch (oper) { case GT_ASG: + // Make sure we're allowed to do this. + if (optValnumCSE_phase) + { + // It is not safe to reorder/delete CSE's + break; + } + if (varTypeIsStruct(typ) && !tree->IsPhiDefn()) { if (tree->OperIsCopyBlkOp()) @@ -14131,14 +14148,6 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree) break; } - /* Make sure we're allowed to do this */ - - if (optValnumCSE_phase) - { - // It is not safe to reorder/delete CSE's - break; - } - if (op2->gtFlags & GTF_ASG) { break; diff --git a/src/coreclr/src/jit/patchpoint.cpp b/src/coreclr/src/jit/patchpoint.cpp new file mode 100644 index 00000000000000..8527bd937188c5 --- /dev/null +++ b/src/coreclr/src/jit/patchpoint.cpp @@ -0,0 +1,244 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "jitpch.h" +#ifdef _MSC_VER +#pragma hdrstop +#endif + +//------------------------------------------------------------------------ +// PatchpointTransformer +// +// Insert patchpoint checks into Tier0 methods, based on locations identified +// during importation (see impImportBlockCode). +// +// Policy decisions implemented here: +// +// * One counter per stack frame, regardless of the number of patchpoints. +// * Shared counter value initialized to zero in prolog. +// * Patchpoint trees fully expanded into jit IR. Deferring expansion could +// lead to more compact code and lessen size overhead for Tier0. +// +// Workarounds and limitations: +// +// * no patchpoints in handler regions +// * no patchpoints for localloc methods +// * no patchpoints in try regions (workaround) +// * no patchpoints for synchronized methods (workaround) +// +class PatchpointTransformer +{ + unsigned ppCounterLclNum; + const int HIGH_PROBABILITY = 99; + Compiler* compiler; + +public: + PatchpointTransformer(Compiler* compiler) : compiler(compiler) + { + ppCounterLclNum = compiler->lvaGrabTemp(true DEBUGARG("patchpoint counter")); + compiler->lvaTable[ppCounterLclNum].lvType = TYP_INT; + } + + //------------------------------------------------------------------------ + // Run: run transformation for each block. + // + // Returns: + // Number of patchpoints transformed. + int Run() + { + // If the first block is a patchpoint, insert a scratch block. + if (compiler->fgFirstBB->bbFlags & BBF_PATCHPOINT) + { + compiler->fgEnsureFirstBBisScratch(); + } + + BasicBlock* block = compiler->fgFirstBB; + TransformEntry(block); + + int count = 0; + for (block = block->bbNext; block != nullptr; block = block->bbNext) + { + if (block->bbFlags & BBF_PATCHPOINT) + { + // If block is in a handler region, don't insert a patchpoint. + // We can't OSR from funclets. + // + // TODO: check this earlier, somehow, and fall back to fully + // optimizing the method (ala QJFL=0). + if (compiler->ehGetBlockHndDsc(block) != nullptr) + { + JITDUMP("Patchpoint: skipping patchpoint for " FMT_BB " as it is in a handler\n", block->bbNum); + continue; + } + + JITDUMP("Patchpoint: instrumenting " FMT_BB "\n", block->bbNum); + assert(block != compiler->fgFirstBB); + TransformBlock(block); + count++; + } + } + + return count; + } + +private: + //------------------------------------------------------------------------ + // CreateAndInsertBasicBlock: ask compiler to create new basic block. + // and insert in into the basic block list. + // + // Arguments: + // jumpKind - jump kind for the new basic block + // insertAfter - basic block, after which compiler has to insert the new one. + // + // Return Value: + // new basic block. + BasicBlock* CreateAndInsertBasicBlock(BBjumpKinds jumpKind, BasicBlock* insertAfter) + { + BasicBlock* block = compiler->fgNewBBafter(jumpKind, insertAfter, true); + if ((insertAfter->bbFlags & BBF_INTERNAL) == 0) + { + block->bbFlags &= ~BBF_INTERNAL; + block->bbFlags |= BBF_IMPORTED; + } + return block; + } + + //------------------------------------------------------------------------ + // TransformBlock: expand current block to include patchpoint logic. + // + // S; + // + // ==> + // + // if (--ppCounter <= 0) + // { + // ppHelper(&ppCounter, ilOffset); + // } + // S; + // + void TransformBlock(BasicBlock* block) + { + // Capture the IL offset + IL_OFFSET ilOffset = block->bbCodeOffs; + assert(ilOffset != BAD_IL_OFFSET); + + // Current block now becomes the test block + BasicBlock* remainderBlock = compiler->fgSplitBlockAtBeginning(block); + BasicBlock* helperBlock = CreateAndInsertBasicBlock(BBJ_NONE, block); + + // Update flow and flags + block->bbJumpKind = BBJ_COND; + block->bbJumpDest = remainderBlock; + helperBlock->bbFlags |= BBF_BACKWARD_JUMP; + + // Update weights + remainderBlock->inheritWeight(block); + helperBlock->inheritWeightPercentage(block, 100 - HIGH_PROBABILITY); + + // Fill in test block + // + // --ppCounter; + GenTree* ppCounterBefore = compiler->gtNewLclvNode(ppCounterLclNum, TYP_INT); + GenTree* ppCounterAfter = compiler->gtNewLclvNode(ppCounterLclNum, TYP_INT); + GenTree* one = compiler->gtNewIconNode(1, TYP_INT); + GenTree* ppCounterSub = compiler->gtNewOperNode(GT_SUB, TYP_INT, ppCounterBefore, one); + GenTree* ppCounterAsg = compiler->gtNewOperNode(GT_ASG, TYP_INT, ppCounterAfter, ppCounterSub); + + compiler->fgNewStmtAtEnd(block, ppCounterAsg); + + // if (ppCounter > 0), bypass helper call + GenTree* ppCounterUpdated = compiler->gtNewLclvNode(ppCounterLclNum, TYP_INT); + GenTree* zero = compiler->gtNewIconNode(0, TYP_INT); + GenTree* compare = compiler->gtNewOperNode(GT_GT, TYP_INT, ppCounterUpdated, zero); + GenTree* jmp = compiler->gtNewOperNode(GT_JTRUE, TYP_VOID, compare); + + compiler->fgNewStmtAtEnd(block, jmp); + + // Fill in helper block + // + // call PPHelper(&ppCounter, ilOffset) + GenTree* ilOffsetNode = compiler->gtNewIconNode(ilOffset, TYP_INT); + GenTree* ppCounterRef = compiler->gtNewLclvNode(ppCounterLclNum, TYP_INT); + GenTree* ppCounterAddr = compiler->gtNewOperNode(GT_ADDR, TYP_I_IMPL, ppCounterRef); + GenTreeCall::Use* helperArgs = compiler->gtNewCallArgs(ppCounterAddr, ilOffsetNode); + GenTreeCall* helperCall = compiler->gtNewHelperCallNode(CORINFO_HELP_PATCHPOINT, TYP_VOID, helperArgs); + + compiler->fgNewStmtAtEnd(helperBlock, helperCall); + } + + // ppCounter = + void TransformEntry(BasicBlock* block) + { + assert((block->bbFlags & BBF_PATCHPOINT) == 0); + + int initialCounterValue = JitConfig.TC_OnStackReplacement_InitialCounter(); + + if (initialCounterValue < 0) + { + initialCounterValue = 0; + } + + GenTree* initialCounterNode = compiler->gtNewIconNode(initialCounterValue, TYP_INT); + GenTree* ppCounterRef = compiler->gtNewLclvNode(ppCounterLclNum, TYP_INT); + GenTree* ppCounterAsg = compiler->gtNewOperNode(GT_ASG, TYP_INT, ppCounterRef, initialCounterNode); + + compiler->fgNewStmtNearEnd(block, ppCounterAsg); + } +}; + +//------------------------------------------------------------------------ +// fgTransformPatchpoints: expansion of patchpoints into control flow. +// +// Notes: +// +// Patchpoints are placed in the JIT IR during importation, and get expanded +// here into normal JIT IR. +// +void Compiler::fgTransformPatchpoints() +{ + JITDUMP("\n*************** in fgTransformPatchpoints\n"); + + if (!doesMethodHavePatchpoints()) + { + JITDUMP(" -- no patchpoints to transform\n"); + return; + } + + // We should only be adding patchpoints at Tier0, so should not be in an inlinee + assert(!compIsForInlining()); + + // We currently can't do OSR in methods with localloc. + // Such methods don't have a fixed relationship between frame and stack pointers. + // + // This is true whether or not the localloc was executed in the original method. + // + // TODO: handle this case, or else check this earlier and fall back to fully + // optimizing the method (ala QJFL=0). + if (compLocallocUsed) + { + JITDUMP(" -- unable to handle methods with localloc\n"); + return; + } + + // We currently can't do OSR in synchronized methods. We need to alter + // the logic in fgAddSyncMethodEnterExit for OSR to not try and obtain the + // monitor (since the original method will have done so) and set the monitor + // obtained flag to true (or reuse the original method slot value). + if ((info.compFlags & CORINFO_FLG_SYNCH) != 0) + { + JITDUMP(" -- unable to handle synchronized methods\n"); + return; + } + + if (opts.IsReversePInvoke()) + { + JITDUMP(" -- unable to handle Reverse P/Invoke\n"); + return; + } + + PatchpointTransformer ppTransformer(this); + int count = ppTransformer.Run(); + JITDUMP("\n*************** After fgTransformPatchpoints() [%d patchpoints transformed]\n", count); + INDEBUG(if (verbose) { fgDispBasicBlocks(true); }); +} diff --git a/src/coreclr/src/jit/rangecheck.cpp b/src/coreclr/src/jit/rangecheck.cpp index 14044bffc11575..3019824427f266 100644 --- a/src/coreclr/src/jit/rangecheck.cpp +++ b/src/coreclr/src/jit/rangecheck.cpp @@ -763,7 +763,7 @@ void RangeCheck::MergeAssertion(BasicBlock* block, GenTree* op, Range* pRange DE assertions = block->bbAssertionIn; } - if (!BitVecOps::MayBeUninit(assertions)) + if (!BitVecOps::MayBeUninit(assertions) && (m_pCompiler->GetAssertionCount() > 0)) { // Perform the merge step to fine tune the range value. MergeEdgeAssertions(op->AsLclVarCommon(), assertions, pRange); @@ -889,7 +889,7 @@ Range RangeCheck::ComputeRangeForLocalDef(BasicBlock* block, } #endif Range range = GetRange(ssaDef->GetBlock(), ssaDef->GetAssignment()->gtGetOp2(), monIncreasing DEBUGARG(indent)); - if (!BitVecOps::MayBeUninit(block->bbAssertionIn)) + if (!BitVecOps::MayBeUninit(block->bbAssertionIn) && (m_pCompiler->GetAssertionCount() > 0)) { JITDUMP("Merge assertions from " FMT_BB ":%s for assignment about [%06d]\n", block->bbNum, BitVecOps::ToString(m_pCompiler->apTraits, block->bbAssertionIn), diff --git a/src/coreclr/src/jit/simdcodegenxarch.cpp b/src/coreclr/src/jit/simdcodegenxarch.cpp index d49fa6008451d8..8ca69e35be37ac 100644 --- a/src/coreclr/src/jit/simdcodegenxarch.cpp +++ b/src/coreclr/src/jit/simdcodegenxarch.cpp @@ -73,11 +73,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type { // AVX supports broadcast instructions to populate YMM reg with a single float/double value from memory. // AVX2 supports broadcast instructions to populate YMM reg with a single value from memory or mm reg. - // If we decide to use AVX2 only, we can remove this assert. - if (!compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_USE_AVX2)) - { - assert(baseType == TYP_FLOAT || baseType == TYP_DOUBLE); - } switch (baseType) { case TYP_FLOAT: diff --git a/src/coreclr/src/jit/valuenum.cpp b/src/coreclr/src/jit/valuenum.cpp index 66f5454f62a572..679e4089828c45 100644 --- a/src/coreclr/src/jit/valuenum.cpp +++ b/src/coreclr/src/jit/valuenum.cpp @@ -5794,9 +5794,17 @@ void Compiler::fgValueNumber() // these are variables that are read before being initialized (at least on some control flow paths) // if they are not must-init, then they get VNF_InitVal(i), as with the param case.) - bool isZeroed = (info.compInitMem || varDsc->lvMustInit); - ValueNum initVal = ValueNumStore::NoVN; // We must assign a new value to initVal - var_types typ = varDsc->TypeGet(); + bool isZeroed = (info.compInitMem || varDsc->lvMustInit); + + // For OSR, locals or promoted fields of locals may be missing the initial def + // because of partial importation. We can't assume they are zero. + if (lvaIsOSRLocal(lclNum)) + { + isZeroed = false; + } + + ValueNum initVal = ValueNumStore::NoVN; // We must assign a new value to initVal + var_types typ = varDsc->TypeGet(); switch (typ) { @@ -6010,7 +6018,8 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk) BasicBlock::MemoryPhiArg* phiArgs = blk->bbMemorySsaPhiFunc[memoryKind]; assert(phiArgs != BasicBlock::EmptyMemoryPhiDef); // There should be > 1 args to a phi. - assert(phiArgs->m_nextArg != nullptr); + // But OSR might leave around "dead" try entry blocks... + assert((phiArgs->m_nextArg != nullptr) || opts.IsOSR()); ValueNum phiAppVN = vnStore->VNForIntCon(phiArgs->GetSsaNum()); JITDUMP(" Building phi application: $%x = SSA# %d.\n", phiAppVN, phiArgs->GetSsaNum()); bool allSame = true; diff --git a/src/coreclr/src/pal/prebuilt/idl/clrinternal_i.cpp b/src/coreclr/src/pal/prebuilt/idl/clrinternal_i.cpp index 5c52018be7dae5..7cfb798aab89ee 100644 --- a/src/coreclr/src/pal/prebuilt/idl/clrinternal_i.cpp +++ b/src/coreclr/src/pal/prebuilt/idl/clrinternal_i.cpp @@ -61,12 +61,6 @@ typedef IID CLSID; #endif // !_MIDL_USE_GUIDDEF_ -MIDL_DEFINE_GUID(IID, IID_IExecutionEngine,0x7AF02DAC,0x2A33,0x494b,0xA0,0x9F,0x25,0xE0,0x0A,0x93,0xC6,0xF8); - - -MIDL_DEFINE_GUID(IID, IID_IEEMemoryManager,0x17713B61,0xB59F,0x4e13,0xBA,0xAF,0x91,0x62,0x3D,0xC8,0xAD,0xC0); - - MIDL_DEFINE_GUID(IID, IID_IPrivateManagedExceptionReporting,0xAD76A023,0x332D,0x4298,0x80,0x01,0x07,0xAA,0x93,0x50,0xDC,0xA4); #undef MIDL_DEFINE_GUID diff --git a/src/coreclr/src/pal/prebuilt/inc/clrinternal.h b/src/coreclr/src/pal/prebuilt/inc/clrinternal.h index 1afbb757f68631..e3625a7c312935 100644 --- a/src/coreclr/src/pal/prebuilt/inc/clrinternal.h +++ b/src/coreclr/src/pal/prebuilt/inc/clrinternal.h @@ -39,20 +39,6 @@ /* Forward Declarations */ -#ifndef __IExecutionEngine_FWD_DEFINED__ -#define __IExecutionEngine_FWD_DEFINED__ -typedef interface IExecutionEngine IExecutionEngine; - -#endif /* __IExecutionEngine_FWD_DEFINED__ */ - - -#ifndef __IEEMemoryManager_FWD_DEFINED__ -#define __IEEMemoryManager_FWD_DEFINED__ -typedef interface IEEMemoryManager IEEMemoryManager; - -#endif /* __IEEMemoryManager_FWD_DEFINED__ */ - - #ifndef __IPrivateManagedExceptionReporting_FWD_DEFINED__ #define __IPrivateManagedExceptionReporting_FWD_DEFINED__ typedef interface IPrivateManagedExceptionReporting IPrivateManagedExceptionReporting; @@ -72,48 +58,6 @@ extern "C"{ /* interface __MIDL_itf_clrinternal_0000_0000 */ /* [local] */ -#if 0 -typedef struct _OSVERSIONINFOA - { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - CHAR szCSDVersion[ 128 ]; - } OSVERSIONINFOA; - -typedef struct _OSVERSIONINFOA *POSVERSIONINFOA; - -typedef struct _OSVERSIONINFOA *LPOSVERSIONINFOA; - -typedef struct _OSVERSIONINFOW - { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - WCHAR szCSDVersion[ 128 ]; - } OSVERSIONINFOW; - -typedef struct _OSVERSIONINFOW *POSVERSIONINFOW; - -typedef struct _OSVERSIONINFOW *LPOSVERSIONINFOW; - -typedef struct _OSVERSIONINFOW RTL_OSVERSIONINFOW; - -typedef struct _OSVERSIONINFOW *PRTL_OSVERSIONINFOW; - -typedef OSVERSIONINFOA OSVERSIONINFO; - -typedef POSVERSIONINFOA POSVERSIONINFO; - -typedef LPOSVERSIONINFOA LPOSVERSIONINFO; - -#endif -EXTERN_GUID(IID_IExecutionEngine, 0x7AF02DAC, 0x2A33, 0x494b, 0xA0, 0x9F, 0x25, 0xE0, 0x0A, 0x93, 0xC6, 0xF8); -EXTERN_GUID(IID_IEEMemoryManager, 0x17713b61, 0xb59f, 0x4e13, 0xba, 0xaf, 0x91, 0x62, 0x3d, 0xc8, 0xad, 0xc0); EXTERN_GUID(CLR_ID_V4_DESKTOP, 0x267f3989, 0xd786, 0x4b9a, 0x9a, 0xf6, 0xd1, 0x9e, 0x42, 0xd5, 0x57, 0xec); EXTERN_GUID(CLR_ID_CORECLR, 0x8CB8E075, 0x0A91, 0x408E, 0x92, 0x28, 0xD6, 0x6E, 0x00, 0xA3, 0xBF, 0xF6 ); EXTERN_GUID(CLR_ID_PHONE_CLR, 0xE7237E9C, 0x31C0, 0x488C, 0xAD, 0x48, 0x32, 0x4D, 0x3E, 0x7E, 0xD9, 0x2A); @@ -121,13 +65,7 @@ EXTERN_GUID(CLR_ID_ONECORE_CLR, 0xb1ee760d, 0x6c4a, 0x4533, 0xba, 0x41, 0x6f, 0x EXTERN_GUID(IID_IPrivateManagedExceptionReporting, 0xad76a023, 0x332d, 0x4298, 0x80, 0x01, 0x07, 0xaa, 0x93, 0x50, 0xdc, 0xa4); typedef void *CRITSEC_COOKIE; -typedef void *EVENT_COOKIE; - -typedef void *SEMAPHORE_COOKIE; - -typedef void *MUTEX_COOKIE; - -typedef /* [public][public] */ +typedef /* [public] */ enum __MIDL___MIDL_itf_clrinternal_0000_0000_0001 { CRST_DEFAULT = 0, @@ -142,555 +80,11 @@ enum __MIDL___MIDL_itf_clrinternal_0000_0000_0001 CRST_DEBUG_ONLY_CHECK_FORBID_SUSPEND_THREAD = 0x200 } CrstFlags; -typedef VOID ( WINAPI *PTLS_CALLBACK_FUNCTION )( - PVOID __MIDL____MIDL_itf_clrinternal_0000_00000000); - extern RPC_IF_HANDLE __MIDL_itf_clrinternal_0000_0000_v0_0_c_ifspec; extern RPC_IF_HANDLE __MIDL_itf_clrinternal_0000_0000_v0_0_s_ifspec; -#ifndef __IExecutionEngine_INTERFACE_DEFINED__ -#define __IExecutionEngine_INTERFACE_DEFINED__ - -/* interface IExecutionEngine */ -/* [object][local][unique][helpstring][uuid] */ - - -EXTERN_C const IID IID_IExecutionEngine; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("7AF02DAC-2A33-494b-A09F-25E00A93C6F8") - IExecutionEngine : public IUnknown - { - public: - virtual CRITSEC_COOKIE STDMETHODCALLTYPE CreateLock( - /* [in] */ LPCSTR szTag, - /* [in] */ LPCSTR level, - /* [in] */ CrstFlags flags) = 0; - - virtual void STDMETHODCALLTYPE DestroyLock( - /* [in] */ CRITSEC_COOKIE lock) = 0; - - virtual void STDMETHODCALLTYPE AcquireLock( - /* [in] */ CRITSEC_COOKIE lock) = 0; - - virtual void STDMETHODCALLTYPE ReleaseLock( - /* [in] */ CRITSEC_COOKIE lock) = 0; - - virtual EVENT_COOKIE STDMETHODCALLTYPE CreateAutoEvent( - /* [in] */ BOOL bInitialState) = 0; - - virtual EVENT_COOKIE STDMETHODCALLTYPE CreateManualEvent( - /* [in] */ BOOL bInitialState) = 0; - - virtual void STDMETHODCALLTYPE CloseEvent( - /* [in] */ EVENT_COOKIE event) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrSetEvent( - /* [in] */ EVENT_COOKIE event) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrResetEvent( - /* [in] */ EVENT_COOKIE event) = 0; - - virtual DWORD STDMETHODCALLTYPE WaitForEvent( - /* [in] */ EVENT_COOKIE event, - /* [in] */ DWORD dwMilliseconds, - /* [in] */ BOOL bAlertable) = 0; - - virtual DWORD STDMETHODCALLTYPE WaitForSingleObject( - /* [in] */ HANDLE handle, - /* [in] */ DWORD dwMilliseconds) = 0; - - virtual SEMAPHORE_COOKIE STDMETHODCALLTYPE ClrCreateSemaphore( - /* [in] */ DWORD dwInitial, - /* [in] */ DWORD dwMax) = 0; - - virtual void STDMETHODCALLTYPE ClrCloseSemaphore( - /* [in] */ SEMAPHORE_COOKIE semaphore) = 0; - - virtual DWORD STDMETHODCALLTYPE ClrWaitForSemaphore( - /* [in] */ SEMAPHORE_COOKIE semaphore, - /* [in] */ DWORD dwMilliseconds, - /* [in] */ BOOL bAlertable) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrReleaseSemaphore( - /* [in] */ SEMAPHORE_COOKIE semaphore, - /* [in] */ LONG lReleaseCount, - /* [in] */ LONG *lpPreviousCount) = 0; - - virtual MUTEX_COOKIE STDMETHODCALLTYPE ClrCreateMutex( - /* [in] */ LPSECURITY_ATTRIBUTES lpMutexAttributes, - /* [in] */ BOOL bInitialOwner, - /* [in] */ LPCTSTR lpName) = 0; - - virtual DWORD STDMETHODCALLTYPE ClrWaitForMutex( - /* [in] */ MUTEX_COOKIE mutex, - /* [in] */ DWORD dwMilliseconds, - /* [in] */ BOOL bAlertable) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrReleaseMutex( - /* [in] */ MUTEX_COOKIE mutex) = 0; - - virtual void STDMETHODCALLTYPE ClrCloseMutex( - /* [in] */ MUTEX_COOKIE mutex) = 0; - - virtual DWORD STDMETHODCALLTYPE ClrSleepEx( - /* [in] */ DWORD dwMilliseconds, - /* [in] */ BOOL bAlertable) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrAllocationDisallowed( void) = 0; - - virtual void STDMETHODCALLTYPE GetLastThrownObjectExceptionFromThread( - /* [out] */ void **ppvException) = 0; - - }; - - -#else /* C style interface */ - - typedef struct IExecutionEngineVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IExecutionEngine * This, - /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - _COM_Outptr_ void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( - IExecutionEngine * This); - - ULONG ( STDMETHODCALLTYPE *Release )( - IExecutionEngine * This); - - CRITSEC_COOKIE ( STDMETHODCALLTYPE *CreateLock )( - IExecutionEngine * This, - /* [in] */ LPCSTR szTag, - /* [in] */ LPCSTR level, - /* [in] */ CrstFlags flags); - - void ( STDMETHODCALLTYPE *DestroyLock )( - IExecutionEngine * This, - /* [in] */ CRITSEC_COOKIE lock); - - void ( STDMETHODCALLTYPE *AcquireLock )( - IExecutionEngine * This, - /* [in] */ CRITSEC_COOKIE lock); - - void ( STDMETHODCALLTYPE *ReleaseLock )( - IExecutionEngine * This, - /* [in] */ CRITSEC_COOKIE lock); - - EVENT_COOKIE ( STDMETHODCALLTYPE *CreateAutoEvent )( - IExecutionEngine * This, - /* [in] */ BOOL bInitialState); - - EVENT_COOKIE ( STDMETHODCALLTYPE *CreateManualEvent )( - IExecutionEngine * This, - /* [in] */ BOOL bInitialState); - - void ( STDMETHODCALLTYPE *CloseEvent )( - IExecutionEngine * This, - /* [in] */ EVENT_COOKIE event); - - BOOL ( STDMETHODCALLTYPE *ClrSetEvent )( - IExecutionEngine * This, - /* [in] */ EVENT_COOKIE event); - - BOOL ( STDMETHODCALLTYPE *ClrResetEvent )( - IExecutionEngine * This, - /* [in] */ EVENT_COOKIE event); - - DWORD ( STDMETHODCALLTYPE *WaitForEvent )( - IExecutionEngine * This, - /* [in] */ EVENT_COOKIE event, - /* [in] */ DWORD dwMilliseconds, - /* [in] */ BOOL bAlertable); - - DWORD ( STDMETHODCALLTYPE *WaitForSingleObject )( - IExecutionEngine * This, - /* [in] */ HANDLE handle, - /* [in] */ DWORD dwMilliseconds); - - SEMAPHORE_COOKIE ( STDMETHODCALLTYPE *ClrCreateSemaphore )( - IExecutionEngine * This, - /* [in] */ DWORD dwInitial, - /* [in] */ DWORD dwMax); - - void ( STDMETHODCALLTYPE *ClrCloseSemaphore )( - IExecutionEngine * This, - /* [in] */ SEMAPHORE_COOKIE semaphore); - - DWORD ( STDMETHODCALLTYPE *ClrWaitForSemaphore )( - IExecutionEngine * This, - /* [in] */ SEMAPHORE_COOKIE semaphore, - /* [in] */ DWORD dwMilliseconds, - /* [in] */ BOOL bAlertable); - - BOOL ( STDMETHODCALLTYPE *ClrReleaseSemaphore )( - IExecutionEngine * This, - /* [in] */ SEMAPHORE_COOKIE semaphore, - /* [in] */ LONG lReleaseCount, - /* [in] */ LONG *lpPreviousCount); - - MUTEX_COOKIE ( STDMETHODCALLTYPE *ClrCreateMutex )( - IExecutionEngine * This, - /* [in] */ LPSECURITY_ATTRIBUTES lpMutexAttributes, - /* [in] */ BOOL bInitialOwner, - /* [in] */ LPCTSTR lpName); - - DWORD ( STDMETHODCALLTYPE *ClrWaitForMutex )( - IExecutionEngine * This, - /* [in] */ MUTEX_COOKIE mutex, - /* [in] */ DWORD dwMilliseconds, - /* [in] */ BOOL bAlertable); - - BOOL ( STDMETHODCALLTYPE *ClrReleaseMutex )( - IExecutionEngine * This, - /* [in] */ MUTEX_COOKIE mutex); - - void ( STDMETHODCALLTYPE *ClrCloseMutex )( - IExecutionEngine * This, - /* [in] */ MUTEX_COOKIE mutex); - - DWORD ( STDMETHODCALLTYPE *ClrSleepEx )( - IExecutionEngine * This, - /* [in] */ DWORD dwMilliseconds, - /* [in] */ BOOL bAlertable); - - BOOL ( STDMETHODCALLTYPE *ClrAllocationDisallowed )( - IExecutionEngine * This); - - void ( STDMETHODCALLTYPE *GetLastThrownObjectExceptionFromThread )( - IExecutionEngine * This, - /* [out] */ void **ppvException); - - END_INTERFACE - } IExecutionEngineVtbl; - - interface IExecutionEngine - { - CONST_VTBL struct IExecutionEngineVtbl *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IExecutionEngine_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) - -#define IExecutionEngine_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) - -#define IExecutionEngine_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) - -#define IExecutionEngine_CreateLock(This,szTag,level,flags) \ - ( (This)->lpVtbl -> CreateLock(This,szTag,level,flags) ) - -#define IExecutionEngine_DestroyLock(This,lock) \ - ( (This)->lpVtbl -> DestroyLock(This,lock) ) - -#define IExecutionEngine_AcquireLock(This,lock) \ - ( (This)->lpVtbl -> AcquireLock(This,lock) ) - -#define IExecutionEngine_ReleaseLock(This,lock) \ - ( (This)->lpVtbl -> ReleaseLock(This,lock) ) - -#define IExecutionEngine_CreateAutoEvent(This,bInitialState) \ - ( (This)->lpVtbl -> CreateAutoEvent(This,bInitialState) ) - -#define IExecutionEngine_CreateManualEvent(This,bInitialState) \ - ( (This)->lpVtbl -> CreateManualEvent(This,bInitialState) ) - -#define IExecutionEngine_CloseEvent(This,event) \ - ( (This)->lpVtbl -> CloseEvent(This,event) ) - -#define IExecutionEngine_ClrSetEvent(This,event) \ - ( (This)->lpVtbl -> ClrSetEvent(This,event) ) - -#define IExecutionEngine_ClrResetEvent(This,event) \ - ( (This)->lpVtbl -> ClrResetEvent(This,event) ) - -#define IExecutionEngine_WaitForEvent(This,event,dwMilliseconds,bAlertable) \ - ( (This)->lpVtbl -> WaitForEvent(This,event,dwMilliseconds,bAlertable) ) - -#define IExecutionEngine_WaitForSingleObject(This,handle,dwMilliseconds) \ - ( (This)->lpVtbl -> WaitForSingleObject(This,handle,dwMilliseconds) ) - -#define IExecutionEngine_ClrCreateSemaphore(This,dwInitial,dwMax) \ - ( (This)->lpVtbl -> ClrCreateSemaphore(This,dwInitial,dwMax) ) - -#define IExecutionEngine_ClrCloseSemaphore(This,semaphore) \ - ( (This)->lpVtbl -> ClrCloseSemaphore(This,semaphore) ) - -#define IExecutionEngine_ClrWaitForSemaphore(This,semaphore,dwMilliseconds,bAlertable) \ - ( (This)->lpVtbl -> ClrWaitForSemaphore(This,semaphore,dwMilliseconds,bAlertable) ) - -#define IExecutionEngine_ClrReleaseSemaphore(This,semaphore,lReleaseCount,lpPreviousCount) \ - ( (This)->lpVtbl -> ClrReleaseSemaphore(This,semaphore,lReleaseCount,lpPreviousCount) ) - -#define IExecutionEngine_ClrCreateMutex(This,lpMutexAttributes,bInitialOwner,lpName) \ - ( (This)->lpVtbl -> ClrCreateMutex(This,lpMutexAttributes,bInitialOwner,lpName) ) - -#define IExecutionEngine_ClrWaitForMutex(This,mutex,dwMilliseconds,bAlertable) \ - ( (This)->lpVtbl -> ClrWaitForMutex(This,mutex,dwMilliseconds,bAlertable) ) - -#define IExecutionEngine_ClrReleaseMutex(This,mutex) \ - ( (This)->lpVtbl -> ClrReleaseMutex(This,mutex) ) - -#define IExecutionEngine_ClrCloseMutex(This,mutex) \ - ( (This)->lpVtbl -> ClrCloseMutex(This,mutex) ) - -#define IExecutionEngine_ClrSleepEx(This,dwMilliseconds,bAlertable) \ - ( (This)->lpVtbl -> ClrSleepEx(This,dwMilliseconds,bAlertable) ) - -#define IExecutionEngine_ClrAllocationDisallowed(This) \ - ( (This)->lpVtbl -> ClrAllocationDisallowed(This) ) - -#define IExecutionEngine_GetLastThrownObjectExceptionFromThread(This,ppvException) \ - ( (This)->lpVtbl -> GetLastThrownObjectExceptionFromThread(This,ppvException) ) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - - -#endif /* __IExecutionEngine_INTERFACE_DEFINED__ */ - - -/* interface __MIDL_itf_clrinternal_0000_0001 */ -/* [local] */ - -#if !defined(_WINNT_) && !defined(_NTMMAPI_) -typedef void *PMEMORY_BASIC_INFORMATION; - -#endif - - -extern RPC_IF_HANDLE __MIDL_itf_clrinternal_0000_0001_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_clrinternal_0000_0001_v0_0_s_ifspec; - -#ifndef __IEEMemoryManager_INTERFACE_DEFINED__ -#define __IEEMemoryManager_INTERFACE_DEFINED__ - -/* interface IEEMemoryManager */ -/* [object][local][unique][helpstring][uuid] */ - - -EXTERN_C const IID IID_IEEMemoryManager; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("17713B61-B59F-4e13-BAAF-91623DC8ADC0") - IEEMemoryManager : public IUnknown - { - public: - virtual LPVOID STDMETHODCALLTYPE ClrVirtualAlloc( - /* [in] */ LPVOID lpAddress, - /* [in] */ SIZE_T dwSize, - /* [in] */ DWORD flAllocationType, - /* [in] */ DWORD flProtect) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrVirtualFree( - /* [in] */ LPVOID lpAddress, - /* [in] */ SIZE_T dwSize, - /* [in] */ DWORD dwFreeType) = 0; - - virtual SIZE_T STDMETHODCALLTYPE ClrVirtualQuery( - /* [in] */ const void *lpAddress, - /* [in] */ PMEMORY_BASIC_INFORMATION lpBuffer, - /* [in] */ SIZE_T dwLength) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrVirtualProtect( - /* [in] */ LPVOID lpAddress, - /* [in] */ SIZE_T dwSize, - /* [in] */ DWORD flNewProtect, - /* [in] */ DWORD *lpflOldProtect) = 0; - - virtual HANDLE STDMETHODCALLTYPE ClrGetProcessHeap( void) = 0; - - virtual HANDLE STDMETHODCALLTYPE ClrHeapCreate( - /* [in] */ DWORD flOptions, - /* [in] */ SIZE_T dwInitialSize, - /* [in] */ SIZE_T dwMaximumSize) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrHeapDestroy( - /* [in] */ HANDLE hHeap) = 0; - - virtual LPVOID STDMETHODCALLTYPE ClrHeapAlloc( - /* [in] */ HANDLE hHeap, - /* [in] */ DWORD dwFlags, - /* [in] */ SIZE_T dwBytes) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrHeapFree( - /* [in] */ HANDLE hHeap, - /* [in] */ DWORD dwFlags, - /* [in] */ LPVOID lpMem) = 0; - - virtual BOOL STDMETHODCALLTYPE ClrHeapValidate( - /* [in] */ HANDLE hHeap, - /* [in] */ DWORD dwFlags, - /* [in] */ const void *lpMem) = 0; - - virtual HANDLE STDMETHODCALLTYPE ClrGetProcessExecutableHeap( void) = 0; - - }; - - -#else /* C style interface */ - - typedef struct IEEMemoryManagerVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IEEMemoryManager * This, - /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - _COM_Outptr_ void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( - IEEMemoryManager * This); - - ULONG ( STDMETHODCALLTYPE *Release )( - IEEMemoryManager * This); - - LPVOID ( STDMETHODCALLTYPE *ClrVirtualAlloc )( - IEEMemoryManager * This, - /* [in] */ LPVOID lpAddress, - /* [in] */ SIZE_T dwSize, - /* [in] */ DWORD flAllocationType, - /* [in] */ DWORD flProtect); - - BOOL ( STDMETHODCALLTYPE *ClrVirtualFree )( - IEEMemoryManager * This, - /* [in] */ LPVOID lpAddress, - /* [in] */ SIZE_T dwSize, - /* [in] */ DWORD dwFreeType); - - SIZE_T ( STDMETHODCALLTYPE *ClrVirtualQuery )( - IEEMemoryManager * This, - /* [in] */ const void *lpAddress, - /* [in] */ PMEMORY_BASIC_INFORMATION lpBuffer, - /* [in] */ SIZE_T dwLength); - - BOOL ( STDMETHODCALLTYPE *ClrVirtualProtect )( - IEEMemoryManager * This, - /* [in] */ LPVOID lpAddress, - /* [in] */ SIZE_T dwSize, - /* [in] */ DWORD flNewProtect, - /* [in] */ DWORD *lpflOldProtect); - - HANDLE ( STDMETHODCALLTYPE *ClrGetProcessHeap )( - IEEMemoryManager * This); - - HANDLE ( STDMETHODCALLTYPE *ClrHeapCreate )( - IEEMemoryManager * This, - /* [in] */ DWORD flOptions, - /* [in] */ SIZE_T dwInitialSize, - /* [in] */ SIZE_T dwMaximumSize); - - BOOL ( STDMETHODCALLTYPE *ClrHeapDestroy )( - IEEMemoryManager * This, - /* [in] */ HANDLE hHeap); - - LPVOID ( STDMETHODCALLTYPE *ClrHeapAlloc )( - IEEMemoryManager * This, - /* [in] */ HANDLE hHeap, - /* [in] */ DWORD dwFlags, - /* [in] */ SIZE_T dwBytes); - - BOOL ( STDMETHODCALLTYPE *ClrHeapFree )( - IEEMemoryManager * This, - /* [in] */ HANDLE hHeap, - /* [in] */ DWORD dwFlags, - /* [in] */ LPVOID lpMem); - - BOOL ( STDMETHODCALLTYPE *ClrHeapValidate )( - IEEMemoryManager * This, - /* [in] */ HANDLE hHeap, - /* [in] */ DWORD dwFlags, - /* [in] */ const void *lpMem); - - HANDLE ( STDMETHODCALLTYPE *ClrGetProcessExecutableHeap )( - IEEMemoryManager * This); - - END_INTERFACE - } IEEMemoryManagerVtbl; - - interface IEEMemoryManager - { - CONST_VTBL struct IEEMemoryManagerVtbl *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IEEMemoryManager_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) - -#define IEEMemoryManager_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) - -#define IEEMemoryManager_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) - - -#define IEEMemoryManager_ClrVirtualAlloc(This,lpAddress,dwSize,flAllocationType,flProtect) \ - ( (This)->lpVtbl -> ClrVirtualAlloc(This,lpAddress,dwSize,flAllocationType,flProtect) ) - -#define IEEMemoryManager_ClrVirtualFree(This,lpAddress,dwSize,dwFreeType) \ - ( (This)->lpVtbl -> ClrVirtualFree(This,lpAddress,dwSize,dwFreeType) ) - -#define IEEMemoryManager_ClrVirtualQuery(This,lpAddress,lpBuffer,dwLength) \ - ( (This)->lpVtbl -> ClrVirtualQuery(This,lpAddress,lpBuffer,dwLength) ) - -#define IEEMemoryManager_ClrVirtualProtect(This,lpAddress,dwSize,flNewProtect,lpflOldProtect) \ - ( (This)->lpVtbl -> ClrVirtualProtect(This,lpAddress,dwSize,flNewProtect,lpflOldProtect) ) - -#define IEEMemoryManager_ClrGetProcessHeap(This) \ - ( (This)->lpVtbl -> ClrGetProcessHeap(This) ) - -#define IEEMemoryManager_ClrHeapCreate(This,flOptions,dwInitialSize,dwMaximumSize) \ - ( (This)->lpVtbl -> ClrHeapCreate(This,flOptions,dwInitialSize,dwMaximumSize) ) - -#define IEEMemoryManager_ClrHeapDestroy(This,hHeap) \ - ( (This)->lpVtbl -> ClrHeapDestroy(This,hHeap) ) - -#define IEEMemoryManager_ClrHeapAlloc(This,hHeap,dwFlags,dwBytes) \ - ( (This)->lpVtbl -> ClrHeapAlloc(This,hHeap,dwFlags,dwBytes) ) - -#define IEEMemoryManager_ClrHeapFree(This,hHeap,dwFlags,lpMem) \ - ( (This)->lpVtbl -> ClrHeapFree(This,hHeap,dwFlags,lpMem) ) - -#define IEEMemoryManager_ClrHeapValidate(This,hHeap,dwFlags,lpMem) \ - ( (This)->lpVtbl -> ClrHeapValidate(This,hHeap,dwFlags,lpMem) ) - -#define IEEMemoryManager_ClrGetProcessExecutableHeap(This) \ - ( (This)->lpVtbl -> ClrGetProcessExecutableHeap(This) ) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - - -#endif /* __IEEMemoryManager_INTERFACE_DEFINED__ */ - - #ifndef __IPrivateManagedExceptionReporting_INTERFACE_DEFINED__ #define __IPrivateManagedExceptionReporting_INTERFACE_DEFINED__ diff --git a/src/coreclr/src/pal/prebuilt/inc/mscoree.h b/src/coreclr/src/pal/prebuilt/inc/mscoree.h index 5eceabf8450b01..2d83809685411e 100644 --- a/src/coreclr/src/pal/prebuilt/inc/mscoree.h +++ b/src/coreclr/src/pal/prebuilt/inc/mscoree.h @@ -70,9 +70,6 @@ extern "C"{ /* interface __MIDL_itf_mscoree_0000_0000 */ /* [local] */ -#define DECLARE_DEPRECATED -#define DEPRECATED_CLR_STDAPI STDAPI - struct IActivationFactory; struct IHostControl; @@ -873,10 +870,6 @@ EXTERN_C const IID IID_ICLRRuntimeHost4; /* interface __MIDL_itf_mscoree_0000_0003 */ /* [local] */ -#undef DEPRECATED_CLR_STDAPI -#undef DECLARE_DEPRECATED -#undef DEPRECATED_CLR_API_MESG - extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0003_v0_0_c_ifspec; extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0003_v0_0_s_ifspec; diff --git a/src/coreclr/src/pal/src/CMakeLists.txt b/src/coreclr/src/pal/src/CMakeLists.txt index 249936cd392708..37aee432577830 100644 --- a/src/coreclr/src/pal/src/CMakeLists.txt +++ b/src/coreclr/src/pal/src/CMakeLists.txt @@ -290,34 +290,11 @@ if(CLR_CMAKE_TARGET_LINUX) pthread rt ) - endif() - - if(CLR_CMAKE_TARGET_ANDROID) - find_library(LZMA NAMES lzma) - - if(LZMA STREQUAL LZMA-NOTFOUND) - message(FATAL_ERROR "Cannot find liblzma.") - endif(LZMA STREQUAL LZMA-NOTFOUND) - + else(NOT CLR_CMAKE_TARGET_ANDROID) target_link_libraries(coreclrpal - gnustl_shared - android-support - android-glob + ${ANDROID_GLOB} ${LZMA}) - endif() - - if(CLR_MAKE_TARGET_ANDROID) - find_library(ANDROID_SUPPORT NAMES android-support) - find_library(ANDROID_GLOB NAMES android-glob) - - if(ANDROID_SUPPORT STREQUAL ANDROID_SUPPORT-NOTFOUND) - message(FATAL_ERROR "Cannot find android-support.") - endif() - - if(ANDROID_GLOB STREQUAL ANDROID_GLOB-NOTFOUND) - message(FATAL_ERROR "Cannot find android-glob.") - endif() - endif() + endif(NOT CLR_CMAKE_TARGET_ANDROID) target_link_libraries(coreclrpal dl diff --git a/src/coreclr/src/pal/src/misc/jitsupport.cpp b/src/coreclr/src/pal/src/misc/jitsupport.cpp index 0da36ab8903a68..70123f8d18faaf 100644 --- a/src/coreclr/src/pal/src/misc/jitsupport.cpp +++ b/src/coreclr/src/pal/src/misc/jitsupport.cpp @@ -21,11 +21,11 @@ PAL_GetJitCpuCapabilityFlags(CORJIT_FLAGS *flags) { _ASSERTE(flags); + CORJIT_FLAGS &CPUCompileFlags = *flags; #if defined(HOST_ARM64) #if HAVE_AUXV_HWCAP_H unsigned long hwCap = getauxval(AT_HWCAP); - CORJIT_FLAGS &CPUCompileFlags = *flags; // HWCAP_* flags are introduced by ARM into the Linux kernel as new extensions are published. // For a given kernel, some of these flags may not be present yet. // Use ifdef for each to allow for compilation with any vintage kernel. @@ -34,95 +34,96 @@ PAL_GetJitCpuCapabilityFlags(CORJIT_FLAGS *flags) // available, using the latest kernel for release should be sufficient. #ifdef HWCAP_AES if (hwCap & HWCAP_AES) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_AES); + CPUCompileFlags.Set(InstructionSet_Aes); #endif #ifdef HWCAP_ATOMICS if (hwCap & HWCAP_ATOMICS) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ATOMICS); + CPUCompileFlags.Set(InstructionSet_Atomics); #endif #ifdef HWCAP_CRC32 if (hwCap & HWCAP_CRC32) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_CRC32); + CPUCompileFlags.Set(InstructionSet_Crc32); #endif #ifdef HWCAP_DCPOP - if (hwCap & HWCAP_DCPOP) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_DCPOP); +// if (hwCap & HWCAP_DCPOP) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_DCPOP); #endif #ifdef HWCAP_ASIMDDP - if (hwCap & HWCAP_ASIMDDP) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_DP); +// if (hwCap & HWCAP_ASIMDDP) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_DP); #endif #ifdef HWCAP_FCMA - if (hwCap & HWCAP_FCMA) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FCMA); +// if (hwCap & HWCAP_FCMA) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FCMA); #endif #ifdef HWCAP_FP - if (hwCap & HWCAP_FP) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FP); +// if (hwCap & HWCAP_FP) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FP); #endif #ifdef HWCAP_FPHP - if (hwCap & HWCAP_FPHP) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FP16); +// if (hwCap & HWCAP_FPHP) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FP16); #endif #ifdef HWCAP_JSCVT - if (hwCap & HWCAP_JSCVT) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_JSCVT); +// if (hwCap & HWCAP_JSCVT) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_JSCVT); #endif #ifdef HWCAP_LRCPC - if (hwCap & HWCAP_LRCPC) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_LRCPC); +// if (hwCap & HWCAP_LRCPC) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_LRCPC); #endif #ifdef HWCAP_PMULL - if (hwCap & HWCAP_PMULL) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_PMULL); +// if (hwCap & HWCAP_PMULL) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_PMULL); #endif #ifdef HWCAP_SHA1 if (hwCap & HWCAP_SHA1) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA1); + CPUCompileFlags.Set(InstructionSet_Sha1); #endif #ifdef HWCAP_SHA2 if (hwCap & HWCAP_SHA2) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA256); + CPUCompileFlags.Set(InstructionSet_Sha256); #endif #ifdef HWCAP_SHA512 - if (hwCap & HWCAP_SHA512) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA512); +// if (hwCap & HWCAP_SHA512) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA512); #endif #ifdef HWCAP_SHA3 - if (hwCap & HWCAP_SHA3) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA3); +// if (hwCap & HWCAP_SHA3) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA3); #endif #ifdef HWCAP_ASIMD if (hwCap & HWCAP_ASIMD) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD); + CPUCompileFlags.Set(InstructionSet_AdvSimd); #endif #ifdef HWCAP_ASIMDRDM - if (hwCap & HWCAP_ASIMDRDM) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD_V81); +// if (hwCap & HWCAP_ASIMDRDM) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD_V81); #endif #ifdef HWCAP_ASIMDHP - if (hwCap & HWCAP_ASIMDHP) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD_FP16); +// if (hwCap & HWCAP_ASIMDHP) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD_FP16); #endif #ifdef HWCAP_SM3 - if (hwCap & HWCAP_SM3) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SM3); +// if (hwCap & HWCAP_SM3) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SM3); #endif #ifdef HWCAP_SM4 - if (hwCap & HWCAP_SM4) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SM4); +// if (hwCap & HWCAP_SM4) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SM4); #endif #ifdef HWCAP_SVE - if (hwCap & HWCAP_SVE) - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SVE); +// if (hwCap & HWCAP_SVE) +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SVE); #endif #else // !HAVE_AUXV_HWCAP_H // CoreCLR SIMD and FP support is included in ARM64 baseline // On exceptional basis platforms may leave out support, but CoreCLR does not // yet support such platforms // Set baseline flags if OS has not exposed mechanism for us to determine CPU capabilities - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD); - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FP); + CPUCompileFlags.Set(InstructionSet_AdvSimd); +// CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FP); #endif // HAVE_AUXV_HWCAP_H #endif // defined(HOST_ARM64) + CPUCompileFlags.Set64BitInstructionSetVariants(); } diff --git a/src/coreclr/src/pal/src/safecrt/mbusafecrt_internal.h b/src/coreclr/src/pal/src/safecrt/mbusafecrt_internal.h index 83c1db99a80bf9..00136ecfe2839f 100644 --- a/src/coreclr/src/pal/src/safecrt/mbusafecrt_internal.h +++ b/src/coreclr/src/pal/src/safecrt/mbusafecrt_internal.h @@ -18,6 +18,8 @@ #ifndef MBUSAFECRT_INTERNAL_H #define MBUSAFECRT_INTERNAL_H +#define PAL_IMPLEMENTATION + #include "pal_mstypes.h" #ifndef DLLEXPORT diff --git a/src/coreclr/src/pal/src/thread/context.cpp b/src/coreclr/src/pal/src/thread/context.cpp index d00f6888564793..a89bdb2649f0d4 100644 --- a/src/coreclr/src/pal/src/thread/context.cpp +++ b/src/coreclr/src/pal/src/thread/context.cpp @@ -203,7 +203,7 @@ BOOL CONTEXT_GetRegisters(DWORD processId, LPCONTEXT lpContext) ucontext_t registers; #if HAVE_PT_REGS struct pt_regs ptrace_registers; - if (ptrace((__ptrace_request)PT_GETREGS, processId, (caddr_t) &ptrace_registers, 0) == -1) + if (ptrace((__ptrace_request)PTRACE_GETREGS, processId, (caddr_t) &ptrace_registers, 0) == -1) #elif HAVE_BSD_REGS_T struct reg ptrace_registers; if (PAL_PTRACE(PT_GETREGS, processId, &ptrace_registers, 0) == -1) @@ -352,7 +352,7 @@ CONTEXT_SetThreadContext( (CONTEXT_CONTROL | CONTEXT_INTEGER) & CONTEXT_AREA_MASK) { #if HAVE_PT_REGS - if (ptrace((__ptrace_request)PT_GETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1) + if (ptrace((__ptrace_request)PTRACE_GETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1) #elif HAVE_BSD_REGS_T if (PAL_PTRACE(PT_GETREGS, dwProcessId, &ptrace_registers, 0) == -1) #endif @@ -383,7 +383,7 @@ CONTEXT_SetThreadContext( #undef ASSIGN_REG #if HAVE_PT_REGS - if (ptrace((__ptrace_request)PT_SETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1) + if (ptrace((__ptrace_request)PTRACE_SETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1) #elif HAVE_BSD_REGS_T if (PAL_PTRACE(PT_SETREGS, dwProcessId, &ptrace_registers, 0) == -1) #endif diff --git a/src/coreclr/src/scripts/genEventing.py b/src/coreclr/src/scripts/genEventing.py index 50fde02fbd02c6..69c96adf5a063f 100644 --- a/src/coreclr/src/scripts/genEventing.py +++ b/src/coreclr/src/scripts/genEventing.py @@ -639,7 +639,8 @@ def generatePlatformIndependentFiles(sClrEtwAllMan, incDir, etmDummyFile, extern { int const Level; ULONGLONG const Keyword; -} EVENT_DESCRIPTOR;""") +} EVENT_DESCRIPTOR; +""") if not is_windows: Clrproviders.write(eventpipe_trace_context_typedef) # define EVENTPIPE_TRACE_CONTEXT diff --git a/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSet.cs b/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSet.cs new file mode 100644 index 00000000000000..aff37abdf06aca --- /dev/null +++ b/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSet.cs @@ -0,0 +1,134 @@ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// FROM /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +// using /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat + +using System; +using System.Runtime.InteropServices; +using Internal.TypeSystem; + +namespace Internal.ReadyToRunConstants +{ + public enum ReadyToRunInstructionSet + { + Sse=1, + Sse2=2, + Sse3=3, + Ssse3=4, + Sse41=5, + Sse42=6, + Avx=7, + Avx2=8, + Aes=9, + Bmi1=10, + Bmi2=11, + Fma=12, + Lzcnt=13, + Pclmulqdq=14, + Popcnt=15, + ArmBase=16, + AdvSimd=17, + Crc32=18, + Sha1=19, + Sha256=20, + Atomics=21, + + } + + public static class ReadyToRunInstructionSetHelper + { + ReadyToRunInstructionSet? R2RInstructionSetFromJitInstructionSet(TargetArchitecture architecture, Internal.JitInterface.InstructionSet instructionSet) + { + switch (architecture) + { + + case TargetArchitecture.ARM64: + { + switch (instructionSet) + { + case InstructionSet.ARM64_ArmBase: return ReadyToRunInstructionSet.ArmBase; + case InstructionSet.ARM64_ArmBase_Arm64: return ReadyToRunInstructionSet.ArmBase; + case InstructionSet.ARM64_AdvSimd: return ReadyToRunInstructionSet.AdvSimd; + case InstructionSet.ARM64_AdvSimd_Arm64: return ReadyToRunInstructionSet.AdvSimd; + case InstructionSet.ARM64_Aes: return ReadyToRunInstructionSet.Aes; + case InstructionSet.ARM64_Crc32: return ReadyToRunInstructionSet.Crc32; + case InstructionSet.ARM64_Crc32_Arm64: return ReadyToRunInstructionSet.Crc32; + case InstructionSet.ARM64_Sha1: return ReadyToRunInstructionSet.Sha1; + case InstructionSet.ARM64_Sha256: return ReadyToRunInstructionSet.Sha256; + case InstructionSet.ARM64_Atomics: return ReadyToRunInstructionSet.Atomics; + case InstructionSet.ARM64_Vector64: return null; + case InstructionSet.ARM64_Vector128: return null; + + default: throw new Exception("Unknown instruction set"); + } + } + + case TargetArchitecture.X64: + { + switch (instructionSet) + { + case InstructionSet.X64_SSE: return ReadyToRunInstructionSet.Sse; + case InstructionSet.X64_SSE_X64: return ReadyToRunInstructionSet.Sse; + case InstructionSet.X64_SSE2: return ReadyToRunInstructionSet.Sse2; + case InstructionSet.X64_SSE2_X64: return ReadyToRunInstructionSet.Sse2; + case InstructionSet.X64_SSE3: return ReadyToRunInstructionSet.Sse3; + case InstructionSet.X64_SSSE3: return ReadyToRunInstructionSet.Ssse3; + case InstructionSet.X64_SSE41: return ReadyToRunInstructionSet.Sse41; + case InstructionSet.X64_SSE41_X64: return ReadyToRunInstructionSet.Sse41; + case InstructionSet.X64_SSE42: return ReadyToRunInstructionSet.Sse42; + case InstructionSet.X64_SSE42_X64: return ReadyToRunInstructionSet.Sse42; + case InstructionSet.X64_AVX: return ReadyToRunInstructionSet.Avx; + case InstructionSet.X64_AVX2: return ReadyToRunInstructionSet.Avx2; + case InstructionSet.X64_AES: return ReadyToRunInstructionSet.Aes; + case InstructionSet.X64_BMI1: return ReadyToRunInstructionSet.Bmi1; + case InstructionSet.X64_BMI1_X64: return ReadyToRunInstructionSet.Bmi1; + case InstructionSet.X64_BMI2: return ReadyToRunInstructionSet.Bmi2; + case InstructionSet.X64_BMI2_X64: return ReadyToRunInstructionSet.Bmi2; + case InstructionSet.X64_FMA: return ReadyToRunInstructionSet.Fma; + case InstructionSet.X64_LZCNT: return ReadyToRunInstructionSet.Lzcnt; + case InstructionSet.X64_LZCNT_X64: return ReadyToRunInstructionSet.Lzcnt; + case InstructionSet.X64_PCLMULQDQ: return ReadyToRunInstructionSet.Pclmulqdq; + case InstructionSet.X64_POPCNT: return ReadyToRunInstructionSet.Popcnt; + case InstructionSet.X64_POPCNT_X64: return ReadyToRunInstructionSet.Popcnt; + case InstructionSet.X64_Vector128: return null; + case InstructionSet.X64_Vector256: return null; + + default: throw new Exception("Unknown instruction set"); + } + } + + case TargetArchitecture.X86: + { + switch (instructionSet) + { + case InstructionSet.X86_SSE: return ReadyToRunInstructionSet.Sse; + case InstructionSet.X86_SSE2: return ReadyToRunInstructionSet.Sse2; + case InstructionSet.X86_SSE3: return ReadyToRunInstructionSet.Sse3; + case InstructionSet.X86_SSSE3: return ReadyToRunInstructionSet.Ssse3; + case InstructionSet.X86_SSE41: return ReadyToRunInstructionSet.Sse41; + case InstructionSet.X86_SSE42: return ReadyToRunInstructionSet.Sse42; + case InstructionSet.X86_AVX: return ReadyToRunInstructionSet.Avx; + case InstructionSet.X86_AVX2: return ReadyToRunInstructionSet.Avx2; + case InstructionSet.X86_AES: return ReadyToRunInstructionSet.Aes; + case InstructionSet.X86_BMI1: return ReadyToRunInstructionSet.Bmi1; + case InstructionSet.X86_BMI2: return ReadyToRunInstructionSet.Bmi2; + case InstructionSet.X86_FMA: return ReadyToRunInstructionSet.Fma; + case InstructionSet.X86_LZCNT: return ReadyToRunInstructionSet.Lzcnt; + case InstructionSet.X86_PCLMULQDQ: return ReadyToRunInstructionSet.Pclmulqdq; + case InstructionSet.X86_POPCNT: return ReadyToRunInstructionSet.Popcnt; + case InstructionSet.X86_Vector128: return null; + case InstructionSet.X86_Vector256: return null; + + default: throw new Exception("Unknown instruction set"); + } + } + + default: throw new Exception("Unknown architecture"); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs index 0a6672326e722f..661d016a0362c5 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs @@ -62,6 +62,10 @@ unsafe partial class CorInfoImpl [UnmanagedFunctionPointerAttribute(default(CallingConvention))] delegate void __getGSCookie(IntPtr _this, IntPtr* ppException, IntPtr* pCookieVal, IntPtr** ppCookieVal); [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate void __setPatchpointInfo(IntPtr _this, IntPtr* ppException, PatchpointInfo* patchpointInfo); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] + delegate PatchpointInfo* __getOSRInfo(IntPtr _this, IntPtr* ppException, ref uint ilOffset); + [UnmanagedFunctionPointerAttribute(default(CallingConvention))] delegate void __resolveToken(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken); [UnmanagedFunctionPointerAttribute(default(CallingConvention))] delegate void __tryResolveToken(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken); @@ -689,6 +693,33 @@ static void _getGSCookie(IntPtr thisHandle, IntPtr* ppException, IntPtr* pCookie } } + static void _setPatchpointInfo(IntPtr thisHandle, IntPtr* ppException, PatchpointInfo* patchpointInfo) + { + var _this = GetThis(thisHandle); + try + { + _this.setPatchpointInfo(patchpointInfo); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + + static PatchpointInfo* _getOSRInfo(IntPtr thisHandle, IntPtr* ppException, ref uint ilOffset) + { + var _this = GetThis(thisHandle); + try + { + return _this.getOSRInfo(ref ilOffset); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default(PatchpointInfo*); + } + } + static void _resolveToken(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken) { var _this = GetThis(thisHandle); @@ -2659,9 +2690,17 @@ static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, ref CORJIT_FLAG static IntPtr GetUnmanagedCallbacks(out Object keepAlive) { + IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 168); Object[] delegates = new Object[168]; + IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 167); + Object[] delegates = new Object[167]; + + IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 169); + Object[] delegates = new Object[169]; + + var d0 = new __getMethodAttribs(_getMethodAttribs); callbacks[0] = Marshal.GetFunctionPointerForDelegate(d0); delegates[0] = d0; @@ -2737,439 +2776,377 @@ static IntPtr GetUnmanagedCallbacks(out Object keepAlive) var d24 = new __getGSCookie(_getGSCookie); callbacks[24] = Marshal.GetFunctionPointerForDelegate(d24); delegates[24] = d24; - var d25 = new __resolveToken(_resolveToken); + var d25 = new __setPatchpointInfo(_setPatchpointInfo); callbacks[25] = Marshal.GetFunctionPointerForDelegate(d25); delegates[25] = d25; - var d26 = new __tryResolveToken(_tryResolveToken); + var d26 = new __getOSRInfo(_getOSRInfo); callbacks[26] = Marshal.GetFunctionPointerForDelegate(d26); delegates[26] = d26; - var d27 = new __findSig(_findSig); + var d27 = new __resolveToken(_resolveToken); callbacks[27] = Marshal.GetFunctionPointerForDelegate(d27); delegates[27] = d27; - var d28 = new __findCallSiteSig(_findCallSiteSig); + var d28 = new __tryResolveToken(_tryResolveToken); callbacks[28] = Marshal.GetFunctionPointerForDelegate(d28); delegates[28] = d28; - var d29 = new __getTokenTypeAsHandle(_getTokenTypeAsHandle); + var d29 = new __findSig(_findSig); callbacks[29] = Marshal.GetFunctionPointerForDelegate(d29); delegates[29] = d29; - var d30 = new __isValidToken(_isValidToken); + var d30 = new __findCallSiteSig(_findCallSiteSig); callbacks[30] = Marshal.GetFunctionPointerForDelegate(d30); delegates[30] = d30; - var d31 = new __isValidStringRef(_isValidStringRef); + var d31 = new __getTokenTypeAsHandle(_getTokenTypeAsHandle); callbacks[31] = Marshal.GetFunctionPointerForDelegate(d31); delegates[31] = d31; - var d32 = new __getStringLiteral(_getStringLiteral); + var d32 = new __isValidToken(_isValidToken); callbacks[32] = Marshal.GetFunctionPointerForDelegate(d32); delegates[32] = d32; - var d33 = new __asCorInfoType(_asCorInfoType); + var d33 = new __isValidStringRef(_isValidStringRef); callbacks[33] = Marshal.GetFunctionPointerForDelegate(d33); delegates[33] = d33; - var d34 = new __getClassName(_getClassName); + var d34 = new __getStringLiteral(_getStringLiteral); callbacks[34] = Marshal.GetFunctionPointerForDelegate(d34); delegates[34] = d34; - var d35 = new __getClassNameFromMetadata(_getClassNameFromMetadata); + var d35 = new __asCorInfoType(_asCorInfoType); callbacks[35] = Marshal.GetFunctionPointerForDelegate(d35); delegates[35] = d35; - var d36 = new __getTypeInstantiationArgument(_getTypeInstantiationArgument); + var d36 = new __getClassName(_getClassName); callbacks[36] = Marshal.GetFunctionPointerForDelegate(d36); delegates[36] = d36; - var d37 = new __appendClassName(_appendClassName); + var d37 = new __getClassNameFromMetadata(_getClassNameFromMetadata); callbacks[37] = Marshal.GetFunctionPointerForDelegate(d37); delegates[37] = d37; - var d38 = new __isValueClass(_isValueClass); + var d38 = new __getTypeInstantiationArgument(_getTypeInstantiationArgument); callbacks[38] = Marshal.GetFunctionPointerForDelegate(d38); delegates[38] = d38; - var d39 = new __canInlineTypeCheck(_canInlineTypeCheck); + var d39 = new __appendClassName(_appendClassName); callbacks[39] = Marshal.GetFunctionPointerForDelegate(d39); delegates[39] = d39; - var d40 = new __getClassAttribs(_getClassAttribs); + var d40 = new __isValueClass(_isValueClass); callbacks[40] = Marshal.GetFunctionPointerForDelegate(d40); delegates[40] = d40; - var d41 = new __isStructRequiringStackAllocRetBuf(_isStructRequiringStackAllocRetBuf); + var d41 = new __canInlineTypeCheck(_canInlineTypeCheck); callbacks[41] = Marshal.GetFunctionPointerForDelegate(d41); delegates[41] = d41; - var d42 = new __getClassModule(_getClassModule); + var d42 = new __getClassAttribs(_getClassAttribs); callbacks[42] = Marshal.GetFunctionPointerForDelegate(d42); delegates[42] = d42; - var d43 = new __getModuleAssembly(_getModuleAssembly); + var d43 = new __isStructRequiringStackAllocRetBuf(_isStructRequiringStackAllocRetBuf); callbacks[43] = Marshal.GetFunctionPointerForDelegate(d43); delegates[43] = d43; - var d44 = new __getAssemblyName(_getAssemblyName); + var d44 = new __getClassModule(_getClassModule); callbacks[44] = Marshal.GetFunctionPointerForDelegate(d44); delegates[44] = d44; - var d45 = new __LongLifetimeMalloc(_LongLifetimeMalloc); + var d45 = new __getModuleAssembly(_getModuleAssembly); callbacks[45] = Marshal.GetFunctionPointerForDelegate(d45); delegates[45] = d45; - var d46 = new __LongLifetimeFree(_LongLifetimeFree); + var d46 = new __getAssemblyName(_getAssemblyName); callbacks[46] = Marshal.GetFunctionPointerForDelegate(d46); delegates[46] = d46; - var d47 = new __getClassModuleIdForStatics(_getClassModuleIdForStatics); + var d47 = new __LongLifetimeMalloc(_LongLifetimeMalloc); callbacks[47] = Marshal.GetFunctionPointerForDelegate(d47); delegates[47] = d47; - var d48 = new __getClassSize(_getClassSize); + var d48 = new __LongLifetimeFree(_LongLifetimeFree); callbacks[48] = Marshal.GetFunctionPointerForDelegate(d48); delegates[48] = d48; - var d49 = new __getHeapClassSize(_getHeapClassSize); + var d49 = new __getClassModuleIdForStatics(_getClassModuleIdForStatics); callbacks[49] = Marshal.GetFunctionPointerForDelegate(d49); delegates[49] = d49; - var d50 = new __canAllocateOnStack(_canAllocateOnStack); + var d50 = new __getClassSize(_getClassSize); callbacks[50] = Marshal.GetFunctionPointerForDelegate(d50); delegates[50] = d50; - var d51 = new __getClassAlignmentRequirement(_getClassAlignmentRequirement); + var d51 = new __getHeapClassSize(_getHeapClassSize); callbacks[51] = Marshal.GetFunctionPointerForDelegate(d51); delegates[51] = d51; - var d52 = new __getClassGClayout(_getClassGClayout); + var d52 = new __canAllocateOnStack(_canAllocateOnStack); callbacks[52] = Marshal.GetFunctionPointerForDelegate(d52); delegates[52] = d52; - var d53 = new __getClassNumInstanceFields(_getClassNumInstanceFields); + var d53 = new __getClassAlignmentRequirement(_getClassAlignmentRequirement); callbacks[53] = Marshal.GetFunctionPointerForDelegate(d53); delegates[53] = d53; - var d54 = new __getFieldInClass(_getFieldInClass); + var d54 = new __getClassGClayout(_getClassGClayout); callbacks[54] = Marshal.GetFunctionPointerForDelegate(d54); delegates[54] = d54; - var d55 = new __checkMethodModifier(_checkMethodModifier); + var d55 = new __getClassNumInstanceFields(_getClassNumInstanceFields); callbacks[55] = Marshal.GetFunctionPointerForDelegate(d55); delegates[55] = d55; - var d56 = new __getNewHelper(_getNewHelper); + var d56 = new __getFieldInClass(_getFieldInClass); callbacks[56] = Marshal.GetFunctionPointerForDelegate(d56); delegates[56] = d56; - var d57 = new __getNewArrHelper(_getNewArrHelper); + var d57 = new __checkMethodModifier(_checkMethodModifier); callbacks[57] = Marshal.GetFunctionPointerForDelegate(d57); delegates[57] = d57; - var d58 = new __getCastingHelper(_getCastingHelper); + var d58 = new __getNewHelper(_getNewHelper); callbacks[58] = Marshal.GetFunctionPointerForDelegate(d58); delegates[58] = d58; - var d59 = new __getSharedCCtorHelper(_getSharedCCtorHelper); + var d59 = new __getNewArrHelper(_getNewArrHelper); callbacks[59] = Marshal.GetFunctionPointerForDelegate(d59); delegates[59] = d59; - var d60 = new __getTypeForBox(_getTypeForBox); + var d60 = new __getCastingHelper(_getCastingHelper); callbacks[60] = Marshal.GetFunctionPointerForDelegate(d60); delegates[60] = d60; - var d61 = new __getBoxHelper(_getBoxHelper); + var d61 = new __getSharedCCtorHelper(_getSharedCCtorHelper); callbacks[61] = Marshal.GetFunctionPointerForDelegate(d61); delegates[61] = d61; - var d62 = new __getUnBoxHelper(_getUnBoxHelper); + var d62 = new __getTypeForBox(_getTypeForBox); callbacks[62] = Marshal.GetFunctionPointerForDelegate(d62); delegates[62] = d62; - var d63 = new __getReadyToRunHelper(_getReadyToRunHelper); + var d63 = new __getBoxHelper(_getBoxHelper); callbacks[63] = Marshal.GetFunctionPointerForDelegate(d63); delegates[63] = d63; - var d64 = new __getReadyToRunDelegateCtorHelper(_getReadyToRunDelegateCtorHelper); + var d64 = new __getUnBoxHelper(_getUnBoxHelper); callbacks[64] = Marshal.GetFunctionPointerForDelegate(d64); delegates[64] = d64; - var d65 = new __getHelperName(_getHelperName); + var d65 = new __getReadyToRunHelper(_getReadyToRunHelper); callbacks[65] = Marshal.GetFunctionPointerForDelegate(d65); delegates[65] = d65; - var d66 = new __initClass(_initClass); + var d66 = new __getReadyToRunDelegateCtorHelper(_getReadyToRunDelegateCtorHelper); callbacks[66] = Marshal.GetFunctionPointerForDelegate(d66); delegates[66] = d66; - var d67 = new __classMustBeLoadedBeforeCodeIsRun(_classMustBeLoadedBeforeCodeIsRun); + var d67 = new __getHelperName(_getHelperName); callbacks[67] = Marshal.GetFunctionPointerForDelegate(d67); delegates[67] = d67; - var d68 = new __getBuiltinClass(_getBuiltinClass); + var d68 = new __initClass(_initClass); callbacks[68] = Marshal.GetFunctionPointerForDelegate(d68); delegates[68] = d68; - var d69 = new __getTypeForPrimitiveValueClass(_getTypeForPrimitiveValueClass); + var d69 = new __classMustBeLoadedBeforeCodeIsRun(_classMustBeLoadedBeforeCodeIsRun); callbacks[69] = Marshal.GetFunctionPointerForDelegate(d69); delegates[69] = d69; - var d70 = new __getTypeForPrimitiveNumericClass(_getTypeForPrimitiveNumericClass); + var d70 = new __getBuiltinClass(_getBuiltinClass); callbacks[70] = Marshal.GetFunctionPointerForDelegate(d70); delegates[70] = d70; - var d71 = new __canCast(_canCast); + var d71 = new __getTypeForPrimitiveValueClass(_getTypeForPrimitiveValueClass); callbacks[71] = Marshal.GetFunctionPointerForDelegate(d71); delegates[71] = d71; - var d72 = new __areTypesEquivalent(_areTypesEquivalent); + var d72 = new __getTypeForPrimitiveNumericClass(_getTypeForPrimitiveNumericClass); callbacks[72] = Marshal.GetFunctionPointerForDelegate(d72); delegates[72] = d72; - var d73 = new __compareTypesForCast(_compareTypesForCast); + var d73 = new __canCast(_canCast); callbacks[73] = Marshal.GetFunctionPointerForDelegate(d73); delegates[73] = d73; - var d74 = new __compareTypesForEquality(_compareTypesForEquality); + var d74 = new __areTypesEquivalent(_areTypesEquivalent); callbacks[74] = Marshal.GetFunctionPointerForDelegate(d74); delegates[74] = d74; - var d75 = new __mergeClasses(_mergeClasses); + var d75 = new __compareTypesForCast(_compareTypesForCast); callbacks[75] = Marshal.GetFunctionPointerForDelegate(d75); delegates[75] = d75; - var d76 = new __isMoreSpecificType(_isMoreSpecificType); + var d76 = new __compareTypesForEquality(_compareTypesForEquality); callbacks[76] = Marshal.GetFunctionPointerForDelegate(d76); delegates[76] = d76; - var d77 = new __getParentType(_getParentType); + var d77 = new __mergeClasses(_mergeClasses); callbacks[77] = Marshal.GetFunctionPointerForDelegate(d77); delegates[77] = d77; - var d78 = new __getChildType(_getChildType); + var d78 = new __isMoreSpecificType(_isMoreSpecificType); callbacks[78] = Marshal.GetFunctionPointerForDelegate(d78); delegates[78] = d78; - var d79 = new __satisfiesClassConstraints(_satisfiesClassConstraints); + var d79 = new __getParentType(_getParentType); callbacks[79] = Marshal.GetFunctionPointerForDelegate(d79); delegates[79] = d79; - var d80 = new __isSDArray(_isSDArray); + var d80 = new __getChildType(_getChildType); callbacks[80] = Marshal.GetFunctionPointerForDelegate(d80); delegates[80] = d80; - var d81 = new __getArrayRank(_getArrayRank); + var d81 = new __satisfiesClassConstraints(_satisfiesClassConstraints); callbacks[81] = Marshal.GetFunctionPointerForDelegate(d81); delegates[81] = d81; - var d82 = new __getArrayInitializationData(_getArrayInitializationData); + var d82 = new __isSDArray(_isSDArray); callbacks[82] = Marshal.GetFunctionPointerForDelegate(d82); delegates[82] = d82; - var d83 = new __canAccessClass(_canAccessClass); + var d83 = new __getArrayRank(_getArrayRank); callbacks[83] = Marshal.GetFunctionPointerForDelegate(d83); delegates[83] = d83; - var d84 = new __getFieldName(_getFieldName); + var d84 = new __getArrayInitializationData(_getArrayInitializationData); callbacks[84] = Marshal.GetFunctionPointerForDelegate(d84); delegates[84] = d84; - var d85 = new __getFieldClass(_getFieldClass); + var d85 = new __canAccessClass(_canAccessClass); callbacks[85] = Marshal.GetFunctionPointerForDelegate(d85); delegates[85] = d85; - var d86 = new __getFieldType(_getFieldType); + var d86 = new __getFieldName(_getFieldName); callbacks[86] = Marshal.GetFunctionPointerForDelegate(d86); delegates[86] = d86; - var d87 = new __getFieldOffset(_getFieldOffset); + var d87 = new __getFieldClass(_getFieldClass); callbacks[87] = Marshal.GetFunctionPointerForDelegate(d87); delegates[87] = d87; - var d88 = new __getFieldInfo(_getFieldInfo); + var d88 = new __getFieldType(_getFieldType); callbacks[88] = Marshal.GetFunctionPointerForDelegate(d88); delegates[88] = d88; - var d89 = new __isFieldStatic(_isFieldStatic); + var d89 = new __getFieldOffset(_getFieldOffset); callbacks[89] = Marshal.GetFunctionPointerForDelegate(d89); delegates[89] = d89; - var d90 = new __getBoundaries(_getBoundaries); + var d90 = new __getFieldInfo(_getFieldInfo); callbacks[90] = Marshal.GetFunctionPointerForDelegate(d90); delegates[90] = d90; - var d91 = new __setBoundaries(_setBoundaries); + var d91 = new __isFieldStatic(_isFieldStatic); callbacks[91] = Marshal.GetFunctionPointerForDelegate(d91); delegates[91] = d91; - var d92 = new __getVars(_getVars); + var d92 = new __getBoundaries(_getBoundaries); callbacks[92] = Marshal.GetFunctionPointerForDelegate(d92); delegates[92] = d92; - var d93 = new __setVars(_setVars); + var d93 = new __setBoundaries(_setBoundaries); callbacks[93] = Marshal.GetFunctionPointerForDelegate(d93); delegates[93] = d93; - var d94 = new __allocateArray(_allocateArray); + var d94 = new __getVars(_getVars); callbacks[94] = Marshal.GetFunctionPointerForDelegate(d94); delegates[94] = d94; - var d95 = new __freeArray(_freeArray); + var d95 = new __setVars(_setVars); callbacks[95] = Marshal.GetFunctionPointerForDelegate(d95); delegates[95] = d95; - var d96 = new __getArgNext(_getArgNext); + var d96 = new __allocateArray(_allocateArray); callbacks[96] = Marshal.GetFunctionPointerForDelegate(d96); delegates[96] = d96; - var d97 = new __getArgType(_getArgType); + var d97 = new __freeArray(_freeArray); callbacks[97] = Marshal.GetFunctionPointerForDelegate(d97); delegates[97] = d97; - var d98 = new __getArgClass(_getArgClass); + var d98 = new __getArgNext(_getArgNext); callbacks[98] = Marshal.GetFunctionPointerForDelegate(d98); delegates[98] = d98; - var d99 = new __getHFAType(_getHFAType); + var d99 = new __getArgType(_getArgType); callbacks[99] = Marshal.GetFunctionPointerForDelegate(d99); delegates[99] = d99; - var d100 = new __GetErrorHRESULT(_GetErrorHRESULT); + var d100 = new __getArgClass(_getArgClass); callbacks[100] = Marshal.GetFunctionPointerForDelegate(d100); delegates[100] = d100; - var d101 = new __GetErrorMessage(_GetErrorMessage); + var d101 = new __getHFAType(_getHFAType); callbacks[101] = Marshal.GetFunctionPointerForDelegate(d101); delegates[101] = d101; - var d102 = new __FilterException(_FilterException); + var d102 = new __GetErrorHRESULT(_GetErrorHRESULT); callbacks[102] = Marshal.GetFunctionPointerForDelegate(d102); delegates[102] = d102; - var d103 = new __HandleException(_HandleException); + var d103 = new __GetErrorMessage(_GetErrorMessage); callbacks[103] = Marshal.GetFunctionPointerForDelegate(d103); delegates[103] = d103; - var d104 = new __ThrowExceptionForJitResult(_ThrowExceptionForJitResult); + var d104 = new __FilterException(_FilterException); callbacks[104] = Marshal.GetFunctionPointerForDelegate(d104); delegates[104] = d104; - var d105 = new __ThrowExceptionForHelper(_ThrowExceptionForHelper); + var d105 = new __HandleException(_HandleException); callbacks[105] = Marshal.GetFunctionPointerForDelegate(d105); delegates[105] = d105; - var d106 = new __runWithErrorTrap(_runWithErrorTrap); + var d106 = new __ThrowExceptionForJitResult(_ThrowExceptionForJitResult); callbacks[106] = Marshal.GetFunctionPointerForDelegate(d106); delegates[106] = d106; - var d107 = new __getEEInfo(_getEEInfo); + var d107 = new __ThrowExceptionForHelper(_ThrowExceptionForHelper); callbacks[107] = Marshal.GetFunctionPointerForDelegate(d107); delegates[107] = d107; - var d108 = new __getJitTimeLogFilename(_getJitTimeLogFilename); + var d108 = new __runWithErrorTrap(_runWithErrorTrap); callbacks[108] = Marshal.GetFunctionPointerForDelegate(d108); delegates[108] = d108; - var d109 = new __getMethodDefFromMethod(_getMethodDefFromMethod); + var d109 = new __getEEInfo(_getEEInfo); callbacks[109] = Marshal.GetFunctionPointerForDelegate(d109); delegates[109] = d109; - var d110 = new __getMethodName(_getMethodName); + var d110 = new __getJitTimeLogFilename(_getJitTimeLogFilename); callbacks[110] = Marshal.GetFunctionPointerForDelegate(d110); delegates[110] = d110; - var d111 = new __getMethodNameFromMetadata(_getMethodNameFromMetadata); + var d111 = new __getMethodDefFromMethod(_getMethodDefFromMethod); callbacks[111] = Marshal.GetFunctionPointerForDelegate(d111); delegates[111] = d111; - var d112 = new __getMethodHash(_getMethodHash); + var d112 = new __getMethodName(_getMethodName); callbacks[112] = Marshal.GetFunctionPointerForDelegate(d112); delegates[112] = d112; - var d113 = new __findNameOfToken(_findNameOfToken); + var d113 = new __getMethodNameFromMetadata(_getMethodNameFromMetadata); callbacks[113] = Marshal.GetFunctionPointerForDelegate(d113); delegates[113] = d113; - var d114 = new __getSystemVAmd64PassStructInRegisterDescriptor(_getSystemVAmd64PassStructInRegisterDescriptor); + var d114 = new __getMethodHash(_getMethodHash); callbacks[114] = Marshal.GetFunctionPointerForDelegate(d114); delegates[114] = d114; - var d115 = new __getThreadTLSIndex(_getThreadTLSIndex); + var d115 = new __findNameOfToken(_findNameOfToken); callbacks[115] = Marshal.GetFunctionPointerForDelegate(d115); delegates[115] = d115; - var d116 = new __getInlinedCallFrameVptr(_getInlinedCallFrameVptr); + var d116 = new __getSystemVAmd64PassStructInRegisterDescriptor(_getSystemVAmd64PassStructInRegisterDescriptor); callbacks[116] = Marshal.GetFunctionPointerForDelegate(d116); delegates[116] = d116; - var d117 = new __getAddrOfCaptureThreadGlobal(_getAddrOfCaptureThreadGlobal); + var d117 = new __getThreadTLSIndex(_getThreadTLSIndex); callbacks[117] = Marshal.GetFunctionPointerForDelegate(d117); delegates[117] = d117; - var d118 = new __getHelperFtn(_getHelperFtn); + var d118 = new __getInlinedCallFrameVptr(_getInlinedCallFrameVptr); callbacks[118] = Marshal.GetFunctionPointerForDelegate(d118); delegates[118] = d118; - var d119 = new __getFunctionEntryPoint(_getFunctionEntryPoint); + var d119 = new __getAddrOfCaptureThreadGlobal(_getAddrOfCaptureThreadGlobal); callbacks[119] = Marshal.GetFunctionPointerForDelegate(d119); delegates[119] = d119; - var d120 = new __getFunctionFixedEntryPoint(_getFunctionFixedEntryPoint); + var d120 = new __getHelperFtn(_getHelperFtn); callbacks[120] = Marshal.GetFunctionPointerForDelegate(d120); delegates[120] = d120; - var d121 = new __getMethodSync(_getMethodSync); + var d121 = new __getFunctionEntryPoint(_getFunctionEntryPoint); callbacks[121] = Marshal.GetFunctionPointerForDelegate(d121); delegates[121] = d121; - var d122 = new __getLazyStringLiteralHelper(_getLazyStringLiteralHelper); + var d122 = new __getFunctionFixedEntryPoint(_getFunctionFixedEntryPoint); callbacks[122] = Marshal.GetFunctionPointerForDelegate(d122); delegates[122] = d122; - var d123 = new __embedModuleHandle(_embedModuleHandle); + var d123 = new __getMethodSync(_getMethodSync); callbacks[123] = Marshal.GetFunctionPointerForDelegate(d123); delegates[123] = d123; - var d124 = new __embedClassHandle(_embedClassHandle); + var d124 = new __getLazyStringLiteralHelper(_getLazyStringLiteralHelper); callbacks[124] = Marshal.GetFunctionPointerForDelegate(d124); delegates[124] = d124; - var d125 = new __embedMethodHandle(_embedMethodHandle); + var d125 = new __embedModuleHandle(_embedModuleHandle); callbacks[125] = Marshal.GetFunctionPointerForDelegate(d125); delegates[125] = d125; - var d126 = new __embedFieldHandle(_embedFieldHandle); + var d126 = new __embedClassHandle(_embedClassHandle); callbacks[126] = Marshal.GetFunctionPointerForDelegate(d126); delegates[126] = d126; - var d127 = new __embedGenericHandle(_embedGenericHandle); + var d127 = new __embedMethodHandle(_embedMethodHandle); callbacks[127] = Marshal.GetFunctionPointerForDelegate(d127); delegates[127] = d127; - var d128 = new __getLocationOfThisType(_getLocationOfThisType); + var d128 = new __embedFieldHandle(_embedFieldHandle); callbacks[128] = Marshal.GetFunctionPointerForDelegate(d128); delegates[128] = d128; - var d129 = new __getAddressOfPInvokeTarget(_getAddressOfPInvokeTarget); + var d129 = new __embedGenericHandle(_embedGenericHandle); callbacks[129] = Marshal.GetFunctionPointerForDelegate(d129); delegates[129] = d129; - var d130 = new __GetCookieForPInvokeCalliSig(_GetCookieForPInvokeCalliSig); + var d130 = new __getLocationOfThisType(_getLocationOfThisType); callbacks[130] = Marshal.GetFunctionPointerForDelegate(d130); delegates[130] = d130; - var d131 = new __canGetCookieForPInvokeCalliSig(_canGetCookieForPInvokeCalliSig); + var d131 = new __getAddressOfPInvokeTarget(_getAddressOfPInvokeTarget); callbacks[131] = Marshal.GetFunctionPointerForDelegate(d131); delegates[131] = d131; - var d132 = new __getJustMyCodeHandle(_getJustMyCodeHandle); + var d132 = new __GetCookieForPInvokeCalliSig(_GetCookieForPInvokeCalliSig); callbacks[132] = Marshal.GetFunctionPointerForDelegate(d132); delegates[132] = d132; - var d133 = new __GetProfilingHandle(_GetProfilingHandle); + var d133 = new __canGetCookieForPInvokeCalliSig(_canGetCookieForPInvokeCalliSig); callbacks[133] = Marshal.GetFunctionPointerForDelegate(d133); delegates[133] = d133; - var d134 = new __getCallInfo(_getCallInfo); + var d134 = new __getJustMyCodeHandle(_getJustMyCodeHandle); callbacks[134] = Marshal.GetFunctionPointerForDelegate(d134); delegates[134] = d134; - var d135 = new __canAccessFamily(_canAccessFamily); + var d135 = new __GetProfilingHandle(_GetProfilingHandle); callbacks[135] = Marshal.GetFunctionPointerForDelegate(d135); delegates[135] = d135; - var d136 = new __isRIDClassDomainID(_isRIDClassDomainID); + var d136 = new __getCallInfo(_getCallInfo); callbacks[136] = Marshal.GetFunctionPointerForDelegate(d136); delegates[136] = d136; - var d137 = new __getClassDomainID(_getClassDomainID); + var d137 = new __canAccessFamily(_canAccessFamily); callbacks[137] = Marshal.GetFunctionPointerForDelegate(d137); delegates[137] = d137; - var d138 = new __getFieldAddress(_getFieldAddress); + var d138 = new __isRIDClassDomainID(_isRIDClassDomainID); callbacks[138] = Marshal.GetFunctionPointerForDelegate(d138); delegates[138] = d138; - var d139 = new __getStaticFieldCurrentClass(_getStaticFieldCurrentClass); + var d139 = new __getClassDomainID(_getClassDomainID); callbacks[139] = Marshal.GetFunctionPointerForDelegate(d139); delegates[139] = d139; - var d140 = new __getVarArgsHandle(_getVarArgsHandle); + var d140 = new __getFieldAddress(_getFieldAddress); callbacks[140] = Marshal.GetFunctionPointerForDelegate(d140); delegates[140] = d140; - var d141 = new __canGetVarArgsHandle(_canGetVarArgsHandle); + var d141 = new __getStaticFieldCurrentClass(_getStaticFieldCurrentClass); callbacks[141] = Marshal.GetFunctionPointerForDelegate(d141); delegates[141] = d141; - var d142 = new __constructStringLiteral(_constructStringLiteral); + var d142 = new __getVarArgsHandle(_getVarArgsHandle); callbacks[142] = Marshal.GetFunctionPointerForDelegate(d142); delegates[142] = d142; - var d143 = new __emptyStringLiteral(_emptyStringLiteral); + var d143 = new __canGetVarArgsHandle(_canGetVarArgsHandle); callbacks[143] = Marshal.GetFunctionPointerForDelegate(d143); delegates[143] = d143; - var d144 = new __getFieldThreadLocalStoreID(_getFieldThreadLocalStoreID); + var d144 = new __constructStringLiteral(_constructStringLiteral); callbacks[144] = Marshal.GetFunctionPointerForDelegate(d144); delegates[144] = d144; - var d145 = new __setOverride(_setOverride); + var d145 = new __emptyStringLiteral(_emptyStringLiteral); callbacks[145] = Marshal.GetFunctionPointerForDelegate(d145); delegates[145] = d145; - var d146 = new __addActiveDependency(_addActiveDependency); + var d146 = new __getFieldThreadLocalStoreID(_getFieldThreadLocalStoreID); callbacks[146] = Marshal.GetFunctionPointerForDelegate(d146); delegates[146] = d146; - var d147 = new __GetDelegateCtor(_GetDelegateCtor); + var d147 = new __setOverride(_setOverride); callbacks[147] = Marshal.GetFunctionPointerForDelegate(d147); delegates[147] = d147; - var d148 = new __MethodCompileComplete(_MethodCompileComplete); + var d148 = new __addActiveDependency(_addActiveDependency); callbacks[148] = Marshal.GetFunctionPointerForDelegate(d148); delegates[148] = d148; - var d149 = new __getTailCallCopyArgsThunk(_getTailCallCopyArgsThunk); + var d149 = new __GetDelegateCtor(_GetDelegateCtor); callbacks[149] = Marshal.GetFunctionPointerForDelegate(d149); - delegates[149] = d149; - var d150 = new __getTailCallHelpers(_getTailCallHelpers); - callbacks[150] = Marshal.GetFunctionPointerForDelegate(d150); - delegates[150] = d150; - var d151 = new __convertPInvokeCalliToCall(_convertPInvokeCalliToCall); - callbacks[151] = Marshal.GetFunctionPointerForDelegate(d151); - delegates[151] = d151; - var d152 = new __allocMem(_allocMem); - callbacks[152] = Marshal.GetFunctionPointerForDelegate(d152); - delegates[152] = d152; - var d153 = new __reserveUnwindInfo(_reserveUnwindInfo); - callbacks[153] = Marshal.GetFunctionPointerForDelegate(d153); - delegates[153] = d153; - var d154 = new __allocUnwindInfo(_allocUnwindInfo); - callbacks[154] = Marshal.GetFunctionPointerForDelegate(d154); - delegates[154] = d154; - var d155 = new __allocGCInfo(_allocGCInfo); - callbacks[155] = Marshal.GetFunctionPointerForDelegate(d155); - delegates[155] = d155; - var d156 = new __setEHcount(_setEHcount); - callbacks[156] = Marshal.GetFunctionPointerForDelegate(d156); - delegates[156] = d156; - var d157 = new __setEHinfo(_setEHinfo); - callbacks[157] = Marshal.GetFunctionPointerForDelegate(d157); - delegates[157] = d157; - var d158 = new __logMsg(_logMsg); - callbacks[158] = Marshal.GetFunctionPointerForDelegate(d158); - delegates[158] = d158; - var d159 = new __doAssert(_doAssert); - callbacks[159] = Marshal.GetFunctionPointerForDelegate(d159); - delegates[159] = d159; - var d160 = new __reportFatalError(_reportFatalError); - callbacks[160] = Marshal.GetFunctionPointerForDelegate(d160); - delegates[160] = d160; - var d161 = new __allocMethodBlockCounts(_allocMethodBlockCounts); - callbacks[161] = Marshal.GetFunctionPointerForDelegate(d161); - delegates[161] = d161; - var d162 = new __getMethodBlockCounts(_getMethodBlockCounts); - callbacks[162] = Marshal.GetFunctionPointerForDelegate(d162); - delegates[162] = d162; - var d163 = new __recordCallSite(_recordCallSite); - callbacks[163] = Marshal.GetFunctionPointerForDelegate(d163); - delegates[163] = d163; - var d164 = new __recordRelocation(_recordRelocation); - callbacks[164] = Marshal.GetFunctionPointerForDelegate(d164); - delegates[164] = d164; - var d165 = new __getRelocTypeHint(_getRelocTypeHint); - callbacks[165] = Marshal.GetFunctionPointerForDelegate(d165); - delegates[165] = d165; - var d166 = new __getExpectedTargetArchitecture(_getExpectedTargetArchitecture); - callbacks[166] = Marshal.GetFunctionPointerForDelegate(d166); - delegates[166] = d166; - var d167 = new __getJitFlags(_getJitFlags); - callbacks[167] = Marshal.GetFunctionPointerForDelegate(d167); - delegates[167] = d167; - - keepAlive = delegates; - return (IntPtr)callbacks; - } - } -} - diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs index a7e726481e0527..0335fc436bb300 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs @@ -2861,13 +2861,36 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) if (targetArchitecture == TargetArchitecture.ARM && !_compilation.TypeSystemContext.Target.IsWindows) flags.Set(CorJitFlag.CORJIT_FLAG_RELATIVE_CODE_RELOCS); - if ((targetArchitecture == TargetArchitecture.X86 - || targetArchitecture == TargetArchitecture.X64) + if (targetArchitecture == TargetArchitecture.X86) + { + flags.Set(InstructionSet.X86_SSE); + flags.Set(InstructionSet.X86_SSE2); +#if !READYTORUN + // This list needs to match the list of intrinsics we can generate detection code for + // in HardwareIntrinsicHelpers.EmitIsSupportedIL. +#else + // For ReadyToRun, this list needs to match up with the behavior of FilterNamedIntrinsicMethodAttribs + // In particular, that this list of supported hardware will not generate non-SSE2 safe instruction + // sequences when paired with the behavior in FilterNamedIntrinsicMethodAttribs + if (isMethodDefinedInCoreLib()) +#endif + { + flags.Set(InstructionSet.X86_AES); + flags.Set(InstructionSet.X86_PCLMULQDQ); + flags.Set(InstructionSet.X86_SSE3); + flags.Set(InstructionSet.X86_SSSE3); + flags.Set(InstructionSet.X86_LZCNT); #if READYTORUN - && isMethodDefinedInCoreLib() + flags.Set(InstructionSet.X86_SSE41); + flags.Set(InstructionSet.X86_SSE42); + flags.Set(InstructionSet.X86_POPCNT); #endif - ) + } + } + else if (targetArchitecture == TargetArchitecture.X64) { + flags.Set(InstructionSet.X64_SSE); + flags.Set(InstructionSet.X64_SSE2); #if !READYTORUN // This list needs to match the list of intrinsics we can generate detection code for // in HardwareIntrinsicHelpers.EmitIsSupportedIL. @@ -2875,19 +2898,29 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) // For ReadyToRun, this list needs to match up with the behavior of FilterNamedIntrinsicMethodAttribs // In particular, that this list of supported hardware will not generate non-SSE2 safe instruction // sequences when paired with the behavior in FilterNamedIntrinsicMethodAttribs + if (isMethodDefinedInCoreLib()) #endif - flags.Set(CorJitFlag.CORJIT_FLAG_USE_AES); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_PCLMULQDQ); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSE3); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSSE3); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_LZCNT); + { + flags.Set(InstructionSet.X64_AES); + flags.Set(InstructionSet.X64_PCLMULQDQ); + flags.Set(InstructionSet.X64_SSE3); + flags.Set(InstructionSet.X64_SSSE3); + flags.Set(InstructionSet.X64_LZCNT); #if READYTORUN - flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSE41); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_SSE42); - flags.Set(CorJitFlag.CORJIT_FLAG_USE_POPCNT); + flags.Set(InstructionSet.X64_SSE41); + flags.Set(InstructionSet.X64_SSE42); + flags.Set(InstructionSet.X64_POPCNT); #endif + } + } + else if (targetArchitecture == TargetArchitecture.ARM64) + { + flags.Set(InstructionSet.ARM64_ArmBase); + flags.Set(InstructionSet.ARM64_AdvSimd); } + flags.Set64BitInstructionSetVariants(targetArchitecture); + if (this.MethodBeingCompiled.IsNativeCallable) { #if READYTORUN diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoInstructionSet.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoInstructionSet.cs new file mode 100644 index 00000000000000..470faeb0713baa --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoInstructionSet.cs @@ -0,0 +1,317 @@ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// FROM /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +// using /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Internal.TypeSystem; + +namespace Internal.JitInterface +{ + public enum InstructionSet + { + ILLEGAL = 0, + NONE = 63, + ARM64_ArmBase=1, + ARM64_ArmBase_Arm64=2, + ARM64_AdvSimd=3, + ARM64_AdvSimd_Arm64=4, + ARM64_Aes=5, + ARM64_Crc32=6, + ARM64_Crc32_Arm64=7, + ARM64_Sha1=8, + ARM64_Sha256=9, + ARM64_Atomics=10, + ARM64_Vector64=11, + ARM64_Vector128=12, + X64_SSE=1, + X64_SSE2=2, + X64_SSE3=3, + X64_SSSE3=4, + X64_SSE41=5, + X64_SSE42=6, + X64_AVX=7, + X64_AVX2=8, + X64_AES=9, + X64_BMI1=10, + X64_BMI2=11, + X64_FMA=12, + X64_LZCNT=13, + X64_PCLMULQDQ=14, + X64_POPCNT=15, + X64_Vector128=16, + X64_Vector256=17, + X64_BMI1_X64=18, + X64_BMI2_X64=19, + X64_LZCNT_X64=20, + X64_POPCNT_X64=21, + X64_SSE_X64=22, + X64_SSE2_X64=23, + X64_SSE41_X64=24, + X64_SSE42_X64=25, + X86_SSE=1, + X86_SSE2=2, + X86_SSE3=3, + X86_SSSE3=4, + X86_SSE41=5, + X86_SSE42=6, + X86_AVX=7, + X86_AVX2=8, + X86_AES=9, + X86_BMI1=10, + X86_BMI2=11, + X86_FMA=12, + X86_LZCNT=13, + X86_PCLMULQDQ=14, + X86_POPCNT=15, + X86_Vector128=16, + X86_Vector256=17, + X86_BMI1_X64=18, + X86_BMI2_X64=19, + X86_LZCNT_X64=20, + X86_POPCNT_X64=21, + X86_SSE_X64=22, + X86_SSE2_X64=23, + X86_SSE41_X64=24, + X86_SSE42_X64=25, + + } + + public struct InstructionSetFlags + { + ulong _flags; + + public void AddInstructionSet(InstructionSet instructionSet) + { + _flags = _flags | (((ulong)1) << (int)instructionSet); + } + + public void RemoveInstructionSet(InstructionSet instructionSet) + { + _flags = _flags & ~(((ulong)1) << (int)instructionSet); + } + + public bool HasInstructionSet(InstructionSet instructionSet) + { + return (_flags & (((ulong)1) << (int)instructionSet)) != 0; + } + + public bool Equals(InstructionSetFlags other) + { + return _flags == other._flags; + } + + public static InstructionSetFlags ExpandInstructionSetByImplication(TargetArchitecture architecture, InstructionSetFlags input) + { + InstructionSetFlags oldflags = input; + InstructionSetFlags resultflags = input; + do + { + oldflags = resultflags; + switch(architecture) + { + + case TargetArchitecture.ARM64: + if (resultflags.HasInstructionSet(InstructionSet.ARM64_ArmBase)) + resultflags.AddInstructionSet(InstructionSet.ARM64_ArmBase_Arm64); + if (resultflags.HasInstructionSet(InstructionSet.ARM64_AdvSimd)) + resultflags.AddInstructionSet(InstructionSet.ARM64_AdvSimd_Arm64); + if (resultflags.HasInstructionSet(InstructionSet.ARM64_Crc32)) + resultflags.AddInstructionSet(InstructionSet.ARM64_Crc32_Arm64); + if (resultflags.HasInstructionSet(InstructionSet.ARM64_AdvSimd)) + resultflags.AddInstructionSet(InstructionSet.ARM64_ArmBase); + if (resultflags.HasInstructionSet(InstructionSet.ARM64_Aes)) + resultflags.AddInstructionSet(InstructionSet.ARM64_ArmBase); + if (resultflags.HasInstructionSet(InstructionSet.ARM64_Crc32)) + resultflags.AddInstructionSet(InstructionSet.ARM64_ArmBase); + if (resultflags.HasInstructionSet(InstructionSet.ARM64_Sha1)) + resultflags.AddInstructionSet(InstructionSet.ARM64_ArmBase); + if (resultflags.HasInstructionSet(InstructionSet.ARM64_Sha256)) + resultflags.AddInstructionSet(InstructionSet.ARM64_ArmBase); + break; + + case TargetArchitecture.X64: + if (resultflags.HasInstructionSet(InstructionSet.X64_SSE)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE_X64); + if (resultflags.HasInstructionSet(InstructionSet.X64_SSE2)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE2_X64); + if (resultflags.HasInstructionSet(InstructionSet.X64_SSE41)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE41_X64); + if (resultflags.HasInstructionSet(InstructionSet.X64_SSE42)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE42_X64); + if (resultflags.HasInstructionSet(InstructionSet.X64_BMI1)) + resultflags.AddInstructionSet(InstructionSet.X64_BMI1_X64); + if (resultflags.HasInstructionSet(InstructionSet.X64_BMI2)) + resultflags.AddInstructionSet(InstructionSet.X64_BMI2_X64); + if (resultflags.HasInstructionSet(InstructionSet.X64_LZCNT)) + resultflags.AddInstructionSet(InstructionSet.X64_LZCNT_X64); + if (resultflags.HasInstructionSet(InstructionSet.X64_POPCNT)) + resultflags.AddInstructionSet(InstructionSet.X64_POPCNT_X64); + if (resultflags.HasInstructionSet(InstructionSet.X64_SSE2)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE); + if (resultflags.HasInstructionSet(InstructionSet.X64_SSE3)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE2); + if (resultflags.HasInstructionSet(InstructionSet.X64_SSSE3)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE3); + if (resultflags.HasInstructionSet(InstructionSet.X64_SSE41)) + resultflags.AddInstructionSet(InstructionSet.X64_SSSE3); + if (resultflags.HasInstructionSet(InstructionSet.X64_SSE42)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE41); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE42); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX2)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX); + if (resultflags.HasInstructionSet(InstructionSet.X64_AES)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE2); + if (resultflags.HasInstructionSet(InstructionSet.X64_BMI1)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX); + if (resultflags.HasInstructionSet(InstructionSet.X64_BMI2)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX); + if (resultflags.HasInstructionSet(InstructionSet.X64_FMA)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX); + if (resultflags.HasInstructionSet(InstructionSet.X64_PCLMULQDQ)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE2); + if (resultflags.HasInstructionSet(InstructionSet.X64_POPCNT)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE42); + break; + + case TargetArchitecture.X86: + if (resultflags.HasInstructionSet(InstructionSet.X86_SSE2)) + resultflags.AddInstructionSet(InstructionSet.X86_SSE); + if (resultflags.HasInstructionSet(InstructionSet.X86_SSE3)) + resultflags.AddInstructionSet(InstructionSet.X86_SSE2); + if (resultflags.HasInstructionSet(InstructionSet.X86_SSSE3)) + resultflags.AddInstructionSet(InstructionSet.X86_SSE3); + if (resultflags.HasInstructionSet(InstructionSet.X86_SSE41)) + resultflags.AddInstructionSet(InstructionSet.X86_SSSE3); + if (resultflags.HasInstructionSet(InstructionSet.X86_SSE42)) + resultflags.AddInstructionSet(InstructionSet.X86_SSE41); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX)) + resultflags.AddInstructionSet(InstructionSet.X86_SSE42); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX2)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX); + if (resultflags.HasInstructionSet(InstructionSet.X86_AES)) + resultflags.AddInstructionSet(InstructionSet.X86_SSE2); + if (resultflags.HasInstructionSet(InstructionSet.X86_BMI1)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX); + if (resultflags.HasInstructionSet(InstructionSet.X86_BMI2)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX); + if (resultflags.HasInstructionSet(InstructionSet.X86_FMA)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX); + if (resultflags.HasInstructionSet(InstructionSet.X86_PCLMULQDQ)) + resultflags.AddInstructionSet(InstructionSet.X86_SSE2); + if (resultflags.HasInstructionSet(InstructionSet.X86_POPCNT)) + resultflags.AddInstructionSet(InstructionSet.X86_SSE42); + break; + + } + } while (!oldflags.Equals(resultflags)); + return resultflags; + } + + public static IEnumerable> ArchitectureToValidInstructionSets(TargetArchitecture architecture) + { + switch (architecture) + { + + case TargetArchitecture.ARM64: + yield return new KeyValuePair("ArmBase", InstructionSet.ARM64_ArmBase); + yield return new KeyValuePair("AdvSimd", InstructionSet.ARM64_AdvSimd); + yield return new KeyValuePair("Aes", InstructionSet.ARM64_Aes); + yield return new KeyValuePair("Crc32", InstructionSet.ARM64_Crc32); + yield return new KeyValuePair("Sha1", InstructionSet.ARM64_Sha1); + yield return new KeyValuePair("Sha256", InstructionSet.ARM64_Sha256); + yield return new KeyValuePair("Atomics", InstructionSet.ARM64_Atomics); + yield return new KeyValuePair("Vector64", InstructionSet.ARM64_Vector64); + yield return new KeyValuePair("Vector128", InstructionSet.ARM64_Vector128); + break; + + case TargetArchitecture.X64: + yield return new KeyValuePair("Sse", InstructionSet.X64_SSE); + yield return new KeyValuePair("Sse2", InstructionSet.X64_SSE2); + yield return new KeyValuePair("Sse3", InstructionSet.X64_SSE3); + yield return new KeyValuePair("Ssse3", InstructionSet.X64_SSSE3); + yield return new KeyValuePair("Sse41", InstructionSet.X64_SSE41); + yield return new KeyValuePair("Sse42", InstructionSet.X64_SSE42); + yield return new KeyValuePair("Avx", InstructionSet.X64_AVX); + yield return new KeyValuePair("Avx2", InstructionSet.X64_AVX2); + yield return new KeyValuePair("Aes", InstructionSet.X64_AES); + yield return new KeyValuePair("Bmi1", InstructionSet.X64_BMI1); + yield return new KeyValuePair("Bmi2", InstructionSet.X64_BMI2); + yield return new KeyValuePair("Fma", InstructionSet.X64_FMA); + yield return new KeyValuePair("Lzcnt", InstructionSet.X64_LZCNT); + yield return new KeyValuePair("Pclmulqdq", InstructionSet.X64_PCLMULQDQ); + yield return new KeyValuePair("Popcnt", InstructionSet.X64_POPCNT); + yield return new KeyValuePair("Vector128", InstructionSet.X64_Vector128); + yield return new KeyValuePair("Vector256", InstructionSet.X64_Vector256); + break; + + case TargetArchitecture.X86: + yield return new KeyValuePair("Sse", InstructionSet.X86_SSE); + yield return new KeyValuePair("Sse2", InstructionSet.X86_SSE2); + yield return new KeyValuePair("Sse3", InstructionSet.X86_SSE3); + yield return new KeyValuePair("Ssse3", InstructionSet.X86_SSSE3); + yield return new KeyValuePair("Sse41", InstructionSet.X86_SSE41); + yield return new KeyValuePair("Sse42", InstructionSet.X86_SSE42); + yield return new KeyValuePair("Avx", InstructionSet.X86_AVX); + yield return new KeyValuePair("Avx2", InstructionSet.X86_AVX2); + yield return new KeyValuePair("Aes", InstructionSet.X86_AES); + yield return new KeyValuePair("Bmi1", InstructionSet.X86_BMI1); + yield return new KeyValuePair("Bmi2", InstructionSet.X86_BMI2); + yield return new KeyValuePair("Fma", InstructionSet.X86_FMA); + yield return new KeyValuePair("Lzcnt", InstructionSet.X86_LZCNT); + yield return new KeyValuePair("Pclmulqdq", InstructionSet.X86_PCLMULQDQ); + yield return new KeyValuePair("Popcnt", InstructionSet.X86_POPCNT); + yield return new KeyValuePair("Vector128", InstructionSet.X86_Vector128); + yield return new KeyValuePair("Vector256", InstructionSet.X86_Vector256); + break; + + } + } + + public void Set64BitInstructionSetVariants(TargetArchitecture architecture) + { + switch (architecture) + { + + case TargetArchitecture.ARM64: + if (HasInstructionSet(InstructionSet.ARM64_ArmBase)) + AddInstructionSet(InstructionSet.ARM64_ArmBase_Arm64); + if (HasInstructionSet(InstructionSet.ARM64_AdvSimd)) + AddInstructionSet(InstructionSet.ARM64_AdvSimd_Arm64); + if (HasInstructionSet(InstructionSet.ARM64_Crc32)) + AddInstructionSet(InstructionSet.ARM64_Crc32_Arm64); + break; + + case TargetArchitecture.X64: + if (HasInstructionSet(InstructionSet.X64_SSE)) + AddInstructionSet(InstructionSet.X64_SSE_X64); + if (HasInstructionSet(InstructionSet.X64_SSE2)) + AddInstructionSet(InstructionSet.X64_SSE2_X64); + if (HasInstructionSet(InstructionSet.X64_SSE41)) + AddInstructionSet(InstructionSet.X64_SSE41_X64); + if (HasInstructionSet(InstructionSet.X64_SSE42)) + AddInstructionSet(InstructionSet.X64_SSE42_X64); + if (HasInstructionSet(InstructionSet.X64_BMI1)) + AddInstructionSet(InstructionSet.X64_BMI1_X64); + if (HasInstructionSet(InstructionSet.X64_BMI2)) + AddInstructionSet(InstructionSet.X64_BMI2_X64); + if (HasInstructionSet(InstructionSet.X64_LZCNT)) + AddInstructionSet(InstructionSet.X64_LZCNT_X64); + if (HasInstructionSet(InstructionSet.X64_POPCNT)) + AddInstructionSet(InstructionSet.X64_POPCNT_X64); + break; + + case TargetArchitecture.X86: + break; + + } + } + } +} diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs index 75f793a3b6f374..fba8baa7c3c455 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; +using Internal.TypeSystem; namespace Internal.JitInterface { @@ -91,6 +92,10 @@ public struct CORINFO_JUST_MY_CODE_HANDLE_ public struct CORINFO_VarArgInfo { } + + public struct PatchpointInfo + { + } public enum _EXCEPTION_POINTERS { } @@ -778,6 +783,11 @@ public enum CorJitFuncKind CORJIT_FUNC_FILTER // a funclet associated with an EH filter } + public unsafe struct CORINFO_OSR_INFO + { + public uint ILOffset; + public void* PatchpointInfo; + } public unsafe struct CORINFO_METHOD_INFO { @@ -791,6 +801,7 @@ public unsafe struct CORINFO_METHOD_INFO public CorInfoRegionKind regionKind; public CORINFO_SIG_INFO args; public CORINFO_SIG_INFO locals; + public CORINFO_OSR_INFO osrInfo; } // // what type of code region we are in @@ -1311,9 +1322,6 @@ public enum CorJitFlag : uint CORJIT_FLAG_UNUSED4 = 11, CORJIT_FLAG_UNUSED5 = 12, CORJIT_FLAG_UNUSED6 = 13, - CORJIT_FLAG_USE_AVX = 14, - CORJIT_FLAG_USE_AVX2 = 15, - CORJIT_FLAG_USE_AVX_512 = 16, CORJIT_FLAG_FEATURE_SIMD = 17, CORJIT_FLAG_MAKEFINALCODE = 18, // Use the final code generator, i.e., not the interpreter. CORJIT_FLAG_READYTORUN = 19, // Use version-resilient code generation @@ -1340,49 +1348,12 @@ public enum CorJitFlag : uint CORJIT_FLAG_TIER1 = 40, // This is the final tier (for now) for tiered compilation which should generate high quality code CORJIT_FLAG_RELATIVE_CODE_RELOCS = 41, // JIT should generate PC-relative address computations instead of EE relocation records CORJIT_FLAG_NO_INLINING = 42, // JIT should not inline any called method into this method - -#region TARGET_ARM64 - CORJIT_FLAG_HAS_ARM64_AES = 43, // ID_AA64ISAR0_EL1.AES is 1 or better - CORJIT_FLAG_HAS_ARM64_ATOMICS = 44, // ID_AA64ISAR0_EL1.Atomic is 2 or better - CORJIT_FLAG_HAS_ARM64_CRC32 = 45, // ID_AA64ISAR0_EL1.CRC32 is 1 or better - CORJIT_FLAG_HAS_ARM64_DCPOP = 46, // ID_AA64ISAR1_EL1.DPB is 1 or better - CORJIT_FLAG_HAS_ARM64_DP = 47, // ID_AA64ISAR0_EL1.DP is 1 or better - CORJIT_FLAG_HAS_ARM64_FCMA = 48, // ID_AA64ISAR1_EL1.FCMA is 1 or better - CORJIT_FLAG_HAS_ARM64_FP = 49, // ID_AA64PFR0_EL1.FP is 0 or better - CORJIT_FLAG_HAS_ARM64_FP16 = 50, // ID_AA64PFR0_EL1.FP is 1 or better - CORJIT_FLAG_HAS_ARM64_JSCVT = 51, // ID_AA64ISAR1_EL1.JSCVT is 1 or better - CORJIT_FLAG_HAS_ARM64_LRCPC = 52, // ID_AA64ISAR1_EL1.LRCPC is 1 or better - CORJIT_FLAG_HAS_ARM64_PMULL = 53, // ID_AA64ISAR0_EL1.AES is 2 or better - CORJIT_FLAG_HAS_ARM64_SHA1 = 54, // ID_AA64ISAR0_EL1.SHA1 is 1 or better - CORJIT_FLAG_HAS_ARM64_SHA256 = 55, // ID_AA64ISAR0_EL1.SHA2 is 1 or better - CORJIT_FLAG_HAS_ARM64_SHA512 = 56, // ID_AA64ISAR0_EL1.SHA2 is 2 or better - CORJIT_FLAG_HAS_ARM64_SHA3 = 57, // ID_AA64ISAR0_EL1.SHA3 is 1 or better - CORJIT_FLAG_HAS_ARM64_SIMD = 58, // ID_AA64PFR0_EL1.AdvSIMD is 0 or better - CORJIT_FLAG_HAS_ARM64_SIMD_V81 = 59, // ID_AA64ISAR0_EL1.RDM is 1 or better - CORJIT_FLAG_HAS_ARM64_SIMD_FP16 = 60, // ID_AA64PFR0_EL1.AdvSIMD is 1 or better - CORJIT_FLAG_HAS_ARM64_SM3 = 61, // ID_AA64ISAR0_EL1.SM3 is 1 or better - CORJIT_FLAG_HAS_ARM64_SM4 = 62, // ID_AA64ISAR0_EL1.SM4 is 1 or better - CORJIT_FLAG_HAS_ARM64_SVE = 63, // ID_AA64PFR0_EL1.SVE is 1 or better -#endregion - -#region x86/x64 - CORJIT_FLAG_USE_SSE3 = 43, - CORJIT_FLAG_USE_SSSE3 = 44, - CORJIT_FLAG_USE_SSE41 = 45, - CORJIT_FLAG_USE_SSE42 = 46, - CORJIT_FLAG_USE_AES = 47, - CORJIT_FLAG_USE_BMI1 = 48, - CORJIT_FLAG_USE_BMI2 = 49, - CORJIT_FLAG_USE_FMA = 50, - CORJIT_FLAG_USE_LZCNT = 51, - CORJIT_FLAG_USE_PCLMULQDQ = 52, - CORJIT_FLAG_USE_POPCNT = 53, -#endregion } public struct CORJIT_FLAGS { private UInt64 _corJitFlags; + InstructionSetFlags _instructionSetFlags; public void Reset() { @@ -1394,6 +1365,11 @@ public void Set(CorJitFlag flag) _corJitFlags |= 1UL << (int)flag; } + public void Set(InstructionSet instructionSet) + { + _instructionSetFlags.AddInstructionSet(instructionSet); + } + public void Clear(CorJitFlag flag) { _corJitFlags &= ~(1UL << (int)flag); @@ -1404,19 +1380,9 @@ public bool IsSet(CorJitFlag flag) return (_corJitFlags & (1UL << (int)flag)) != 0; } - public void Add(ref CORJIT_FLAGS other) - { - _corJitFlags |= other._corJitFlags; - } - - public void Remove(ref CORJIT_FLAGS other) - { - _corJitFlags &= ~other._corJitFlags; - } - - public bool IsEmpty() + public void Set64BitInstructionSetVariants(TargetArchitecture architecture) { - return _corJitFlags == 0; + _instructionSetFlags.Set64BitInstructionSetVariants(architecture); } } } diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt new file mode 100644 index 00000000000000..9c8404fe8969f0 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt @@ -0,0 +1,81 @@ +; Define the set of instruction sets available on a platform +; Format is +; +; Add new instruction set +; instructionset,,,,, +; +; Add jit 64bit architecture specific instruction set when instruction set is available +; instructionset64bit,, +; +; Add an instruction set implication (i.e, if instruction set A is present, then instruction set B must be present too.) +; implication,,, +; +; Copy instruction sets defined for other architecture at this point in the file. +; copyinstructionsets,, + +; Definition of X86 instruction sets + +definearch ,X86 ,32Bit ,X64 +instructionset ,X86 ,Sse , ,1 ,SSE +instructionset ,X86 ,Sse2 , ,2 ,SSE2 +implication ,X86 ,SSE2 ,SSE +instructionset ,X86 ,Sse3 , ,3 ,SSE3 +implication ,X86 ,SSE3 ,SSE2 +instructionset ,X86 ,Ssse3 , ,4 ,SSSE3 +implication ,X86 ,SSSE3 ,SSE3 +instructionset ,X86 ,Sse41 , ,5 ,SSE41 +implication ,X86 ,SSE41 ,SSSE3 +instructionset ,X86 ,Sse42 , ,6 ,SSE42 +implication ,X86 ,SSE42 ,SSE41 +instructionset ,X86 ,Avx , ,7 ,AVX +implication ,X86 ,AVX ,SSE42 +instructionset ,X86 ,Avx2 , ,8 ,AVX2 +implication ,X86 ,AVX2 ,AVX +instructionset ,X86 ,Aes , ,9 ,AES +implication ,X86 ,AES ,SSE2 +instructionset ,X86 ,Bmi1 , ,10 ,BMI1 +implication ,X86 ,BMI1 ,AVX +instructionset ,X86 ,Bmi2 , ,11 ,BMI2 +implication ,X86 ,BMI2 ,AVX +instructionset ,X86 ,Fma , ,12 ,FMA +implication ,X86 ,FMA ,AVX +instructionset ,X86 ,Lzcnt , ,13 ,LZCNT +instructionset ,X86 ,Pclmulqdq , ,14 ,PCLMULQDQ +implication ,X86 ,PCLMULQDQ ,SSE2 +instructionset ,X86 ,Popcnt , ,15 ,POPCNT +implication ,X86 ,POPCNT ,SSE42 +instructionset ,X86 , , , ,Vector128 +instructionset ,X86 , , , ,Vector256 + +; Definition of X64 instruction sets (Define ) +definearch ,X64 ,64Bit ,X64 +instructionset64bit,X86 ,BMI1 +instructionset64bit,X86 ,BMI2 +instructionset64bit,X86 ,LZCNT +instructionset64bit,X86 ,POPCNT +instructionset64bit,X86 ,SSE +instructionset64bit,X86 ,SSE2 +instructionset64bit,X86 ,SSE41 +instructionset64bit,X86 ,SSE42 + +copyinstructionsets,X86 ,X64 + +; Definition of the Arm64 instruction sets +definearch ,ARM64 ,64Bit ,Arm64 +instructionset ,ARM64 ,ArmBase , ,16 ,ArmBase +instructionset64bit,ARM64 ,ArmBase +instructionset ,ARM64 ,AdvSimd , ,17 ,AdvSimd +instructionset64bit,ARM64 ,AdvSimd +implication ,ARM64 ,AdvSimd ,ArmBase +instructionset ,ARM64 ,Aes , ,9 ,Aes +implication ,ARM64 ,Aes ,ArmBase +instructionset ,ARM64 ,Crc32 , ,18 ,Crc32 +instructionset64bit,ARM64 ,Crc32 +implication ,ARM64 ,Crc32 ,ArmBase +instructionset ,ARM64 ,Sha1 , ,19 ,Sha1 +implication ,ARM64 ,Sha1 ,ArmBase +instructionset ,ARM64 ,Sha256 , ,20 ,Sha256 +implication ,ARM64 ,Sha256 ,ArmBase +instructionset ,ARM64 , ,Atomics ,21 ,Atomics +instructionset ,ARM64 , , , ,Vector64 +instructionset ,ARM64 , , , ,Vector128 diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetGenerator.cs b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetGenerator.cs new file mode 100644 index 00000000000000..3d5ea118732e30 --- /dev/null +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetGenerator.cs @@ -0,0 +1,645 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using System.Diagnostics; + +namespace Thunkerator +{ + public class InstructionSetGenerator + { + class InstructionSetInfo + { + public string Architecture { get; } + public string ManagedName { get; } + public string R2rName { get; } + public string R2rNumericValue { get; } + public string JitName { get; } + + public InstructionSetInfo(string architecture, string managedName, string r2rName, string r2rNumericValue, string jitName) + { + Architecture = architecture; + ManagedName = managedName; + R2rName = String.IsNullOrEmpty(r2rName) ? managedName : r2rName; + R2rNumericValue = r2rNumericValue; + JitName = jitName; + } + + public InstructionSetInfo(string architecture, InstructionSetInfo similarInstructionSet) + { + Architecture = architecture; + ManagedName = similarInstructionSet.ManagedName; + R2rName = similarInstructionSet.R2rName; + R2rNumericValue = similarInstructionSet.R2rNumericValue; + JitName = similarInstructionSet.JitName; + } + + public string PublicName + { + get + { + if (!String.IsNullOrEmpty(ManagedName)) + return ManagedName; + else if (!String.IsNullOrEmpty(R2rName)) + return R2rName; + else + return JitName; + } + } + } + + class InstructionSetImplication + { + public string Architecture { get; } + public string JitName { get; } + public string ImpliedJitName { get; } + + public InstructionSetImplication(string architecture, string jitName, string impliedJitName) + { + Architecture = architecture; + JitName = jitName; + ImpliedJitName = impliedJitName; + } + + public InstructionSetImplication(string architecture, InstructionSetImplication similarInstructionSet) + { + Architecture = architecture; + ImpliedJitName = similarInstructionSet.ImpliedJitName; + JitName = similarInstructionSet.JitName; + } + } + + List _instructionSets = new List(); + List _implications = new List(); + Dictionary> _64bitVariants = new Dictionary>(); + SortedDictionary _r2rNamesByName = new SortedDictionary(); + SortedDictionary _r2rNamesByNumber = new SortedDictionary(); + SortedSet _architectures = new SortedSet(); + Dictionary> _architectureJitNames = new Dictionary>(); + HashSet _64BitArchitectures = new HashSet(); + Dictionary _64BitVariantArchitectureJitNameSuffix = new Dictionary(); + + void ArchitectureEncountered(string arch) + { + if (!_64bitVariants.ContainsKey(arch)) + _64bitVariants.Add(arch, new HashSet()); + _architectures.Add(arch); + if (!_architectureJitNames.ContainsKey(arch)) + _architectureJitNames.Add(arch, new List()); + } + + void ValidateArchitectureEncountered(string arch) + { + if (!_architectures.Contains(arch)) + throw new Exception("Architecture not defined"); + } + + private string ArchToIfDefArch(string arch) + { + if (arch == "X64") + return "AMD64"; + return arch; + } + + + private string ArchToInstructionSetSuffixArch(string arch) + { + return _64BitVariantArchitectureJitNameSuffix[arch]; + } + + public bool ParseInput(TextReader tr) + { + int currentLineIndex = 1; + for (string currentLine = tr.ReadLine(); currentLine != null; currentLine = tr.ReadLine(), currentLineIndex++) + { + try + { + if (currentLine.Length == 0) + { + continue; // Its an empty line, ignore + } + + if (currentLine[0] == ';') + { + continue; // Its a comment + } + + string[] command = currentLine.Split(','); + for (int i = 0; i < command.Length; i++) + { + command[i] = command[i].Trim(); + } + switch(command[0]) + { + case "definearch": + if (command.Length != 4) + throw new Exception($"Incorrect number of args for definearch {command.Length}"); + ArchitectureEncountered(command[1]); + if (command[2] == "64Bit") + { + _64BitArchitectures.Add(command[1]); + } + else if (command[2] != "32Bit") + { + throw new Exception("Architecture must be 32Bit or 64Bit"); + } + _64BitVariantArchitectureJitNameSuffix[command[1]] = command[3]; + break; + case "instructionset": + if (command.Length != 6) + throw new Exception("Incorrect number of args for instructionset"); + ValidateArchitectureEncountered(command[1]); + _architectureJitNames[command[1]].Add(command[5]); + _instructionSets.Add(new InstructionSetInfo(command[1],command[2],command[3],command[4],command[5])); + break; + case "instructionset64bit": + if (command.Length != 3) + throw new Exception("Incorrect number of args for instructionset"); + ValidateArchitectureEncountered(command[1]); + _64bitVariants[command[1]].Add(command[2]); + _architectureJitNames[command[1]].Add(command[2] + "_" + ArchToInstructionSetSuffixArch(command[1])); + break; + case "implication": + if (command.Length != 4) + throw new Exception("Incorrect number of args for instructionset"); + ValidateArchitectureEncountered(command[1]); + _implications.Add(new InstructionSetImplication(command[1],command[2], command[3])); + break; + case "copyinstructionsets": + if (command.Length != 3) + throw new Exception("Incorrect number of args for instructionset"); + ValidateArchitectureEncountered(command[1]); + ValidateArchitectureEncountered(command[2]); + string arch = command[1]; + string targetarch = command[2]; + foreach (var val in _instructionSets.ToArray()) + { + if (val.Architecture != arch) + continue; + _instructionSets.Add(new InstructionSetInfo(targetarch, val)); + _architectureJitNames[targetarch].Add(val.JitName); + } + foreach (var val in _implications.ToArray()) + { + if (val.Architecture != arch) + continue; + _implications.Add(new InstructionSetImplication(targetarch, val)); + } + foreach (var val in _64bitVariants[arch]) + { + _64bitVariants[targetarch].Add(val); + _architectureJitNames[targetarch].Add(val + "_" + ArchToInstructionSetSuffixArch(targetarch)); + } + break; + default: + throw new Exception("Unknown command"); + } + } + catch (Exception e) + { + Console.Error.WriteLine("Error parsing line {0} : {1}", currentLineIndex, e.Message); + return false; + } + } + + foreach (var instructionSet in _instructionSets) + { + if (!String.IsNullOrEmpty(instructionSet.R2rName)) + { + int r2rValue = Int32.Parse(instructionSet.R2rNumericValue); + if (_r2rNamesByName.ContainsKey(instructionSet.R2rName)) + { + if (_r2rNamesByName[instructionSet.R2rName] != r2rValue) + throw new Exception("R2R name/number mismatch"); + } + else + { + _r2rNamesByName.Add(instructionSet.R2rName, r2rValue); + _r2rNamesByNumber.Add(r2rValue, instructionSet.R2rName); + } + } + } + + foreach (var architectureInfo in _architectureJitNames) + { + if (architectureInfo.Value.Count > 62) + { + throw new Exception("Too many instruction sets added. Scheme of using uint64_t as instruction mask will need updating"); + } + } + + return true; + } + + public void WriteManagedReadyToRunInstructionSet(TextWriter tr) + { + // Write header + tr.Write(@" +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// FROM /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +// using /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat + +using System; +using System.Runtime.InteropServices; +using Internal.TypeSystem; + +namespace Internal.ReadyToRunConstants +{ + public enum ReadyToRunInstructionSet + { +"); + + foreach (var r2rEntry in _r2rNamesByNumber) + { + tr.WriteLine($" {r2rEntry.Value}={r2rEntry.Key},"); + } + tr.Write(@" + } + + public static class ReadyToRunInstructionSetHelper + { + ReadyToRunInstructionSet? R2RInstructionSetFromJitInstructionSet(TargetArchitecture architecture, Internal.JitInterface.InstructionSet instructionSet) + { + switch (architecture) + { +"); + foreach (string architecture in _architectures) + { + tr.Write($@" + case TargetArchitecture.{architecture}: + {{ + switch (instructionSet) + {{ +"); + foreach (var instructionSet in _instructionSets) + { + if (instructionSet.Architecture != architecture) continue; + + string r2rEnumerationValue; + if (!String.IsNullOrEmpty(instructionSet.R2rName)) + r2rEnumerationValue = $"ReadyToRunInstructionSet.{instructionSet.R2rName}"; + else + r2rEnumerationValue = $"null"; + + tr.WriteLine($" case InstructionSet.{architecture}_{instructionSet.JitName}: return {r2rEnumerationValue};"); + if (_64BitArchitectures.Contains(architecture) && _64bitVariants[architecture].Contains(instructionSet.JitName)) + tr.WriteLine($" case InstructionSet.{architecture}_{instructionSet.JitName}_{ArchToInstructionSetSuffixArch(architecture)}: return {r2rEnumerationValue};"); + } + + tr.Write(@" + default: throw new Exception(""Unknown instruction set""); + } + } +"); + } + + tr.Write(@" + default: throw new Exception(""Unknown architecture""); + } + } + } +} +"); + } + + public void WriteManagedJitInstructionSet(TextWriter tr) + { + // Write header + tr.Write(@" +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// FROM /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +// using /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Internal.TypeSystem; + +namespace Internal.JitInterface +{ + public enum InstructionSet + { + ILLEGAL = 0, + NONE = 63, +"); + foreach (string architecture in _architectures) + { + int counter = 1; + foreach (var jitName in _architectureJitNames[architecture]) + { + tr.WriteLine($" {architecture}_{jitName}={counter++},"); + } + } + + tr.Write(@" + } + + public struct InstructionSetFlags + { + ulong _flags; + + public void AddInstructionSet(InstructionSet instructionSet) + { + _flags = _flags | (((ulong)1) << (int)instructionSet); + } + + public void RemoveInstructionSet(InstructionSet instructionSet) + { + _flags = _flags & ~(((ulong)1) << (int)instructionSet); + } + + public bool HasInstructionSet(InstructionSet instructionSet) + { + return (_flags & (((ulong)1) << (int)instructionSet)) != 0; + } + + public bool Equals(InstructionSetFlags other) + { + return _flags == other._flags; + } + + public static InstructionSetFlags ExpandInstructionSetByImplication(TargetArchitecture architecture, InstructionSetFlags input) + { + InstructionSetFlags oldflags = input; + InstructionSetFlags resultflags = input; + do + { + oldflags = resultflags; + switch(architecture) + { +"); + foreach (string architecture in _architectures) + { + tr.Write($@" + case TargetArchitecture.{architecture}: +"); + foreach (var instructionSet in _instructionSets) + { + if (instructionSet.Architecture != architecture) continue; + if (_64BitArchitectures.Contains(architecture) && _64bitVariants[architecture].Contains(instructionSet.JitName)) + AddImplication(architecture, instructionSet.JitName, $"{instructionSet.JitName}_{ArchToInstructionSetSuffixArch(architecture)}"); + } + foreach (var implication in _implications) + { + if (implication.Architecture != architecture) continue; + AddImplication(architecture, implication.JitName, implication.ImpliedJitName); + } + tr.WriteLine(" break;"); + } + + tr.Write(@" + } + } while (!oldflags.Equals(resultflags)); + return resultflags; + } + + public static IEnumerable> ArchitectureToValidInstructionSets(TargetArchitecture architecture) + { + switch (architecture) + { +"); + foreach (string architecture in _architectures) + { + tr.Write($@" + case TargetArchitecture.{architecture}: +"); + foreach (var instructionSet in _instructionSets) + { + if (instructionSet.Architecture != architecture) continue; + tr.WriteLine($" yield return new KeyValuePair(\"{instructionSet.PublicName}\", InstructionSet.{architecture}_{instructionSet.JitName});"); + } + tr.WriteLine(" break;"); + } + tr.Write(@" + } + } + + public void Set64BitInstructionSetVariants(TargetArchitecture architecture) + { + switch (architecture) + { +"); + foreach (string architecture in _architectures) + { + tr.Write($@" + case TargetArchitecture.{architecture}: +"); + foreach (var instructionSet in _instructionSets) + { + if (instructionSet.Architecture != architecture) continue; + + if (_64BitArchitectures.Contains(architecture) && _64bitVariants[architecture].Contains(instructionSet.JitName)) + { + tr.WriteLine($" if (HasInstructionSet(InstructionSet.{architecture}_{instructionSet.JitName}))"); + tr.WriteLine($" AddInstructionSet(InstructionSet.{architecture}_{instructionSet.JitName}_{ArchToInstructionSetSuffixArch(architecture)});"); + } + } + + tr.WriteLine(" break;"); + } + tr.Write(@" + } + } + } +} +"); + return; + void AddImplication(string architecture, string jitName, string impliedJitName) + { + tr.WriteLine($" if (resultflags.HasInstructionSet(InstructionSet.{architecture}_{jitName}))"); + tr.WriteLine($" resultflags.AddInstructionSet(InstructionSet.{architecture}_{impliedJitName});"); + } + } + + public void WriteNativeCorInfoInstructionSet(TextWriter tr) + { + // Write header + tr.Write(@" +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// FROM /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +// using /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat + +#ifndef CORINFOINSTRUCTIONSET_H +#define CORINFOINSTRUCTIONSET_H + +enum CORINFO_InstructionSet +{ + InstructionSet_ILLEGAL = 0, + InstructionSet_NONE = 63, +"); + foreach (string architecture in _architectures) + { + tr.WriteLine($"#ifdef TARGET_{ArchToIfDefArch(architecture)}"); + int counter = 1; + foreach (var jitName in _architectureJitNames[architecture]) + { + tr.WriteLine($" InstructionSet_{jitName}={counter++},"); + } + tr.WriteLine($"#endif // TARGET_{ArchToIfDefArch(architecture)}"); + } + tr.Write(@" +}; + +struct CORINFO_InstructionSetFlags +{ +private: + uint64_t _flags = 0; +public: + void AddInstructionSet(CORINFO_InstructionSet instructionSet) + { + _flags = _flags | (((uint64_t)1) << instructionSet); + } + + void RemoveInstructionSet(CORINFO_InstructionSet instructionSet) + { + _flags = _flags & ~(((uint64_t)1) << instructionSet); + } + + bool HasInstructionSet(CORINFO_InstructionSet instructionSet) const + { + return _flags & (((uint64_t)1) << instructionSet); + } + + bool Equals(CORINFO_InstructionSetFlags other) const + { + return _flags == other._flags; + } + + void Add(CORINFO_InstructionSetFlags other) + { + _flags |= other._flags; + } + + bool IsEmpty() const + { + return _flags == 0; + } + + void Reset() + { + _flags = 0; + } + + void Set64BitInstructionSetVariants() + { +"); + foreach (string architecture in _architectures) + { + tr.WriteLine($"#ifdef TARGET_{ArchToIfDefArch(architecture)}"); + foreach (var instructionSet in _instructionSets) + { + if (instructionSet.Architecture != architecture) continue; + + if (_64BitArchitectures.Contains(architecture) && _64bitVariants[architecture].Contains(instructionSet.JitName)) + { + tr.WriteLine($" if (HasInstructionSet(InstructionSet_{instructionSet.JitName}))"); + tr.WriteLine($" AddInstructionSet(InstructionSet_{instructionSet.JitName}_{ArchToInstructionSetSuffixArch(architecture)});"); + } + } + + tr.WriteLine($"#endif // TARGET_{ArchToIfDefArch(architecture)}"); + } + tr.Write(@" + } + + uint64_t GetFlagsRaw() + { + return _flags; + } + + void SetFromFlagsRaw(uint64_t flags) + { + _flags = flags; + } +}; + +inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_InstructionSetFlags input) +{ + CORINFO_InstructionSetFlags oldflags = input; + CORINFO_InstructionSetFlags resultflags = input; + do + { + oldflags = resultflags; +"); + foreach (string architecture in _architectures) + { + tr.WriteLine($"#ifdef TARGET_{ArchToIfDefArch(architecture)}"); + foreach (var instructionSet in _instructionSets) + { + if (instructionSet.Architecture != architecture) continue; + if (_64BitArchitectures.Contains(architecture) && _64bitVariants[architecture].Contains(instructionSet.JitName)) + AddImplication(architecture, instructionSet.JitName, $"{instructionSet.JitName}_{ArchToInstructionSetSuffixArch(architecture)}"); + } + foreach (var implication in _implications) + { + if (implication.Architecture != architecture) continue; + AddImplication(architecture, implication.JitName, implication.ImpliedJitName); + } + tr.WriteLine($"#endif // TARGET_{ArchToIfDefArch(architecture)}"); + } + tr.Write(@" + } while (!oldflags.Equals(resultflags)); + return resultflags; +} + + + +#endif // CORINFOINSTRUCTIONSET_H +"); + return; + + void AddImplication(string architecture, string jitName, string impliedJitName) + { + tr.WriteLine($" if (resultflags.HasInstructionSet(InstructionSet_{jitName}) && !resultflags.HasInstructionSet(InstructionSet_{impliedJitName}))"); + tr.WriteLine($" resultflags.RemoveInstructionSet(InstructionSet_{jitName});"); + } + } + + public void WriteNativeReadyToRunInstructionSet(TextWriter tr) + { + // Write header + tr.Write(@" +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// FROM /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +// using /src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat + +#ifndef READYTORUNINSTRUCTIONSET_H +#define READYTORUNINSTRUCTIONSET_H +enum ReadyToRunInstructionSet +{ +"); + + foreach (var r2rEntry in _r2rNamesByNumber) + { + tr.WriteLine($" READYTORUN_INSTRUCTION_{r2rEntry.Value}={r2rEntry.Key},"); + } + tr.Write(@" +}; + +#endif // READYTORUNINSTRUCTIONSET_H +"); + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/Program.cs b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/Program.cs index 78b513211cc4a0..94fa40662716d2 100644 --- a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/Program.cs +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/Program.cs @@ -493,16 +493,49 @@ class JitInterfaceWrapper static void Main(string[] args) { - IEnumerable functions = ParseInput(new StreamReader(args[0])); - using (TextWriter tw = new StreamWriter(args[1])) + if (args[0] == "InstructionSetGenerator") { - Console.WriteLine("Generating {0}", args[1]); - WriteManagedThunkInterface(tw, functions); + InstructionSetGenerator generator = new InstructionSetGenerator(); + if (!generator.ParseInput(new StreamReader(args[1]))) + return; + + using (TextWriter tw = new StreamWriter(args[2])) + { + Console.WriteLine("Generating {0}", args[2]); + generator.WriteManagedReadyToRunInstructionSet(tw); + } + + using (TextWriter tw = new StreamWriter(args[3])) + { + Console.WriteLine("Generating {0}", args[3]); + generator.WriteManagedJitInstructionSet(tw); + } + + using (TextWriter tw = new StreamWriter(args[4])) + { + Console.WriteLine("Generating {0}", args[4]); + generator.WriteNativeCorInfoInstructionSet(tw); + } + + using (TextWriter tw = new StreamWriter(args[5])) + { + Console.WriteLine("Generating {0}", args[5]); + generator.WriteNativeReadyToRunInstructionSet(tw); + } } - using (TextWriter tw = new StreamWriter(args[2])) + else { - Console.WriteLine("Generating {0}", args[2]); - WriteNativeWrapperInterface(tw, functions); + IEnumerable functions = ParseInput(new StreamReader(args[0])); + using (TextWriter tw = new StreamWriter(args[1])) + { + Console.WriteLine("Generating {0}", args[1]); + WriteManagedThunkInterface(tw, functions); + } + using (TextWriter tw = new StreamWriter(args[2])) + { + Console.WriteLine("Generating {0}", args[2]); + WriteNativeWrapperInterface(tw, functions); + } } } } diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 64ffbc793d1453..826aa55ffafbf8 100644 --- a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -96,6 +96,7 @@ CORINFO_GENERICHANDLE_RESULT*,ref CORINFO_GENERICHANDLE_RESULT,void* CORINFO_METHOD_INFO*,CORINFO_METHOD_INFO*,void* CORINFO_FIELD_INFO*,CORINFO_FIELD_INFO*,void* CORINFO_CALL_INFO*,CORINFO_CALL_INFO*,void* +PatchpointInfo*,PatchpointInfo*,void* DelegateCtorArgs*,ref DelegateCtorArgs,void* ICorDynamicInfo*,IntPtr,void* va_list,IntPtr @@ -186,6 +187,8 @@ FUNCTIONS void methodMustBeLoadedBeforeCodeIsRun( CORINFO_METHOD_HANDLE method ); CORINFO_METHOD_HANDLE mapMethodDeclToMethodImpl( CORINFO_METHOD_HANDLE method ); void getGSCookie( GSCookie * pCookieVal, GSCookie ** ppCookieVal ); + void setPatchpointInfo(PatchpointInfo* patchpointInfo); + PatchpointInfo* getOSRInfo(unsigned * ilOffset); void resolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken); void tryResolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken); void findSig( CORINFO_MODULE_HANDLE module, unsigned sigTOK, CORINFO_CONTEXT_HANDLE context, CORINFO_SIG_INFO *sig ); diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat index 46328b52d08baf..f90ce4554e37a8 100644 --- a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.bat @@ -1,2 +1,4 @@ -cd /d %~dp0 -dotnet run -- ThunkInput.txt ..\CorInfoBase.cs ..\..\..\crossgen2\jitinterface\jitinterface.h \ No newline at end of file +pushd %~dp0 +call ..\..\..\..\..\..\..\dotnet.cmd run -- ThunkInput.txt ..\CorInfoBase.cs ..\..\..\crossgen2\jitinterface\jitinterface.h +call ..\..\..\..\..\..\..\dotnet.cmd run -- InstructionSetGenerator InstructionSetDesc.txt ..\..\Internal\Runtime\ReadyToRunInstructionSet.cs ..\CorInfoInstructionSet.cs ..\..\..\..\inc\corinfoinstructionset.h ..\..\..\..\inc\readytoruninstructionset.h +popd \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.sh b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.sh index 59672c72d4156b..041e410ae98aa1 100755 --- a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.sh +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/gen.sh @@ -1,3 +1,4 @@ #!/usr/bin/env bash cd "$(dirname ${BASH_SOURCE[0]})" -dotnet run -- ThunkInput.txt ../CorInfoBase.cs ../../../crossgen2/jitinterface/jitinterface.h +../../../../../../../dotnet.sh run -- ThunkInput.txt ../CorInfoBase.cs ../../../crossgen2/jitinterface/jitinterface.h +../../../../../../../dotnet.sh run -- InstructionSetGenerator InstructionSetDesc.txt ../../Internal/Runtime/ReadyToRunInstructionSet.cs ../CorInfoInstructionSet.cs ../../../../inc/corinfoinstructionset.h ../../../../inc/readytoruninstructionset.h \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs index d27fbf6b4806a9..dbd21a08347675 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs @@ -419,7 +419,7 @@ private static void FindBaseUnificationGroup(MetadataType currentType, Unificati foreach (MethodDesc memberMethod in unificationGroup) { MethodDesc nameSigMatchMemberMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(memberMethod, currentType, reverseMethodSearch: true); - if (nameSigMatchMemberMethod != null) + if (nameSigMatchMemberMethod != null && nameSigMatchMemberMethod != memberMethod) { if (separatedMethods == null) separatedMethods = new MethodDescHashtable(); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs index 32cae03ba4016c..88abad8269ac0b 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs @@ -40,6 +40,11 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) EcmaModule targetModule = factory.SignatureContext.GetTargetModule(_fieldDesc); SignatureContext innerContext = dataBuilder.EmitFixup(factory, _fixupKind, targetModule, factory.SignatureContext); + if (_fixupKind == ReadyToRunFixupKind.Check_FieldOffset) + { + dataBuilder.EmitInt(_fieldDesc.Offset.AsInt); + } + dataBuilder.EmitFieldSignature(_fieldDesc, innerContext); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs index 735ada49e61917..30191aad4e9737 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs @@ -80,6 +80,14 @@ private void CreateNodeCaches() ); }); + _checkFieldOffsetCache = new NodeCache(key => + { + return new PrecodeHelperImport( + _codegenNodeFactory, + new FieldFixupSignature(ReadyToRunFixupKind.Check_FieldOffset, key) + ); + }); + _interfaceDispatchCells = new NodeCache(cellKey => { return new DelayLoadHelperMethodImport( @@ -376,6 +384,13 @@ public ISymbolNode FieldOffset(FieldDesc fieldDesc) return _fieldOffsetCache.GetOrAdd(fieldDesc); } + private NodeCache _checkFieldOffsetCache; + + public ISymbolNode CheckFieldOffset(FieldDesc fieldDesc) + { + return _checkFieldOffsetCache.GetOrAdd(fieldDesc); + } + private NodeCache _fieldBaseOffsetCache; public ISymbolNode FieldBaseOffset(TypeDesc typeDesc) diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index 03be7bab7e8ea0..77781f0ba76067 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -70,6 +70,17 @@ protected Compilation( public bool CanInline(MethodDesc caller, MethodDesc callee) { + if (JitConfigProvider.Instance.HasFlag(CorJitFlag.CORJIT_FLAG_DEBUG_CODE)) + { + // If the callee wants debuggable code, don't allow it to be inlined + return false; + } + + if (callee.IsNoInlining) + { + return false; + } + // Check to see if the method requires a security object. This means they call demand and // shouldn't be inlined. if (callee.RequireSecObject) @@ -77,6 +88,18 @@ public bool CanInline(MethodDesc caller, MethodDesc callee) return false; } + // If the method is MethodImpl'd by another method within the same type, then we have + // an issue that the importer will import the wrong body. In this case, we'll just + // disallow inlining because getFunctionEntryPoint will do the right thing. + if (callee.IsVirtual) + { + MethodDesc calleeMethodImpl = callee.OwningType.FindVirtualFunctionTargetMethodOnObjectType(callee); + if (calleeMethodImpl != callee) + { + return false; + } + } + return NodeFactory.CompilationModuleGroup.CanInline(caller, callee); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 9c416513431dd0..a1e95d8a19cdca 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -234,6 +234,9 @@ JitInterface\CorInfoTypes.cs + + JitInterface\CorInfoInstructionSet.cs + JitInterface\JitConfigProvider.cs diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 2e72b4c45fe6a9..08c0b884e5c859 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -2126,7 +2126,10 @@ private void EncodeFieldBaseOffset(FieldDesc field, CORINFO_FIELD_INFO* pResult, { if (pMT.IsValueType) { - throw new NotImplementedException("https://github.com/dotnet/runtime/issues/32630: ENCODE_CHECK_FIELD_OFFSET: root field check import"); + // ENCODE_CHECK_FIELD_OFFSET + pResult->offset = 0; + pResult->fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INSTANCE_WITH_BASE; + pResult->fieldLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); } else { @@ -2175,6 +2178,24 @@ private void getGSCookie(IntPtr* pCookieVal, IntPtr** ppCookieVal) *ppCookieVal = (IntPtr *)ObjectToHandle(_compilation.NodeFactory.GetReadyToRunHelperCell(ReadyToRunHelper.GSCookie)); } + /// + /// Record patchpoint info for the method + /// + private void setPatchpointInfo(PatchpointInfo* patchpointInfo) + { + // No patchpoint info when prejitting + throw new NotImplementedException(); + } + + /// + /// Retrieve OSR info for the method + /// + private PatchpointInfo* getOSRInfo(ref uint ilOffset) + { + // No patchpoint info when prejitting + throw new NotImplementedException(); + } + private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, ref bool isRelative) { throw new NotImplementedException("getMethodVTableOffset"); } private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_GENERICHANDLE_RESULT pResult) diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs index 944f8b288329bc..ac63ae303a1c09 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs @@ -620,6 +620,7 @@ public static PEHeaderBuilder Create(Characteristics imageCharacteristics, DllCh machine: target.MachineFromTarget(), sectionAlignment: sectionAlignment, fileAlignment: fileAlignment, + imageBase: imageBase, majorLinkerVersion: PEHeaderConstants.MajorLinkerVersion, minorLinkerVersion: PEHeaderConstants.MinorLinkerVersion, majorOperatingSystemVersion: PEHeaderConstants.MajorOperatingSystemVersion, diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs index 4f7c0dcd92cd12..fd60500cb9e3c9 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs @@ -386,7 +386,6 @@ private unsafe void Initialize(MetadataReader metadata) throw new BadImageFormatException("The file is not a ReadyToRun image"); } - Debug.Assert(!Composite); _assemblyCache.Add(metadata); DirectoryEntry r2rHeaderDirectory = PEReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory; diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs index e977f304fd11d9..b1425ba7637c3c 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs @@ -407,6 +407,23 @@ private SignatureDecoder(IAssemblyResolver options, MetadataReader metadataReade _contextReader = contextReader; } + /// + /// Construct the signature decoder by storing the image byte array and offset within the array. + /// This variant uses the outer global metadata reader + /// + /// Dump options and paths + /// Signature to parse + /// Signature offset within the signature byte array + /// Top-level signature context reader + private SignatureDecoder(IAssemblyResolver options, byte[] signature, int offset, ReadyToRunReader contextReader) + { + _metadataReader = contextReader.GetGlobalMetadataReader(); + _options = options; + _image = signature; + _offset = offset; + _contextReader = contextReader; + } + /// /// Read a single byte from the signature stream and advances the current offset. /// @@ -996,7 +1013,9 @@ private void ParseType(StringBuilder builder) break; case CorElementType.ELEMENT_TYPE_GENERICINST: - ParseGenericTypeInstance(builder); + SignatureDecoder outerTypeDecoder = new SignatureDecoder(_options, _image, _offset, _contextReader); + outerTypeDecoder.ParseGenericTypeInstance(builder); + _offset = outerTypeDecoder._offset; break; case CorElementType.ELEMENT_TYPE_TYPEDBYREF: diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj b/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj index f1e8aaece83e06..69357bba2b39a7 100644 --- a/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj +++ b/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj @@ -9,6 +9,7 @@ x64;x86 $(ArchGroup) false + true $(BinDir)/crossgen2 true false diff --git a/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h b/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h index 39703fa0028da3..ec3554f679cc65 100644 --- a/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h +++ b/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h @@ -35,6 +35,8 @@ struct JitInterfaceCallbacks void (* methodMustBeLoadedBeforeCodeIsRun)(void * thisHandle, CorInfoException** ppException, void* method); void* (* mapMethodDeclToMethodImpl)(void * thisHandle, CorInfoException** ppException, void* method); void (* getGSCookie)(void * thisHandle, CorInfoException** ppException, void* pCookieVal, void** ppCookieVal); + void (* setPatchpointInfo)(void * thisHandle, CorInfoException** ppException, void* patchpointInfo); + void* (* getOSRInfo)(void * thisHandle, CorInfoException** ppException, unsigned* ilOffset); void (* resolveToken)(void * thisHandle, CorInfoException** ppException, void* pResolvedToken); void (* tryResolveToken)(void * thisHandle, CorInfoException** ppException, void* pResolvedToken); void (* findSig)(void * thisHandle, CorInfoException** ppException, void* module, unsigned sigTOK, void* context, void* sig); @@ -408,6 +410,23 @@ class JitInterfaceWrapper throw pException; } + virtual void setPatchpointInfo(void* patchpointInfo) + { + CorInfoException* pException = nullptr; + _callbacks->setPatchpointInfo(_thisHandle, &pException, patchpointInfo); + if (pException != nullptr) + throw pException; + } + + virtual void* getOSRInfo(unsigned* ilOffset) + { + CorInfoException* pException = nullptr; + void* _ret = _callbacks->getOSRInfo(_thisHandle, &pException, ilOffset); + if (pException != nullptr) + throw pException; + return _ret; + } + virtual void resolveToken(void* pResolvedToken) { CorInfoException* pException = nullptr; diff --git a/src/coreclr/src/utilcode/ccomprc.cpp b/src/coreclr/src/utilcode/ccomprc.cpp index 421fbc8aacac50..4e2c9b97a5ed74 100644 --- a/src/coreclr/src/utilcode/ccomprc.cpp +++ b/src/coreclr/src/utilcode/ccomprc.cpp @@ -15,6 +15,7 @@ __attribute__((visibility("default"))) DECLARE_NATIVE_STRING_RESOURCE_TABLE(NATI #endif #include "sstring.h" #include "stringarraylist.h" +#include "corpriv.h" #include @@ -672,19 +673,21 @@ HRESULT CCompRC::LoadLibraryThrows(HRESOURCEDLL * pHInst) // The resources are embeded into the .exe itself for crossgen *pHInst = GetModuleInst(); #else + +#ifdef SELF_NO_HOST + _ASSERTE(!"CCompRC::LoadLibraryThrows not implemented for SELF_NO_HOST"); + hr = E_NOTIMPL; +#else PathString rcPath; // Path to resource DLL. // Try first in the same directory as this dll. - VALIDATECORECLRCALLBACKS(); - - - hr = g_CoreClrCallbacks.m_pfnGetCORSystemDirectory(rcPath); + hr = GetCORSystemDirectoryInternaL(rcPath); if (FAILED(hr)) return hr; hr = LoadLibraryHelper(pHInst, rcPath); - +#endif #endif // CROSSGEN_COMPILE diff --git a/src/coreclr/src/utilcode/clrhost.cpp b/src/coreclr/src/utilcode/clrhost.cpp index 090b533563ae3a..23d6eeaf904886 100644 --- a/src/coreclr/src/utilcode/clrhost.cpp +++ b/src/coreclr/src/utilcode/clrhost.cpp @@ -10,11 +10,10 @@ #include "clrhost.h" #include "utilcode.h" #include "ex.h" -#include "hostimpl.h" #include "clrnt.h" #include "contract.h" -CoreClrCallbacks g_CoreClrCallbacks; +HINSTANCE g_hmodCoreCLR; thread_local int t_CantAllocCount; @@ -114,38 +113,12 @@ HMODULE GetCLRModule () STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_SUPPORTS_DAC; // DAC can call in here since we initialize the SxS callbacks in ClrDataAccess::Initialize. -#ifdef DACCESS_COMPILE - // For DAC, "g_CoreClrCallbacks" is populated in InitUtilCode when the latter is invoked - // from ClrDataAccess::Initialize alongwith a reference to a structure allocated in the - // host-process address space. - // - // This function will be invoked in the host when DAC uses SEHException::GetHr that calls into - // IsComplusException, which calls into WasThrownByUs that calls GetCLRModule when EH SxS is enabled. - // However, this function can also be executed within the target space as well. - // - // Since DACCop gives the warning to DACize this global that, actually, would be used only - // in the respective address spaces and does not require marshalling, we need to ignore this - // warning. - DACCOP_IGNORE(UndacizedGlobalVariable, "g_CoreClrCallbacks has the dual mode DAC issue."); -#endif // DACCESS_COMPILE - VALIDATECORECLRCALLBACKS(); - - // This is the normal coreclr case - we return the module handle that was captured in our DllMain. -#ifdef DACCESS_COMPILE - // For DAC, "g_CoreClrCallbacks" is populated in InitUtilCode when the latter is invoked - // from ClrDataAccess::Initialize alongwith a reference to a structure allocated in the - // host-process address space. - // - // This function will be invoked in the host when DAC uses SEHException::GetHr that calls into - // IsComplusException, which calls into WasThrownByUs that calls GetCLRModule when EH SxS is enabled. - // However, this function can also be executed within the target space as well. - // - // Since DACCop gives the warning to DACize this global that, actually, would be used only - // in the respective address spaces and does not require marshalling, we need to ignore this - // warning. - DACCOP_IGNORE(UndacizedGlobalVariable, "g_CoreClrCallbacks has the dual mode DAC issue."); -#endif // DACCESS_COMPILE - return g_CoreClrCallbacks.m_hmodCoreCLR; + // You got here because the dll that included this copy of utilcode.lib. + // did not set g_hmodCoreCLR. The most likely cause is that you're running + // a dll (other than coreclr.dll) that links to utilcode.lib. + _ASSERTE(g_hmodCoreCLR != NULL); + + return g_hmodCoreCLR; } @@ -276,65 +249,3 @@ LoadsTypeHolder::~LoadsTypeHolder() } #endif //defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL) - - -//-------------------------------------------------------------------------- -// Side by side inproc support -// -// These are new abstractions designed to support loading multiple CLR -// versions in the same process. -//-------------------------------------------------------------------------- - - -//-------------------------------------------------------------------------- -// One-time initialized called by coreclr.dll in its dllmain. -//-------------------------------------------------------------------------- -VOID InitUtilcode(CoreClrCallbacks const & cccallbacks) -{ - //! WARNING: At the time this function is invoked, the C Runtime has NOT been fully initialized, let alone the CLR. - //! So don't put in a runtime contract and don't invoke other functions in the CLR (not even _ASSERTE!) - - LIMITED_METHOD_CONTRACT; - - g_CoreClrCallbacks = cccallbacks; -} - -CoreClrCallbacks const & GetClrCallbacks() -{ - LIMITED_METHOD_CONTRACT; - - VALIDATECORECLRCALLBACKS(); - return g_CoreClrCallbacks; -} - -#ifdef _DEBUG -void OnUninitializedCoreClrCallbacks() -{ - // Supports DAC since it can be called from GetCLRModule which supports DAC as well. - LIMITED_METHOD_DAC_CONTRACT; - - // If you got here, the most likely cause of the failure is that you're loading some DLL - // (other than coreclr.dll) that links to utilcode.lib, or that you're using a nohost - // variant of utilcode.lib but hitting code that assumes there is a CLR in the process. - // - // It is expected that coreclr.dll - // is the ONLY dll that links to utilcode libraries. - // - // If you must introduce a new dll that links to utilcode.lib, it is your responsibility - // to ensure that that dll invoke InitUtilcode() and forward it the right data from the *correct* - // loaded instance of coreclr. And you'll have to do without the CRT being initialized. - // - // Can't use an _ASSERTE here because even that's broken if we get to this point. - MessageBoxW(0, - W("g_CoreClrCallbacks not initialized."), - W("\n\n") - W("You got here because the dll that included this copy of utilcode.lib ") - W("did not call InitUtilcode() The most likely cause is that you're running ") - W("a dll (other than coreclr.dll) that links to utilcode.lib.") - , - 0); - _ASSERTE(FALSE); - DebugBreak(); -} -#endif // _DEBUG - diff --git a/src/coreclr/src/utilcode/clrhost_nodependencies.cpp b/src/coreclr/src/utilcode/clrhost_nodependencies.cpp index d531182b8a43ea..c8b5377ecfe0ad 100644 --- a/src/coreclr/src/utilcode/clrhost_nodependencies.cpp +++ b/src/coreclr/src/utilcode/clrhost_nodependencies.cpp @@ -10,7 +10,6 @@ #include "clrhost.h" #include "utilcode.h" #include "ex.h" -#include "hostimpl.h" #include "clrnt.h" #include "contract.h" @@ -92,53 +91,6 @@ void FreeClrDebugState(LPVOID pTlsData) #endif //_DEBUG } -// This is a drastic shutoff toggle that forces all new threads to fail their CLRInitDebugState calls. -// We only invoke this if FLS can't allocate its master block, preventing us from tracking the shutoff -// on a per-thread basis. -BYTE* GetGlobalContractShutoffFlag() -{ -#ifdef SELF_NO_HOST - - static BYTE gGlobalContractShutoffFlag = 0; - return &gGlobalContractShutoffFlag; -#else //!SELF_NO_HOST - HINSTANCE hmod = GetCLRModule(); - if (!hmod) - { - return NULL; - } - typedef BYTE*(__stdcall * PGETSHUTOFFADDRFUNC)(); - PGETSHUTOFFADDRFUNC pGetContractShutoffFlagFunc = (PGETSHUTOFFADDRFUNC)GetProcAddress(hmod, "GetAddrOfContractShutoffFlag"); - if (!pGetContractShutoffFlagFunc) - { - return NULL; - } - return pGetContractShutoffFlagFunc(); -#endif //!SELF_NO_HOST -} - -static BOOL AreContractsShutoff() -{ - BYTE *pShutoff = GetGlobalContractShutoffFlag(); - if (!pShutoff) - { - return FALSE; - } - else - { - return 0 != *pShutoff; - } -} - -static VOID ShutoffContracts() -{ - BYTE *pShutoff = GetGlobalContractShutoffFlag(); - if (pShutoff) - { - *pShutoff = 1; - } -} - //============================================================================================= // Used to initialize the per-thread ClrDebugState. This is called once per thread (with // possible exceptions for OOM scenarios.) @@ -160,41 +112,34 @@ ClrDebugState *CLRInitDebugState() ClrDebugState *pClrDebugState = NULL; DbgStateLockData *pNewLockData = NULL; - if (AreContractsShutoff()) - { - pNewClrDebugState = NULL; - } - else - { - // Yuck. We cannot call the hosted allocator for ClrDebugState (it is impossible to maintain a guarantee - // that none of code paths, many of them called conditionally, don't themselves trigger a ClrDebugState creation.) - // We have to call the OS directly for this. + // Yuck. We cannot call the hosted allocator for ClrDebugState (it is impossible to maintain a guarantee + // that none of code paths, many of them called conditionally, don't themselves trigger a ClrDebugState creation.) + // We have to call the OS directly for this. #undef HeapAlloc #undef GetProcessHeap - pNewClrDebugState = (ClrDebugState*)::HeapAlloc(GetProcessHeap(), 0, sizeof(ClrDebugState)); - if (pNewClrDebugState != NULL) - { - // Only allocate a DbgStateLockData if its owning ClrDebugState was successfully allocated - pNewLockData = (DbgStateLockData *)::HeapAlloc(GetProcessHeap(), 0, sizeof(DbgStateLockData)); - } + pNewClrDebugState = (ClrDebugState*)::HeapAlloc(GetProcessHeap(), 0, sizeof(ClrDebugState)); + if (pNewClrDebugState != NULL) + { + // Only allocate a DbgStateLockData if its owning ClrDebugState was successfully allocated + pNewLockData = (DbgStateLockData *)::HeapAlloc(GetProcessHeap(), 0, sizeof(DbgStateLockData)); + } #define GetProcessHeap() Dont_Use_GetProcessHeap() #define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes) - if ((pNewClrDebugState != NULL) && (pNewLockData != NULL)) - { - // Both allocations succeeded, so initialize the structures, and have - // pNewClrDebugState point to pNewLockData. If either of the allocations - // failed, we'll use gBadClrDebugState for this thread, and free whichever of - // pNewClrDebugState or pNewLockData actually did get allocated (if either did). - // (See code in this function below, outside this block.) - - pNewClrDebugState->SetStartingValues(); - pNewClrDebugState->ViolationMaskSet( CanFreeMe ); - _ASSERTE(!(pNewClrDebugState->ViolationMask() & BadDebugState)); - - pNewLockData->SetStartingValues(); - pNewClrDebugState->SetDbgStateLockData(pNewLockData); - } + if ((pNewClrDebugState != NULL) && (pNewLockData != NULL)) + { + // Both allocations succeeded, so initialize the structures, and have + // pNewClrDebugState point to pNewLockData. If either of the allocations + // failed, we'll use gBadClrDebugState for this thread, and free whichever of + // pNewClrDebugState or pNewLockData actually did get allocated (if either did). + // (See code in this function below, outside this block.) + + pNewClrDebugState->SetStartingValues(); + pNewClrDebugState->ViolationMaskSet( CanFreeMe ); + _ASSERTE(!(pNewClrDebugState->ViolationMask() & BadDebugState)); + + pNewLockData->SetStartingValues(); + pNewClrDebugState->SetDbgStateLockData(pNewLockData); } @@ -531,330 +476,3 @@ BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length) } #endif //_DEBUG - - - - -// Access various ExecutionEngine support services, like a logical TLS that abstracts -// fiber vs. thread issues. We obtain it from a DLL export via the shim. - -typedef IExecutionEngine * (__stdcall * IEE_FPTR) (); - -// -// Access various ExecutionEngine support services, like a logical TLS that abstracts -// fiber vs. thread issues. -// From an IExecutionEngine is possible to get other services via QueryInterfaces such -// as memory management -// -IExecutionEngine *g_pExecutionEngine = NULL; - -#ifdef SELF_NO_HOST -BYTE g_ExecutionEngineInstance[sizeof(UtilExecutionEngine)]; -#endif - - -IExecutionEngine *GetExecutionEngine() -{ - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_CANNOT_TAKE_LOCK; - SUPPORTS_DAC_HOST_ONLY; - - if (g_pExecutionEngine == NULL) - { - IExecutionEngine* pExecutionEngine; -#ifdef SELF_NO_HOST - // Create a local copy on the stack and then copy it over to the static instance. - // This avoids race conditions caused by multiple initializations of vtable in the constructor - UtilExecutionEngine local; - memcpy((void*)&g_ExecutionEngineInstance, (void*)&local, sizeof(UtilExecutionEngine)); - pExecutionEngine = (IExecutionEngine*)(UtilExecutionEngine*)&g_ExecutionEngineInstance; -#else - // statically linked. - VALIDATECORECLRCALLBACKS(); - pExecutionEngine = g_CoreClrCallbacks.m_pfnIEE(); -#endif // SELF_NO_HOST - - //We use an explicit memory barrier here so that the reference g_pExecutionEngine is valid when - //it is used, This ia a requirement on platforms with weak memory model . We cannot use VolatileStore - //because they are the same as normal assignment for DAC builds [see code:VOLATILE] - - MemoryBarrier(); - g_pExecutionEngine = pExecutionEngine; - } - - // It's a bug to ask for the ExecutionEngine interface in scenarios where the - // ExecutionEngine cannot be loaded. - _ASSERTE(g_pExecutionEngine); - return g_pExecutionEngine; -} // GetExecutionEngine - -IEEMemoryManager * GetEEMemoryManager() -{ - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_CANNOT_TAKE_LOCK; - SUPPORTS_DAC_HOST_ONLY; - - static IEEMemoryManager *pEEMemoryManager = NULL; - if (NULL == pEEMemoryManager) { - IExecutionEngine *pExecutionEngine = GetExecutionEngine(); - _ASSERTE(pExecutionEngine); - - // It is dangerous to pass a global pointer to QueryInterface. The pointer may be set - // to NULL in the call. Imagine that thread 1 calls QI, and get a pointer. But before thread 1 - // returns the pointer to caller, thread 2 calls QI and the pointer is set to NULL. - IEEMemoryManager *pEEMM; - pExecutionEngine->QueryInterface(IID_IEEMemoryManager, (void**)&pEEMM); - pEEMemoryManager = pEEMM; - } - // It's a bug to ask for the MemoryManager interface in scenarios where it cannot be loaded. - _ASSERTE(pEEMemoryManager); - return pEEMemoryManager; -} - -// should return some error code or exception -void SetExecutionEngine(IExecutionEngine *pExecutionEngine) -{ - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - - _ASSERTE(pExecutionEngine && !g_pExecutionEngine); - if (!g_pExecutionEngine) { - g_pExecutionEngine = pExecutionEngine; - g_pExecutionEngine->AddRef(); - } -} - -CRITSEC_COOKIE ClrCreateCriticalSection(CrstType crstType, CrstFlags flags) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->CreateLock(NULL, (LPCSTR)crstType, flags); -} - -HRESULT ClrDeleteCriticalSection(CRITSEC_COOKIE cookie) -{ - WRAPPER_NO_CONTRACT; - GetExecutionEngine()->DestroyLock(cookie); - return S_OK; -} - -void ClrEnterCriticalSection(CRITSEC_COOKIE cookie) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->AcquireLock(cookie); -} - -void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ReleaseLock(cookie); -} - -EVENT_COOKIE ClrCreateAutoEvent(BOOL bInitialState) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->CreateAutoEvent(bInitialState); -} - -EVENT_COOKIE ClrCreateManualEvent(BOOL bInitialState) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->CreateManualEvent(bInitialState); -} - -void ClrCloseEvent(EVENT_COOKIE event) -{ - WRAPPER_NO_CONTRACT; - - GetExecutionEngine()->CloseEvent(event); -} - -BOOL ClrSetEvent(EVENT_COOKIE event) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ClrSetEvent(event); -} - -BOOL ClrResetEvent(EVENT_COOKIE event) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ClrResetEvent(event); -} - -DWORD ClrWaitEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->WaitForEvent(event, dwMilliseconds, bAlertable); -} - -SEMAPHORE_COOKIE ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ClrCreateSemaphore(dwInitial, dwMax); -} - -void ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore) -{ - WRAPPER_NO_CONTRACT; - - GetExecutionEngine()->ClrCloseSemaphore(semaphore); -} - -BOOL ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ClrReleaseSemaphore(semaphore, lReleaseCount, lpPreviousCount); -} - -DWORD ClrWaitSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ClrWaitForSemaphore(semaphore, dwMilliseconds, bAlertable); -} - -MUTEX_COOKIE ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, - BOOL bInitialOwner, - LPCTSTR lpName) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ClrCreateMutex(lpMutexAttributes, bInitialOwner, lpName); -} - -void ClrCloseMutex(MUTEX_COOKIE mutex) -{ - WRAPPER_NO_CONTRACT; - - GetExecutionEngine()->ClrCloseMutex(mutex); -} - -BOOL ClrReleaseMutex(MUTEX_COOKIE mutex) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ClrReleaseMutex(mutex); -} - -DWORD ClrWaitForMutex(MUTEX_COOKIE mutex, DWORD dwMilliseconds, BOOL bAlertable) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ClrWaitForMutex(mutex, dwMilliseconds, bAlertable); -} - -DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable) -{ - WRAPPER_NO_CONTRACT; - - return GetExecutionEngine()->ClrSleepEx(dwMilliseconds, bAlertable); -} - -LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) -{ - WRAPPER_NO_CONTRACT; - - LPVOID result = GetEEMemoryManager()->ClrVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); - LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualAlloc (0x%p, 0x%06x, 0x%06x, 0x%02x) = 0x%p\n", lpAddress, dwSize, flAllocationType, flProtect, result)); - - return result; -} - -BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) -{ - WRAPPER_NO_CONTRACT; - - LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualFree (0x%p, 0x%06x, 0x%04x)\n", lpAddress, dwSize, dwFreeType)); - BOOL result = GetEEMemoryManager()->ClrVirtualFree(lpAddress, dwSize, dwFreeType); - - return result; -} - -SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) -{ - WRAPPER_NO_CONTRACT; - - LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualQuery (0x%p)\n", lpAddress)); - return GetEEMemoryManager()->ClrVirtualQuery(lpAddress, lpBuffer, dwLength); -} - -BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) -{ - WRAPPER_NO_CONTRACT; - - LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualProtect(0x%p, 0x%06x, 0x%02x)\n", lpAddress, dwSize, flNewProtect)); - return GetEEMemoryManager()->ClrVirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); -} - -HANDLE ClrGetProcessHeap() -{ - WRAPPER_NO_CONTRACT; - - return GetEEMemoryManager()->ClrGetProcessHeap(); -} - -HANDLE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize) -{ - WRAPPER_NO_CONTRACT; - - return GetEEMemoryManager()->ClrHeapCreate(flOptions, dwInitialSize, dwMaximumSize); -} - -BOOL ClrHeapDestroy(HANDLE hHeap) -{ - WRAPPER_NO_CONTRACT; - - return GetEEMemoryManager()->ClrHeapDestroy(hHeap); -} - -LPVOID ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, S_SIZE_T dwBytes) -{ - WRAPPER_NO_CONTRACT; - - if(dwBytes.IsOverflow()) return NULL; - - LPVOID result = GetEEMemoryManager()->ClrHeapAlloc(hHeap, dwFlags, dwBytes.Value()); - - return result; -} - -BOOL ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) -{ - WRAPPER_NO_CONTRACT; - - BOOL result = GetEEMemoryManager()->ClrHeapFree(hHeap, dwFlags, lpMem); - - return result; -} - -BOOL ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) -{ - WRAPPER_NO_CONTRACT; - - return GetEEMemoryManager()->ClrHeapValidate(hHeap, dwFlags, lpMem); -} - -HANDLE ClrGetProcessExecutableHeap() -{ - WRAPPER_NO_CONTRACT; - - return GetEEMemoryManager()->ClrGetProcessExecutableHeap(); -} - -void GetLastThrownObjectExceptionFromThread(void **ppvException) -{ - WRAPPER_NO_CONTRACT; - - GetExecutionEngine()->GetLastThrownObjectExceptionFromThread(ppvException); -} diff --git a/src/coreclr/src/utilcode/ex.cpp b/src/coreclr/src/utilcode/ex.cpp index d6690551a027c5..35bcd6c33652a3 100644 --- a/src/coreclr/src/utilcode/ex.cpp +++ b/src/coreclr/src/utilcode/ex.cpp @@ -30,7 +30,7 @@ GVAL_IMPL_INIT(HRESULT, g_hrFatalError, S_OK); // Helper function to get an exception object from outside the exception. In // the CLR, it may be from the Thread object. Non-CLR users have no thread object, // and it will do nothing. -void GetLastThrownObjectExceptionFromThread(void **ppvException); +void GetLastThrownObjectExceptionFromThread(Exception **ppException); Exception *Exception::g_OOMException = NULL; @@ -865,7 +865,7 @@ Exception* DelegatingException::GetDelegate() { // .. get it now. NULL in case there isn't one and we take default action. m_delegatedException = NULL; - GetLastThrownObjectExceptionFromThread(reinterpret_cast(&m_delegatedException)); + GetLastThrownObjectExceptionFromThread(&m_delegatedException); } return m_delegatedException; diff --git a/src/coreclr/src/utilcode/hostimpl.cpp b/src/coreclr/src/utilcode/hostimpl.cpp index 2354d18b8b74dc..6cfaf67c675790 100644 --- a/src/coreclr/src/utilcode/hostimpl.cpp +++ b/src/coreclr/src/utilcode/hostimpl.cpp @@ -2,237 +2,87 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// ==++== -// - -// -// - -// -// ==--== - #include "stdafx.h" #include "mscoree.h" #include "clrinternal.h" -#include "hostimpl.h" - -// to avoid to include clrhost.h in this file -#ifdef FAILPOINTS_ENABLED -extern int RFS_HashStack(); -#endif - -#ifdef SELF_NO_HOST -HANDLE (*g_fnGetExecutableHeapHandle)(); -#endif +#include "clrhost.h" +#include "ex.h" thread_local size_t t_ThreadType; -HRESULT STDMETHODCALLTYPE UtilExecutionEngine::QueryInterface(REFIID id, void **pInterface) -{ - if (!pInterface) - return E_POINTER; - - *pInterface = NULL; - - if (id == IID_IExecutionEngine) - *pInterface = (IExecutionEngine *)this; - else if (id == IID_IEEMemoryManager) - *pInterface = (IEEMemoryManager *)this; - else if (id == IID_IUnknown) - *pInterface = (IUnknown *)(IExecutionEngine *)this; - else - return E_NOINTERFACE; - - AddRef(); - return S_OK; -} // UtilExecutionEngine::QueryInterface - -// -// lifetime of this object is that of the app it lives in so no point in AddRef/Release -// -ULONG STDMETHODCALLTYPE UtilExecutionEngine::AddRef() -{ - return 1; -} - -ULONG STDMETHODCALLTYPE UtilExecutionEngine::Release() -{ - return 1; -} - -CRITSEC_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags) +CRITSEC_COOKIE ClrCreateCriticalSection(CrstType crstType, CrstFlags flags) { CRITICAL_SECTION *cs = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION)); InitializeCriticalSection(cs); return (CRITSEC_COOKIE)cs; } -void STDMETHODCALLTYPE UtilExecutionEngine::DestroyLock(CRITSEC_COOKIE lock) -{ - _ASSERTE(lock); - DeleteCriticalSection((CRITICAL_SECTION*)lock); - free(lock); -} - -void STDMETHODCALLTYPE UtilExecutionEngine::AcquireLock(CRITSEC_COOKIE lock) -{ - _ASSERTE(lock); - EnterCriticalSection((CRITICAL_SECTION*)lock); -} - -void STDMETHODCALLTYPE UtilExecutionEngine::ReleaseLock(CRITSEC_COOKIE lock) -{ - _ASSERTE(lock); - LeaveCriticalSection((CRITICAL_SECTION*)lock); -} - -EVENT_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateAutoEvent(BOOL bInitialState) -{ - HANDLE handle = WszCreateEvent(NULL, FALSE, bInitialState, NULL); - _ASSERTE(handle); - return (EVENT_COOKIE)handle; -} - -EVENT_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateManualEvent(BOOL bInitialState) -{ - HANDLE handle = WszCreateEvent(NULL, TRUE, bInitialState, NULL); - _ASSERTE(handle); - return (EVENT_COOKIE)handle; -} - -void STDMETHODCALLTYPE UtilExecutionEngine::CloseEvent(EVENT_COOKIE event) -{ - _ASSERTE(event); - CloseHandle((HANDLE)event); -} - -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrSetEvent(EVENT_COOKIE event) -{ - _ASSERTE(event); - return SetEvent((HANDLE)event); -} - -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrResetEvent(EVENT_COOKIE event) -{ - _ASSERTE(event); - return ResetEvent((HANDLE)event); -} - -DWORD STDMETHODCALLTYPE UtilExecutionEngine::WaitForEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable) -{ - _ASSERTE(event); - return WaitForSingleObjectEx((HANDLE)event, dwMilliseconds, bAlertable); -} - -DWORD STDMETHODCALLTYPE UtilExecutionEngine::WaitForSingleObject(HANDLE handle, DWORD dwMilliseconds) -{ - _ASSERTE(handle); - return WaitForSingleObjectEx(handle, dwMilliseconds, FALSE); -} - -SEMAPHORE_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax) -{ - HANDLE handle = WszCreateSemaphore(NULL, (LONG)dwInitial, (LONG)dwMax, NULL); - _ASSERTE(handle); - return (SEMAPHORE_COOKIE)handle; -} - -void STDMETHODCALLTYPE UtilExecutionEngine::ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore) -{ - _ASSERTE(semaphore); - CloseHandle((HANDLE)semaphore); -} - -DWORD STDMETHODCALLTYPE UtilExecutionEngine::ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable) -{ - _ASSERTE(semaphore); - return WaitForSingleObjectEx((HANDLE)semaphore, dwMilliseconds, bAlertable); -} - -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount) -{ - _ASSERTE(semaphore); - return ReleaseSemaphore((HANDLE)semaphore, lReleaseCount, lpPreviousCount); -} - -MUTEX_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, - BOOL bInitialOwner, - LPCTSTR lpName) -{ - return (MUTEX_COOKIE)WszCreateMutex(lpMutexAttributes,bInitialOwner,lpName); -} - -void STDMETHODCALLTYPE UtilExecutionEngine::ClrCloseMutex(MUTEX_COOKIE mutex) -{ - _ASSERTE(mutex); - CloseHandle((HANDLE)mutex); -} - -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrReleaseMutex(MUTEX_COOKIE mutex) +void ClrDeleteCriticalSection(CRITSEC_COOKIE cookie) { - _ASSERTE(mutex); - return ReleaseMutex((HANDLE)mutex); + _ASSERTE(cookie); + DeleteCriticalSection((CRITICAL_SECTION*)cookie); + free(cookie); } -DWORD STDMETHODCALLTYPE UtilExecutionEngine::ClrWaitForMutex(MUTEX_COOKIE mutex, - DWORD dwMilliseconds, - BOOL bAlertable) +void ClrEnterCriticalSection(CRITSEC_COOKIE cookie) { - _ASSERTE(mutex); - return WaitForSingleObjectEx ((HANDLE)mutex, dwMilliseconds, bAlertable); + _ASSERTE(cookie); + EnterCriticalSection((CRITICAL_SECTION*)cookie); } -DWORD STDMETHODCALLTYPE UtilExecutionEngine::ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable) +void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie) { - return SleepEx (dwMilliseconds, bAlertable); + _ASSERTE(cookie); + LeaveCriticalSection((CRITICAL_SECTION*)cookie); } -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrAllocationDisallowed() +DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable) { - return FALSE; + return SleepEx(dwMilliseconds, bAlertable); } -LPVOID STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) +LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) { #ifdef FAILPOINTS_ENABLED - if (RFS_HashStack ()) - return NULL; + if (RFS_HashStack ()) + return NULL; #endif return VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); } -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) +BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) { return VirtualFree(lpAddress, dwSize, dwFreeType); } -SIZE_T STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) +SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) { return VirtualQuery(lpAddress, lpBuffer, dwLength); } -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) +BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) { return VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); } -HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrGetProcessHeap() +#undef GetProcessHeap +HANDLE ClrGetProcessHeap() { return GetProcessHeap(); } +#define GetProcessHeap() Dont_Use_GetProcessHeap() -HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrGetProcessExecutableHeap() +HANDLE ClrGetProcessExecutableHeap() { #ifndef CROSSGEN_COMPILE - _ASSERTE(g_fnGetExecutableHeapHandle); - return (g_fnGetExecutableHeapHandle != NULL) ? g_fnGetExecutableHeapHandle() : NULL; + return NULL; #else - return GetProcessHeap(); + return ClrGetProcessHeap(); #endif } -HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize) +HANDLE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize) { #ifdef TARGET_UNIX return NULL; @@ -241,7 +91,7 @@ HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapCreate(DWORD flOptions, SIZ #endif } -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapDestroy(HANDLE hHeap) +BOOL ClrHeapDestroy(HANDLE hHeap) { #ifdef TARGET_UNIX return FALSE; @@ -250,43 +100,33 @@ BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapDestroy(HANDLE hHeap) #endif } -LPVOID STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) +#undef HeapAlloc +LPVOID ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, S_SIZE_T dwBytes) { + if (dwBytes.IsOverflow()) return NULL; + #ifdef FAILPOINTS_ENABLED - if (RFS_HashStack ()) - return NULL; + if (RFS_HashStack()) + return NULL; #endif - return HeapAlloc(hHeap, dwFlags, dwBytes); -} -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) -{ - return HeapFree(hHeap, dwFlags, lpMem); + return HeapAlloc(hHeap, dwFlags, dwBytes.Value()); } +#define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes) -BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) +#undef HeapFree +BOOL ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) { -#ifdef TARGET_UNIX - return FALSE; -#else - return HeapValidate(hHeap, dwFlags, lpMem); -#endif + return HeapFree(hHeap, dwFlags, lpMem); } - +#define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem) //------------------------------------------------------------------------------ // Helper function to get an exception from outside the exception. In // the CLR, it may be from the Thread object. Non-CLR users have no thread object, // and it will do nothing. -void UtilExecutionEngine::GetLastThrownObjectExceptionFromThread(void **ppvException) +void GetLastThrownObjectExceptionFromThread(Exception** ppException) { - // Declare class so we can declare Exception** - class Exception; - - // Cast to our real type. - Exception **ppException = reinterpret_cast(ppvException); - *ppException = NULL; -} // UtilExecutionEngine::GetLastThrownObjectExceptionFromThread - +} diff --git a/src/coreclr/src/utilcode/hostimpl.h b/src/coreclr/src/utilcode/hostimpl.h deleted file mode 100644 index 326a3ee1eb2950..00000000000000 --- a/src/coreclr/src/utilcode/hostimpl.h +++ /dev/null @@ -1,92 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// ==++== -// - -// -// - -// -// ==--== - -#ifndef __HOSTIMPL_H__ -#define __HOSTIMPL_H__ - -#ifdef SELF_NO_HOST -extern HANDLE g_ExecutableHeapHandle; -#endif - -// We have an internal class that is used to make sure the hosting api -// is forwarded to the os. This is a must for the shim because mscorwks -// which normally contains the implementation of the hosting api has not -// been loaded yet. In fact the shim is the one component responsible -// for that loading -class UtilExecutionEngine : public IExecutionEngine, public IEEMemoryManager -{ -private: - - //*************************************************************************** - // IUnknown methods - //*************************************************************************** - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, void **pInterface); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - - //*************************************************************************** - // IExecutionEngine methods for locking - //*************************************************************************** - - CRITSEC_COOKIE STDMETHODCALLTYPE CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags); - void STDMETHODCALLTYPE DestroyLock(CRITSEC_COOKIE lock); - void STDMETHODCALLTYPE AcquireLock(CRITSEC_COOKIE lock); - void STDMETHODCALLTYPE ReleaseLock(CRITSEC_COOKIE lock); - - EVENT_COOKIE STDMETHODCALLTYPE CreateAutoEvent(BOOL bInitialState); - EVENT_COOKIE STDMETHODCALLTYPE CreateManualEvent(BOOL bInitialState); - void STDMETHODCALLTYPE CloseEvent(EVENT_COOKIE event); - BOOL STDMETHODCALLTYPE ClrSetEvent(EVENT_COOKIE event); - BOOL STDMETHODCALLTYPE ClrResetEvent(EVENT_COOKIE event); - DWORD STDMETHODCALLTYPE WaitForEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable); - DWORD STDMETHODCALLTYPE WaitForSingleObject(HANDLE handle, DWORD dwMilliseconds); - - SEMAPHORE_COOKIE STDMETHODCALLTYPE ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax); - void STDMETHODCALLTYPE ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore); - DWORD STDMETHODCALLTYPE ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable); - BOOL STDMETHODCALLTYPE ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount); - - MUTEX_COOKIE STDMETHODCALLTYPE ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, - BOOL bInitialOwner, - LPCTSTR lpName); - void STDMETHODCALLTYPE ClrCloseMutex(MUTEX_COOKIE mutex); - BOOL STDMETHODCALLTYPE ClrReleaseMutex(MUTEX_COOKIE mutex); - DWORD STDMETHODCALLTYPE ClrWaitForMutex(MUTEX_COOKIE mutex, - DWORD dwMilliseconds, - BOOL bAlertable); - - DWORD STDMETHODCALLTYPE ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable); - - BOOL STDMETHODCALLTYPE ClrAllocationDisallowed(); - - void STDMETHODCALLTYPE GetLastThrownObjectExceptionFromThread(void **ppvException); - - //*************************************************************************** - // IEEMemoryManager methods for locking - //*************************************************************************** - LPVOID STDMETHODCALLTYPE ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - BOOL STDMETHODCALLTYPE ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); - SIZE_T STDMETHODCALLTYPE ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength); - BOOL STDMETHODCALLTYPE ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); - HANDLE STDMETHODCALLTYPE ClrGetProcessHeap(); - HANDLE STDMETHODCALLTYPE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); - BOOL STDMETHODCALLTYPE ClrHeapDestroy(HANDLE hHeap); - LPVOID STDMETHODCALLTYPE ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); - BOOL STDMETHODCALLTYPE ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); - BOOL STDMETHODCALLTYPE ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); - HANDLE STDMETHODCALLTYPE ClrGetProcessExecutableHeap(); - -}; // class UtilExecutionEngine - -#endif //__HOSTIMPL_H__ diff --git a/src/coreclr/src/utilcode/log.cpp b/src/coreclr/src/utilcode/log.cpp index b4907e325f8b5c..75097c574918cd 100644 --- a/src/coreclr/src/utilcode/log.cpp +++ b/src/coreclr/src/utilcode/log.cpp @@ -34,7 +34,7 @@ static DWORD LogFlags = 0; static CQuickWSTR szLogFileName; static HANDLE LogFileHandle = INVALID_HANDLE_VALUE; -static volatile MUTEX_COOKIE LogFileMutex = 0; +static volatile HANDLE LogFileMutex = 0; static DWORD LogFacilityMask = LF_ALL; static DWORD LogFacilityMask2 = 0; static DWORD LogVMLevel = LL_INFO100; @@ -160,7 +160,7 @@ VOID EnterLogLock() if(LogFileMutex != 0) { DWORD status; - status = ClrWaitForMutex(LogFileMutex, INFINITE, FALSE); + status = WaitForSingleObjectEx(LogFileMutex, INFINITE, FALSE); _ASSERTE(WAIT_OBJECT_0 == status); } } @@ -173,7 +173,7 @@ VOID LeaveLogLock() if(LogFileMutex != 0) { BOOL success; - success = ClrReleaseMutex(LogFileMutex); + success = ReleaseMutex(LogFileMutex); _ASSERTE(success); } } @@ -186,11 +186,11 @@ VOID InitializeLogging() if (bLoggingInitialized) return; - MUTEX_COOKIE mutexCookie = ClrCreateMutex(NULL, FALSE, NULL); - _ASSERTE(mutexCookie != 0); - if (InterlockedCompareExchangeT(&LogFileMutex, mutexCookie, 0) != 0) + HANDLE mutex = WszCreateMutex(NULL, FALSE, NULL); + _ASSERTE(mutex != 0); + if (InterlockedCompareExchangeT(&LogFileMutex, mutex, 0) != 0) { - ClrCloseMutex(mutexCookie); + CloseHandle(mutex); } EnterLogLock(); diff --git a/src/coreclr/src/utilcode/longfilepathwrappers.cpp b/src/coreclr/src/utilcode/longfilepathwrappers.cpp index 4a0bf3b86b424a..319685034c1a99 100644 --- a/src/coreclr/src/utilcode/longfilepathwrappers.cpp +++ b/src/coreclr/src/utilcode/longfilepathwrappers.cpp @@ -770,7 +770,7 @@ FindFirstFileExWrapper( #ifdef HOST_WINDOWS #if ! defined(DACCESS_COMPILE) && !defined(SELF_NO_HOST) -extern HINSTANCE g_pMSCorEE; +extern HINSTANCE g_hThisInst; #endif// ! defined(DACCESS_COMPILE) && !defined(SELF_NO_HOST) BOOL PAL_GetPALDirectoryWrapper(SString& pbuffer) @@ -783,7 +783,7 @@ BOOL PAL_GetPALDirectoryWrapper(SString& pbuffer) HINSTANCE hinst = NULL; #if ! defined(DACCESS_COMPILE) && !defined(SELF_NO_HOST) - hinst = g_pMSCorEE; + hinst = g_hThisInst; #endif// ! defined(DACCESS_COMPILE) && !defined(SELF_NO_HOST) #ifndef CROSSGEN_COMPILE diff --git a/src/coreclr/src/utilcode/utsem.cpp b/src/coreclr/src/utilcode/utsem.cpp index c5387d31755870..79c8b3abc6a23a 100644 --- a/src/coreclr/src/utilcode/utsem.cpp +++ b/src/coreclr/src/utilcode/utsem.cpp @@ -122,8 +122,8 @@ UTSemReadWrite::UTSemReadWrite() #endif //SELF_NO_HOST && !CROSSGEN_COMPILE m_dwFlag = 0; - m_pReadWaiterSemaphore = NULL; - m_pWriteWaiterEvent = NULL; + m_hReadWaiterSemaphore = NULL; + m_hWriteWaiterEvent = NULL; } @@ -143,11 +143,11 @@ UTSemReadWrite::~UTSemReadWrite() _ASSERTE_MSG((m_dwFlag == (ULONG)0), "Destroying a UTSemReadWrite while in use"); - if (m_pReadWaiterSemaphore != NULL) - delete m_pReadWaiterSemaphore; + if (m_hReadWaiterSemaphore != NULL) + CloseHandle(m_hReadWaiterSemaphore); - if (m_pWriteWaiterEvent != NULL) - delete m_pWriteWaiterEvent; + if (m_hWriteWaiterEvent != NULL) + CloseHandle(m_hWriteWaiterEvent); } //======================================================================================= @@ -164,30 +164,17 @@ UTSemReadWrite::Init() } CONTRACTL_END; - HRESULT hr = S_OK; - _ASSERTE(m_pReadWaiterSemaphore == NULL); - _ASSERTE(m_pWriteWaiterEvent == NULL); + _ASSERTE(m_hReadWaiterSemaphore == NULL); + _ASSERTE(m_hWriteWaiterEvent == NULL); - EX_TRY - { - CONTRACT_VIOLATION(ThrowsViolation); - - m_pReadWaiterSemaphore = new Semaphore(); - m_pReadWaiterSemaphore->Create(0, MAXLONG); + m_hReadWaiterSemaphore = WszCreateSemaphore(NULL, 0, MAXLONG, NULL); + IfNullRet(m_hReadWaiterSemaphore); - m_pWriteWaiterEvent = new Event(); - m_pWriteWaiterEvent->CreateAutoEvent(FALSE); - } - EX_CATCH - { - hr = E_OUTOFMEMORY; - } - EX_END_CATCH(SwallowAllExceptions) - IfFailGo(hr); + m_hWriteWaiterEvent = WszCreateEvent(NULL, FALSE, FALSE, NULL); + IfNullRet(m_hWriteWaiterEvent); -ErrExit: - return hr; + return S_OK; } // UTSemReadWrite::Init /****************************************************************************** @@ -266,7 +253,7 @@ HRESULT UTSemReadWrite::LockRead() { // Try to add waiting reader and then wait for signal if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, dwFlag + READWAITERS_INCR, dwFlag)) { - m_pReadWaiterSemaphore->Wait(INFINITE, FALSE); + WaitForSingleObjectEx(m_hReadWaiterSemaphore, INFINITE, FALSE); break; } } @@ -354,7 +341,7 @@ HRESULT UTSemReadWrite::LockWrite() { // Try to add waiting writer and then wait for signal if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, dwFlag + WRITEWAITERS_INCR, dwFlag)) { - m_pWriteWaiterEvent->Wait(INFINITE, FALSE); + WaitForSingleObjectEx(m_hWriteWaiterEvent, INFINITE, FALSE); break; } } @@ -425,7 +412,7 @@ void UTSemReadWrite::UnlockRead() dwFlag - READERS_INCR - WRITEWAITERS_INCR + WRITERS_INCR, dwFlag)) { - m_pWriteWaiterEvent->Set(); + SetEvent(m_hWriteWaiterEvent); break; } } @@ -478,7 +465,7 @@ void UTSemReadWrite::UnlockWrite() dwFlag - WRITERS_INCR - count * READWAITERS_INCR + count * READERS_INCR, dwFlag)) { - m_pReadWaiterSemaphore->Release(count, NULL); + ReleaseSemaphore(m_hReadWaiterSemaphore, count, NULL); break; } } @@ -489,7 +476,7 @@ void UTSemReadWrite::UnlockWrite() // (remove a writer (us), remove a write waiter, add a writer if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, dwFlag - WRITEWAITERS_INCR, dwFlag)) { - m_pWriteWaiterEvent->Set(); + SetEvent(m_hWriteWaiterEvent); break; } } diff --git a/src/coreclr/src/vm/CMakeLists.txt b/src/coreclr/src/vm/CMakeLists.txt index 93a4d21b76c3e8..1e8fd924f61334 100644 --- a/src/coreclr/src/vm/CMakeLists.txt +++ b/src/coreclr/src/vm/CMakeLists.txt @@ -100,6 +100,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON methodtable.cpp nativeimage.cpp object.cpp + onstackreplacement.cpp pefile.cpp peimage.cpp peimagelayout.cpp @@ -207,6 +208,7 @@ set(VM_HEADERS_DAC_AND_WKS_COMMON methodtable.inl object.h object.inl + onstackreplacement.h pefile.h pefile.inl peimage.h @@ -473,7 +475,6 @@ set(VM_HEADERS_WKS gcenv.ee.h gcenv.os.h gchelpers.h - hosting.h ibclogger.h ilmarshalers.h interopconverter.h diff --git a/src/coreclr/src/vm/ceemain.cpp b/src/coreclr/src/vm/ceemain.cpp index e32fe3171f60f8..5f7965e0a0abf5 100644 --- a/src/coreclr/src/vm/ceemain.cpp +++ b/src/coreclr/src/vm/ceemain.cpp @@ -660,6 +660,7 @@ void EEStartupHelper() CodeVersionManager::StaticInitialize(); TieredCompilationManager::StaticInitialize(); CallCountingManager::StaticInitialize(); + OnStackReplacementManager::StaticInitialize(); InitThreadManager(); STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "Returned successfully from InitThreadManager"); @@ -795,7 +796,7 @@ void EEStartupHelper() #ifndef TARGET_UNIX { // Record mscorwks geometry - PEDecoder pe(g_pMSCorEE); + PEDecoder pe(g_hThisInst); g_runtimeLoadedBaseAddress = (SIZE_T)pe.GetBase(); g_runtimeVirtualSize = (SIZE_T)pe.GetVirtualSize(); @@ -924,10 +925,12 @@ void EEStartupHelper() hr = g_pGCHeap->Initialize(); IfFailGo(hr); +#ifdef FEATURE_EVENT_TRACE // Finish setting up rest of EventPipe - specifically enable SampleProfiler if it was requested at startup. // SampleProfiler needs to cooperate with the GC which hasn't fully finished setting up in the first part of the // EventPipe initialization, so this is done after the GC has been fully initialized. EventPipe::FinishInitialize(); +#endif // This isn't done as part of InitializeGarbageCollector() above because thread // creation requires AppDomains to have been set up. @@ -1868,10 +1871,6 @@ BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error. // life of the DLL. GetSystemInfo(&g_SystemInfo); - // Remember module instance - g_pMSCorEE = pParam->hInst; - - // Set callbacks so that LoadStringRC knows which language our // threads are in so that it can return the proper localized string. // TODO: This shouldn't rely on the LCID (id), but only the name @@ -1948,7 +1947,7 @@ BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error. if (dwReason == DLL_THREAD_DETACH || dwReason == DLL_PROCESS_DETACH) { - CExecutionEngine::ThreadDetaching(); + ThreadDetaching(); } return TRUE; } diff --git a/src/coreclr/src/vm/ceemain.h b/src/coreclr/src/vm/ceemain.h index bd926f6e2b98ba..3201503a3b7366 100644 --- a/src/coreclr/src/vm/ceemain.h +++ b/src/coreclr/src/vm/ceemain.h @@ -40,98 +40,8 @@ enum ShutdownCompleteAction // Force shutdown of the EE void ForceEEShutdown(ShutdownCompleteAction sca = SCA_ExitProcessWhenShutdownComplete); -// Setup thread statics, including ClrDebugState and StressLog. -void SetupTLSForThread(Thread* pThread); - -// We have an internal class that can be used to expose EE functionality to other CLR -// DLLs, via the deliberately obscure IEE DLL exports from the shim and the EE -// NOTE: This class must not ever contain any instance variables. The reason for -// this is that the IEE function (corhost.cpp) relies on the fact that you -// may initialize the object more than once without ill effects. If you -// change this class so that this condition is violated, you must rewrite -// how the g_pCEE and related variables are initialized. -class CExecutionEngine : public IExecutionEngine, public IEEMemoryManager -{ - friend struct _DacGlobals; - - //*************************************************************************** - // public API: - //*************************************************************************** -public: - - // Notification of a DLL_THREAD_DETACH or a Thread Terminate. - static void ThreadDetaching(); - -private: - - //*************************************************************************** - // IUnknown methods - //*************************************************************************** - - HRESULT STDMETHODCALLTYPE QueryInterface( - REFIID id, - void **pInterface); - - ULONG STDMETHODCALLTYPE AddRef(); - - ULONG STDMETHODCALLTYPE Release(); - - //*************************************************************************** - // IExecutionEngine methods for locking - //*************************************************************************** - - CRITSEC_COOKIE STDMETHODCALLTYPE CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags); - - void STDMETHODCALLTYPE DestroyLock(CRITSEC_COOKIE lock); - - void STDMETHODCALLTYPE AcquireLock(CRITSEC_COOKIE lock); - - void STDMETHODCALLTYPE ReleaseLock(CRITSEC_COOKIE lock); - - EVENT_COOKIE STDMETHODCALLTYPE CreateAutoEvent(BOOL bInitialState); - EVENT_COOKIE STDMETHODCALLTYPE CreateManualEvent(BOOL bInitialState); - void STDMETHODCALLTYPE CloseEvent(EVENT_COOKIE event); - BOOL STDMETHODCALLTYPE ClrSetEvent(EVENT_COOKIE event); - BOOL STDMETHODCALLTYPE ClrResetEvent(EVENT_COOKIE event); - DWORD STDMETHODCALLTYPE WaitForEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable); - DWORD STDMETHODCALLTYPE WaitForSingleObject(HANDLE handle, DWORD dwMilliseconds); - - SEMAPHORE_COOKIE STDMETHODCALLTYPE ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax); - void STDMETHODCALLTYPE ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore); - DWORD STDMETHODCALLTYPE ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable); - BOOL STDMETHODCALLTYPE ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount); - - MUTEX_COOKIE STDMETHODCALLTYPE ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, - BOOL bInitialOwner, - LPCTSTR lpName); - void STDMETHODCALLTYPE ClrCloseMutex(MUTEX_COOKIE mutex); - BOOL STDMETHODCALLTYPE ClrReleaseMutex(MUTEX_COOKIE mutex); - DWORD STDMETHODCALLTYPE ClrWaitForMutex(MUTEX_COOKIE mutex, - DWORD dwMilliseconds, - BOOL bAlertable); - - DWORD STDMETHODCALLTYPE ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable); - - BOOL STDMETHODCALLTYPE ClrAllocationDisallowed(); - - void STDMETHODCALLTYPE GetLastThrownObjectExceptionFromThread(void **ppvException); - - //*************************************************************************** - // IEEMemoryManager methods for locking - //*************************************************************************** - LPVOID STDMETHODCALLTYPE ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - BOOL STDMETHODCALLTYPE ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); - SIZE_T STDMETHODCALLTYPE ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength); - BOOL STDMETHODCALLTYPE ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); - HANDLE STDMETHODCALLTYPE ClrGetProcessHeap(); - HANDLE STDMETHODCALLTYPE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); - BOOL STDMETHODCALLTYPE ClrHeapDestroy(HANDLE hHeap); - LPVOID STDMETHODCALLTYPE ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); - BOOL STDMETHODCALLTYPE ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); - BOOL STDMETHODCALLTYPE ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); - HANDLE STDMETHODCALLTYPE ClrGetProcessExecutableHeap(); - -}; +// Notification of a DLL_THREAD_DETACH or a Thread Terminate. +void ThreadDetaching(); void SetLatchedExitCode (INT32 code); INT32 GetLatchedExitCode (void); diff --git a/src/coreclr/src/vm/clrex.cpp b/src/coreclr/src/vm/clrex.cpp index 5ada2e67b41c65..5153f92dc68934 100644 --- a/src/coreclr/src/vm/clrex.cpp +++ b/src/coreclr/src/vm/clrex.cpp @@ -2489,7 +2489,7 @@ CLRLastThrownObjectException* CLRLastThrownObjectException::Validate() // Helper function to get an exception from outside the exception. // Create and return a LastThrownObjectException. Its virtual destructor // will clean up properly. -void GetLastThrownObjectExceptionFromThread_Internal(Exception **ppException) +void GetLastThrownObjectExceptionFromThread(Exception **ppException) { CONTRACTL { @@ -2511,7 +2511,7 @@ void GetLastThrownObjectExceptionFromThread_Internal(Exception **ppException) *ppException = NULL; } -} // void GetLastThrownObjectExceptionFromThread_Internal() +} // void GetLastThrownObjectExceptionFromThread() #endif // CROSSGEN_COMPILE diff --git a/src/coreclr/src/vm/clrex.h b/src/coreclr/src/vm/clrex.h index 34ca1c0823dd8c..16b32574f5a39f 100644 --- a/src/coreclr/src/vm/clrex.h +++ b/src/coreclr/src/vm/clrex.h @@ -195,7 +195,7 @@ class CLRException : public Exception }; // prototype for helper function to get exception object from thread's LastThrownObject. -void GetLastThrownObjectExceptionFromThread_Internal(Exception **ppException); +void GetLastThrownObjectExceptionFromThread(Exception **ppException); // --------------------------------------------------------------------------- diff --git a/src/coreclr/src/vm/codeman.cpp b/src/coreclr/src/vm/codeman.cpp index d3ca9d9c52d8a3..947bcf6eb6431f 100644 --- a/src/coreclr/src/vm/codeman.cpp +++ b/src/coreclr/src/vm/codeman.cpp @@ -1296,11 +1296,6 @@ void EEJitManager::SetCpuInfo() CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_CMOV); CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_FCOMI); } - - if (CPU_X86_USE_SSE2(cpuInfo.dwFeatures)) - { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE2); - } #endif // TARGET_X86 #if defined(TARGET_X86) || defined(TARGET_AMD64) @@ -1372,46 +1367,48 @@ void EEJitManager::SetCpuInfo() if ((buffer[15] & 0x06) == 0x06) // SSE & SSE2 { + CPUCompileFlags.Set(InstructionSet_SSE); + CPUCompileFlags.Set(InstructionSet_SSE2); if ((buffer[11] & 0x02) != 0) // AESNI { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_AES); + CPUCompileFlags.Set(InstructionSet_AES); } if ((buffer[8] & 0x02) != 0) // PCLMULQDQ { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_PCLMULQDQ); + CPUCompileFlags.Set(InstructionSet_PCLMULQDQ); } if ((buffer[8] & 0x01) != 0) // SSE3 { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE3); + CPUCompileFlags.Set(InstructionSet_SSE3); if ((buffer[9] & 0x02) != 0) // SSSE3 { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSSE3); + CPUCompileFlags.Set(InstructionSet_SSSE3); if ((buffer[10] & 0x08) != 0) // SSE4.1 { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE41); + CPUCompileFlags.Set(InstructionSet_SSE41); if ((buffer[10] & 0x10) != 0) // SSE4.2 { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE42); + CPUCompileFlags.Set(InstructionSet_SSE42); if ((buffer[10] & 0x80) != 0) // POPCNT { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_POPCNT); + CPUCompileFlags.Set(InstructionSet_POPCNT); } if ((buffer[11] & 0x18) == 0x18) // AVX & OSXSAVE { if(DoesOSSupportAVX() && (xmmYmmStateSupport() == 1)) { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX); + CPUCompileFlags.Set(InstructionSet_AVX); if ((buffer[9] & 0x10) != 0) // FMA { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_FMA); + CPUCompileFlags.Set(InstructionSet_FMA); } if (maxCpuId >= 0x07) @@ -1420,7 +1417,7 @@ void EEJitManager::SetCpuInfo() if ((buffer[4] & 0x20) != 0) // AVX2 { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX2); + CPUCompileFlags.Set(InstructionSet_AVX2); } } } @@ -1439,7 +1436,7 @@ void EEJitManager::SetCpuInfo() if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SIMD16ByteOnly) != 0) { - CPUCompileFlags.Clear(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX2); + CPUCompileFlags.Clear(InstructionSet_AVX2); } } @@ -1449,14 +1446,16 @@ void EEJitManager::SetCpuInfo() if ((buffer[4] & 0x08) != 0) // BMI1 { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_BMI1); + CPUCompileFlags.Set(InstructionSet_BMI1); } if ((buffer[5] & 0x01) != 0) // BMI2 { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_BMI2); + CPUCompileFlags.Set(InstructionSet_BMI2); } } + + CPUCompileFlags.EnsureValidInstructionSetSupport(); } DWORD maxCpuIdEx = getcpuid(0x80000000, buffer); @@ -1471,7 +1470,7 @@ void EEJitManager::SetCpuInfo() if ((buffer[8] & 0x20) != 0) // LZCNT { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_LZCNT); + CPUCompileFlags.Set(InstructionSet_LZCNT); } } #endif // defined(TARGET_X86) || defined(TARGET_AMD64) @@ -1486,23 +1485,25 @@ void EEJitManager::SetCpuInfo() PAL_GetJitCpuCapabilityFlags(&CPUCompileFlags); #elif defined(HOST_64BIT) // FP and SIMD support are enabled by default - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_ADVSIMD); - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_FP); + CPUCompileFlags.Set(InstructionSet_ArmBase); + CPUCompileFlags.Set(InstructionSet_AdvSimd); // PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE (30) if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)) { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_AES); - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA1); - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_SHA256); + CPUCompileFlags.Set(InstructionSet_Aes); + CPUCompileFlags.Set(InstructionSet_Sha1); + CPUCompileFlags.Set(InstructionSet_Sha256); } // PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE (31) if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)) { - CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_HAS_ARM64_CRC32); + CPUCompileFlags.Set(InstructionSet_Crc32); } #endif // HOST_64BIT #endif // TARGET_ARM64 + CPUCompileFlags.Set64BitInstructionSetVariants(); + m_CPUCompileFlags = CPUCompileFlags; } @@ -3581,12 +3582,20 @@ BOOL EEJitManager::GetBoundariesAndVars( if (pDebugInfo == NULL) return FALSE; +#ifdef FEATURE_ON_STACK_REPLACEMENT + BOOL hasFlagByte = TRUE; +#else + BOOL hasFlagByte = FALSE; +#endif + // Uncompress. This allocates memory and may throw. CompressDebugInfo::RestoreBoundariesAndVars( fpNew, pNewData, // allocators pDebugInfo, // input - pcMap, ppMap, - pcVars, ppVars); // output + pcMap, ppMap, // output + pcVars, ppVars, // output + hasFlagByte + ); return TRUE; } @@ -3608,9 +3617,15 @@ void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJ this->pRealCodeHeader.EnumMem(); #endif // USE_INDIRECT_CODEHEADER +#ifdef FEATURE_ON_STACK_REPLACEMENT + BOOL hasFlagByte = TRUE; +#else + BOOL hasFlagByte = FALSE; +#endif + if (this->GetDebugInfo() != NULL) { - CompressDebugInfo::EnumMemoryRegions(flags, this->GetDebugInfo()); + CompressDebugInfo::EnumMemoryRegions(flags, this->GetDebugInfo(), hasFlagByte); } } @@ -5521,8 +5536,9 @@ BOOL NativeImageJitManager::GetBoundariesAndVars( CompressDebugInfo::RestoreBoundariesAndVars( fpNew, pNewData, // allocators pDebugInfo, // input - pcMap, ppMap, - pcVars, ppVars); // output + pcMap, ppMap, // output + pcVars, ppVars, // output + FALSE); // no patchpoint info return TRUE; } @@ -6735,8 +6751,9 @@ BOOL ReadyToRunJitManager::GetBoundariesAndVars( CompressDebugInfo::RestoreBoundariesAndVars( fpNew, pNewData, // allocators pDebugInfo, // input - pcMap, ppMap, - pcVars, ppVars); // output + pcMap, ppMap, // output + pcVars, ppVars, // output + FALSE); // no patchpoint info return TRUE; } @@ -6760,7 +6777,7 @@ void ReadyToRunJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemory if (pDebugInfo == NULL) return; - CompressDebugInfo::EnumMemoryRegions(flags, pDebugInfo); + CompressDebugInfo::EnumMemoryRegions(flags, pDebugInfo, FALSE); } #endif diff --git a/src/coreclr/src/vm/codeman.h b/src/coreclr/src/vm/codeman.h index 433ae895bc63ce..38a475cbd9a596 100644 --- a/src/coreclr/src/vm/codeman.h +++ b/src/coreclr/src/vm/codeman.h @@ -262,6 +262,7 @@ typedef struct _hpCodeHdr { SUPPORTS_DAC; return pRealCodeHeader->phdrJitGCInfo; + } PTR_MethodDesc GetMethodDesc() { diff --git a/src/coreclr/src/vm/codeversion.cpp b/src/coreclr/src/vm/codeversion.cpp index af833fc2121ad1..6981e057986513 100644 --- a/src/coreclr/src/vm/codeversion.cpp +++ b/src/coreclr/src/vm/codeversion.cpp @@ -8,6 +8,7 @@ #include "common.h" #include "codeversion.h" +#include "patchpointinfo.h" #ifdef FEATURE_CODE_VERSIONING #include "threadsuspend.h" @@ -52,7 +53,9 @@ NativeCodeVersionNode::NativeCodeVersionNode( NativeCodeVersionId id, MethodDesc* pMethodDesc, ReJITID parentId, - NativeCodeVersion::OptimizationTier optimizationTier) + NativeCodeVersion::OptimizationTier optimizationTier, + PatchpointInfo* patchpointInfo, + unsigned ilOffset) : m_pNativeCode(NULL), m_pMethodDesc(pMethodDesc), @@ -64,6 +67,10 @@ NativeCodeVersionNode::NativeCodeVersionNode( #endif #ifdef HAVE_GCCOVER m_gcCover(PTR_NULL), +#endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + m_patchpointInfo(patchpointInfo), + m_ilOffset(ilOffset), #endif m_flags(0) {} @@ -153,6 +160,17 @@ void NativeCodeVersionNode::SetOptimizationTier(NativeCodeVersion::OptimizationT #endif // FEATURE_TIERED_COMPILATION +#ifdef FEATURE_ON_STACK_REPLACEMENT + +PatchpointInfo* NativeCodeVersionNode::GetOSRInfo(unsigned * ilOffset) +{ + LIMITED_METHOD_DAC_CONTRACT; + *ilOffset = m_ilOffset; + return m_patchpointInfo; +} + +#endif // FEATURE_ON_STACK_REPLACEMENT + #ifdef HAVE_GCCOVER PTR_GCCoverageInfo NativeCodeVersionNode::GetGCCoverageInfo() const @@ -334,6 +352,24 @@ void NativeCodeVersion::SetOptimizationTier(OptimizationTier tier) #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + +PatchpointInfo * NativeCodeVersion::GetOSRInfo(unsigned * ilOffset) +{ + LIMITED_METHOD_DAC_CONTRACT; + if (m_storageKind == StorageKind::Explicit) + { + return AsNode()->GetOSRInfo(ilOffset); + } + else + { + return NULL; + } +} + +#endif + + #ifdef HAVE_GCCOVER PTR_GCCoverageInfo NativeCodeVersion::GetGCCoverageInfo() const @@ -929,11 +965,14 @@ void ILCodeVersion::SetInstrumentedILMap(SIZE_T cMap, COR_IL_MAP * rgMap) HRESULT ILCodeVersion::AddNativeCodeVersion( MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, - NativeCodeVersion* pNativeCodeVersion) + NativeCodeVersion* pNativeCodeVersion, + PatchpointInfo* patchpointInfo, + unsigned ilOffset + ) { LIMITED_METHOD_CONTRACT; CodeVersionManager* pManager = GetModule()->GetCodeVersionManager(); - HRESULT hr = pManager->AddNativeCodeVersion(*this, pClosedMethodDesc, optimizationTier, pNativeCodeVersion); + HRESULT hr = pManager->AddNativeCodeVersion(*this, pClosedMethodDesc, optimizationTier, pNativeCodeVersion, patchpointInfo, ilOffset); if (FAILED(hr)) { _ASSERTE(hr == E_OUTOFMEMORY); @@ -1555,7 +1594,9 @@ HRESULT CodeVersionManager::AddNativeCodeVersion( ILCodeVersion ilCodeVersion, MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, - NativeCodeVersion* pNativeCodeVersion) + NativeCodeVersion* pNativeCodeVersion, + PatchpointInfo* patchpointInfo, + unsigned ilOffset) { LIMITED_METHOD_CONTRACT; _ASSERTE(IsLockOwnedByCurrentThread()); @@ -1569,7 +1610,7 @@ HRESULT CodeVersionManager::AddNativeCodeVersion( } NativeCodeVersionId newId = pMethodVersioningState->AllocateVersionId(); - NativeCodeVersionNode* pNativeCodeVersionNode = new (nothrow) NativeCodeVersionNode(newId, pClosedMethodDesc, ilCodeVersion.GetVersionId(), optimizationTier); + NativeCodeVersionNode* pNativeCodeVersionNode = new (nothrow) NativeCodeVersionNode(newId, pClosedMethodDesc, ilCodeVersion.GetVersionId(), optimizationTier, patchpointInfo, ilOffset); if (pNativeCodeVersionNode == NULL) { return E_OUTOFMEMORY; diff --git a/src/coreclr/src/vm/codeversion.h b/src/coreclr/src/vm/codeversion.h index 724d91a825246b..f318e2ec801598 100644 --- a/src/coreclr/src/vm/codeversion.h +++ b/src/coreclr/src/vm/codeversion.h @@ -37,6 +37,11 @@ class GCCoverageInfo; typedef DPTR(class GCCoverageInfo) PTR_GCCoverageInfo; #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT +struct PatchpointInfo; +typedef DPTR(struct PatchpointInfo) PTR_PatchpointInfo; +#endif + class NativeCodeVersion { #ifdef FEATURE_CODE_VERSIONING @@ -71,6 +76,7 @@ class NativeCodeVersion { OptimizationTier0, OptimizationTier1, + OptimizationTier1OSR, OptimizationTierOptimized, // may do less optimizations than tier 1 }; #ifdef FEATURE_TIERED_COMPILATION @@ -80,6 +86,10 @@ class NativeCodeVersion #endif #endif // FEATURE_TIERED_COMPILATION +#ifdef FEATURE_ON_STACK_REPLACEMENT + PatchpointInfo * GetOSRInfo(unsigned * iloffset); +#endif // FEATURE_ON_STACK_REPLACEMENT + #ifdef HAVE_GCCOVER PTR_GCCoverageInfo GetGCCoverageInfo() const; void SetGCCoverageInfo(PTR_GCCoverageInfo gcCover); @@ -165,7 +175,8 @@ class ILCodeVersion void SetIL(COR_ILMETHOD* pIL); void SetJitFlags(DWORD flags); void SetInstrumentedILMap(SIZE_T cMap, COR_IL_MAP * rgMap); - HRESULT AddNativeCodeVersion(MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, NativeCodeVersion* pNativeCodeVersion); + HRESULT AddNativeCodeVersion(MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, + NativeCodeVersion* pNativeCodeVersion, PatchpointInfo* patchpointInfo = NULL, unsigned ilOffset = 0); HRESULT GetOrCreateActiveNativeCodeVersion(MethodDesc* pClosedMethodDesc, NativeCodeVersion* pNativeCodeVersion); HRESULT SetActiveNativeCodeVersion(NativeCodeVersion activeNativeCodeVersion); #endif //DACCESS_COMPILE @@ -244,7 +255,8 @@ class NativeCodeVersionNode public: #ifndef DACCESS_COMPILE - NativeCodeVersionNode(NativeCodeVersionId id, MethodDesc* pMethod, ReJITID parentId, NativeCodeVersion::OptimizationTier optimizationTier); + NativeCodeVersionNode(NativeCodeVersionId id, MethodDesc* pMethod, ReJITID parentId, NativeCodeVersion::OptimizationTier optimizationTier, + PatchpointInfo* patchpointInfo, unsigned ilOffset); #endif PTR_MethodDesc GetMethodDesc() const; @@ -270,6 +282,10 @@ class NativeCodeVersionNode void SetGCCoverageInfo(PTR_GCCoverageInfo gcCover); #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + PatchpointInfo * GetOSRInfo(unsigned * ilOffset); +#endif + private: //union - could save a little memory? //{ @@ -286,6 +302,10 @@ class NativeCodeVersionNode #ifdef HAVE_GCCOVER PTR_GCCoverageInfo m_gcCover; #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + PTR_PatchpointInfo m_patchpointInfo; + unsigned m_ilOffset; +#endif enum NativeCodeVersionNodeFlags { @@ -569,7 +589,8 @@ class CodeVersionManager }; HRESULT AddILCodeVersion(Module* pModule, mdMethodDef methodDef, ReJITID rejitId, ILCodeVersion* pILCodeVersion); - HRESULT AddNativeCodeVersion(ILCodeVersion ilCodeVersion, MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, NativeCodeVersion* pNativeCodeVersion); + HRESULT AddNativeCodeVersion(ILCodeVersion ilCodeVersion, MethodDesc* pClosedMethodDesc, NativeCodeVersion::OptimizationTier optimizationTier, NativeCodeVersion* pNativeCodeVersion, + PatchpointInfo* patchpointInfo = NULL, unsigned ilOffset = 0); PCODE PublishVersionableCodeIfNecessary( MethodDesc* pMethodDesc, CallerGCMode callerGCMode, diff --git a/src/coreclr/src/vm/compile.cpp b/src/coreclr/src/vm/compile.cpp index c250d5b70d1a5c..cbd51fe0b1c0ec 100644 --- a/src/coreclr/src/vm/compile.cpp +++ b/src/coreclr/src/vm/compile.cpp @@ -1018,7 +1018,7 @@ void CEECompileInfo::CompressDebugInfo( { STANDARD_VM_CONTRACT; - CompressDebugInfo::CompressBoundariesAndVars(pOffsetMapping, iOffsetMapping, pNativeVarInfo, iNativeVarInfo, pDebugInfoBuffer, NULL); + CompressDebugInfo::CompressBoundariesAndVars(pOffsetMapping, iOffsetMapping, pNativeVarInfo, iNativeVarInfo, NULL, pDebugInfoBuffer, NULL); } ICorJitHost* CEECompileInfo::GetJitHost() diff --git a/src/coreclr/src/vm/comutilnative.cpp b/src/coreclr/src/vm/comutilnative.cpp index 7d0dea14da052c..1f0e257a548865 100644 --- a/src/coreclr/src/vm/comutilnative.cpp +++ b/src/coreclr/src/vm/comutilnative.cpp @@ -1047,7 +1047,7 @@ FCIMPLEND ** zeroingOptional -> whether caller prefers to skip clearing the content of the array, if possible. **Exceptions: IDS_EE_ARRAY_DIMENSIONS_EXCEEDED when size is too large. OOM if can't allocate. ==============================================================================*/ -FCIMPL3(Object*, GCInterface::AllocateNewArray, void* arrayTypeHandle, INT32 length, CLR_BOOL zeroingOptional) +FCIMPL3(Object*, GCInterface::AllocateNewArray, void* arrayTypeHandle, INT32 length, INT32 flags) { CONTRACTL { FCALL_CHECK; @@ -1058,7 +1058,10 @@ FCIMPL3(Object*, GCInterface::AllocateNewArray, void* arrayTypeHandle, INT32 len HELPER_METHOD_FRAME_BEGIN_RET_0(); - pRet = AllocateSzArray(arrayType, length, zeroingOptional ? GC_ALLOC_ZEROING_OPTIONAL : GC_ALLOC_NO_FLAGS); + //Only the following flags are used by GC.cs, so we'll just assert it here. + _ASSERTE((flags & ~(GC_ALLOC_ZEROING_OPTIONAL | GC_ALLOC_PINNED_OBJECT_HEAP)) == 0); + + pRet = AllocateSzArray(arrayType, length, (GC_ALLOC_FLAGS)flags); HELPER_METHOD_FRAME_END(); diff --git a/src/coreclr/src/vm/comutilnative.h b/src/coreclr/src/vm/comutilnative.h index 56030c4382a81b..4493ec271326f1 100644 --- a/src/coreclr/src/vm/comutilnative.h +++ b/src/coreclr/src/vm/comutilnative.h @@ -128,7 +128,7 @@ class GCInterface { static FCDECL0(INT64, GetAllocatedBytesForCurrentThread); static FCDECL1(INT64, GetTotalAllocatedBytes, CLR_BOOL precise); - static FCDECL3(Object*, AllocateNewArray, void* elementTypeHandle, INT32 length, CLR_BOOL zeroingOptional); + static FCDECL3(Object*, AllocateNewArray, void* elementTypeHandle, INT32 length, INT32 flags); #ifdef FEATURE_BASICFREEZE static diff --git a/src/coreclr/src/vm/corhost.cpp b/src/coreclr/src/vm/corhost.cpp index 08519c9fa92dce..763c82ddaa9db0 100644 --- a/src/coreclr/src/vm/corhost.cpp +++ b/src/coreclr/src/vm/corhost.cpp @@ -19,7 +19,6 @@ #include "eeconfig.h" #include "dbginterface.h" #include "ceemain.h" -#include "hosting.h" #include "eepolicy.h" #include "clrex.h" #include "comcallablewrapper.h" @@ -1176,77 +1175,7 @@ HRESULT CorHost2::GetCLRControl(ICLRControl** pCLRControl) return E_NOTIMPL; } -// This is the instance that exposes interfaces out to all the other DLLs of the CLR -// so they can use our services for TLS, synchronization, memory allocation, etc. -static BYTE g_CEEInstance[sizeof(CExecutionEngine)]; -static Volatile g_pCEE = NULL; - -extern "C" IExecutionEngine * __stdcall IEE() -{ - LIMITED_METHOD_CONTRACT; - - // Unfortunately,we can't probe here. The probing system requires the - // use of TLS, and in order to initialize TLS we need to call IEE. - - //BEGIN_ENTRYPOINT_VOIDRET; - - - // The following code does NOT contain a race condition. The following code is BY DESIGN. - // The issue is that we can have two separate threads inside this if statement, both of which are - // initializing the g_CEEInstance variable (and subsequently updating g_pCEE). This works fine, - // and will not cause an inconsistent state due to the fact that CExecutionEngine has no - // local variables. If multiple threads make it inside this if statement, it will copy the same - // bytes over g_CEEInstance and there will not be a time when there is an inconsistent state. - if ( !g_pCEE ) - { - // Create a local copy on the stack and then copy it over to the static instance. - // This avoids race conditions caused by multiple initializations of vtable in the constructor - CExecutionEngine local; - memcpy(&g_CEEInstance, (void*)&local, sizeof(CExecutionEngine)); - - g_pCEE = (IExecutionEngine*)(CExecutionEngine*)&g_CEEInstance; - } - //END_ENTRYPOINT_VOIDRET; - - return g_pCEE; -} - - -HRESULT STDMETHODCALLTYPE CExecutionEngine::QueryInterface(REFIID id, void **pInterface) -{ - LIMITED_METHOD_CONTRACT; - - if (!pInterface) - return E_POINTER; - - *pInterface = NULL; - - //CANNOTTHROWCOMPLUSEXCEPTION(); - if (id == IID_IExecutionEngine) - *pInterface = (IExecutionEngine *)this; - else if (id == IID_IEEMemoryManager) - *pInterface = (IEEMemoryManager *)this; - else if (id == IID_IUnknown) - *pInterface = (IUnknown *)(IExecutionEngine *)this; - else - return E_NOINTERFACE; - - AddRef(); - return S_OK; -} // HRESULT STDMETHODCALLTYPE CExecutionEngine::QueryInterface() - - -ULONG STDMETHODCALLTYPE CExecutionEngine::AddRef() -{ - LIMITED_METHOD_CONTRACT; - return 1; -} - -ULONG STDMETHODCALLTYPE CExecutionEngine::Release() -{ - LIMITED_METHOD_CONTRACT; - return 1; -} +/////////////////////////////////////////////////////////////////////////////// // Note: Sampling profilers also use this function to initialize TLS for a unmanaged // sampling thread so that initialization can be done in advance to avoid deadlocks. @@ -1270,10 +1199,7 @@ void SetupTLSForThread(Thread* pThread) #ifdef ENABLE_CONTRACTS // Profilers need the side effect of GetClrDebugState() to perform initialization // in advance to avoid deadlocks. Refer to ProfToEEInterfaceImpl::InitializeCurrentThread - ClrDebugState* pDebugState = ::GetClrDebugState(); - - if (pThread) - pThread->m_pClrDebugState = pDebugState; + ::GetClrDebugState(); #endif } @@ -1283,7 +1209,7 @@ void FreeClrDebugState(LPVOID pTlsData); #endif // Called here from a thread detach or from destruction of a Thread object. -void CExecutionEngine::ThreadDetaching() +void ThreadDetaching() { // Can not cause memory allocation during thread detach, so no real contracts. STATIC_CONTRACT_NOTHROW; @@ -1314,614 +1240,6 @@ void CExecutionEngine::ThreadDetaching() #endif // ENABLE_CONTRACTS_IMPL } -CRITSEC_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - ENTRY_POINT; - } - CONTRACTL_END; - - CRITSEC_COOKIE cookie = NULL; - BEGIN_ENTRYPOINT_VOIDRET; - cookie = ::EECreateCriticalSection(*(CrstType*)&level, flags); - END_ENTRYPOINT_VOIDRET; - return cookie; -} - -void STDMETHODCALLTYPE CExecutionEngine::DestroyLock(CRITSEC_COOKIE cookie) -{ - WRAPPER_NO_CONTRACT; - ::EEDeleteCriticalSection(cookie); -} - -void STDMETHODCALLTYPE CExecutionEngine::AcquireLock(CRITSEC_COOKIE cookie) -{ - WRAPPER_NO_CONTRACT; - ::EEEnterCriticalSection(cookie); -} - -void STDMETHODCALLTYPE CExecutionEngine::ReleaseLock(CRITSEC_COOKIE cookie) -{ - WRAPPER_NO_CONTRACT; - ::EELeaveCriticalSection(cookie); -} - -// Locking routines supplied by the EE to the other DLLs of the CLR. In a _DEBUG -// build of the EE, we poison the Crst as a poor man's attempt to do some argument -// validation. -#define POISON_BITS 3 - -static inline EVENT_COOKIE CLREventToCookie(CLREvent * pEvent) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE((((uintptr_t) pEvent) & POISON_BITS) == 0); -#ifdef _DEBUG - pEvent = (CLREvent *) (((uintptr_t) pEvent) | POISON_BITS); -#endif - return (EVENT_COOKIE) pEvent; -} - -static inline CLREvent *CookieToCLREvent(EVENT_COOKIE cookie) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS); -#ifdef _DEBUG - if (cookie) - { - cookie = (EVENT_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS); - } -#endif - return (CLREvent *) cookie; -} - - -EVENT_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateAutoEvent(BOOL bInitialState) -{ - CONTRACTL - { - THROWS; - MODE_ANY; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - EVENT_COOKIE event = NULL; - BEGIN_ENTRYPOINT_THROWS; - NewHolder pEvent(new CLREvent()); - pEvent->CreateAutoEvent(bInitialState); - event = CLREventToCookie(pEvent); - pEvent.SuppressRelease(); - END_ENTRYPOINT_THROWS; - - return event; -} - -EVENT_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateManualEvent(BOOL bInitialState) -{ - CONTRACTL - { - THROWS; - MODE_ANY; - GC_NOTRIGGER; - ENTRY_POINT; - } - CONTRACTL_END; - - EVENT_COOKIE event = NULL; - BEGIN_ENTRYPOINT_THROWS; - - NewHolder pEvent(new CLREvent()); - pEvent->CreateManualEvent(bInitialState); - event = CLREventToCookie(pEvent); - pEvent.SuppressRelease(); - - END_ENTRYPOINT_THROWS; - - return event; -} - -void STDMETHODCALLTYPE CExecutionEngine::CloseEvent(EVENT_COOKIE event) -{ - WRAPPER_NO_CONTRACT; - if (event) { - CLREvent *pEvent = CookieToCLREvent(event); - pEvent->CloseEvent(); - delete pEvent; - } -} - -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrSetEvent(EVENT_COOKIE event) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - if (event) { - CLREvent *pEvent = CookieToCLREvent(event); - return pEvent->Set(); - } - return FALSE; -} - -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrResetEvent(EVENT_COOKIE event) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - if (event) { - CLREvent *pEvent = CookieToCLREvent(event); - return pEvent->Reset(); - } - return FALSE; -} - -DWORD STDMETHODCALLTYPE CExecutionEngine::WaitForEvent(EVENT_COOKIE event, - DWORD dwMilliseconds, - BOOL bAlertable) -{ - WRAPPER_NO_CONTRACT; - if (event) { - CLREvent *pEvent = CookieToCLREvent(event); - return pEvent->Wait(dwMilliseconds,bAlertable); - } - - if (GetThread() && bAlertable) - ThrowHR(E_INVALIDARG); - return WAIT_FAILED; -} - -DWORD STDMETHODCALLTYPE CExecutionEngine::WaitForSingleObject(HANDLE handle, - DWORD dwMilliseconds) -{ - STATIC_CONTRACT_WRAPPER; - return ::WaitForSingleObject(handle,dwMilliseconds); -} - -static inline SEMAPHORE_COOKIE CLRSemaphoreToCookie(CLRSemaphore * pSemaphore) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE((((uintptr_t) pSemaphore) & POISON_BITS) == 0); -#ifdef _DEBUG - pSemaphore = (CLRSemaphore *) (((uintptr_t) pSemaphore) | POISON_BITS); -#endif - return (SEMAPHORE_COOKIE) pSemaphore; -} - -static inline CLRSemaphore *CookieToCLRSemaphore(SEMAPHORE_COOKIE cookie) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS); -#ifdef _DEBUG - if (cookie) - { - cookie = (SEMAPHORE_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS); - } -#endif - return (CLRSemaphore *) cookie; -} - - -SEMAPHORE_COOKIE STDMETHODCALLTYPE CExecutionEngine::ClrCreateSemaphore(DWORD dwInitial, - DWORD dwMax) -{ - CONTRACTL - { - THROWS; - MODE_ANY; - GC_NOTRIGGER; - } - CONTRACTL_END; - - NewHolder pSemaphore(new CLRSemaphore()); - pSemaphore->Create(dwInitial, dwMax); - SEMAPHORE_COOKIE ret = CLRSemaphoreToCookie(pSemaphore);; - pSemaphore.SuppressRelease(); - return ret; -} - -void STDMETHODCALLTYPE CExecutionEngine::ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore); - pSemaphore->Close(); - delete pSemaphore; -} - -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, - LONG lReleaseCount, - LONG *lpPreviousCount) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore); - return pSemaphore->Release(lReleaseCount,lpPreviousCount); -} - -DWORD STDMETHODCALLTYPE CExecutionEngine::ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore, - DWORD dwMilliseconds, - BOOL bAlertable) -{ - WRAPPER_NO_CONTRACT; - CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore); - return pSemaphore->Wait(dwMilliseconds,bAlertable); -} - -static inline MUTEX_COOKIE CLRMutexToCookie(CLRMutex * pMutex) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE((((uintptr_t) pMutex) & POISON_BITS) == 0); -#ifdef _DEBUG - pMutex = (CLRMutex *) (((uintptr_t) pMutex) | POISON_BITS); -#endif - return (MUTEX_COOKIE) pMutex; -} - -static inline CLRMutex *CookieToCLRMutex(MUTEX_COOKIE cookie) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS); -#ifdef _DEBUG - if (cookie) - { - cookie = (MUTEX_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS); - } -#endif - return (CLRMutex *) cookie; -} - - -MUTEX_COOKIE STDMETHODCALLTYPE CExecutionEngine::ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, - BOOL bInitialOwner, - LPCTSTR lpName) -{ - CONTRACTL - { - NOTHROW; - MODE_ANY; - GC_NOTRIGGER; - } - CONTRACTL_END; - - - MUTEX_COOKIE mutex = 0; - CLRMutex *pMutex = new (nothrow) CLRMutex(); - if (pMutex) - { - EX_TRY - { - pMutex->Create(lpMutexAttributes, bInitialOwner, lpName); - mutex = CLRMutexToCookie(pMutex); - } - EX_CATCH - { - delete pMutex; - } - EX_END_CATCH(SwallowAllExceptions); - } - return mutex; -} - -void STDMETHODCALLTYPE CExecutionEngine::ClrCloseMutex(MUTEX_COOKIE mutex) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - CLRMutex *pMutex = CookieToCLRMutex(mutex); - pMutex->Close(); - delete pMutex; -} - -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrReleaseMutex(MUTEX_COOKIE mutex) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - CLRMutex *pMutex = CookieToCLRMutex(mutex); - return pMutex->Release(); -} - -DWORD STDMETHODCALLTYPE CExecutionEngine::ClrWaitForMutex(MUTEX_COOKIE mutex, - DWORD dwMilliseconds, - BOOL bAlertable) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - CLRMutex *pMutex = CookieToCLRMutex(mutex); - return pMutex->Wait(dwMilliseconds,bAlertable); -} - -#undef ClrSleepEx -DWORD STDMETHODCALLTYPE CExecutionEngine::ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable) -{ - WRAPPER_NO_CONTRACT; - return EESleepEx(dwMilliseconds,bAlertable); -} -#define ClrSleepEx EESleepEx - -#undef ClrAllocationDisallowed -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrAllocationDisallowed() -{ - WRAPPER_NO_CONTRACT; - return EEAllocationDisallowed(); -} -#define ClrAllocationDisallowed EEAllocationDisallowed - -#undef ClrVirtualAlloc -LPVOID STDMETHODCALLTYPE CExecutionEngine::ClrVirtualAlloc(LPVOID lpAddress, - SIZE_T dwSize, - DWORD flAllocationType, - DWORD flProtect) -{ - WRAPPER_NO_CONTRACT; - return EEVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); -} -#define ClrVirtualAlloc EEVirtualAlloc - -#undef ClrVirtualFree -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrVirtualFree(LPVOID lpAddress, - SIZE_T dwSize, - DWORD dwFreeType) -{ - WRAPPER_NO_CONTRACT; - return EEVirtualFree(lpAddress, dwSize, dwFreeType); -} -#define ClrVirtualFree EEVirtualFree - -#undef ClrVirtualQuery -SIZE_T STDMETHODCALLTYPE CExecutionEngine::ClrVirtualQuery(LPCVOID lpAddress, - PMEMORY_BASIC_INFORMATION lpBuffer, - SIZE_T dwLength) -{ - WRAPPER_NO_CONTRACT; - return EEVirtualQuery(lpAddress, lpBuffer, dwLength); -} -#define ClrVirtualQuery EEVirtualQuery - -#if defined(_DEBUG) && !defined(TARGET_UNIX) -static VolatilePtr s_pStartOfUEFSection = NULL; -static VolatilePtr s_pEndOfUEFSectionBoundary = NULL; -static Volatile s_dwProtection = 0; -#endif // _DEBUG && !TARGET_UNIX - -#undef ClrVirtualProtect - -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrVirtualProtect(LPVOID lpAddress, - SIZE_T dwSize, - DWORD flNewProtect, - PDWORD lpflOldProtect) -{ - WRAPPER_NO_CONTRACT; - - // Get the UEF installation details - we will use these to validate - // that the calls to ClrVirtualProtect are not going to affect the UEF. - // - // The OS UEF invocation mechanism was updated. When a UEF is setup,the OS captures - // the following details about it: - // 1) Protection of the pages in which the UEF lives - // 2) The size of the region in which the UEF lives - // 3) The region's Allocation Base - // - // The OS verifies details surrounding the UEF before invocation. For security reasons - // the page protection cannot change between SetUnhandledExceptionFilter and invocation. - // - // Prior to this change, the UEF lived in a common section of code_Seg, along with - // JIT_PatchedCode. Thus, their pages have the same protection, they live - // in the same region (and thus, its size is the same). - // - // In EEStartupHelper, when we setup the UEF and then invoke InitJitHelpers1 and InitJitHelpers2, - // they perform some optimizations that result in the memory page protection being changed. When - // the UEF is to be invoked, the OS does the check on the UEF's cached details against the current - // memory pages. This check used to fail when on 64bit retail builds when JIT_PatchedCode was - // aligned after the UEF with a different memory page protection (post the optimizations by InitJitHelpers). - // Thus, the UEF was never invoked. - // - // To circumvent this, we put the UEF in its own section in the code segment so that any modifications - // to memory pages will not affect the UEF details that the OS cached. This is done in Excep.cpp - // using the "#pragma code_seg" directives. - // - // Below, we double check that: - // - // 1) the address being protected does not lie in the region of of the UEF. - // 2) the section after UEF is not having the same memory protection as UEF section. - // - // We assert if either of the two conditions above are true. - -#if defined(_DEBUG) && !defined(TARGET_UNIX) - // We do this check in debug/checked builds only - - // Do we have the UEF details? - if (s_pEndOfUEFSectionBoundary.Load() == NULL) - { - // Get reference to MSCORWKS image in memory... - PEDecoder pe(g_pMSCorEE); - - // Find the UEF section from the image - IMAGE_SECTION_HEADER* pUEFSection = pe.FindSection(CLR_UEF_SECTION_NAME); - _ASSERTE(pUEFSection != NULL); - if (pUEFSection) - { - // We got our section - get the start of the section - BYTE* pStartOfUEFSection = static_cast(pe.GetBase())+pUEFSection->VirtualAddress; - s_pStartOfUEFSection = pStartOfUEFSection; - - // Now we need the protection attributes for the memory region in which the - // UEF section is... - MEMORY_BASIC_INFORMATION uefInfo; - if (ClrVirtualQuery(pStartOfUEFSection, &uefInfo, sizeof(uefInfo)) != 0) - { - // Calculate how many pages does the UEF section take to get to the start of the - // next section. We dont calculate this as - // - // pStartOfUEFSection + uefInfo.RegionSize - // - // because the section following UEF will also be included in the region size - // if it has the same protection as the UEF section. - DWORD dwUEFSectionPageCount = ((pUEFSection->Misc.VirtualSize + GetOsPageSize() - 1)/GetOsPageSize()); - - BYTE* pAddressOfFollowingSection = pStartOfUEFSection + (GetOsPageSize() * dwUEFSectionPageCount); - - // Ensure that the section following us is having different memory protection - MEMORY_BASIC_INFORMATION nextSectionInfo; - _ASSERTE(ClrVirtualQuery(pAddressOfFollowingSection, &nextSectionInfo, sizeof(nextSectionInfo)) != 0); - _ASSERTE(nextSectionInfo.Protect != uefInfo.Protect); - - // save the memory protection details - s_dwProtection = uefInfo.Protect; - - // Get the end of the UEF section - BYTE* pEndOfUEFSectionBoundary = pAddressOfFollowingSection - 1; - - // Set the end of UEF section boundary - FastInterlockExchangePointer(s_pEndOfUEFSectionBoundary.GetPointer(), pEndOfUEFSectionBoundary); - } - else - { - _ASSERTE(!"Unable to get UEF Details!"); - } - } - } - - if (s_pEndOfUEFSectionBoundary.Load() != NULL) - { - // Is the protection being changed? - if (flNewProtect != s_dwProtection) - { - // Is the target address NOT affecting the UEF ? Possible cases: - // 1) Starts and ends before the UEF start - // 2) Starts after the UEF start - - void* pEndOfRangeAddr = static_cast(lpAddress)+dwSize-1; - - _ASSERTE_MSG(((pEndOfRangeAddr < s_pStartOfUEFSection.Load()) || (lpAddress > s_pEndOfUEFSectionBoundary.Load())), - "Do not virtual protect the section in which UEF lives!"); - } - } -#endif // _DEBUG && !TARGET_UNIX - - return EEVirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); -} -#define ClrVirtualProtect EEVirtualProtect - -#undef ClrGetProcessHeap -HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrGetProcessHeap() -{ - WRAPPER_NO_CONTRACT; - return EEGetProcessHeap(); -} -#define ClrGetProcessHeap EEGetProcessHeap - -#undef ClrGetProcessExecutableHeap -HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrGetProcessExecutableHeap() -{ - WRAPPER_NO_CONTRACT; - return EEGetProcessExecutableHeap(); -} -#define ClrGetProcessExecutableHeap EEGetProcessExecutableHeap - - -#undef ClrHeapCreate -HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrHeapCreate(DWORD flOptions, - SIZE_T dwInitialSize, - SIZE_T dwMaximumSize) -{ - WRAPPER_NO_CONTRACT; - return EEHeapCreate(flOptions, dwInitialSize, dwMaximumSize); -} -#define ClrHeapCreate EEHeapCreate - -#undef ClrHeapDestroy -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapDestroy(HANDLE hHeap) -{ - WRAPPER_NO_CONTRACT; - return EEHeapDestroy(hHeap); -} -#define ClrHeapDestroy EEHeapDestroy - -#undef ClrHeapAlloc -LPVOID STDMETHODCALLTYPE CExecutionEngine::ClrHeapAlloc(HANDLE hHeap, - DWORD dwFlags, - SIZE_T dwBytes) -{ - WRAPPER_NO_CONTRACT; - - return EEHeapAlloc(hHeap, dwFlags, dwBytes); -} -#define ClrHeapAlloc EEHeapAlloc - -#undef ClrHeapFree -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapFree(HANDLE hHeap, - DWORD dwFlags, - LPVOID lpMem) -{ - WRAPPER_NO_CONTRACT; - return EEHeapFree(hHeap, dwFlags, lpMem); -} -#define ClrHeapFree EEHeapFree - -#undef ClrHeapValidate -BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapValidate(HANDLE hHeap, - DWORD dwFlags, - LPCVOID lpMem) -{ - WRAPPER_NO_CONTRACT; - return EEHeapValidate(hHeap, dwFlags, lpMem); -} -#define ClrHeapValidate EEHeapValidate - -//------------------------------------------------------------------------------ -// Helper function to get an exception object from outside the exception. In -// the CLR, it may be from the Thread object. Non-CLR users have no thread object, -// and it will do nothing. - -void CExecutionEngine::GetLastThrownObjectExceptionFromThread(void **ppvException) -{ - WRAPPER_NO_CONTRACT; - - // Cast to our real type. - Exception **ppException = reinterpret_cast(ppvException); - - // Try to get a better message. - GetLastThrownObjectExceptionFromThread_Internal(ppException); - -} // HRESULT CExecutionEngine::GetLastThrownObjectExceptionFromThread() HRESULT CorHost2::DllGetActivationFactory(DWORD appDomainID, LPCWSTR wszTypeName, IActivationFactory ** factory) { diff --git a/src/coreclr/src/vm/crst.h b/src/coreclr/src/vm/crst.h index 68c1f6e9e4e195..17330f236e6d04 100644 --- a/src/coreclr/src/vm/crst.h +++ b/src/coreclr/src/vm/crst.h @@ -119,10 +119,9 @@ template friend class ListLockBase; template friend class ListLockEntryBase; -//friend class CExecutionEngine; friend struct SavedExceptionInfo; -friend void EEEnterCriticalSection(CRITSEC_COOKIE cookie); -friend void EELeaveCriticalSection(CRITSEC_COOKIE cookie); +friend void ClrEnterCriticalSection(CRITSEC_COOKIE cookie); +friend void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie); friend class CodeVersionManager; friend class Debugger; diff --git a/src/coreclr/src/vm/debuginfostore.cpp b/src/coreclr/src/vm/debuginfostore.cpp index 295dbe5f201bc5..2c9d17c22f17c4 100644 --- a/src/coreclr/src/vm/debuginfostore.cpp +++ b/src/coreclr/src/vm/debuginfostore.cpp @@ -8,6 +8,7 @@ #include "common.h" #include "debuginfostore.h" #include "nibblestream.h" +#include "patchpointinfo.h" #ifdef _DEBUG @@ -440,6 +441,7 @@ PTR_BYTE CompressDebugInfo::CompressBoundariesAndVars( IN ULONG iOffsetMapping, IN ICorDebugInfo::NativeVarInfo * pNativeVarInfo, IN ULONG iNativeVarInfo, + IN PatchpointInfo * patchpointInfo, IN OUT SBuffer * pDebugInfoBuffer, IN LoaderHeap * pLoaderHeap ) @@ -451,6 +453,18 @@ PTR_BYTE CompressDebugInfo::CompressBoundariesAndVars( PRECONDITION((pDebugInfoBuffer != NULL) ^ (pLoaderHeap != NULL)); } CONTRACTL_END; + // Patchpoint info is currently uncompressed. + DWORD cbPatchpointInfo = 0; + +#ifdef FEATURE_ON_STACK_REPLACEMENT + if (patchpointInfo != NULL) + { + cbPatchpointInfo = patchpointInfo->PatchpointInfoSize(); + } +#else + _ASSERTE(patchpointInfo == NULL); +#endif + // Actually do the compression. These will throw on oom. NibbleWriter boundsBuffer; DWORD cbBounds = 0; @@ -479,7 +493,12 @@ PTR_BYTE CompressDebugInfo::CompressBoundariesAndVars( DWORD cbHeader; PVOID pHeader = w.GetBlob(&cbHeader); +#ifdef FEATURE_ON_STACK_REPLACEMENT + S_UINT32 cbFinalSize = S_UINT32(1) + S_UINT32(cbPatchpointInfo) + S_UINT32(cbHeader) + S_UINT32(cbBounds) + S_UINT32(cbVars); +#else S_UINT32 cbFinalSize = S_UINT32(cbHeader) + S_UINT32(cbBounds) + S_UINT32(cbVars); +#endif + if (cbFinalSize.IsOverflow()) ThrowHR(COR_E_OVERFLOW); @@ -497,6 +516,22 @@ PTR_BYTE CompressDebugInfo::CompressBoundariesAndVars( BYTE *ptr = ptrStart; +#ifdef FEATURE_ON_STACK_REPLACEMENT + + // First byte is a flag byte: + // 0 - no patchpoint info + // 1 - patchpoint info + + *ptr++ = (cbPatchpointInfo > 0) ? 1 : 0; + + if (cbPatchpointInfo > 0) + { + memcpy(ptr, (BYTE*) patchpointInfo, cbPatchpointInfo); + ptr += cbPatchpointInfo; + } + +#endif + memcpy(ptr, pHeader, cbHeader); ptr += cbHeader; @@ -519,11 +554,6 @@ PTR_BYTE CompressDebugInfo::CompressBoundariesAndVars( #endif // DACCESS_COMPILE -//----------------------------------------------------------------------------- -// Compression routines -// DAC only needs to run the uncompression routines. -//----------------------------------------------------------------------------- - //----------------------------------------------------------------------------- // Uncompression (restore) routines //----------------------------------------------------------------------------- @@ -535,7 +565,8 @@ void CompressDebugInfo::RestoreBoundariesAndVars( OUT ULONG32 * pcMap, // number of entries in ppMap OUT ICorDebugInfo::OffsetMapping **ppMap, // pointer to newly allocated array OUT ULONG32 *pcVars, - OUT ICorDebugInfo::NativeVarInfo **ppVars + OUT ICorDebugInfo::NativeVarInfo **ppVars, + BOOL hasFlagByte ) { CONTRACTL @@ -552,6 +583,28 @@ void CompressDebugInfo::RestoreBoundariesAndVars( if (pcVars != NULL) *pcVars = 0; if (ppVars != NULL) *ppVars = NULL; +#ifdef FEATURE_ON_STACK_REPLACEMENT + if (hasFlagByte) + { + // Check flag byte and skip over any patchpoint info + BYTE flagByte = *pDebugInfo; + pDebugInfo++; + + if (flagByte == 1) + { + PTR_PatchpointInfo patchpointInfo = dac_cast(pDebugInfo); + pDebugInfo += patchpointInfo->PatchpointInfoSize(); + } + else + { + _ASSERTE(flagByte == 0); + } + } + +#else + _ASSERTE(!hasFlagByte); +#endif + NibbleReader r(pDebugInfo, 12 /* maximum size of compressed 2 UINT32s */); ULONG cbBounds = r.ReadEncodedU32(); @@ -615,8 +668,41 @@ void CompressDebugInfo::RestoreBoundariesAndVars( } } +#ifdef FEATURE_ON_STACK_REPLACEMENT + +PatchpointInfo * CompressDebugInfo::RestorePatchpointInfo(IN PTR_BYTE pDebugInfo) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SUPPORTS_DAC; + } + CONTRACTL_END; + + PTR_PatchpointInfo patchpointInfo = NULL; + + // Check flag byte. + BYTE flagByte = *pDebugInfo; + pDebugInfo++; + + if (flagByte == 1) + { + patchpointInfo = dac_cast(pDebugInfo); + } + else + { + _ASSERTE(flagByte == 0); + } + + return patchpointInfo; +} + +#endif + #ifdef DACCESS_COMPILE -void CompressDebugInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, PTR_BYTE pDebugInfo) +void CompressDebugInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, PTR_BYTE pDebugInfo, BOOL hasFlagByte) { CONTRACTL { @@ -626,6 +712,27 @@ void CompressDebugInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, PTR_BYTE } CONTRACTL_END; +#ifdef FEATURE_ON_STACK_REPLACEMENT + if (hasFlagByte) + { + // Check flag byte and skip over any patchpoint info + BYTE flagByte = *pDebugInfo; + pDebugInfo++; + + if (flagByte == 1) + { + PTR_PatchpointInfo patchpointInfo = dac_cast(pDebugInfo); + pDebugInfo += patchpointInfo->PatchpointInfoSize(); + } + else + { + _ASSERTE(flagByte == 0); + } + } +#else + _ASSERTE(!hasFlagByte); +#endif + NibbleReader r(pDebugInfo, 12 /* maximum size of compressed 2 UINT32s */); ULONG cbBounds = r.ReadEncodedU32(); diff --git a/src/coreclr/src/vm/debuginfostore.h b/src/coreclr/src/vm/debuginfostore.h index 453e41fa907c10..518333705a9710 100644 --- a/src/coreclr/src/vm/debuginfostore.h +++ b/src/coreclr/src/vm/debuginfostore.h @@ -83,6 +83,7 @@ class CompressDebugInfo IN ULONG iOffsetMapping, IN ICorDebugInfo::NativeVarInfo * pNativeVarInfo, IN ULONG iNativeVarInfo, + IN PatchpointInfo * patchpointInfo, IN OUT SBuffer * pDebugInfoBuffer, IN LoaderHeap * pLoaderHeap ); @@ -95,11 +96,18 @@ class CompressDebugInfo OUT ULONG32 * pcMap, // number of entries in ppMap OUT ICorDebugInfo::OffsetMapping **ppMap, // pointer to newly allocated array OUT ULONG32 *pcVars, - OUT ICorDebugInfo::NativeVarInfo **ppVars + OUT ICorDebugInfo::NativeVarInfo **ppVars, + BOOL hasFlagByte ); +#ifdef FEATURE_ON_STACK_REPLACEMENT + static PatchpointInfo * RestorePatchpointInfo( + IN PTR_BYTE pDebugInfo + ); +#endif + #ifdef DACCESS_COMPILE - static void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, PTR_BYTE pDebugInfo); + static void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, PTR_BYTE pDebugInfo, BOOL hasFlagByte); #endif }; diff --git a/src/coreclr/src/vm/dwreport.cpp b/src/coreclr/src/vm/dwreport.cpp index dbc6bb3e65dc83..4cc5950f7fc9a6 100644 --- a/src/coreclr/src/vm/dwreport.cpp +++ b/src/coreclr/src/vm/dwreport.cpp @@ -143,7 +143,7 @@ BOOL RegisterOutOfProcessWatsonCallbacks() if (SUCCEEDED(::GetCORSystemDirectoryInternaL(wszDACPath))) { wszDACPath.Append(wszDACName); - hr = (*pFnWerRegisterRuntimeExceptionModule)(wszDACPath, (PDWORD)g_pMSCorEE); + hr = (*pFnWerRegisterRuntimeExceptionModule)(wszDACPath, (PDWORD)g_hThisInst); } else { hr = E_FAIL; diff --git a/src/coreclr/src/vm/eeconfig.cpp b/src/coreclr/src/vm/eeconfig.cpp index 205730d8b57cbd..dc43f141eabf52 100644 --- a/src/coreclr/src/vm/eeconfig.cpp +++ b/src/coreclr/src/vm/eeconfig.cpp @@ -339,6 +339,11 @@ HRESULT EEConfig::Init() tieredCompilation_DeleteCallCountingStubsAfter = 0; #endif +#if defined(FEATURE_ON_STACK_REPLACEMENT) + dwOSR_HitLimit = 10; + dwOSR_CounterBump = 5000; +#endif + #ifndef CROSSGEN_COMPILE backpatchEntryPointSlots = false; #endif @@ -1265,6 +1270,16 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ } #endif +#if defined(FEATURE_ON_STACK_REPLACEMENT) + dwOSR_HitLimit = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_OSR_HitLimit); + dwOSR_CounterBump = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_OSR_CounterBump); +#endif + +#if defined(FEATURE_ON_STACK_REPLACEMENT) && defined(_DEBUG) + dwOSR_LowId = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_OSR_LowId); + dwOSR_HighId = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_OSR_HighId); +#endif + #ifndef CROSSGEN_COMPILE backpatchEntryPointSlots = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_BackpatchEntryPointSlots) != 0; #endif diff --git a/src/coreclr/src/vm/eeconfig.h b/src/coreclr/src/vm/eeconfig.h index 3359a4a33eb03e..e28f64834ebe32 100644 --- a/src/coreclr/src/vm/eeconfig.h +++ b/src/coreclr/src/vm/eeconfig.h @@ -290,6 +290,17 @@ class EEConfig DWORD TieredCompilation_DeleteCallCountingStubsAfter() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_DeleteCallCountingStubsAfter; } #endif +#if defined(FEATURE_ON_STACK_REPLACEMENT) + // OSR Config + DWORD OSR_CounterBump() const { LIMITED_METHOD_CONTRACT; return dwOSR_CounterBump; } + DWORD OSR_HitLimit() const { LIMITED_METHOD_CONTRACT; return dwOSR_HitLimit; } +#endif + +#if defined(FEATURE_ON_STACK_REPLACEMENT) && defined(_DEBUG) + DWORD OSR_LowId() const { LIMITED_METHOD_CONTRACT; return dwOSR_LowId; } + DWORD OSR_HighId() const { LIMITED_METHOD_CONTRACT; return dwOSR_HighId; } +#endif + #ifndef CROSSGEN_COMPILE bool BackpatchEntryPointSlots() const { LIMITED_METHOD_CONTRACT; return backpatchEntryPointSlots; } #endif @@ -1023,6 +1034,16 @@ class EEConfig DWORD tieredCompilation_DeleteCallCountingStubsAfter; #endif +#if defined(FEATURE_ON_STACK_REPLACEMENT) + DWORD dwOSR_HitLimit; + DWORD dwOSR_CounterBump; +#endif + +#if defined(FEATURE_ON_STACK_REPLACEMENT) && defined(_DEBUG) + DWORD dwOSR_LowId; + DWORD dwOSR_HighId; +#endif + #ifndef CROSSGEN_COMPILE bool backpatchEntryPointSlots; #endif diff --git a/src/coreclr/src/vm/eecontract.cpp b/src/coreclr/src/vm/eecontract.cpp index cf25adfa2b4f29..105bc36c8b0a8a 100644 --- a/src/coreclr/src/vm/eecontract.cpp +++ b/src/coreclr/src/vm/eecontract.cpp @@ -35,10 +35,7 @@ void EEContract::DoChecks(UINT testmask, __in_z const char *szFunction, __in_z c // allow such calls. BEGIN_GETTHREAD_ALLOWED_IN_NO_THROW_REGION; m_pThread = GetThread(); - if (m_pThread != NULL) - { - m_pClrDebugState = m_pThread->GetClrDebugState(); - } + m_pClrDebugState = GetClrDebugState(); // Call our base DoChecks. BaseContract::DoChecks(testmask, szFunction, szFile, lineNum); @@ -256,16 +253,3 @@ void EEContract::DoChecks(UINT testmask, __in_z const char *szFunction, __in_z c } } #endif // ENABLE_CONTRACTS - - -BYTE* __stdcall GetAddrOfContractShutoffFlag() -{ - LIMITED_METHOD_CONTRACT; - - // Exposed entrypoint where we cannot probe or do anything TLS - // related - static BYTE gContractShutoffFlag = 0; - - return &gContractShutoffFlag; -} - diff --git a/src/coreclr/src/vm/eepolicy.cpp b/src/coreclr/src/vm/eepolicy.cpp index d01c98883e5390..bec99146cd6017 100644 --- a/src/coreclr/src/vm/eepolicy.cpp +++ b/src/coreclr/src/vm/eepolicy.cpp @@ -1012,13 +1012,13 @@ void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage addressString.Printf(W("%p"), pExceptionInfo? (UINT_PTR)pExceptionInfo->ExceptionRecord->ExceptionAddress : address); // We should always have the reference to the runtime's instance - _ASSERTE(g_pMSCorEE != NULL); + _ASSERTE(g_hThisInst != NULL); // Setup the string to contain the runtime's base address. Thus, when customers report FEEE with just // the event log entry containing this string, we can use the absolute and base addresses to determine // where the fault happened inside the runtime. SmallStackSString runtimeBaseAddressString; - runtimeBaseAddressString.Printf(W("%p"), g_pMSCorEE); + runtimeBaseAddressString.Printf(W("%p"), g_hThisInst); SmallStackSString exitCodeString; exitCodeString.Printf(W("%x"), exitCode); diff --git a/src/coreclr/src/vm/eventpipesession.h b/src/coreclr/src/vm/eventpipesession.h index adcddb3bdc5043..cc86d9b9d26ae3 100644 --- a/src/coreclr/src/vm/eventpipesession.h +++ b/src/coreclr/src/vm/eventpipesession.h @@ -8,7 +8,6 @@ #ifdef FEATURE_PERFTRACING #include "common.h" -#include "hosting.h" #include "threadsuspend.h" class EventPipeBufferManager; diff --git a/src/coreclr/src/vm/excep.cpp b/src/coreclr/src/vm/excep.cpp index ecec22455d711b..e77851c4497d04 100644 --- a/src/coreclr/src/vm/excep.cpp +++ b/src/coreclr/src/vm/excep.cpp @@ -5110,7 +5110,7 @@ LONG EntryPointFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID _pData) // Updated to be in its own code segment named CLR_UEF_SECTION_NAME to prevent // "VirtualProtect" calls from affecting its pages and thus, its // invocation. For details, see the comment within the implementation of -// CExecutionEngine::ClrVirtualProtect. +// ClrVirtualProtect. // // Parameters // pExceptionInfo -- information about the exception @@ -7359,7 +7359,7 @@ LONG WINAPI CLRVectoredExceptionHandlerPhase2(PEXCEPTION_POINTERS pExceptionInfo CONTRACT_VIOLATION(TakesLockViolation); fExternalException = (!ExecutionManager::IsManagedCode(GetIP(pExceptionInfo->ContextRecord)) && - !IsIPInModule(g_pMSCorEE, GetIP(pExceptionInfo->ContextRecord))); + !IsIPInModule(g_hThisInst, GetIP(pExceptionInfo->ContextRecord))); } if (fExternalException) @@ -7526,7 +7526,7 @@ VEH_ACTION WINAPI CLRVectoredExceptionHandlerPhase3(PEXCEPTION_POINTERS pExcepti if ((!fAVisOk) && !(pExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)) { PCODE ip = (PCODE)GetIP(pContext); - if (IsIPInModule(g_pMSCorEE, ip) || IsIPInModule(GCHeapUtilities::GetGCModule(), ip)) + if (IsIPInModule(g_hThisInst, ip) || IsIPInModule(GCHeapUtilities::GetGCModule(), ip)) { CONTRACT_VIOLATION(ThrowsViolation|FaultViolation); @@ -7979,6 +7979,7 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) // // 1) We have a valid Thread object (implies exception on managed thread) // 2) Not a valid Thread object but the IP is in the execution engine (implies native thread within EE faulted) + // 3) The exception occurred in a GC marked location when no thread exists (i.e. reverse P/Invoke with NativeCallableAttribute). if (pThread || fExceptionInEE) { if (!bIsGCMarker) @@ -8066,6 +8067,11 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) #endif // FEATURE_EH_FUNCLETS } + else if (bIsGCMarker) + { + _ASSERTE(pThread == NULL); + result = EXCEPTION_CONTINUE_EXECUTION; + } SetLastError(dwLastError); diff --git a/src/coreclr/src/vm/excep.h b/src/coreclr/src/vm/excep.h index b6fb51242dc1f2..33a616f81aa7d9 100644 --- a/src/coreclr/src/vm/excep.h +++ b/src/coreclr/src/vm/excep.h @@ -186,7 +186,7 @@ void UninstallUnhandledExceptionFilter(); // within a section, no matter where it was located - and for this case, we need the UEF code // at the right location to ensure that we can check the memory protection of its following // section so that shouldnt affect UEF's memory protection. For details, read the comment in -// "CExecutionEngine::ClrVirtualProtect". +// ClrVirtualProtect. // // Keeping UEF in its own section helps prevent code movement as BBT does not reorder // sections. As per my understanding of the linker, ".text" section always comes first, @@ -194,7 +194,7 @@ void UninstallUnhandledExceptionFilter(); // The order of user defined executable sections is typically defined by the linker // in terms of which section it sees first. So, if there is another custom executable // section that comes after UEF section, it can affect the UEF section and we will -// assert about it in "CExecutionEngine::ClrVirtualProtect". +// assert about it in ClrVirtualProtect. #define CLR_UEF_SECTION_NAME ".CLR_UEF" #endif //!defined(TARGET_UNIX) LONG __stdcall COMUnhandledExceptionFilter(EXCEPTION_POINTERS *pExceptionInfo); diff --git a/src/coreclr/src/vm/exceptionhandling.cpp b/src/coreclr/src/vm/exceptionhandling.cpp index 655a102407c119..41b3627438aa3f 100644 --- a/src/coreclr/src/vm/exceptionhandling.cpp +++ b/src/coreclr/src/vm/exceptionhandling.cpp @@ -818,6 +818,8 @@ UINT_PTR ExceptionTracker::FinishSecondPass( return uResumePC; } +void CleanUpForSecondPass(Thread* pThread, bool fIsSO, LPVOID MemoryStackFpForFrameChain, LPVOID MemoryStackFp); + // On CoreARM, the MemoryStackFp is ULONG when passed by RtlDispatchException, // unlike its 64bit counterparts. EXTERN_C EXCEPTION_DISPOSITION @@ -974,7 +976,7 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord BOOL fExternalException; fExternalException = (!ExecutionManager::IsManagedCode(ip) && - !IsIPInModule(g_pMSCorEE, ip)); + !IsIPInModule(g_hThisInst, ip)); if (fExternalException) { @@ -1262,6 +1264,22 @@ lExit: ; if ((ExceptionContinueSearch == returnDisposition)) { + if (dwExceptionFlags & EXCEPTION_UNWINDING) + { + EECodeInfo codeInfo(pDispatcherContext->ControlPc); + if (codeInfo.IsValid()) + { + GcInfoDecoder gcInfoDecoder(codeInfo.GetGCInfoToken(), DECODE_REVERSE_PINVOKE_VAR); + if (gcInfoDecoder.GetReversePInvokeFrameStackSlot() != NO_REVERSE_PINVOKE_FRAME) + { + // Exception is being propagated from a native callable method into its native caller. + // The explicit frame chain needs to be unwound at this boundary. + bool fIsSO = pExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW; + CleanUpForSecondPass(pThread, fIsSO, (void*)MemoryStackFp, (void*)MemoryStackFp); + } + } + } + GCX_PREEMP_NO_DTOR(); } @@ -5824,7 +5842,7 @@ BOOL IsSafeToUnwindFrameChain(Thread* pThread, LPVOID MemoryStackFpForFrameChain // We're safe only if the managed method will be unwound also LPVOID managedSP = dac_cast(GetRegdisplaySP(&rd)); - if (managedSP < MemoryStackFpForFrameChain) + if (managedSP <= MemoryStackFpForFrameChain) { return TRUE; } @@ -6841,7 +6859,7 @@ StackFrame ExceptionTracker::FindParentStackFrameHelper(CrawlFrame* pCF, #if defined(DACCESS_COMPILE) HMODULE_TGT hEE = DacGlobalBase(); #else // !DACCESS_COMPILE - HMODULE_TGT hEE = g_pMSCorEE; + HMODULE_TGT hEE = g_hThisInst; #endif // !DACCESS_COMPILE fIsCallerInVM = IsIPInModule(hEE, callerIP); #endif // TARGET_UNIX diff --git a/src/coreclr/src/vm/gccover.cpp b/src/coreclr/src/vm/gccover.cpp index c5801e259fec76..96cd53ce2c3f05 100644 --- a/src/coreclr/src/vm/gccover.cpp +++ b/src/coreclr/src/vm/gccover.cpp @@ -1400,7 +1400,16 @@ BOOL OnGcCoverageInterrupt(PCONTEXT regs) } Thread* pThread = GetThread(); - _ASSERTE(pThread); + if (!pThread) + { + // No thread at the moment so we aren't doing coverage for this function. + // This should only occur for methods with the NativeCallableAttribute, + // where the call could be coming from a thread unknown to the CLR and + // we haven't created a thread yet - see PreStubWorker_Preemptive(). + _ASSERTE(pMD->HasNativeCallableAttribute()); + RemoveGcCoverageInterrupt(instrPtr, savedInstrPtr); + return TRUE; + } #if defined(USE_REDIRECT_FOR_GCSTRESS) && !defined(TARGET_UNIX) // If we're unable to redirect, then we simply won't test GC at this @@ -1452,6 +1461,7 @@ void DoGcStress (PCONTEXT regs, NativeCodeVersion nativeCodeVersion) DWORD offset = codeInfo.GetRelOffset(); Thread *pThread = GetThread(); + _ASSERTE(pThread); if (!IsGcCoverageInterruptInstruction(instrPtr)) { diff --git a/src/coreclr/src/vm/gchelpers.cpp b/src/coreclr/src/vm/gchelpers.cpp index e9352bde7cde9c..5f375da096c2f9 100644 --- a/src/coreclr/src/vm/gchelpers.cpp +++ b/src/coreclr/src/vm/gchelpers.cpp @@ -42,14 +42,6 @@ // //======================================================================== -#define ProfileTrackArrayAlloc(orObject) \ - OBJECTREF objref = ObjectToOBJECTREF((Object*)orObject);\ - GCPROTECT_BEGIN(objref);\ - ProfilerObjectAllocatedCallback(objref, (ClassID) orObject->GetTypeHandle().AsPtr());\ - GCPROTECT_END();\ - orObject = (ArrayBase *) OBJECTREFToObject(objref); - - inline gc_alloc_context* GetThreadAllocContext() { WRAPPER_NO_CONTRACT; @@ -281,7 +273,7 @@ bool ToLogOrNotToLog(size_t size, const char *typeName) // this function is called on managed allocation path with unprotected Object* // as a result LogAlloc cannot call anything that would toggle the GC mode else // you'll introduce several GC holes! -inline void LogAlloc(size_t size, MethodTable *pMT, Object* object) +inline void LogAlloc(Object* object) { CONTRACTL { @@ -292,6 +284,9 @@ inline void LogAlloc(size_t size, MethodTable *pMT, Object* object) CONTRACTL_END; #ifdef LOGGING + MethodTable* pMT = object->GetMethodTable(); + size_t size = object->GetSize(); + if (LoggingOn(LF_GCALLOC, LL_INFO10)) { LogSpewAlways("Allocated %5d bytes for %s_TYPE" FMT_ADDR FMT_CLASS "\n", @@ -311,9 +306,44 @@ inline void LogAlloc(size_t size, MethodTable *pMT, Object* object) #endif } #else -#define LogAlloc(size, pMT, object) +#define LogAlloc( object) #endif +// signals completion of the object to GC and sends events if necessary +template +void PublishObjectAndNotify(TObj* &orObject, GC_ALLOC_FLAGS flags) +{ + _ASSERTE(orObject->HasEmptySyncBlockInfo()); + + if (flags & GC_ALLOC_USER_OLD_HEAP) + { + GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orObject); + } + +#ifdef _LOGALLOC + LogAlloc(orObject); +#endif // _LOGALLOC + + // Notify the profiler of the allocation + // do this after initializing bounds so callback has size information + if (TrackAllocations() || + (TrackLargeAllocations() && flags & GC_ALLOC_LARGE_OBJECT_HEAP)) + { + OBJECTREF objref = ObjectToOBJECTREF((Object*)orObject); + GCPROTECT_BEGIN(objref); + ProfilerObjectAllocatedCallback(objref, (ClassID) orObject->GetTypeHandle().AsPtr()); + GCPROTECT_END(); + orObject = (TObj*) OBJECTREFToObject(objref); + } + +#ifdef FEATURE_EVENT_TRACE + // Send ETW event for allocation + if(ETW::TypeSystemLog::IsHeapAllocEventEnabled()) + { + ETW::TypeSystemLog::SendObjectAllocatedEvent(orObject); + } +#endif // FEATURE_EVENT_TRACE +} inline SIZE_T MaxArrayLength(SIZE_T componentSize) { @@ -324,7 +354,7 @@ inline SIZE_T MaxArrayLength(SIZE_T componentSize) return (componentSize == 1) ? 0X7FFFFFC7 : 0X7FEFFFFF; } -OBJECTREF AllocateSzArray(TypeHandle arrayType, INT32 cElements, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap) +OBJECTREF AllocateSzArray(TypeHandle arrayType, INT32 cElements, GC_ALLOC_FLAGS flags) { CONTRACTL{ THROWS; @@ -334,10 +364,10 @@ OBJECTREF AllocateSzArray(TypeHandle arrayType, INT32 cElements, GC_ALLOC_FLAGS MethodTable* pArrayMT = arrayType.AsMethodTable(); - return AllocateSzArray(pArrayMT, cElements, flags, bAllocateInLargeHeap); + return AllocateSzArray(pArrayMT, cElements, flags); } -OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap) +OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS flags) { CONTRACTL{ THROWS; @@ -345,6 +375,8 @@ OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS MODE_COOPERATIVE; // returns an objref without pinning it => cooperative } CONTRACTL_END; + // IBC Log MethodTable access + g_IBCLogger.LogMethodTableAccess(pArrayMT); SetTypeHandleOnThreadForAlloc(TypeHandle(pArrayMT)); _ASSERTE(pArrayMT->CheckInstanceActivated()); @@ -356,9 +388,6 @@ OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS if (elemType == ELEMENT_TYPE_VOID) COMPlusThrow(kArgumentException); - // IBC Log MethodTable access - g_IBCLogger.LogMethodTableAccess(pArrayMT); - if (cElements < 0) COMPlusThrow(kOverflowException); @@ -385,22 +414,21 @@ OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS ((DWORD)cElements >= g_pConfig->GetDoubleArrayToLargeObjectHeapThreshold())) { STRESS_LOG2(LF_GC, LL_INFO10, "Allocating double MD array of size %d and length %d to large object heap\n", totalSize, cElements); - bAllocateInLargeHeap = TRUE; + flags |= GC_ALLOC_LARGE_OBJECT_HEAP; } #endif if (totalSize >= g_pConfig->GetGCLOHThreshold()) - { - bAllocateInLargeHeap = TRUE; - } + flags |= GC_ALLOC_LARGE_OBJECT_HEAP; - flags |= (pArrayMT->ContainsPointers() ? GC_ALLOC_CONTAINS_REF : GC_ALLOC_NO_FLAGS); + if (pArrayMT->ContainsPointers()) + flags |= GC_ALLOC_CONTAINS_REF; ArrayBase* orArray = NULL; - if (bAllocateInLargeHeap) + if (flags & GC_ALLOC_USER_OLD_HEAP) { - orArray = (ArrayBase*)Alloc(totalSize, flags | GC_ALLOC_LARGE_OBJECT_HEAP); - orArray->SetArrayMethodTableForLargeObject(pArrayMT); + orArray = (ArrayBase*)Alloc(totalSize, flags); + orArray->SetMethodTableForUOHObject(pArrayMT); } else { @@ -457,40 +485,14 @@ OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS #endif orArray = (ArrayBase*)Alloc(totalSize, flags); } - orArray->SetArrayMethodTable(pArrayMT); + orArray->SetMethodTable(pArrayMT); } // Initialize Object orArray->m_NumComponents = cElements; - bool bProfilerNotifyLargeAllocation = false; - - if (bAllocateInLargeHeap) - { - GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orArray); - bProfilerNotifyLargeAllocation = TrackLargeAllocations(); - } - -#ifdef _LOGALLOC - LogAlloc(totalSize, pArrayMT, orArray); -#endif // _LOGALLOC - - // Notify the profiler of the allocation - // do this after initializing bounds so callback has size information - if (TrackAllocations() || bProfilerNotifyLargeAllocation) - { - ProfileTrackArrayAlloc(orArray); - } - -#ifdef FEATURE_EVENT_TRACE - // Send ETW event for allocation - if(ETW::TypeSystemLog::IsHeapAllocEventEnabled()) - { - ETW::TypeSystemLog::SendObjectAllocatedEvent(orArray); - } -#endif // FEATURE_EVENT_TRACE - - return ObjectToOBJECTREF((Object *) orArray); + PublishObjectAndNotify(orArray, flags); + return ObjectToOBJECTREF((Object*)orArray); } void ThrowOutOfMemoryDimensionsExceeded() @@ -511,7 +513,7 @@ void ThrowOutOfMemoryDimensionsExceeded() // // This is wrapper overload to handle TypeHandle arrayType // -OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap) +OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags) { CONTRACTL { @@ -520,7 +522,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, G MethodTable* pArrayMT = arrayType.AsMethodTable(); - return AllocateArrayEx(pArrayMT, pArgs, dwNumArgs, flags, bAllocateInLargeHeap); + return AllocateArrayEx(pArrayMT, pArgs, dwNumArgs, flags); } // @@ -530,7 +532,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, G // allocate sub-arrays and fill them in. // // For arrays with lower bounds, pBounds is , , , ... -OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap) +OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags) { CONTRACTL { THROWS; @@ -540,8 +542,6 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, PRECONDITION(dwNumArgs > 0); } CONTRACTL_END; - ArrayBase * orArray = NULL; - #ifdef _DEBUG if (g_pConfig->ShouldInjectFault(INJECTFAULT_GCHEAP)) { @@ -550,6 +550,15 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, } #endif + // IBC Log MethodTable access + g_IBCLogger.LogMethodTableAccess(pArrayMT); + SetTypeHandleOnThreadForAlloc(TypeHandle(pArrayMT)); + + // keep original flags in case the call is recursive (jugged array case) + // the aditional flags that we infer here, such as GC_ALLOC_CONTAINS_REF + // may not be applicable to inner arrays + GC_ALLOC_FLAGS flagsOriginal = flags; + _ASSERTE(pArrayMT->CheckInstanceActivated()); PREFIX_ASSUME(pArrayMT != NULL); CorElementType kind = pArrayMT->GetInternalCorElementType(); @@ -562,11 +571,6 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, // Calculate the total number of elements in the array UINT32 cElements; - - // IBC Log MethodTable access - g_IBCLogger.LogMethodTableAccess(pArrayMT); - SetTypeHandleOnThreadForAlloc(TypeHandle(pArrayMT)); - SIZE_T componentSize = pArrayMT->GetComponentSize(); bool maxArrayDimensionLengthOverflow = false; bool providedLowerBounds = false; @@ -580,7 +584,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, if (rank == 1 && (dwNumArgs == 1 || pArgs[0] == 0)) { TypeHandle szArrayType = ClassLoader::LoadArrayTypeThrowing(pArrayMT->GetArrayElementTypeHandle(), ELEMENT_TYPE_SZARRAY, 1); - return AllocateSzArray(szArrayType, pArgs[dwNumArgs - 1], flags, bAllocateInLargeHeap); + return AllocateSzArray(szArrayType, pArgs[dwNumArgs - 1], flags); } providedLowerBounds = (dwNumArgs == 2*rank); @@ -642,21 +646,21 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, (cElements >= g_pConfig->GetDoubleArrayToLargeObjectHeapThreshold())) { STRESS_LOG2(LF_GC, LL_INFO10, "Allocating double MD array of size %d and length %d to large object heap\n", totalSize, cElements); - bAllocateInLargeHeap = TRUE; + flags |= GC_ALLOC_LARGE_OBJECT_HEAP; } #endif if (totalSize >= g_pConfig->GetGCLOHThreshold()) - { - bAllocateInLargeHeap = TRUE; - } + flags |= GC_ALLOC_LARGE_OBJECT_HEAP; - flags |= (pArrayMT->ContainsPointers() ? GC_ALLOC_CONTAINS_REF : GC_ALLOC_NO_FLAGS); + if (pArrayMT->ContainsPointers()) + flags |= GC_ALLOC_CONTAINS_REF; - if (bAllocateInLargeHeap) + ArrayBase* orArray = NULL; + if (flags & GC_ALLOC_USER_OLD_HEAP) { - orArray = (ArrayBase *) Alloc(totalSize, flags | GC_ALLOC_LARGE_OBJECT_HEAP); - orArray->SetArrayMethodTableForLargeObject(pArrayMT); + orArray = (ArrayBase*)Alloc(totalSize, flags); + orArray->SetMethodTableForUOHObject(pArrayMT); } else { @@ -674,24 +678,11 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, } #endif orArray = (ArrayBase*)Alloc(totalSize, flags); - orArray->SetArrayMethodTable(pArrayMT); + orArray->SetMethodTable(pArrayMT); } // Initialize Object orArray->m_NumComponents = cElements; - - bool bProfilerNotifyLargeAllocation = false; - - if (bAllocateInLargeHeap) - { - GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orArray); - bProfilerNotifyLargeAllocation = TrackLargeAllocations(); - } - -#ifdef _LOGALLOC - LogAlloc(totalSize, pArrayMT, orArray); -#endif // _LOGALLOC - if (kind == ELEMENT_TYPE_ARRAY) { INT32 *pCountsPtr = (INT32 *) orArray->GetBoundsPtr(); @@ -704,20 +695,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, } } - // Notify the profiler of the allocation - // do this after initializing bounds so callback has size information - if (TrackAllocations() || bProfilerNotifyLargeAllocation) - { - ProfileTrackArrayAlloc(orArray); - } - -#ifdef FEATURE_EVENT_TRACE - // Send ETW event for allocation - if(ETW::TypeSystemLog::IsHeapAllocEventEnabled()) - { - ETW::TypeSystemLog::SendObjectAllocatedEvent(orArray); - } -#endif // FEATURE_EVENT_TRACE + PublishObjectAndNotify(orArray, flags); if (kind != ELEMENT_TYPE_ARRAY) { @@ -741,7 +719,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, TypeHandle subArrayType = pArrayMT->GetArrayElementTypeHandle(); for (UINT32 i = 0; i < cElements; i++) { - OBJECTREF obj = AllocateArrayEx(subArrayType, &pArgs[1], dwNumArgs-1, flags, bAllocateInLargeHeap); + OBJECTREF obj = AllocateArrayEx(subArrayType, &pArgs[1], dwNumArgs-1, flagsOriginal); outerArray->SetAt(i, obj); } @@ -848,7 +826,8 @@ OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle elementType, BOOL bAll _ASSERTE(arrayType.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY); #endif //_DEBUG - return AllocateSzArray(arrayType, (INT32) cElements, GC_ALLOC_NO_FLAGS, bAllocateInLargeHeap); + GC_ALLOC_FLAGS flags = bAllocateInLargeHeap ? GC_ALLOC_LARGE_OBJECT_HEAP : GC_ALLOC_NO_FLAGS; + return AllocateSzArray(arrayType, (INT32) cElements, flags); } STRINGREF AllocateString( DWORD cchStringLength ) @@ -859,8 +838,6 @@ STRINGREF AllocateString( DWORD cchStringLength ) MODE_COOPERATIVE; // returns an objref without pinning it => cooperative } CONTRACTL_END; - StringObject *orObject = NULL; - #ifdef _DEBUG if (g_pConfig->ShouldInjectFault(INJECTFAULT_GCHEAP)) { @@ -876,50 +853,23 @@ STRINGREF AllocateString( DWORD cchStringLength ) if (cchStringLength > 0x3FFFFFDF) ThrowOutOfMemory(); - SIZE_T ObjectSize = PtrAlign(StringObject::GetSize(cchStringLength)); - _ASSERTE(ObjectSize > cchStringLength); + SIZE_T totalSize = PtrAlign(StringObject::GetSize(cchStringLength)); + _ASSERTE(totalSize > cchStringLength); SetTypeHandleOnThreadForAlloc(TypeHandle(g_pStringClass)); - orObject = (StringObject *)Alloc( ObjectSize, GC_ALLOC_NO_FLAGS); + GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS; + if (totalSize >= g_pConfig->GetGCLOHThreshold()) + flags |= GC_ALLOC_LARGE_OBJECT_HEAP; - // Object is zero-init already - _ASSERTE( orObject->HasEmptySyncBlockInfo() ); + StringObject* orString = (StringObject*)Alloc(totalSize, flags); // Initialize Object - //@TODO need to build a LARGE g_pStringMethodTable before - orObject->SetMethodTable( g_pStringClass ); - orObject->SetStringLength( cchStringLength ); - - bool bProfilerNotifyLargeAllocation = false; - if (ObjectSize >= g_pConfig->GetGCLOHThreshold()) - { - bProfilerNotifyLargeAllocation = TrackLargeAllocations(); - GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orObject); - } + orString->SetMethodTable(g_pStringClass); + orString->SetStringLength(cchStringLength); - // Notify the profiler of the allocation - if (TrackAllocations() || bProfilerNotifyLargeAllocation) - { - OBJECTREF objref = ObjectToOBJECTREF((Object*)orObject); - GCPROTECT_BEGIN(objref); - ProfilerObjectAllocatedCallback(objref, (ClassID) orObject->GetTypeHandle().AsPtr()); - GCPROTECT_END(); - - orObject = (StringObject *) OBJECTREFToObject(objref); - } - -#ifdef FEATURE_EVENT_TRACE - // Send ETW event for allocation - if(ETW::TypeSystemLog::IsHeapAllocEventEnabled()) - { - ETW::TypeSystemLog::SendObjectAllocatedEvent(orObject); - } -#endif // FEATURE_EVENT_TRACE - - LogAlloc(ObjectSize, g_pStringClass, orObject); - - return( ObjectToSTRINGREF(orObject) ); + PublishObjectAndNotify(orString, flags); + return ObjectToSTRINGREF(orString); } #ifdef FEATURE_UTF8STRING @@ -931,8 +881,6 @@ UTF8STRINGREF AllocateUtf8String(DWORD cchStringLength) MODE_COOPERATIVE; // returns an objref without pinning it => cooperative } CONTRACTL_END; - Utf8StringObject *orObject = NULL; - #ifdef _DEBUG if (g_pConfig->ShouldInjectFault(INJECTFAULT_GCHEAP)) { @@ -953,50 +901,23 @@ UTF8STRINGREF AllocateUtf8String(DWORD cchStringLength) if (cchStringLength > 0x7FFFFFBF) ThrowOutOfMemory(); - SIZE_T ObjectSize = PtrAlign(Utf8StringObject::GetSize(cchStringLength)); - _ASSERTE(ObjectSize > cchStringLength); + SIZE_T totalSize = PtrAlign(Utf8StringObject::GetSize(cchStringLength)); + _ASSERTE(totalSize > cchStringLength); SetTypeHandleOnThreadForAlloc(TypeHandle(g_pUtf8StringClass)); - orObject = (Utf8StringObject *)Alloc(ObjectSize, GC_ALLOC_NO_FLAGS); + GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS; + if (totalSize >= g_pConfig->GetGCLOHThreshold()) + flags |= GC_ALLOC_LARGE_OBJECT_HEAP; - // Object is zero-init already - _ASSERTE(orObject->HasEmptySyncBlockInfo()); + Utf8StringObject* orString = (Utf8StringObject*)Alloc(totalSize, flags); // Initialize Object - orObject->SetMethodTable(g_pUtf8StringClass); - orObject->SetLength(cchStringLength); - - bool bProfilerNotifyLargeAllocation = false; - - if (ObjectSize >= g_pConfig->GetGCLOHThreshold()) - { - GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orObject); - bProfilerNotifyLargeAllocation = TrackLargeAllocations(); - } - - // Notify the profiler of the allocation - if (TrackAllocations() || bProfilerNotifyLargeAllocation) - { - OBJECTREF objref = ObjectToOBJECTREF((Object*)orObject); - GCPROTECT_BEGIN(objref); - ProfilerObjectAllocatedCallback(objref, (ClassID)orObject->GetTypeHandle().AsPtr()); - GCPROTECT_END(); - - orObject = (Utf8StringObject *)OBJECTREFToObject(objref); - } + orString->SetMethodTable(g_pUtf8StringClass); + orString->SetLength(cchStringLength); -#ifdef FEATURE_EVENT_TRACE - // Send ETW event for allocation - if (ETW::TypeSystemLog::IsHeapAllocEventEnabled()) - { - ETW::TypeSystemLog::SendObjectAllocatedEvent(orObject); - } -#endif // FEATURE_EVENT_TRACE - - LogAlloc(ObjectSize, g_pUtf8StringClass, orObject); - - return( ObjectToUTF8STRINGREF(orObject) ); + PublishObjectAndNotify(orString, flags); + return ObjectToUTF8STRINGREF(orString); } #endif // FEATURE_UTF8STRING @@ -1073,9 +994,16 @@ OBJECTREF AllocateObject(MethodTable *pMT #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION #endif // FEATURE_COMINTEROP { - DWORD baseSize = pMT->GetBaseSize(); - GC_ALLOC_FLAGS flags = ((pMT->ContainsPointers() ? GC_ALLOC_CONTAINS_REF : GC_ALLOC_NO_FLAGS) | - (pMT->HasFinalizer() ? GC_ALLOC_FINALIZE : GC_ALLOC_NO_FLAGS)); + GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS; + if (pMT->ContainsPointers()) + flags |= GC_ALLOC_CONTAINS_REF; + + if (pMT->HasFinalizer()) + flags |= GC_ALLOC_FINALIZE; + + DWORD totalSize = pMT->GetBaseSize(); + if (totalSize >= g_pConfig->GetGCLOHThreshold()) + flags |= GC_ALLOC_LARGE_OBJECT_HEAP; #ifdef FEATURE_64BIT_ALIGNMENT if (pMT->RequiresAlign8()) @@ -1089,50 +1017,22 @@ OBJECTREF AllocateObject(MethodTable *pMT _ASSERTE(sizeof(Object) == 4); flags |= GC_ALLOC_ALIGN8; if (pMT->IsValueType()) - { flags |= GC_ALLOC_ALIGN8_BIAS; - } } #endif // FEATURE_64BIT_ALIGNMENT - Object* orObject = (Object*)Alloc(baseSize, flags); - - // verify zero'd memory (at least for sync block) - _ASSERTE( orObject->HasEmptySyncBlockInfo() ); + Object* orObject = (Object*)Alloc(totalSize, flags); - bool bProfilerNotifyLargeAllocation = false; - if ((baseSize >= g_pConfig->GetGCLOHThreshold())) + if (flags & GC_ALLOC_USER_OLD_HEAP) { - orObject->SetMethodTableForLargeObject(pMT); - bProfilerNotifyLargeAllocation = TrackLargeAllocations(); - GCHeapUtilities::GetGCHeap()->PublishObject((BYTE*)orObject); + orObject->SetMethodTableForUOHObject(pMT); } else { orObject->SetMethodTable(pMT); } - // Notify the profiler of the allocation - if (TrackAllocations() || bProfilerNotifyLargeAllocation) - { - OBJECTREF objref = ObjectToOBJECTREF((Object*)orObject); - GCPROTECT_BEGIN(objref); - ProfilerObjectAllocatedCallback(objref, (ClassID) orObject->GetTypeHandle().AsPtr()); - GCPROTECT_END(); - - orObject = (Object *) OBJECTREFToObject(objref); - } - -#ifdef FEATURE_EVENT_TRACE - // Send ETW event for allocation - if(ETW::TypeSystemLog::IsHeapAllocEventEnabled()) - { - ETW::TypeSystemLog::SendObjectAllocatedEvent(orObject); - } -#endif // FEATURE_EVENT_TRACE - - LogAlloc(pMT->GetBaseSize(), pMT, orObject); - + PublishObjectAndNotify(orObject, flags); oref = OBJECTREF_TO_UNCHECKED_OBJECTREF(orObject); } @@ -1466,7 +1366,7 @@ void ErectWriteBarrierForMT(MethodTable **dst, MethodTable *ref) #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - BYTE *refObject = *(BYTE **)((MethodTable*)ref)->GetLoaderAllocatorObjectHandle(); + BYTE *refObject = *(BYTE **)ref->GetLoaderAllocatorObjectHandle(); if((BYTE*) refObject >= g_ephemeral_low && (BYTE*) refObject < g_ephemeral_high) { // VolatileLoadWithoutBarrier() is used here to prevent fetch of g_card_table from being reordered diff --git a/src/coreclr/src/vm/gchelpers.h b/src/coreclr/src/vm/gchelpers.h index 5fe51ce6c77df3..9cf70b12d78307 100644 --- a/src/coreclr/src/vm/gchelpers.h +++ b/src/coreclr/src/vm/gchelpers.h @@ -21,12 +21,12 @@ //======================================================================== // Allocate single-dimensional array given array type -OBJECTREF AllocateSzArray(MethodTable *pArrayMT, INT32 length, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS, BOOL bAllocateInLargeHeap = FALSE); -OBJECTREF AllocateSzArray(TypeHandle arrayType, INT32 length, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS, BOOL bAllocateInLargeHeap = FALSE); +OBJECTREF AllocateSzArray(MethodTable *pArrayMT, INT32 length, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS); +OBJECTREF AllocateSzArray(TypeHandle arrayType, INT32 length, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS); // The main Array allocation routine, can do multi-dimensional -OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS, BOOL bAllocateInLargeHeap = FALSE); -OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS, BOOL bAllocateInLargeHeap = FALSE); +OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS); +OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS); // Create a SD array of primitive types given an element type OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements); diff --git a/src/coreclr/src/vm/gctoclreventsink.cpp b/src/coreclr/src/vm/gctoclreventsink.cpp index 1389d417737c2e..a9bc4bd7654d17 100644 --- a/src/coreclr/src/vm/gctoclreventsink.cpp +++ b/src/coreclr/src/vm/gctoclreventsink.cpp @@ -25,6 +25,7 @@ void GCToCLREventSink::FireDynamicEvent(const char* eventName, void* payload, ui void GCToCLREventSink::FireGCStart_V2(uint32_t count, uint32_t depth, uint32_t reason, uint32_t type) { +#ifdef FEATURE_EVENT_TRACE LIMITED_METHOD_CONTRACT; ETW::GCLog::ETW_GC_INFO gcStartInfo; @@ -33,6 +34,7 @@ void GCToCLREventSink::FireGCStart_V2(uint32_t count, uint32_t depth, uint32_t r gcStartInfo.GCStart.Reason = static_cast(reason); gcStartInfo.GCStart.Type = static_cast(type); ETW::GCLog::FireGcStart(&gcStartInfo); +#endif } void GCToCLREventSink::FireGCGenerationRange(uint8_t generation, void* rangeStart, uint64_t rangeUsedLength, uint64_t rangeReservedLength) diff --git a/src/coreclr/src/vm/hosting.cpp b/src/coreclr/src/vm/hosting.cpp index 78db9389dd7380..95cf5ee6e46319 100644 --- a/src/coreclr/src/vm/hosting.cpp +++ b/src/coreclr/src/vm/hosting.cpp @@ -3,12 +3,9 @@ // See the LICENSE file in the project root for more information. // -// - #include "common.h" -#include "hosting.h" #include "mscoree.h" #include "corhost.h" #include "threads.h" @@ -20,7 +17,7 @@ HANDLE g_ExecutableHeapHandle = NULL; #undef VirtualAlloc -LPVOID EEVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) { +LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) { CONTRACTL { NOTHROW; @@ -36,7 +33,10 @@ LPVOID EEVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, D #ifdef _DEBUG if (g_fEEStarted) { - _ASSERTE (!EEAllocationDisallowed()); + // On Debug build we make sure that a thread is not going to do memory allocation + // after it suspends another thread, since the another thread may be suspended while + // having OS Heap lock. + _ASSERTE (Thread::Debug_AllowCallout()); } _ASSERTE (lpAddress || (dwSize % g_SystemInfo.dwAllocationGranularity) == 0); #endif @@ -89,7 +89,7 @@ LPVOID EEVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, D #define VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect) Dont_Use_VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect) #undef VirtualFree -BOOL EEVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) { +BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) { CONTRACTL { NOTHROW; @@ -102,7 +102,7 @@ BOOL EEVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) { #define VirtualFree(lpAddress, dwSize, dwFreeType) Dont_Use_VirtualFree(lpAddress, dwSize, dwFreeType) #undef VirtualQuery -SIZE_T EEVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) +SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) { CONTRACTL { @@ -117,8 +117,14 @@ SIZE_T EEVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZ } #define VirtualQuery(lpAddress, lpBuffer, dwLength) Dont_Use_VirtualQuery(lpAddress, lpBuffer, dwLength) +#if defined(_DEBUG) && !defined(TARGET_UNIX) +static VolatilePtr s_pStartOfUEFSection = NULL; +static VolatilePtr s_pEndOfUEFSectionBoundary = NULL; +static Volatile s_dwProtection = 0; +#endif // _DEBUG && !TARGET_UNIX + #undef VirtualProtect -BOOL EEVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) +BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) { CONTRACTL { @@ -127,14 +133,120 @@ BOOL EEVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWOR } CONTRACTL_END; + // Get the UEF installation details - we will use these to validate + // that the calls to ClrVirtualProtect are not going to affect the UEF. + // + // The OS UEF invocation mechanism was updated. When a UEF is setup,the OS captures + // the following details about it: + // 1) Protection of the pages in which the UEF lives + // 2) The size of the region in which the UEF lives + // 3) The region's Allocation Base + // + // The OS verifies details surrounding the UEF before invocation. For security reasons + // the page protection cannot change between SetUnhandledExceptionFilter and invocation. + // + // Prior to this change, the UEF lived in a common section of code_Seg, along with + // JIT_PatchedCode. Thus, their pages have the same protection, they live + // in the same region (and thus, its size is the same). + // + // In EEStartupHelper, when we setup the UEF and then invoke InitJitHelpers1 and InitJitHelpers2, + // they perform some optimizations that result in the memory page protection being changed. When + // the UEF is to be invoked, the OS does the check on the UEF's cached details against the current + // memory pages. This check used to fail when on 64bit retail builds when JIT_PatchedCode was + // aligned after the UEF with a different memory page protection (post the optimizations by InitJitHelpers). + // Thus, the UEF was never invoked. + // + // To circumvent this, we put the UEF in its own section in the code segment so that any modifications + // to memory pages will not affect the UEF details that the OS cached. This is done in Excep.cpp + // using the "#pragma code_seg" directives. + // + // Below, we double check that: + // + // 1) the address being protected does not lie in the region of of the UEF. + // 2) the section after UEF is not having the same memory protection as UEF section. + // + // We assert if either of the two conditions above are true. + +#if defined(_DEBUG) && !defined(TARGET_UNIX) + // We do this check in debug/checked builds only + + // Do we have the UEF details? + if (s_pEndOfUEFSectionBoundary.Load() == NULL) { - return ::VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); + CONTRACT_VIOLATION(ThrowsViolation); + + // Get reference to MSCORWKS image in memory... + PEDecoder pe(g_hThisInst); + + // Find the UEF section from the image + IMAGE_SECTION_HEADER* pUEFSection = pe.FindSection(CLR_UEF_SECTION_NAME); + _ASSERTE(pUEFSection != NULL); + if (pUEFSection) + { + // We got our section - get the start of the section + BYTE* pStartOfUEFSection = static_cast(pe.GetBase()) + pUEFSection->VirtualAddress; + s_pStartOfUEFSection = pStartOfUEFSection; + + // Now we need the protection attributes for the memory region in which the + // UEF section is... + MEMORY_BASIC_INFORMATION uefInfo; + if (ClrVirtualQuery(pStartOfUEFSection, &uefInfo, sizeof(uefInfo)) != 0) + { + // Calculate how many pages does the UEF section take to get to the start of the + // next section. We dont calculate this as + // + // pStartOfUEFSection + uefInfo.RegionSize + // + // because the section following UEF will also be included in the region size + // if it has the same protection as the UEF section. + DWORD dwUEFSectionPageCount = ((pUEFSection->Misc.VirtualSize + GetOsPageSize() - 1) / GetOsPageSize()); + + BYTE* pAddressOfFollowingSection = pStartOfUEFSection + (GetOsPageSize() * dwUEFSectionPageCount); + + // Ensure that the section following us is having different memory protection + MEMORY_BASIC_INFORMATION nextSectionInfo; + _ASSERTE(ClrVirtualQuery(pAddressOfFollowingSection, &nextSectionInfo, sizeof(nextSectionInfo)) != 0); + _ASSERTE(nextSectionInfo.Protect != uefInfo.Protect); + + // save the memory protection details + s_dwProtection = uefInfo.Protect; + + // Get the end of the UEF section + BYTE* pEndOfUEFSectionBoundary = pAddressOfFollowingSection - 1; + + // Set the end of UEF section boundary + FastInterlockExchangePointer(s_pEndOfUEFSectionBoundary.GetPointer(), pEndOfUEFSectionBoundary); + } + else + { + _ASSERTE(!"Unable to get UEF Details!"); + } + } } + + if (s_pEndOfUEFSectionBoundary.Load() != NULL) + { + // Is the protection being changed? + if (flNewProtect != s_dwProtection) + { + // Is the target address NOT affecting the UEF ? Possible cases: + // 1) Starts and ends before the UEF start + // 2) Starts after the UEF start + + void* pEndOfRangeAddr = static_cast(lpAddress) + dwSize - 1; + + _ASSERTE_MSG(((pEndOfRangeAddr < s_pStartOfUEFSection.Load()) || (lpAddress > s_pEndOfUEFSectionBoundary.Load())), + "Do not virtual protect the section in which UEF lives!"); + } + } +#endif // _DEBUG && !TARGET_UNIX + + return ::VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); } #define VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect) Dont_Use_VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect) #undef GetProcessHeap -HANDLE EEGetProcessHeap() +HANDLE ClrGetProcessHeap() { // Note: this can be called a little early for real contracts, so we use static contracts instead. STATIC_CONTRACT_NOTHROW; @@ -145,7 +257,7 @@ HANDLE EEGetProcessHeap() #define GetProcessHeap() Dont_Use_GetProcessHeap() #undef HeapCreate -HANDLE EEHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize) +HANDLE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize) { CONTRACTL { @@ -166,7 +278,7 @@ HANDLE EEHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize) #define HeapCreate(flOptions, dwInitialSize, dwMaximumSize) Dont_Use_HeapCreate(flOptions, dwInitialSize, dwMaximumSize) #undef HeapDestroy -BOOL EEHeapDestroy(HANDLE hHeap) +BOOL ClrHeapDestroy(HANDLE hHeap) { CONTRACTL { @@ -196,7 +308,7 @@ BOOL EEHeapDestroy(HANDLE hHeap) #undef HeapAlloc -LPVOID EEHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) +LPVOID ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, S_SIZE_T dwBytes) { STATIC_CONTRACT_NOTHROW; @@ -205,30 +317,30 @@ LPVOID EEHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) return NULL; #endif + if (dwBytes.IsOverflow()) return NULL; + { LPVOID p = NULL; #ifdef _DEBUG // Store the heap handle to detect heap contamination - p = ::HeapAlloc (hHeap, dwFlags, dwBytes + OS_HEAP_ALIGN); + p = ::HeapAlloc (hHeap, dwFlags, dwBytes.Value() + OS_HEAP_ALIGN); if(p) { *((HANDLE*)p) = hHeap; p = (BYTE*)p + OS_HEAP_ALIGN; } #else - p = ::HeapAlloc (hHeap, dwFlags, dwBytes); + p = ::HeapAlloc (hHeap, dwFlags, dwBytes.Value()); #endif if(p == NULL - //under OOM, we might not be able to get Execution Engine and can't access stress log - && GetExecutionEngine () // If we have not created StressLog ring buffer, we should not try to use it. // StressLog is going to do a memory allocation. We may enter an endless loop. && StressLog::t_pCurrentThreadLog != NULL ) { - STRESS_LOG_OOM_STACK(dwBytes); + STRESS_LOG_OOM_STACK(dwBytes.Value()); } return p; @@ -236,20 +348,20 @@ LPVOID EEHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) } #define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes) -LPVOID EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes) +LPVOID ClrHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes) { WRAPPER_NO_CONTRACT; static HANDLE ProcessHeap = NULL; if (ProcessHeap == NULL) - ProcessHeap = EEGetProcessHeap(); + ProcessHeap = ClrGetProcessHeap(); - return EEHeapAlloc(ProcessHeap,dwFlags,dwBytes); + return ClrHeapAlloc(ProcessHeap,dwFlags,S_SIZE_T(dwBytes)); } #undef HeapFree -BOOL EEHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) +BOOL ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; @@ -281,7 +393,7 @@ BOOL EEHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) } #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem) -BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem) +BOOL ClrHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem) { CONTRACTL { @@ -294,29 +406,12 @@ BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem) static HANDLE ProcessHeap = NULL; if (ProcessHeap == NULL) - ProcessHeap = EEGetProcessHeap(); + ProcessHeap = ClrGetProcessHeap(); - return EEHeapFree(ProcessHeap,dwFlags,lpMem); + return ClrHeapFree(ProcessHeap,dwFlags,lpMem); } - -#undef HeapValidate -BOOL EEHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) { - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - -#ifndef TARGET_UNIX - - { - return ::HeapValidate(hHeap, dwFlags, lpMem); - } -#else // !TARGET_UNIX - return TRUE; -#endif // !TARGET_UNIX -} -#define HeapValidate(hHeap, dwFlags, lpMem) Dont_Use_HeapValidate(hHeap, dwFlags, lpMem) - -HANDLE EEGetProcessExecutableHeap() { +HANDLE ClrGetProcessExecutableHeap() { // Note: this can be called a little early for real contracts, so we use static contracts instead. STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; @@ -363,7 +458,7 @@ HANDLE EEGetProcessExecutableHeap() { #undef SleepEx #undef Sleep -DWORD EESleepEx(DWORD dwMilliseconds, BOOL bAlertable) +DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable) { CONTRACTL { @@ -490,7 +585,7 @@ static inline Crst *CookieToCrst(CRITSEC_COOKIE cookie) { return (Crst *) cookie; } -CRITSEC_COOKIE EECreateCriticalSection(CrstType crstType, CrstFlags flags) { +CRITSEC_COOKIE ClrCreateCriticalSection(CrstType crstType, CrstFlags flags) { CONTRACTL { NOTHROW; @@ -518,7 +613,7 @@ CRITSEC_COOKIE EECreateCriticalSection(CrstType crstType, CrstFlags flags) { return ret; } -void EEDeleteCriticalSection(CRITSEC_COOKIE cookie) +void ClrDeleteCriticalSection(CRITSEC_COOKIE cookie) { CONTRACTL { @@ -533,7 +628,7 @@ void EEDeleteCriticalSection(CRITSEC_COOKIE cookie) delete pCrst; } -DEBUG_NOINLINE void EEEnterCriticalSection(CRITSEC_COOKIE cookie) { +DEBUG_NOINLINE void ClrEnterCriticalSection(CRITSEC_COOKIE cookie) { // Entering a critical section has many different contracts // depending on the flags used to initialize the critical section. @@ -555,7 +650,7 @@ DEBUG_NOINLINE void EEEnterCriticalSection(CRITSEC_COOKIE cookie) { pCrst->Enter(); } -DEBUG_NOINLINE void EELeaveCriticalSection(CRITSEC_COOKIE cookie) +DEBUG_NOINLINE void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie) { CONTRACTL { @@ -571,18 +666,3 @@ DEBUG_NOINLINE void EELeaveCriticalSection(CRITSEC_COOKIE cookie) pCrst->Leave(); } - -BOOL EEAllocationDisallowed() -{ - WRAPPER_NO_CONTRACT; - -#ifdef _DEBUG - // On Debug build we make sure that a thread is not going to do memory allocation - // after it suspends another thread, since the another thread may be suspended while - // having OS Heap lock. - return !Thread::Debug_AllowCallout(); -#else - return FALSE; -#endif -} - diff --git a/src/coreclr/src/vm/hosting.h b/src/coreclr/src/vm/hosting.h deleted file mode 100644 index b4e6fd8ebc3864..00000000000000 --- a/src/coreclr/src/vm/hosting.h +++ /dev/null @@ -1,57 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -// - - -#ifndef __HOSTING_H__ -#define __HOSTING_H__ - -#include "clrhost.h" - -#define ClrVirtualAlloc EEVirtualAlloc -#define ClrVirtualFree EEVirtualFree -#define ClrVirtualQuery EEVirtualQuery -#define ClrVirtualProtect EEVirtualProtect -#define ClrHeapCreate EEHeapCreate -#define ClrHeapDestroy EEHeapDestroy -#define ClrHeapAlloc EEHeapAlloc -#define ClrHeapFree EEHeapFree -#define ClrHeapValidate EEHeapValidate -#define ClrCreateCriticalSection EECreateCriticalSection -#define ClrDestroyCriticalSection EEDestroyCriticalSection -#define ClrEnterCriticalSection EEEnterCriticalSection -#define ClrLeaveCriticalSection EELeaveCriticalSection -#define ClrSleepEx EESleepEx -#define ClrTlsSetValue EETlsSetValue -#define ClrTlsGetValue EETlsGetValue - -#define ClrAllocationDisallowed EEAllocationDisallowed - -// memory management function -LPVOID EEVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); -BOOL EEVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); -SIZE_T EEVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength); -BOOL EEVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); -HANDLE EEGetProcessHeap(); -HANDLE EEHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); -BOOL EEHeapDestroy(HANDLE hHeap); -LPVOID EEHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); -BOOL EEHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); -BOOL EEHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); - -BOOL EEAllocationDisallowed(); -HANDLE EEGetProcessExecutableHeap(); - -// critical section functions -CRITSEC_COOKIE EECreateCriticalSection(CrstType crstType, CrstFlags flags); -void EEDeleteCriticalSection(CRITSEC_COOKIE cookie); -void EEEnterCriticalSection(CRITSEC_COOKIE cookie); -void EELeaveCriticalSection(CRITSEC_COOKIE cookie); - -DWORD EESleepEx(DWORD dwMilliseconds, BOOL bAlertable); - -#endif - diff --git a/src/coreclr/src/vm/i386/jitinterfacex86.cpp b/src/coreclr/src/vm/i386/jitinterfacex86.cpp index 566668770ea207..edc3fa1270ab3e 100644 --- a/src/coreclr/src/vm/i386/jitinterfacex86.cpp +++ b/src/coreclr/src/vm/i386/jitinterfacex86.cpp @@ -717,7 +717,7 @@ void *JIT_TrialAlloc::GenAllocString(Flags flags) // we need to load the method table for string from the global - // mov ecx, [g_pStringMethodTable] + // mov ecx, [g_pStringClass] sl.Emit16(0x0d8b); sl.Emit32((int)(size_t)&g_pStringClass); diff --git a/src/coreclr/src/vm/ilmarshalers.cpp b/src/coreclr/src/vm/ilmarshalers.cpp index a9257e048bf705..ec846aaadc624b 100644 --- a/src/coreclr/src/vm/ilmarshalers.cpp +++ b/src/coreclr/src/vm/ilmarshalers.cpp @@ -4515,7 +4515,7 @@ void MngdNativeArrayMarshaler::DoClearNativeContents(MngdNativeArrayMarshaler* p if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL) { - pMarshaler->ClearOleArray((BASEARRAYREF*)pManagedHome, *pNativeHome, cElements, pThis->m_pElementMT, pThis->m_pManagedMarshaler); + pMarshaler->ClearOleArray(*pNativeHome, cElements, pThis->m_pElementMT, pThis->m_pManagedMarshaler); } } } @@ -4733,15 +4733,13 @@ FCIMPL3(void, MngdFixedArrayMarshaler::ClearNativeContents, MngdFixedArrayMarsha { FCALL_CONTRACT; - BASEARRAYREF arrayRef = (BASEARRAYREF)*pManagedHome; - - HELPER_METHOD_FRAME_BEGIN_1(arrayRef); + HELPER_METHOD_FRAME_BEGIN_0(); const OleVariant::Marshaler* pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, FALSE); if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL) { - pMarshaler->ClearOleArray(&arrayRef, pNativeHome, pThis->m_cElements, pThis->m_pElementMT, pThis->m_pManagedElementMarshaler); + pMarshaler->ClearOleArray(pNativeHome, pThis->m_cElements, pThis->m_pElementMT, pThis->m_pManagedElementMarshaler); } HELPER_METHOD_FRAME_END(); diff --git a/src/coreclr/src/vm/jithelpers.cpp b/src/coreclr/src/vm/jithelpers.cpp index 6fcb1c82d6d671..8d64b2629fffa9 100644 --- a/src/coreclr/src/vm/jithelpers.cpp +++ b/src/coreclr/src/vm/jithelpers.cpp @@ -54,6 +54,7 @@ #include "runtimehandles.h" #include "castcache.h" +#include "onstackreplacement.h" //======================================================================== // @@ -2608,7 +2609,7 @@ HCIMPL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, IN _ASSERTE(allocPtr != nullptr); ArrayBase *array = reinterpret_cast(allocPtr); - array->SetArrayMethodTable(pArrayMT); + array->SetMethodTable(pArrayMT); _ASSERTE(static_cast(componentCount) == componentCount); array->m_NumComponents = static_cast(componentCount); @@ -2667,7 +2668,7 @@ HCIMPL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, I _ASSERTE(allocPtr != nullptr); ArrayBase *array = reinterpret_cast(allocPtr); - array->SetArrayMethodTable(pArrayMT); + array->SetMethodTable(pArrayMT); _ASSERTE(static_cast(componentCount) == componentCount); array->m_NumComponents = static_cast(componentCount); @@ -5004,6 +5005,331 @@ HCIMPL0(void, JIT_DebugLogLoopCloning) } HCIMPLEND +#ifdef FEATURE_ON_STACK_REPLACEMENT + +// Helper method to jit the OSR version of a method. +// +// Returns the address of the jitted code. +// Returns NULL if osr method can't be created. +static PCODE JitPatchpointWorker(MethodDesc* pMD, EECodeInfo& codeInfo, int ilOffset) +{ + PCODE osrVariant = NULL; + + GCX_PREEMP(); + + // Fetch the patchpoint info for the current method + EEJitManager* jitMgr = ExecutionManager::GetEEJitManager(); + CodeHeader* codeHdr = jitMgr->GetCodeHeaderFromStartAddress(codeInfo.GetStartAddress()); + PTR_BYTE debugInfo = codeHdr->GetDebugInfo(); + PatchpointInfo* patchpointInfo = CompressDebugInfo::RestorePatchpointInfo(debugInfo); + + if (patchpointInfo == NULL) + { + // Unexpected, but not fatal + STRESS_LOG1(LF_TIEREDCOMPILATION, LL_WARNING, "JitPatchpointWorker: failed to restore patchpoint info for Method=0x%pM\n", pMD); + return NULL; + } + + // Set up a new native code version for the OSR variant of this method. + NativeCodeVersion osrNativeCodeVersion; + { + CodeVersionManager::LockHolder codeVersioningLockHolder; + + NativeCodeVersion currentNativeCodeVersion = codeInfo.GetNativeCodeVersion(); + ILCodeVersion ilCodeVersion = currentNativeCodeVersion.GetILCodeVersion(); + HRESULT hr = ilCodeVersion.AddNativeCodeVersion(pMD, NativeCodeVersion::OptimizationTier1OSR, &osrNativeCodeVersion, patchpointInfo, ilOffset); + if (FAILED(hr)) + { + // Unexpected, but not fatal + STRESS_LOG1(LF_TIEREDCOMPILATION, LL_WARNING, "JitPatchpointWorker: failed to add native code version for Method=0x%pM\n", pMD); + return NULL; + } + } + + // Invoke the jit to compile the OSR version + LOG((LF_TIEREDCOMPILATION, LL_INFO10, "JitPatchpointWorker: creating OSR version of Method=0x%pM (%s::%s) at offset %d\n", + pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); + + PrepareCodeConfigBuffer configBuffer(osrNativeCodeVersion); + PrepareCodeConfig *config = configBuffer.GetConfig(); + osrVariant = pMD->PrepareCode(config); + + return osrVariant; +} + +// Helper method wrapper to set up a frame so we can invoke methods that might GC +HCIMPL3(PCODE, JIT_Patchpoint_Framed, MethodDesc* pMD, EECodeInfo& codeInfo, int ilOffset) +{ + PCODE result = NULL; + + HELPER_METHOD_FRAME_BEGIN_RET_0(); + + result = JitPatchpointWorker(pMD, codeInfo, ilOffset); + + HELPER_METHOD_FRAME_END(); + + return result; +} +HCIMPLEND + +// Jit helper invoked at a patchpoint. +// +// Checks to see if this is a known patchpoint, if not, +// an entry is added to the patchpoint table. +// +// When the patchpoint has been hit often enough to trigger +// a transition, create an OSR method. +// +// Currently, counter is a pointer into the Tier0 method stack +// frame so we have exclusive access. + +void JIT_Patchpoint(int* counter, int ilOffset) +{ + // This method may not return normally + STATIC_CONTRACT_GC_NOTRIGGER; + STATIC_CONTRACT_MODE_COOPERATIVE; + + // Patchpoint identity is the helper return address + PCODE ip = (PCODE)_ReturnAddress(); + + // Fetch or setup patchpoint info for this patchpoint. + EECodeInfo codeInfo(ip); + MethodDesc* pMD = codeInfo.GetMethodDesc(); + LoaderAllocator* allocator = pMD->GetLoaderAllocator(); + OnStackReplacementManager* manager = allocator->GetOnStackReplacementManager(); + PerPatchpointInfo * ppInfo = manager->GetPerPatchpointInfo(ip); + + // In the current prototype, counter is shared by all patchpoints + // in a method, so no matter what happens below, we don't want to + // impair those other patchpoints. + // + // One might be tempted, for instance, to set the counter for + // invalid or ignored patchpoints to some high value to reduce + // the amount of back and forth with the runtime, but this would + // lock out other patchpoints in the method. + // + // So we always reset the counter to the bump value. + // + // In the prototype, counter is a location in a stack frame, + // so we can update it without worrying about other threads. + const int counterBump = g_pConfig->OSR_CounterBump(); + *counter = counterBump; + +#if _DEBUG + const int ppId = ppInfo->m_patchpointId; +#endif + + // Is this a patchpoint that was previously marked as invalid? If so, just return to the Tier0 method. + if ((ppInfo->m_flags & PerPatchpointInfo::patchpoint_invalid) == PerPatchpointInfo::patchpoint_invalid) + { + LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "Jit_Patchpoint: invalid patchpoint [%d] (0x%p) in Method=0x%pM (%s::%s) at offset %d\n", + ppId, ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); + return; + } + + // See if we have an OSR method for this patchpoint. + PCODE osrMethodCode = ppInfo->m_osrMethodCode; + bool isNewMethod = false; + + if (osrMethodCode == NULL) + { + // No OSR method yet, let's see if we should create one. + // + // First, optionally ignore some patchpoints to increase + // coverage (stress mode). + // + // Because there are multiple patchpoints in a method, and + // each OSR method covers the remainder of the method from + // that point until the method returns, if we trigger on an + // early patchpoint in a method, we may never see triggers on + // a later one. + +#ifdef _DEBUG + const int lowId = g_pConfig->OSR_LowId(); + const int highId = g_pConfig->OSR_HighId(); + + if ((ppId < lowId) || (ppId > highId)) + { + LOG((LF_TIEREDCOMPILATION, LL_INFO10, "Jit_Patchpoint: ignoring patchpoint [%d] (0x%p) in Method=0x%pM (%s::%s) at offset %d\n", + ppId, ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); + return; + } +#endif + + // Second, only request the OSR method if this patchpoint has + // been hit often enough. + // + // Note the initial invocation of the helper depends on the + // initial counter value baked into jitted code (call this J); + // subsequent invocations depend on the counter bump (call + // this B). + // + // J and B may differ, so the total number of loop iterations + // before an OSR method is created is: + // + // J, if hitLimit <= 1; + // J + (hitLimit-1)* B, if hitLimit > 1; + // + // Current thinking is: + // + // J should be in the range of tens to hundreds, so that newly + // called Tier0 methods that already have OSR methods + // available can transition to OSR methods quickly, but + // methods called only a few times do not invoke this + // helper and so create PerPatchpoint runtime state. + // + // B should be in the range of hundreds to thousands, so that + // we're not too eager to create OSR methods (since there is + // some jit cost), but are eager enough to transition before + // we run too much Tier0 code. + // + const int hitLimit = g_pConfig->OSR_HitLimit(); + const int hitCount = InterlockedIncrement(&ppInfo->m_patchpointCount); + const int hitLogLevel = (hitCount == 1) ? LL_INFO10 : LL_INFO1000; + + LOG((LF_TIEREDCOMPILATION, hitLogLevel, "Jit_Patchpoint: patchpoint [%d] (0x%p) hit %d in Method=0x%pM (%s::%s) [il offset %d] (limit %d)\n", + ppId, ip, hitCount, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset, hitLimit)); + + // Defer, if we haven't yet reached the limit + if (hitCount < hitLimit) + { + return; + } + + // Third, make sure no other thread is trying to create the OSR method. + LONG oldFlags = ppInfo->m_flags; + if ((oldFlags & PerPatchpointInfo::patchpoint_triggered) == PerPatchpointInfo::patchpoint_triggered) + { + LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "Jit_Patchpoint: AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, ip)); + return; + } + + LONG newFlags = ppInfo->m_flags | PerPatchpointInfo::patchpoint_triggered; + BOOL triggerTransition = InterlockedCompareExchange(&ppInfo->m_flags, newFlags, oldFlags) == oldFlags; + + if (!triggerTransition) + { + LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "Jit_Patchpoint: (lost race) AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, ip)); + return; + } + + // Time to create the OSR method. + // + // We currently do this synchronously. We could instead queue + // up a request on some worker thread, like we do for + // rejitting, and return control to the Tier0 method. It may + // eventually return here, if the patchpoint is hit often + // enough. + // + // There is a chance the async version will create methods + // that are never used (just like there is a chance that Tier1 + // methods are ever called). + // + // In this prototype we want to expose bugs in the jitted code + // for OSR methods, so we stick with synchronous creation. + LOG((LF_TIEREDCOMPILATION, LL_INFO10, "Jit_Patchpoint: patchpoint [%d] (0x%p) TRIGGER at count %d\n", ppId, ip, hitCount)); + + // Invoke the helper to build the OSR method + osrMethodCode = HCCALL3(JIT_Patchpoint_Framed, pMD, codeInfo, ilOffset); + + // If that failed, mark the patchpoint as invalid. + if (osrMethodCode == NULL) + { + // Unexpected, but not fatal + STRESS_LOG4(LF_TIEREDCOMPILATION, LL_WARNING, "Jit_Patchpoint: patchpoint (0x%p) OSR method creation failed," + " marking patchpoint invalid for Method=0x%pM il offset %d\n", ip, hitCount, pMD, ilOffset); + + InterlockedOr(&ppInfo->m_flags, (LONG)PerPatchpointInfo::patchpoint_invalid); + return; + } + + // We've successfully created the osr method; make it available. + _ASSERTE(ppInfo->m_osrMethodCode == NULL); + ppInfo->m_osrMethodCode = osrMethodCode; + isNewMethod = true; + } + + // If we get here, we have code to transition to... + _ASSERTE(osrMethodCode != NULL); + + Thread *pThread = GetThread(); + +#ifdef FEATURE_HIJACK + // We can't crawl the stack of a thread that currently has a hijack pending + // (since the hijack routine won't be recognized by any code manager). So we + // Undo any hijack, the EE will re-attempt it later. + pThread->UnhijackThread(); +#endif + + // Find context for the original method + CONTEXT frameContext; + frameContext.ContextFlags = CONTEXT_FULL; + RtlCaptureContext(&frameContext); + + // Walk back to the original method frame + pThread->VirtualUnwindToFirstManagedCallFrame(&frameContext); + + // Remember original method FP and SP because new method will inherit them. + UINT_PTR currentSP = GetSP(&frameContext); + UINT_PTR currentFP = GetFP(&frameContext); + + // We expect to be back at the right IP + if ((UINT_PTR)ip != GetIP(&frameContext)) + { + // Should be fatal + STRESS_LOG2(LF_TIEREDCOMPILATION, LL_INFO10, "Jit_Patchpoint: patchpoint (0x%p) TRANSITION" + " unexpected context IP 0x%p\n", ip, GetIP(&frameContext)); + } + + // Now unwind back to the original method caller frame. + EECodeInfo callerCodeInfo(GetIP(&frameContext)); + frameContext.ContextFlags = CONTEXT_FULL; + ULONG_PTR establisherFrame = 0; + PVOID handlerData = NULL; + RtlVirtualUnwind(UNW_FLAG_NHANDLER, callerCodeInfo.GetModuleBase(), GetIP(&frameContext), callerCodeInfo.GetFunctionEntry(), + &frameContext, &handlerData, &establisherFrame, NULL); + + // Now, set FP and SP back to the values they had just before this helper was called, + // since the new method must have access to the original method frame. + // + // TODO: if we access the patchpointInfo here, we can read out the FP-SP delta from there and + // use that to adjust the stack, likely saving some stack space. + +#if defined(TARGET_AMD64) + // If calls push the return address, we need to simulate that here, so the OSR + // method sees the "expected" SP misalgnment on entry. + _ASSERTE(currentSP % 16 == 0); + currentSP -= 8; +#endif + + SetSP(&frameContext, currentSP); + frameContext.Rbp = currentFP; + + // Note we can get here w/o triggering, if there is an existing OSR method and + // we hit the patchpoint. + const int transitionLogLevel = isNewMethod ? LL_INFO10 : LL_INFO1000; + LOG((LF_TIEREDCOMPILATION, transitionLogLevel, "Jit_Patchpoint: patchpoint [%d] (0x%p) TRANSITION to ip 0x%p\n", ppId, ip, osrMethodCode)); + + // Install new entry point as IP + SetIP(&frameContext, osrMethodCode); + + // Transition! + RtlRestoreContext(&frameContext, NULL); +} + +#else + +void JIT_Patchpoint(int* counter, int ilOffset) +{ + // Stub version if OSR feature is disabled + // + // Should not be called. + + UNREACHABLE(); +} + +#endif // FEATURE_ON_STACK_REPLACEMENT + //======================================================================== // // INTEROP HELPERS @@ -5177,7 +5503,7 @@ void InitJITHelpers2() g_pJitGenericHandleCacheCrst.Init(CrstJitGenericHandleCache, CRST_UNSAFE_COOPGC); - // Allocate and initialize the table + // Allocate and initialize the generic handle cache NewHolder tempGenericHandleCache (new JitGenericHandleCache()); LockOwner sLock = {&g_pJitGenericHandleCacheCrst, IsOwnerOfCrst}; if (!tempGenericHandleCache->Init(59, &sLock)) @@ -5558,10 +5884,10 @@ void InitJitHelperLogging() { #ifdef TARGET_X86 - IMAGE_DOS_HEADER *pDOS = (IMAGE_DOS_HEADER *)g_pMSCorEE; + IMAGE_DOS_HEADER *pDOS = (IMAGE_DOS_HEADER *)g_hThisInst; _ASSERTE(pDOS->e_magic == VAL16(IMAGE_DOS_SIGNATURE) && pDOS->e_lfanew != 0); - IMAGE_NT_HEADERS *pNT = (IMAGE_NT_HEADERS*)((LPBYTE)g_pMSCorEE + VAL32(pDOS->e_lfanew)); + IMAGE_NT_HEADERS *pNT = (IMAGE_NT_HEADERS*)((LPBYTE)g_hThisInst + VAL32(pDOS->e_lfanew)); #ifdef HOST_64BIT _ASSERTE(pNT->Signature == VAL32(IMAGE_NT_SIGNATURE) && pNT->FileHeader.SizeOfOptionalHeader == VAL16(sizeof(IMAGE_OPTIONAL_HEADER64)) @@ -5665,7 +5991,7 @@ void InitJitHelperLogging() #else // TARGET_X86 // Is the address in mscoree.dll at all? (All helpers are in // mscoree.dll) - if (dynamicHlpFunc->pfnHelper >= (LPBYTE*)g_pMSCorEE && dynamicHlpFunc->pfnHelper < (LPBYTE*)g_pMSCorEE + VAL32(pNT->OptionalHeader.SizeOfImage)) + if (dynamicHlpFunc->pfnHelper >= (LPBYTE*)g_hThisInst && dynamicHlpFunc->pfnHelper < (LPBYTE*)g_hThisInst + VAL32(pNT->OptionalHeader.SizeOfImage)) { // See note above. How do I get the size on x86 for a static method? hlpFuncCount->helperSize = 0; diff --git a/src/coreclr/src/vm/jitinterface.cpp b/src/coreclr/src/vm/jitinterface.cpp index 458085486fbf72..60c4b413fab3de 100644 --- a/src/coreclr/src/vm/jitinterface.cpp +++ b/src/coreclr/src/vm/jitinterface.cpp @@ -7746,6 +7746,7 @@ getMethodInfoHelper( &methInfo->locals, ftn, true); + } // getMethodInfoHelper //--------------------------------------------------------------------------------------- @@ -10967,6 +10968,50 @@ void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo EE_TO_JIT_TRANSITION(); } +void CEEJitInfo::setPatchpointInfo(PatchpointInfo* patchpointInfo) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION(); + +#ifdef FEATURE_ON_STACK_REPLACEMENT + // We receive ownership of the array + _ASSERTE(m_pPatchpointInfoFromJit == NULL); + m_pPatchpointInfoFromJit = patchpointInfo; +#else + UNREACHABLE(); +#endif + + EE_TO_JIT_TRANSITION(); +} + +PatchpointInfo* CEEJitInfo::getOSRInfo(unsigned* ilOffset) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + PatchpointInfo* result = NULL; + *ilOffset = 0; + + JIT_TO_EE_TRANSITION(); + +#ifdef FEATURE_ON_STACK_REPLACEMENT + result = m_pPatchpointInfoFromRuntime; + *ilOffset = m_ilOffset; +#endif + + EE_TO_JIT_TRANSITION(); + + return result; +} + void CEEJitInfo::CompressDebugInfo() { CONTRACTL { @@ -10975,11 +11020,20 @@ void CEEJitInfo::CompressDebugInfo() MODE_PREEMPTIVE; } CONTRACTL_END; +#ifdef FEATURE_ON_STACK_REPLACEMENT + PatchpointInfo* patchpointInfo = m_pPatchpointInfoFromJit; +#else + PatchpointInfo* patchpointInfo = NULL; +#endif + // Don't track JIT info for DynamicMethods. if (m_pMethodBeingCompiled->IsDynamicMethod() && !g_pConfig->GetTrackDynamicMethodDebugInfo()) + { + _ASSERTE(patchpointInfo == NULL); return; + } - if (m_iOffsetMapping == 0 && m_iNativeVarInfo == 0) + if ((m_iOffsetMapping == 0) && (m_iNativeVarInfo == 0) && (patchpointInfo == NULL)) return; JIT_TO_EE_TRANSITION(); @@ -10989,6 +11043,7 @@ void CEEJitInfo::CompressDebugInfo() PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars( m_pOffsetMapping, m_iOffsetMapping, m_pNativeVarInfo, m_iNativeVarInfo, + patchpointInfo, NULL, m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap()); @@ -12126,7 +12181,7 @@ CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr, info, CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS, nativeEntry, - nativeSizeOfCode ); + nativeSizeOfCode); #ifdef FEATURE_STACK_SAMPLING if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)) @@ -12688,9 +12743,11 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, flags = GetCompileFlags(ftn, flags, &methodInfo); - // If the reverse P/Invoke flag is used, we aren't going to support - // any tiered compilation. - if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_REVERSE_PINVOKE)) +#ifdef FEATURE_TIERED_COMPILATION + // Clearing all tier flags and mark as optimized if the reverse P/Invoke + // flag is used and the function is eligible. + if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_REVERSE_PINVOKE) + && ftn->IsEligibleForTieredCompilation()) { _ASSERTE(config->GetCallerGCMode() != CallerGCMode::Coop); @@ -12698,10 +12755,9 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_TIER0); flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_TIER1); -#ifdef FEATURE_TIERED_COMPILATION config->SetJitSwitchedToOptimized(); -#endif // FEATURE_TIERED_COMPILATION } +#endif // FEATURE_TIERED_COMPILATION #ifdef _DEBUG if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION)) @@ -12748,6 +12804,16 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, jitInfo.SetReserveForJumpStubs(reserveForJumpStubs); #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + // If this is an OSR jit request, grab the OSR info so we can pass it to the jit + if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_OSR)) + { + unsigned ilOffset = 0; + PatchpointInfo* patchpointInfo = nativeCodeVersion.GetOSRInfo(&ilOffset); + jitInfo.SetOSRInfo(patchpointInfo, ilOffset); + } +#endif + MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(ftnHnd); //Since the check could trigger a demand, we have to do this every time. @@ -13985,6 +14051,18 @@ void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::N UNREACHABLE(); // only called on derived class. } +void CEEInfo::setPatchpointInfo(PatchpointInfo* patchpointInfo) +{ + LIMITED_METHOD_CONTRACT; + UNREACHABLE(); // only called on derived class. +} + +PatchpointInfo* CEEInfo::getOSRInfo(unsigned* ilOffset) +{ + LIMITED_METHOD_CONTRACT; + UNREACHABLE(); // only called on derived class. +} + void* CEEInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ void ** ppIndirection) /* OUT */ { diff --git a/src/coreclr/src/vm/jitinterface.h b/src/coreclr/src/vm/jitinterface.h index b77cd0cf15069e..742ce48f8b9ead 100644 --- a/src/coreclr/src/vm/jitinterface.h +++ b/src/coreclr/src/vm/jitinterface.h @@ -534,6 +534,9 @@ class CEEInfo : public ICorJitInfo CORINFO_CLASS_HANDLE getBuiltinClass(CorInfoClassId classId); void getGSCookie(GSCookie * pCookieVal, GSCookie ** ppCookieVal); + void setPatchpointInfo(PatchpointInfo* patchpointInfo); + PatchpointInfo* getOSRInfo(unsigned* ilOffset); + // "System.Int32" ==> CORINFO_TYPE_INT.. CorInfoType getTypeForPrimitiveValueClass( CORINFO_CLASS_HANDLE cls @@ -1310,6 +1313,15 @@ class CEEJitInfo : public CEEInfo m_iNativeVarInfo = 0; m_pNativeVarInfo = NULL; +#ifdef FEATURE_ON_STACK_REPLACEMENT + if (m_pPatchpointInfoFromJit != NULL) + delete [] ((BYTE*) m_pPatchpointInfoFromJit); + + m_pPatchpointInfoFromJit = NULL; + m_pPatchpointInfoFromRuntime = NULL; + m_ilOffset = 0; +#endif + #ifdef FEATURE_EH_FUNCLETS m_moduleBase = NULL; m_totalUnwindSize = 0; @@ -1372,6 +1384,17 @@ class CEEJitInfo : public CEEInfo } #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + // Called by the runtime to supply patchpoint information to the jit. + void SetOSRInfo(PatchpointInfo* patchpointInfo, unsigned ilOffset) + { + _ASSERTE(m_pPatchpointInfoFromRuntime == NULL); + _ASSERTE(patchpointInfo != NULL); + m_pPatchpointInfoFromRuntime = patchpointInfo; + m_ilOffset = ilOffset; + } +#endif + CEEJitInfo(MethodDesc* fd, COR_ILMETHOD_DECODER* header, EEJitManager* jm, bool fVerifyOnly, bool allowInlining = true) : CEEInfo(fd, fVerifyOnly, allowInlining), @@ -1399,6 +1422,11 @@ class CEEJitInfo : public CEEInfo m_pOffsetMapping(NULL), m_iNativeVarInfo(0), m_pNativeVarInfo(NULL), +#ifdef FEATURE_ON_STACK_REPLACEMENT + m_pPatchpointInfoFromJit(NULL), + m_pPatchpointInfoFromRuntime(NULL), + m_ilOffset(0), +#endif m_gphCache() { CONTRACTL @@ -1425,6 +1453,12 @@ class CEEJitInfo : public CEEInfo if (m_pNativeVarInfo != NULL) delete [] ((BYTE*) m_pNativeVarInfo); + +#ifdef FEATURE_ON_STACK_REPLACEMENT + if (m_pPatchpointInfoFromJit != NULL) + delete [] ((BYTE*) m_pPatchpointInfoFromJit); +#endif + } // ICorDebugInfo stuff. @@ -1460,6 +1494,9 @@ class CEEJitInfo : public CEEInfo void BackoutJitData(EEJitManager * jitMgr); + void setPatchpointInfo(PatchpointInfo* patchpointInfo); + PatchpointInfo* getOSRInfo(unsigned* ilOffset); + protected : EEJitManager* m_jitManager; // responsible for allocating memory CodeHeader* m_CodeHeader; // descriptor for JITTED code @@ -1495,6 +1532,12 @@ protected : ULONG32 m_iNativeVarInfo; ICorDebugInfo::NativeVarInfo * m_pNativeVarInfo; +#ifdef FEATURE_ON_STACK_REPLACEMENT + PatchpointInfo * m_pPatchpointInfoFromJit; + PatchpointInfo * m_pPatchpointInfoFromRuntime; + unsigned m_ilOffset; +#endif + // The first time a call is made to CEEJitInfo::GetProfilingHandle() from this thread // for this method, these values are filled in. Thereafter, these values are used // in lieu of calling into the base CEEInfo::GetProfilingHandle() again. This protects the diff --git a/src/coreclr/src/vm/loaderallocator.cpp b/src/coreclr/src/vm/loaderallocator.cpp index d39cf0a2a44f9c..406f45a89e3290 100644 --- a/src/coreclr/src/vm/loaderallocator.cpp +++ b/src/coreclr/src/vm/loaderallocator.cpp @@ -58,6 +58,10 @@ LoaderAllocator::LoaderAllocator() m_callCountingManager = NULL; #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + m_onStackReplacementManager = NULL; +#endif + m_fGCPressure = false; m_fTerminated = false; m_fUnloaded = false; @@ -1343,6 +1347,14 @@ void LoaderAllocator::Terminate() } #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + if (m_onStackReplacementManager != NULL) + { + delete m_onStackReplacementManager; + m_onStackReplacementManager = NULL; + } +#endif + // In collectible types we merge the low frequency and high frequency heaps // So don't destroy them twice. if ((m_pLowFrequencyHeap != NULL) && (m_pLowFrequencyHeap != m_pHighFrequencyHeap)) @@ -2019,3 +2031,34 @@ BOOL LoaderAllocator::InsertComInteropData(MethodTable* pMT, InteropMethodTableD #endif // FEATURE_COMINTEROP #endif // !DACCESS_COMPILE + + +#ifdef FEATURE_ON_STACK_REPLACEMENT +#ifndef DACCESS_COMPILE +PTR_OnStackReplacementManager LoaderAllocator::GetOnStackReplacementManager() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + INJECT_FAULT(COMPlusThrowOM();); + } + CONTRACTL_END; + + if (m_onStackReplacementManager == NULL) + { + OnStackReplacementManager * newManager = new OnStackReplacementManager(this); + + if (FastInterlockCompareExchangePointer(&m_onStackReplacementManager, newManager, NULL) != NULL) + { + // some thread swooped in and set the field + delete newManager; + } + } + _ASSERTE(m_onStackReplacementManager != NULL); + return m_onStackReplacementManager; +} +#endif // +#endif // FEATURE_ON_STACK_REPLACEMENT + diff --git a/src/coreclr/src/vm/loaderallocator.hpp b/src/coreclr/src/vm/loaderallocator.hpp index 4938b9545ab217..ea3da4a9cbe602 100644 --- a/src/coreclr/src/vm/loaderallocator.hpp +++ b/src/coreclr/src/vm/loaderallocator.hpp @@ -23,6 +23,7 @@ class FuncPtrStubs; #include "callcounting.h" #include "methoddescbackpatchinfo.h" #include "crossloaderallocatorhash.h" +#include "onstackreplacement.h" #define VPTRU_LoaderAllocator 0x3200 @@ -283,6 +284,10 @@ class LoaderAllocator MethodDescBackpatchInfoTracker m_methodDescBackpatchInfoTracker; #endif +#ifdef FEATURE_ON_STACK_REPLACEMENT + PTR_OnStackReplacementManager m_onStackReplacementManager; +#endif + #ifndef DACCESS_COMPILE public: @@ -611,6 +616,12 @@ class LoaderAllocator return &m_methodDescBackpatchInfoTracker; } #endif + +#ifdef FEATURE_ON_STACK_REPLACEMENT +public: + PTR_OnStackReplacementManager GetOnStackReplacementManager(); +#endif // FEATURE_ON_STACK_REPLACEMENT + }; // class LoaderAllocator typedef VPTR(LoaderAllocator) PTR_LoaderAllocator; diff --git a/src/coreclr/src/vm/method.hpp b/src/coreclr/src/vm/method.hpp index 7efecae85e129e..9a558d293084bf 100644 --- a/src/coreclr/src/vm/method.hpp +++ b/src/coreclr/src/vm/method.hpp @@ -2038,6 +2038,9 @@ class PrepareCodeConfig virtual BOOL SetNativeCode(PCODE pCode, PCODE * ppAlternateCodeToUse); virtual COR_ILMETHOD* GetILHeader(); virtual CORJIT_FLAGS GetJitCompilationFlags(); +#ifdef FEATURE_ON_STACK_REPLACEMENT + virtual unsigned GetILOffset() const { return 0; } +#endif BOOL ProfilerRejectedPrecompiledCode(); BOOL ReadyToRunRejectedPrecompiledCode(); void SetProfilerRejectedPrecompiledCode(); @@ -2100,6 +2103,7 @@ class PrepareCodeConfig Optimized, QuickJitted, OptimizedTier1, + OptimizedTier1OSR, Count }; diff --git a/src/coreclr/src/vm/object.h b/src/coreclr/src/vm/object.h index a7d68c10796578..8a091514ad4bf9 100644 --- a/src/coreclr/src/vm/object.h +++ b/src/coreclr/src/vm/object.h @@ -149,33 +149,17 @@ class Object m_pMethTab = pMT; } - VOID SetMethodTable(MethodTable *pMT - DEBUG_ARG(BOOL bAllowArray = FALSE)) + VOID SetMethodTable(MethodTable *pMT) { - LIMITED_METHOD_CONTRACT; - m_pMethTab = pMT; - -#ifdef _DEBUG - if (!bAllowArray) - { - AssertNotArray(); - } -#endif // _DEBUG + WRAPPER_NO_CONTRACT; + RawSetMethodTable(pMT); } - VOID SetMethodTableForLargeObject(MethodTable *pMT - DEBUG_ARG(BOOL bAllowArray = FALSE)) + VOID SetMethodTableForUOHObject(MethodTable *pMT) { - // This function must be used if the allocation occurs on the large object heap, and the method table might be a collectible type WRAPPER_NO_CONTRACT; + // This function must be used if the allocation occurs on a UOH heap, and the method table might be a collectible type ErectWriteBarrierForMT(&m_pMethTab, pMT); - -#ifdef _DEBUG - if (!bAllowArray) - { - AssertNotArray(); - } -#endif // _DEBUG } #endif //!DACCESS_COMPILE @@ -477,16 +461,6 @@ class Object private: VOID ValidateInner(BOOL bDeep, BOOL bVerifyNextHeader, BOOL bVerifySyncBlock); - -#ifdef _DEBUG - void AssertNotArray() - { - if (m_pMethTab->IsArray()) - { - _ASSERTE(!"ArrayBase::SetArrayMethodTable/ArrayBase::SetArrayMethodTableForLargeObject should be used for arrays"); - } - } -#endif // _DEBUG }; /* @@ -547,8 +521,8 @@ class ArrayBase : public Object friend class GCHeap; friend class CObjectHeader; friend class Object; - friend OBJECTREF AllocateSzArray(MethodTable *pArrayMT, INT32 length, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap); - friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap); + friend OBJECTREF AllocateSzArray(MethodTable *pArrayMT, INT32 length, GC_ALLOC_FLAGS flags); + friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags); friend FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); friend FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); friend class JIT_TrialAlloc; @@ -575,20 +549,15 @@ class ArrayBase : public Object // type is stored in the array or not inline TypeHandle GetArrayElementTypeHandle() const; - // Get the CorElementType for the elements in the array. Avoids creating a TypeHandle + // Get the CorElementType for the elements in the array. Avoids creating a TypeHandle inline CorElementType GetArrayElementType() const; inline unsigned GetRank() const; - // Total element count for the array + // Total element count for the array inline DWORD GetNumComponents() const; -#ifndef DACCESS_COMPILE - inline void SetArrayMethodTable(MethodTable *pArrayMT); - inline void SetArrayMethodTableForLargeObject(MethodTable *pArrayMT); -#endif // !DACCESS_COMPILE - - // Get pointer to elements, handles any number of dimensions + // Get pointer to elements, handles any number of dimensions PTR_BYTE GetDataPtr(BOOL inGC = FALSE) const { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; @@ -699,7 +668,7 @@ class PtrArray : public ArrayBase { friend class GCHeap; friend class ClrDataAccess; - friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, DWORD flags, BOOL bAllocateInLargeHeap); + friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, DWORD flags); friend class JIT_TrialAlloc; friend class CheckAsmOffsets; diff --git a/src/coreclr/src/vm/object.inl b/src/coreclr/src/vm/object.inl index 8ed202dc25b5ae..cac15829543a95 100644 --- a/src/coreclr/src/vm/object.inl +++ b/src/coreclr/src/vm/object.inl @@ -175,24 +175,6 @@ inline DWORD ArrayBase::GetNumComponents() const return m_NumComponents; } -#ifndef DACCESS_COMPILE -inline void ArrayBase::SetArrayMethodTable(MethodTable *pArrayMT) -{ - LIMITED_METHOD_CONTRACT; - - SetMethodTable(pArrayMT - DEBUG_ARG(TRUE)); -} - -inline void ArrayBase::SetArrayMethodTableForLargeObject(MethodTable *pArrayMT) -{ - LIMITED_METHOD_CONTRACT; - - SetMethodTableForLargeObject(pArrayMT - DEBUG_ARG(TRUE)); -} -#endif // !DACCESS_COMPILE - inline /* static */ unsigned ArrayBase::GetDataPtrOffset(MethodTable* pMT) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/src/vm/olevariant.cpp b/src/coreclr/src/vm/olevariant.cpp index 7be1d015db8a39..240b56427f7619 100644 --- a/src/coreclr/src/vm/olevariant.cpp +++ b/src/coreclr/src/vm/olevariant.cpp @@ -1835,7 +1835,7 @@ void OleVariant::MarshalIUnknownArrayComToOle(BASEARRAYREF *pComArray, void *ole MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, FALSE, cElements); } -void OleVariant::ClearInterfaceArray(BASEARRAYREF* pComArray, void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) +void OleVariant::ClearInterfaceArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { CONTRACTL { @@ -2009,7 +2009,7 @@ void OleVariant::MarshalBSTRArrayComToOle(BASEARRAYREF *pComArray, void *oleArra GCPROTECT_END(); } -void OleVariant::ClearBSTRArray(BASEARRAYREF* pComArray, void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) +void OleVariant::ClearBSTRArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { CONTRACTL { @@ -2112,7 +2112,7 @@ void OleVariant::MarshalNonBlittableRecordArrayComToOle(BASEARRAYREF *pComArray, } } -void OleVariant::ClearNonBlittableRecordArray(BASEARRAYREF* pComArray, void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) +void OleVariant::ClearNonBlittableRecordArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { CONTRACTL { @@ -2124,20 +2124,15 @@ void OleVariant::ClearNonBlittableRecordArray(BASEARRAYREF* pComArray, void *ole } CONTRACTL_END; - ASSERT_PROTECTED(pComArray); - SIZE_T elemSize = pInterfaceMT->GetNativeSize(); + SIZE_T componentSize = TypeHandle(pInterfaceMT).MakeSZArray().GetMethodTable()->GetComponentSize(); BYTE *pOle = (BYTE *) oleArray; BYTE *pOleEnd = pOle + elemSize * cElements; - SIZE_T srcofs = *pComArray != NULL ? ArrayBase::GetDataPtrOffset((*pComArray)->GetMethodTable()) : 0; while (pOle < pOleEnd) { - BYTE* managedData = (BYTE*)(*(LPVOID*)pComArray) + srcofs; - - MarshalStructViaILStubCode(pManagedMarshalerCode, managedData, pOle, StructMarshalStubs::MarshalOperation::Cleanup); + MarshalStructViaILStubCode(pManagedMarshalerCode, nullptr, pOle, StructMarshalStubs::MarshalOperation::Cleanup); pOle += elemSize; - srcofs += (*pComArray)->GetComponentSize(); } } @@ -2255,7 +2250,7 @@ void OleVariant::MarshalLPWSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleA } } -void OleVariant::ClearLPWSTRArray(BASEARRAYREF* pComArray, void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) +void OleVariant::ClearLPWSTRArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { CONTRACTL { @@ -2392,7 +2387,7 @@ void OleVariant::MarshalLPSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleAr } } -void OleVariant::ClearLPSTRArray(BASEARRAYREF* pComArray, void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) +void OleVariant::ClearLPSTRArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { CONTRACTL { @@ -2736,7 +2731,7 @@ void OleVariant::MarshalRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleAr } -void OleVariant::ClearRecordArray(BASEARRAYREF* pComArray, void *oleArray, SIZE_T cElements, MethodTable *pElementMT, PCODE pManagedMarshalerCode) +void OleVariant::ClearRecordArray(void *oleArray, SIZE_T cElements, MethodTable *pElementMT, PCODE pManagedMarshalerCode) { CONTRACTL { @@ -2751,7 +2746,7 @@ void OleVariant::ClearRecordArray(BASEARRAYREF* pComArray, void *oleArray, SIZE_ if (!pElementMT->IsBlittable()) { _ASSERTE(pElementMT->HasLayout()); - ClearNonBlittableRecordArray(pComArray, oleArray, cElements, pElementMT, pManagedMarshalerCode); + ClearNonBlittableRecordArray(oleArray, cElements, pElementMT, pManagedMarshalerCode); } } @@ -4072,7 +4067,7 @@ void OleVariant::MarshalVariantArrayComToOle(BASEARRAYREF *pComArray, void *oleA GCPROTECT_END(); } -void OleVariant::ClearVariantArray(BASEARRAYREF* pComArray, void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) +void OleVariant::ClearVariantArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { CONTRACTL { diff --git a/src/coreclr/src/vm/olevariant.h b/src/coreclr/src/vm/olevariant.h index 2cca65fadf8cbb..a09616d7818092 100644 --- a/src/coreclr/src/vm/olevariant.h +++ b/src/coreclr/src/vm/olevariant.h @@ -462,7 +462,7 @@ class OleVariant BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid,SIZE_T cElements, PCODE pManagedMarshalerCode); - void (*ClearOleArray)(BASEARRAYREF* pComArray, void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); + void (*ClearOleArray)(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); }; static const Marshaler* GetMarshalerForVarType(VARTYPE vt, BOOL fThrow); @@ -521,7 +521,7 @@ class OleVariant MethodTable* pInterfaceMT, BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid, SIZE_T cElements, PCODE pManagedMarshalerCode); - static void ClearBSTRArray(BASEARRAYREF* comArray, void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); + static void ClearBSTRArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); #endif // FEATURE_COMINTEROP static void MarshalNonBlittableRecordArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray, @@ -530,7 +530,7 @@ class OleVariant MethodTable* pInterfaceMT, BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid, SIZE_T cElements, PCODE pManagedMarshalerCode); - static void ClearNonBlittableRecordArray(BASEARRAYREF* comArray, void* oleArray, + static void ClearNonBlittableRecordArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); @@ -540,7 +540,7 @@ class OleVariant MethodTable* pInterfaceMT, BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid, SIZE_T cElements, PCODE pManagedMarshalerCode); - static void ClearLPWSTRArray(BASEARRAYREF* comArray, void* oleArray, + static void ClearLPWSTRArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); static void MarshalLPSTRArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray, @@ -549,7 +549,7 @@ class OleVariant MethodTable* pInterfaceMT, BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid, SIZE_T cElements, PCODE pManagedMarshalerCode); - static void ClearLPSTRArray(BASEARRAYREF* comArray, void* oleArray, + static void ClearLPSTRArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); static void MarshalDateArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray, @@ -564,7 +564,7 @@ class OleVariant BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid, SIZE_T cElements, PCODE pManagedMarshalerCode); - static void ClearRecordArray(BASEARRAYREF* comArray, void* oleArray, SIZE_T cElements, MethodTable* pElementMT, PCODE pManagedMarshalerCode); + static void ClearRecordArray(void* oleArray, SIZE_T cElements, MethodTable* pElementMT, PCODE pManagedMarshalerCode); #ifdef FEATURE_COMINTEROP static HRESULT MarshalCommonOleRefVariantForObject(OBJECTREF *pObj, VARIANT *pOle); @@ -574,7 +574,7 @@ class OleVariant MethodTable* pInterfaceMT, BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid, SIZE_T cElements, PCODE pManagedMarshalerCode); - static void ClearInterfaceArray(BASEARRAYREF* comArray, void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); + static void ClearInterfaceArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); static void MarshalBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); @@ -623,7 +623,7 @@ class OleVariant MethodTable* pInterfaceMT, BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid, SIZE_T cElements, PCODE pManagedMarshalerCode); - static void ClearVariantArray(BASEARRAYREF* comArray, void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); + static void ClearVariantArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); #ifdef FEATURE_CLASSIC_COMINTEROP static void MarshalArrayVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); diff --git a/src/coreclr/src/vm/onstackreplacement.cpp b/src/coreclr/src/vm/onstackreplacement.cpp new file mode 100644 index 00000000000000..4bb80efc5e94b2 --- /dev/null +++ b/src/coreclr/src/vm/onstackreplacement.cpp @@ -0,0 +1,84 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// =========================================================================== +// File: onstackreplacement.cpp +// +// =========================================================================== + +#include "common.h" +#include "onstackreplacement.h" + +#ifdef FEATURE_ON_STACK_REPLACEMENT + + +CrstStatic OnStackReplacementManager::s_lock; + +#if _DEBUG +int OnStackReplacementManager::s_patchpointId = 0; +#endif + +#ifndef DACCESS_COMPILE + +void OnStackReplacementManager::StaticInitialize() +{ + WRAPPER_NO_CONTRACT; + s_lock.Init(CrstJitPatchpoint, CrstFlags(CRST_UNSAFE_COOPGC)); +} + +OnStackReplacementManager::OnStackReplacementManager(LoaderAllocator * loaderAllocator) : m_allocator(loaderAllocator), m_jitPatchpointTable() +{ + CONTRACTL + { + GC_NOTRIGGER; + CAN_TAKE_LOCK; + MODE_ANY; + } + CONTRACTL_END; + + LockOwner lock = {&s_lock, IsOwnerOfCrst}; + m_jitPatchpointTable.Init(INITIAL_TABLE_SIZE, &lock, m_allocator->GetLowFrequencyHeap()); +} + +// Fetch or create patchpoint info for this patchpoint. +PerPatchpointInfo* OnStackReplacementManager::GetPerPatchpointInfo(PCODE ip) +{ + CONTRACTL + { + GC_NOTRIGGER; + CAN_TAKE_LOCK; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + PTR_PCODE ppId = dac_cast(ip); + PTR_PerPatchpointInfo ppInfo = NULL; + + BOOL hasData = m_jitPatchpointTable.GetValueSpeculative(ppId, (HashDatum*)&ppInfo); + + if (!hasData) + { + CrstHolder lock(&s_lock); + hasData = m_jitPatchpointTable.GetValue(ppId, (HashDatum*)&ppInfo); + + if (!hasData) + { + void * pMem = m_allocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PerPatchpointInfo))); + ppInfo = dac_cast(new (pMem) PerPatchpointInfo()); + m_jitPatchpointTable.InsertValue(ppId, (HashDatum)ppInfo); + +#if _DEBUG + ppInfo->m_patchpointId = ++s_patchpointId; +#endif + + } + } + + return ppInfo; +} + +#endif // !DACCESS_COMPILE + +#endif // FEATURE_ON_STACK_REPLACEMENT + + diff --git a/src/coreclr/src/vm/onstackreplacement.h b/src/coreclr/src/vm/onstackreplacement.h new file mode 100644 index 00000000000000..8ef3188cfc22a8 --- /dev/null +++ b/src/coreclr/src/vm/onstackreplacement.h @@ -0,0 +1,113 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// =========================================================================== +// File: onstackreplacement.h +// +// =========================================================================== + +#ifndef ON_STACK_REPLACEMENT_H +#define ON_STACK_REPLACEMENT_H + +#ifdef FEATURE_ON_STACK_REPLACEMENT + +#include "daccess.h" +#include "eehash.h" + +// PerPatchpointInfo is the runtime state tracked for each active patchpoint. +// +// A patchpoint becomes active when the JIT_HELP_PATCHPOINT helper is invoked +// by jitted code. +// +struct PerPatchpointInfo +{ + PerPatchpointInfo() : + m_osrMethodCode(0), + m_patchpointCount(0), + m_flags(0) +#if _DEBUG + , m_patchpointId(0) +#endif + { + } + + // Flag bits + enum + { + patchpoint_triggered = 0x1, + patchpoint_invalid = 0x2 + }; + + // The OSR method entry point for this patchpoint. + // NULL if no method has yet been jitted, or jitting failed. + PCODE m_osrMethodCode; + // Number of times jitted code has called the helper at this patchpoint. + LONG m_patchpointCount; + // Status of this patchpoint + LONG m_flags; + +#if _DEBUG + int m_patchpointId; +#endif +}; + +typedef DPTR(PerPatchpointInfo) PTR_PerPatchpointInfo; +typedef EEPtrHashTable JitPatchpointTable; + +// OnStackReplacementManager keeps track of mapping from patchpoint id to +// per patchpoint info. +// +// Patchpoint identity is currently the return address of the helper call +// in the jitted code. +// +class OnStackReplacementManager +{ +#if DACCESS_COMPILE +public: + OnStackReplacementManager(LoaderAllocator *) {}; +#else +public: + static void StaticInitialize(); + +public: + OnStackReplacementManager(LoaderAllocator * loaderHeaAllocator); + +public: + PerPatchpointInfo* GetPerPatchpointInfo(PCODE ip); +#endif // DACCESS_COMPILE + +private: + + enum + { + INITIAL_TABLE_SIZE = 10 + }; + + static CrstStatic s_lock; + +#if _DEBUG + static int s_patchpointId; +#endif + +private: + + PTR_LoaderAllocator m_allocator; + JitPatchpointTable m_jitPatchpointTable; +}; + +#else // FEATURE_TIERED_COMPILATION + +class OnStackReplacementManager +{ +public: + static void StaticInitialize() {} +public: + + OnStackReplacementManager(LoaderAllocator *) {} +}; + +#endif // FEATURE_TIERED_COMPILATION + +typedef DPTR(OnStackReplacementManager) PTR_OnStackReplacementManager; + +#endif // ON_STACK_REPLACEMENT_H diff --git a/src/coreclr/src/vm/prestub.cpp b/src/coreclr/src/vm/prestub.cpp index d8544448c2f4b2..24c8dbd411e4b6 100644 --- a/src/coreclr/src/vm/prestub.cpp +++ b/src/coreclr/src/vm/prestub.cpp @@ -997,10 +997,13 @@ PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEn // The profiler may have changed the code on the callback. Need to // pick up the new code. + // + // (don't want this for OSR, need to see how it works) COR_ILMETHOD_DECODER ilDecoderTemp; COR_ILMETHOD_DECODER *pilHeader = GetAndVerifyILHeader(pConfig, &ilDecoderTemp); *pFlags = pConfig->GetJitCompilationFlags(); PCODE pOtherCode = NULL; + EX_TRY { #ifndef CROSSGEN_COMPILE @@ -1287,6 +1290,9 @@ PrepareCodeConfig::JitOptimizationTier PrepareCodeConfig::GetJitOptimizationTier case NativeCodeVersion::OptimizationTier1: return JitOptimizationTier::OptimizedTier1; + case NativeCodeVersion::OptimizationTier1OSR: + return JitOptimizationTier::OptimizedTier1OSR; + case NativeCodeVersion::OptimizationTierOptimized: return JitOptimizationTier::Optimized; @@ -1311,6 +1317,7 @@ const char *PrepareCodeConfig::GetJitOptimizationTierStr(PrepareCodeConfig *conf case JitOptimizationTier::Optimized: return "Optimized"; case JitOptimizationTier::QuickJitted: return "QuickJitted"; case JitOptimizationTier::OptimizedTier1: return "OptimizedTier1"; + case JitOptimizationTier::OptimizedTier1OSR: return "OptimizedTier1OSR"; default: UNREACHABLE(); diff --git a/src/coreclr/src/vm/sampleprofiler.cpp b/src/coreclr/src/vm/sampleprofiler.cpp index e3abbb4365e6b3..d93b47114fb1cc 100644 --- a/src/coreclr/src/vm/sampleprofiler.cpp +++ b/src/coreclr/src/vm/sampleprofiler.cpp @@ -6,7 +6,6 @@ #include "eventpipebuffermanager.h" #include "eventpipeeventinstance.h" #include "sampleprofiler.h" -#include "hosting.h" #include "threadsuspend.h" #ifdef FEATURE_PERFTRACING diff --git a/src/coreclr/src/vm/spinlock.cpp b/src/coreclr/src/vm/spinlock.cpp index 00bb1a39818a95..7bae099c4c00f5 100644 --- a/src/coreclr/src/vm/spinlock.cpp +++ b/src/coreclr/src/vm/spinlock.cpp @@ -31,27 +31,12 @@ ULONG SpinLockProfiler::s_ulSpins [LOCK_TYPE_DEFAULT + 1] = { 0 }; SpinLock::SpinLock() { - // Global SpinLock variables will cause the constructor to be - // called during DllInit, which means we cannot use full contracts - // because we have not called InitUtilCode yet. STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; m_Initialized = UnInitialized; } - -SpinLock::~SpinLock() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - -} - void SpinLock::Init(LOCK_TYPE type, bool RequireCoopGC) { CONTRACTL diff --git a/src/coreclr/src/vm/spinlock.h b/src/coreclr/src/vm/spinlock.h index b79ab6b5c08ba1..aad85618b144b8 100644 --- a/src/coreclr/src/vm/spinlock.h +++ b/src/coreclr/src/vm/spinlock.h @@ -175,7 +175,6 @@ class SpinLock public: SpinLock (); - ~SpinLock (); //Init method, initialize lock and _DEBUG flags void Init(LOCK_TYPE type, bool RequireCoopGC = FALSE); diff --git a/src/coreclr/src/vm/threads.cpp b/src/coreclr/src/vm/threads.cpp index 9af009fce16f3c..5025ad4c59150b 100644 --- a/src/coreclr/src/vm/threads.cpp +++ b/src/coreclr/src/vm/threads.cpp @@ -1005,10 +1005,6 @@ HRESULT Thread::DetachThread(BOOL fDLLThreadDetach) SetThread(NULL); SetAppDomain(NULL); -#ifdef ENABLE_CONTRACTS_DATA - m_pClrDebugState = NULL; -#endif //ENABLE_CONTRACTS_DATA - FastInterlockOr((ULONG*)&m_State, (int) (Thread::TS_Detached | Thread::TS_ReportDead)); // Do not touch Thread object any more. It may be destroyed. @@ -1337,7 +1333,6 @@ Thread::Thread() #endif #ifdef ENABLE_CONTRACTS - m_pClrDebugState = NULL; m_ulEnablePreemptiveGCCount = 0; #endif @@ -6118,7 +6113,7 @@ size_t getStackHash(size_t* stackTrace, size_t* stackTop, size_t* stackStop, siz NULL ); - if (((UINT_PTR)g_pMSCorEE) != uImageBase) + if (((UINT_PTR)g_hThisInst) != uImageBase) { break; } diff --git a/src/coreclr/src/vm/threads.h b/src/coreclr/src/vm/threads.h index ebb37230484793..faab0567a813f8 100644 --- a/src/coreclr/src/vm/threads.h +++ b/src/coreclr/src/vm/threads.h @@ -1049,8 +1049,9 @@ class Thread friend class DacDbiInterfaceImpl; // DacDbiInterfaceImpl::GetThreadHandle(HANDLE * phThread); #endif // DACCESS_COMPILE friend class ProfToEEInterfaceImpl; // HRESULT ProfToEEInterfaceImpl::GetHandleFromThread(ThreadID threadId, HANDLE *phThread); + friend void SetupTLSForThread(Thread* pThread); - friend class UnC; + friend class CheckAsmOffsets; friend class ExceptionTracker; @@ -1913,14 +1914,6 @@ class Thread bool DetectHandleILStubsForDebugger(); -#ifdef ENABLE_CONTRACTS - ClrDebugState *GetClrDebugState() - { - LIMITED_METHOD_CONTRACT; - return m_pClrDebugState; - } -#endif - //************************************************************** // GC interaction //************************************************************** @@ -2057,29 +2050,33 @@ class Thread void BeginNoTriggerGC(const char *szFile, int lineNum) { WRAPPER_NO_CONTRACT; - m_pClrDebugState->IncrementGCNoTriggerCount(); + + ClrDebugState* pClrDebugState = GetClrDebugState(); + pClrDebugState->IncrementGCNoTriggerCount(); + if (PreemptiveGCDisabled()) { - m_pClrDebugState->IncrementGCForbidCount(); + pClrDebugState->IncrementGCForbidCount(); } } void EndNoTriggerGC() { WRAPPER_NO_CONTRACT; - _ASSERTE(m_pClrDebugState->GetGCNoTriggerCount() != 0 || (m_pClrDebugState->ViolationMask() & BadDebugState)); - m_pClrDebugState->DecrementGCNoTriggerCount(); + ClrDebugState* pClrDebugState = GetClrDebugState(); + + _ASSERTE(pClrDebugState->GetGCNoTriggerCount() != 0 || (pClrDebugState->ViolationMask() & BadDebugState)); + pClrDebugState->DecrementGCNoTriggerCount(); - if (m_pClrDebugState->GetGCForbidCount()) + if (pClrDebugState->GetGCForbidCount()) { - m_pClrDebugState->DecrementGCForbidCount(); + pClrDebugState->DecrementGCForbidCount(); } } void BeginForbidGC(const char *szFile, int lineNum) { WRAPPER_NO_CONTRACT; - _ASSERTE(this == GetThread()); #ifdef PROFILING_SUPPORTED _ASSERTE(PreemptiveGCDisabled() || CORProfilerPresent() || // This added to allow profiler to use GetILToNativeMapping @@ -2094,7 +2091,6 @@ class Thread void EndForbidGC() { WRAPPER_NO_CONTRACT; - _ASSERTE(this == GetThread()); #ifdef PROFILING_SUPPORTED _ASSERTE(PreemptiveGCDisabled() || CORProfilerPresent() || // This added to allow profiler to use GetILToNativeMapping @@ -2109,43 +2105,45 @@ class Thread BOOL GCNoTrigger() { WRAPPER_NO_CONTRACT; - _ASSERTE(this == GetThread()); - if ( (GCViolation|BadDebugState) & m_pClrDebugState->ViolationMask() ) + ClrDebugState* pClrDebugState = GetClrDebugState(); + if ( (GCViolation|BadDebugState) & pClrDebugState->ViolationMask() ) { return FALSE; } - return m_pClrDebugState->GetGCNoTriggerCount(); + return pClrDebugState->GetGCNoTriggerCount(); } BOOL GCForbidden() { WRAPPER_NO_CONTRACT; - _ASSERTE(this == GetThread()); - if ( (GCViolation|BadDebugState) & m_pClrDebugState->ViolationMask()) + ClrDebugState* pClrDebugState = GetClrDebugState(); + if ( (GCViolation|BadDebugState) & pClrDebugState->ViolationMask()) { return FALSE; } - return m_pClrDebugState->GetGCForbidCount(); + return pClrDebugState->GetGCForbidCount(); } BOOL RawGCNoTrigger() { LIMITED_METHOD_CONTRACT; - if (m_pClrDebugState->ViolationMask() & BadDebugState) + ClrDebugState* pClrDebugState = GetClrDebugState(); + if (pClrDebugState->ViolationMask() & BadDebugState) { return 0; } - return m_pClrDebugState->GetGCNoTriggerCount(); + return pClrDebugState->GetGCNoTriggerCount(); } BOOL RawGCForbidden() { LIMITED_METHOD_CONTRACT; - if (m_pClrDebugState->ViolationMask() & BadDebugState) + ClrDebugState* pClrDebugState = GetClrDebugState(); + if (pClrDebugState->ViolationMask() & BadDebugState) { return 0; } - return m_pClrDebugState->GetGCForbidCount(); + return pClrDebugState->GetGCForbidCount(); } #endif // ENABLE_CONTRACTS_IMPL @@ -3495,8 +3493,6 @@ class Thread private: #ifdef ENABLE_CONTRACTS_DATA - struct ClrDebugState *m_pClrDebugState; // Pointer to ClrDebugState for quick access - ULONG m_ulEnablePreemptiveGCCount; #endif // _DEBUG @@ -5829,8 +5825,7 @@ class GCForbid : AutoCleanupGCAssert m_fConditional = fConditional; if (m_fConditional) { - Thread *pThread = GetThread(); - m_pClrDebugState = pThread ? pThread->GetClrDebugState() : ::GetClrDebugState(); + m_pClrDebugState = ::GetClrDebugState(); m_oldClrDebugState = *m_pClrDebugState; m_pClrDebugState->ViolationMaskReset( GCViolation ); @@ -5854,8 +5849,7 @@ class GCForbid : AutoCleanupGCAssert m_fConditional = TRUE; - Thread *pThread = GetThread(); - m_pClrDebugState = pThread ? pThread->GetClrDebugState() : ::GetClrDebugState(); + m_pClrDebugState = ::GetClrDebugState(); m_oldClrDebugState = *m_pClrDebugState; m_pClrDebugState->ViolationMaskReset( GCViolation ); @@ -5914,7 +5908,7 @@ class GCNoTrigger if (m_fConditional) { Thread * pThread = GetThreadNULLOk(); - m_pClrDebugState = pThread ? pThread->GetClrDebugState() : ::GetClrDebugState(); + m_pClrDebugState = ::GetClrDebugState(); m_oldClrDebugState = *m_pClrDebugState; m_pClrDebugState->ViolationMaskReset( GCViolation ); @@ -5941,7 +5935,7 @@ class GCNoTrigger m_fConditional = TRUE; Thread * pThread = GetThreadNULLOk(); - m_pClrDebugState = pThread ? pThread->GetClrDebugState() : ::GetClrDebugState(); + m_pClrDebugState = ::GetClrDebugState(); m_oldClrDebugState = *m_pClrDebugState; m_pClrDebugState->ViolationMaskReset( GCViolation ); diff --git a/src/coreclr/src/vm/tieredcompilation.cpp b/src/coreclr/src/vm/tieredcompilation.cpp index ffd986a53bd24d..e2ff313e8f1f51 100644 --- a/src/coreclr/src/vm/tieredcompilation.cpp +++ b/src/coreclr/src/vm/tieredcompilation.cpp @@ -933,6 +933,12 @@ CORJIT_FLAGS TieredCompilationManager::GetJitFlags(NativeCodeVersion nativeCodeV nativeCodeVersion.SetOptimizationTier(NativeCodeVersion::OptimizationTierOptimized); goto Optimized; +#ifdef FEATURE_ON_STACK_REPLACEMENT + case NativeCodeVersion::OptimizationTier1OSR: + flags.Set(CORJIT_FLAGS::CORJIT_FLAG_OSR); + // fall through +#endif + case NativeCodeVersion::OptimizationTier1: flags.Set(CORJIT_FLAGS::CORJIT_FLAG_TIER1); // fall through diff --git a/src/coreclr/src/vm/vars.cpp b/src/coreclr/src/vm/vars.cpp index ba0cac3dea478b..6c72710c50e2d0 100644 --- a/src/coreclr/src/vm/vars.cpp +++ b/src/coreclr/src/vm/vars.cpp @@ -30,7 +30,7 @@ const char g_psBaseLibrarySatelliteAssemblyName[] = CoreLibSatelliteName_A; Volatile g_TrapReturningThreads; -HINSTANCE g_pMSCorEE; +HINSTANCE g_hThisInst; BBSweep g_BBSweep; #ifdef _DEBUG @@ -178,8 +178,6 @@ int g_IGCTrimCommit = 0; #endif -BOOL g_fEnableETW = FALSE; - // // Global state variable indicating if the EE is in its init phase. // @@ -221,12 +219,6 @@ bool dbg_fDrasticShutdown = false; #endif bool g_fInControlC = false; -// -// -// IJW needs the shim HINSTANCE -// -HINSTANCE g_hInstShim = NULL; - #endif // #ifndef DACCESS_COMPILE #ifdef DACCESS_COMPILE diff --git a/src/coreclr/src/vm/vars.hpp b/src/coreclr/src/vm/vars.hpp index 65bb74fff44e92..ef9c8dfe8cee55 100644 --- a/src/coreclr/src/vm/vars.hpp +++ b/src/coreclr/src/vm/vars.hpp @@ -347,7 +347,7 @@ GARY_DECL(TypeHandle, g_pPredefinedArrayTypes, ELEMENT_TYPE_MAX); extern "C" Volatile g_TrapReturningThreads; -EXTERN HINSTANCE g_pMSCorEE; +EXTERN HINSTANCE g_hThisInst; EXTERN BBSweep g_BBSweep; EXTERN IBCLogger g_IBCLogger; @@ -471,8 +471,6 @@ extern int g_IGCHoardVM; extern int g_IGCTrimCommit; #endif -extern BOOL g_fEnableETW; - // Returns a BOOL to indicate if the runtime is active or not BOOL IsRuntimeActive(); @@ -629,12 +627,6 @@ inline bool CORDebuggerAttached() - -// -// IJW needs the shim HINSTANCE -// -EXTERN HINSTANCE g_hInstShim; - #ifndef TARGET_UNIX GVAL_DECL(SIZE_T, g_runtimeLoadedBaseAddress); GVAL_DECL(SIZE_T, g_runtimeVirtualSize); diff --git a/src/coreclr/src/zap/zapinfo.cpp b/src/coreclr/src/zap/zapinfo.cpp index 9163da06daf92d..534674fd5fc002 100644 --- a/src/coreclr/src/zap/zapinfo.cpp +++ b/src/coreclr/src/zap/zapinfo.cpp @@ -509,7 +509,7 @@ void ZapInfo::CompileMethod() &m_currentMethodInfo, CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS, &pCode, - &cCode ); + &cCode); if (FAILED(res)) { // We will fall back to the "main" JIT on failure. @@ -2998,6 +2998,18 @@ void ZapInfo::setVars(CORINFO_METHOD_HANDLE ftn, return; } +void ZapInfo::setPatchpointInfo(PatchpointInfo* patchpointInfo) +{ + // No patchpoint info when prejitting + UNREACHABLE(); +} + +PatchpointInfo* ZapInfo::getOSRInfo(unsigned * ilOffset) +{ + // No patchpoint info when prejitting + UNREACHABLE(); +} + void * ZapInfo::allocateArray(size_t cBytes) { return new BYTE[cBytes]; diff --git a/src/coreclr/src/zap/zapinfo.h b/src/coreclr/src/zap/zapinfo.h index 4ddcab11ea1e47..35f7e9e17bffea 100644 --- a/src/coreclr/src/zap/zapinfo.h +++ b/src/coreclr/src/zap/zapinfo.h @@ -707,6 +707,10 @@ class ZapInfo void getGSCookie(GSCookie * pCookieVal, GSCookie** ppCookieVal); + + void setPatchpointInfo(PatchpointInfo * patchpointInfo); + PatchpointInfo * getOSRInfo(unsigned * ilOffset); + // ICorErrorInfo HRESULT GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers); diff --git a/src/coreclr/src/zap/zapper.cpp b/src/coreclr/src/zap/zapper.cpp index a11f605aa83801..70388bd50018bc 100644 --- a/src/coreclr/src/zap/zapper.cpp +++ b/src/coreclr/src/zap/zapper.cpp @@ -1181,10 +1181,17 @@ void Zapper::InitializeCompilerFlags(CORCOMPILE_VERSION_INFO * pVersionInfo) } // .NET Core requires SSE2. - m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE2); - #endif // TARGET_X86 +#if defined(TARGET_X86) || defined(TARGET_AMD64) + m_pOpt->m_compilerFlags.Set(InstructionSet_SSE); + m_pOpt->m_compilerFlags.Set(InstructionSet_SSE2); +#endif +#if defined(TARGET_ARM64) + m_pOpt->m_compilerFlags.Set(InstructionSet_ArmBase); + m_pOpt->m_compilerFlags.Set(InstructionSet_AdvSimd); +#endif + #if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64) // If we're crossgenning CoreLib, allow generating non-VEX intrinsics. The generated code might // not actually be supported by the processor at runtime so we compensate for it by @@ -1198,21 +1205,24 @@ void Zapper::InitializeCompilerFlags(CORCOMPILE_VERSION_INFO * pVersionInfo) m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_FEATURE_SIMD); #if defined(TARGET_X86) || defined(TARGET_AMD64) - m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_AES); - m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_PCLMULQDQ); - m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE3); - m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSSE3); - m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE41); - m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE42); - m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_POPCNT); + m_pOpt->m_compilerFlags.Set(InstructionSet_SSE); + m_pOpt->m_compilerFlags.Set(InstructionSet_SSE2); + m_pOpt->m_compilerFlags.Set(InstructionSet_AES); + m_pOpt->m_compilerFlags.Set(InstructionSet_PCLMULQDQ); + m_pOpt->m_compilerFlags.Set(InstructionSet_SSE3); + m_pOpt->m_compilerFlags.Set(InstructionSet_SSSE3); + m_pOpt->m_compilerFlags.Set(InstructionSet_SSE41); + m_pOpt->m_compilerFlags.Set(InstructionSet_SSE42); + m_pOpt->m_compilerFlags.Set(InstructionSet_POPCNT); // Leaving out CORJIT_FLAGS::CORJIT_FLAG_USE_AVX, CORJIT_FLAGS::CORJIT_FLAG_USE_FMA // CORJIT_FLAGS::CORJIT_FLAG_USE_AVX2, CORJIT_FLAGS::CORJIT_FLAG_USE_BMI1, // CORJIT_FLAGS::CORJIT_FLAG_USE_BMI2 on purpose - these require VEX encodings // and the JIT doesn't support generating code for methods with mixed encodings. - m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_LZCNT); + m_pOpt->m_compilerFlags.Set(InstructionSet_LZCNT); #endif // defined(TARGET_X86) || defined(TARGET_AMD64) } #endif // defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64) + m_pOpt->m_compilerFlags.Set64BitInstructionSetVariants(); if ( m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO) && m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE) diff --git a/src/coreclr/tests/CMakeLists.txt b/src/coreclr/tests/CMakeLists.txt index 47ee1e3a9a4de3..1ea31cdd8a0357 100644 --- a/src/coreclr/tests/CMakeLists.txt +++ b/src/coreclr/tests/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14.2) cmake_policy(SET CMP0042 NEW) project(Tests) -include(${CLR_ENG_NATIVE_DIR}/configureplatform.cmake) +include(${CLR_ENG_NATIVE_DIR}/configuretools.cmake) set(INC_PLATFORM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/Common/Platform) if (CLR_CMAKE_TARGET_WIN32) @@ -12,7 +12,6 @@ endif() # Include global configure settings include(${CMAKE_CURRENT_SOURCE_DIR}/../configurecompiler.cmake) -include(${CLR_ENG_NATIVE_DIR}/configuretools.cmake) # Compile options if (CLR_CMAKE_HOST_WIN32) diff --git a/src/coreclr/tests/Directory.Build.props b/src/coreclr/tests/Directory.Build.props index 7d7cf074c2f9c0..7e57e7a601e994 100644 --- a/src/coreclr/tests/Directory.Build.props +++ b/src/coreclr/tests/Directory.Build.props @@ -15,11 +15,10 @@ - $(MSBuildThisFileDirectory)..\..\..\artifacts\ - $(RootBinDir)bin\coreclr\$(TargetOS).$(BuildArch).$(BuildType)\ + $(ArtifactsDir)bin\coreclr\$(TargetOS).$(BuildArch).$(BuildType)\ $(__TestWorkingDir)\ - $(RootBinDir)tests\coreclr\$(TargetOS).$(BuildArch).$(BuildType)\ + $(ArtifactsDir)tests\coreclr\$(TargetOS).$(BuildArch).$(BuildType)\ $(__AltJitArch) @@ -28,14 +27,14 @@ - $(RootBinDir)obj\ + $(ArtifactsDir)obj\ $(BaseIntermediateOutputPath)\$(TargetOS).$(BuildArch).$(BuildType) $(BaseIntermediateOutputPath)\coreclr\$(TargetOS).$(BuildArch).$(BuildType) - $(RootBinDir)TargetingPack\ + $(ArtifactsDir)TargetingPack\ diff --git a/src/coreclr/tests/dir.common.props b/src/coreclr/tests/dir.common.props index c2560603383813..cece71183fbf88 100644 --- a/src/coreclr/tests/dir.common.props +++ b/src/coreclr/tests/dir.common.props @@ -17,10 +17,10 @@ - $(RootRepoDir)/artifacts/tests/coreclr/obj/$(OSPlatformConfig)/Managed/$(BuildProjectRelativeDir) + $(RepoRoot)/artifacts/tests/coreclr/obj/$(OSPlatformConfig)/Managed/$(BuildProjectRelativeDir) $(BaseIntermediateOutputPath) - $(RootRepoDir)/artifacts/tests/coreclr/$(OSPlatformConfig)/$(BuildProjectRelativeDir) + $(RepoRoot)/artifacts/tests/coreclr/$(OSPlatformConfig)/$(BuildProjectRelativeDir) $(BaseOutputPath) diff --git a/src/coreclr/tests/issues.targets b/src/coreclr/tests/issues.targets index 1030d821f79929..e89dc91c3c05a4 100644 --- a/src/coreclr/tests/issues.targets +++ b/src/coreclr/tests/issues.targets @@ -967,9 +967,6 @@ needs triage - - needs triage - needs triage diff --git a/src/coreclr/tests/override.targets b/src/coreclr/tests/override.targets index b45306f93cc6b2..e51db2c91a3466 100644 --- a/src/coreclr/tests/override.targets +++ b/src/coreclr/tests/override.targets @@ -14,7 +14,7 @@ > - + diff --git a/src/coreclr/tests/publishdependency.targets b/src/coreclr/tests/publishdependency.targets index 13a4f730000602..bdb61e870d427b 100644 --- a/src/coreclr/tests/publishdependency.targets +++ b/src/coreclr/tests/publishdependency.targets @@ -21,7 +21,7 @@ - $(RootRepoDir)\artifacts\bin\coreclr\$(TargetOS).$(BuildArch).$(BuildType) + $(RepoRoot)\artifacts\bin\coreclr\$(TargetOS).$(BuildArch).$(BuildType) $(ProductDestination)\ref diff --git a/src/coreclr/tests/runtest.cmd b/src/coreclr/tests/runtest.cmd index c80629d28e045b..bfe2925f2b713e 100644 --- a/src/coreclr/tests/runtest.cmd +++ b/src/coreclr/tests/runtest.cmd @@ -177,7 +177,7 @@ if defined RunInUnloadableContext ( set __RuntestPyArgs=%__RuntestPyArgs% --run_in_context ) -set NEXTCMD=python "%__ProjectDir%\runtest.py" %__RuntestPyArgs% +set NEXTCMD=python3 "%__ProjectDir%\runtest.py" %__RuntestPyArgs% echo !NEXTCMD! !NEXTCMD! diff --git a/src/coreclr/tests/runtest.py b/src/coreclr/tests/runtest.py index 7ae9c97e58dbf4..09fb8466af0dc3 100755 --- a/src/coreclr/tests/runtest.py +++ b/src/coreclr/tests/runtest.py @@ -1250,7 +1250,7 @@ def to_unicode(s): return unicode(s, "utf-8") else: def to_unicode(s): - return str(s, "utf-8") + return s def find_test_from_name(host_os, test_location, test_name): """ Given a test's name return the location on disk diff --git a/src/coreclr/tests/src/Directory.Build.props b/src/coreclr/tests/src/Directory.Build.props index 2d3ee4bf90cf8a..b70d49f4253fc8 100644 --- a/src/coreclr/tests/src/Directory.Build.props +++ b/src/coreclr/tests/src/Directory.Build.props @@ -24,11 +24,11 @@ - $(RootRepoDir)\artifacts\tests\coreclr + $(RepoRoot)\artifacts\tests\coreclr $(__TestRootDir) $(BaseOutputPath)\$(OSPlatformConfig)\ $(BaseOutputPathWithConfig) - $(RootRepoDir)\artifacts\tests\coreclr\obj\$(OSPlatformConfig)\Managed\ + $(RepoRoot)\artifacts\tests\coreclr\obj\$(OSPlatformConfig)\Managed\ $(__ManagedTestIntermediatesDir)\ <__NativeTestIntermediatesDir Condition="'$(__NativeTestIntermediatesDir)' == ''">$([System.IO.Path]::GetFullPath($(BaseOutputPathWithConfig)..\..\coreclr\obj\$(TargetOS).$(BuildArch).$(Configuration)\Native\)) $(MSBuildProjectName)\ diff --git a/src/coreclr/tests/src/GC/API/GC/AllocateUninitializedArray.cs b/src/coreclr/tests/src/GC/API/GC/AllocateUninitializedArray.cs deleted file mode 100644 index 28dcd969ab5e4e..00000000000000 --- a/src/coreclr/tests/src/GC/API/GC/AllocateUninitializedArray.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// Tests GC.Collect() - -using System; - -public class Test { - - - public static int Main() { - // allocate a bunch of SOH byte arrays and touch them. - var r = new Random(1234); - for (int i = 0; i < 10000; i++) - { - int size = r.Next(10000); - var arr = AllocUninitialized.Call(size); - - if (size > 1) - { - arr[0] = 5; - arr[size - 1] = 17; - if (arr[0] != 5 || arr[size - 1] != 17) - { - Console.WriteLine("Scenario 1 for GC.AllocUninitialized() failed!"); - return 1; - } - } - } - - // allocate a bunch of LOH int arrays and touch them. - for (int i = 0; i < 1000; i++) - { - int size = r.Next(100000, 1000000); - var arr = AllocUninitialized.Call(size); - - arr[0] = 5; - arr[size - 1] = 17; - if (arr[0] != 5 || arr[size - 1] != 17) - { - Console.WriteLine("Scenario 2 for GC.AllocUninitialized() failed!"); - return 1; - } - } - - // allocate a string array - { - int i = 100; - var arr = AllocUninitialized.Call(i); - - arr[0] = "5"; - arr[i - 1] = "17"; - if (arr[0] != "5" || arr[i - 1] != "17") - { - Console.WriteLine("Scenario 3 for GC.AllocUninitialized() failed!"); - return 1; - } - } - - // allocate max size byte array - { - if (IntPtr.Size == 8) - { - int i = 0x7FFFFFC7; - var arr = AllocUninitialized.Call(i); - - arr[0] = 5; - arr[i - 1] = 17; - if (arr[0] != 5 || arr[i - 1] != 17) - { - Console.WriteLine("Scenario 4 for GC.AllocUninitialized() failed!"); - return 1; - } - } - } - - // negative size - { - int GetNegativeValue() => -1; - int negativeSize = GetNegativeValue(); - Type expectedExceptionType = null; - - try - { - GC.KeepAlive(new byte[negativeSize]); - - Console.WriteLine("Scenario 5 Expected exception (new operator)!"); - return 1; - } - catch (Exception newOperatorEx) - { - expectedExceptionType = newOperatorEx.GetType(); - } - - try - { - var arr = AllocUninitialized.Call(-1); - - Console.WriteLine("Scenario 5 Expected exception (GC.AllocateUninitializedArray)!"); - return 1; - } - catch (Exception allocUninitializedEx) when (allocUninitializedEx.GetType() == expectedExceptionType) - { - // OK - } - catch (Exception other) - { - Console.WriteLine($"Scenario 5 Expected exception type mismatch: expected {expectedExceptionType}, but got {other.GetType()}!"); - return 1; - } - } - - // too large - { - try - { - var arr = AllocUninitialized.Call(int.MaxValue); - - Console.WriteLine("Scenario 6 Expected exception!"); - return 1; - } - catch (OutOfMemoryException) - { - } - } - - - Console.WriteLine("Test for GC.Collect() passed!"); - return 100; - } - - //TODO: This should be removed once the API is public. - static class AllocUninitialized - { - public static Func Call = (i) => - { - // replace the stub with actual impl. - Call = (Func)typeof(System.GC). - GetMethod("AllocateUninitializedArray", - bindingAttr: System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static, - binder: null, - new Type[] { typeof(int) }, - modifiers: new System.Reflection.ParameterModifier[0]). - MakeGenericMethod(new Type[] { typeof(T) }). - CreateDelegate(typeof(Func)); - - // call the impl. - return Call(i); - }; - } -} diff --git a/src/coreclr/tests/src/GC/API/GC/AllocateUninitializedArray.csproj b/src/coreclr/tests/src/GC/API/GC/AllocateUninitializedArray.csproj deleted file mode 100644 index 41499bc43fdbfb..00000000000000 --- a/src/coreclr/tests/src/GC/API/GC/AllocateUninitializedArray.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - 0 - - - - PdbOnly - - - - - diff --git a/src/coreclr/tests/src/Interop/COM/Dynamic/Server/DispatchImpl.cpp b/src/coreclr/tests/src/Interop/COM/Dynamic/Server/DispatchImpl.cpp index 9885eacf0cc70b..39ade024a34dc4 100644 --- a/src/coreclr/tests/src/Interop/COM/Dynamic/Server/DispatchImpl.cpp +++ b/src/coreclr/tests/src/Interop/COM/Dynamic/Server/DispatchImpl.cpp @@ -26,7 +26,7 @@ DispatchImpl::DispatchImpl(GUID guid, void *instance, const wchar_t* tlb) DispatchImpl::~DispatchImpl() { - if (_typeInfo != nullptr) + if (_typeLib != nullptr) _typeLib->Release(); if (_typeInfo != nullptr) @@ -44,8 +44,8 @@ HRESULT DispatchImpl::DoGetTypeInfo(UINT iTInfo, ITypeInfo** ppTInfo) if (iTInfo != 0) return DISP_E_BADINDEX; - *ppTInfo = _typeInfo; - return S_OK; + assert(_typeInfo != nullptr); + return _typeInfo->QueryInterface(__uuidof(*ppTInfo), (void**)ppTInfo); } HRESULT DispatchImpl::DoGetIDsOfNames(LPOLESTR* rgszNames, UINT cNames, DISPID* rgDispId) diff --git a/src/coreclr/tests/src/Interop/PInvoke/Generics/CMakeLists.txt b/src/coreclr/tests/src/Interop/PInvoke/Generics/CMakeLists.txt index 1aceaf5d91bfd5..ebb09a85e7b049 100644 --- a/src/coreclr/tests/src/Interop/PInvoke/Generics/CMakeLists.txt +++ b/src/coreclr/tests/src/Interop/PInvoke/Generics/CMakeLists.txt @@ -13,6 +13,10 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM64) add_definitions(-DTARGET_ARM64) add_definitions(-DTARGET_ARMARCH) endif() +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # The ABI for passing parameters with 32-byte alignment has changed in GCC 4.6 + add_compile_options(-Wno-psabi) +endif() set(SOURCES GenericsNative.IUnknown.cpp GenericsNative.NullableB.cpp diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj index 07a3c5940f5531..c2bc7b3491ee51 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj @@ -429,6 +429,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj index 10562a585f1869..a35c1c23146914 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj @@ -429,6 +429,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs index dd20b98214422b..f45f02ceedc939 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs @@ -433,6 +433,26 @@ static Program() ["PopCount.Vector128.SByte"] = PopCount_Vector128_SByte, ["SqrtScalar.Vector64.Double"] = SqrtScalar_Vector64_Double, ["SqrtScalar.Vector64.Single"] = SqrtScalar_Vector64_Single, + ["Store.Vector64.Byte"] = Store_Vector64_Byte, + ["Store.Vector64.Double"] = Store_Vector64_Double, + ["Store.Vector64.Int16"] = Store_Vector64_Int16, + ["Store.Vector64.Int32"] = Store_Vector64_Int32, + ["Store.Vector64.Int64"] = Store_Vector64_Int64, + ["Store.Vector64.SByte"] = Store_Vector64_SByte, + ["Store.Vector64.Single"] = Store_Vector64_Single, + ["Store.Vector64.UInt16"] = Store_Vector64_UInt16, + ["Store.Vector64.UInt32"] = Store_Vector64_UInt32, + ["Store.Vector64.UInt64"] = Store_Vector64_UInt64, + ["Store.Vector128.Byte"] = Store_Vector128_Byte, + ["Store.Vector128.Double"] = Store_Vector128_Double, + ["Store.Vector128.Int16"] = Store_Vector128_Int16, + ["Store.Vector128.Int32"] = Store_Vector128_Int32, + ["Store.Vector128.Int64"] = Store_Vector128_Int64, + ["Store.Vector128.SByte"] = Store_Vector128_SByte, + ["Store.Vector128.Single"] = Store_Vector128_Single, + ["Store.Vector128.UInt16"] = Store_Vector128_UInt16, + ["Store.Vector128.UInt32"] = Store_Vector128_UInt32, + ["Store.Vector128.UInt64"] = Store_Vector128_UInt64, ["Subtract.Vector64.Byte"] = Subtract_Vector64_Byte, ["Subtract.Vector64.Int16"] = Subtract_Vector64_Int16, ["Subtract.Vector64.Int32"] = Subtract_Vector64_Int32, diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Byte.cs new file mode 100644 index 00000000000000..0c53a2bccc2458 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Byte.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_Byte() + { + var test = new StoreUnaryOpTest__Store_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_Byte testClass) + { + AdvSimd.Store((Byte*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Byte*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((Byte*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Byte*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Byte*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Byte*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Byte*)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Byte*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_Byte(); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Byte*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Byte*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Byte*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Double.cs new file mode 100644 index 00000000000000..790527f659bfce --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Double.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_Double() + { + var test = new StoreUnaryOpTest__Store_Vector128_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_Double testClass) + { + AdvSimd.Store((Double*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_Double testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Double*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((Double*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Double*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Double*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Double*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Double*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Double*)), + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Double*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Double*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_Double(); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_Double(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Double*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Double*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Double*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Double*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Int16.cs new file mode 100644 index 00000000000000..80289519e83dcb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Int16.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_Int16() + { + var test = new StoreUnaryOpTest__Store_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_Int16 testClass) + { + AdvSimd.Store((Int16*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Int16*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((Int16*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int16*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int16*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int16*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int16*)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int16*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_Int16(); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int16*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int16*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int16*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Int32.cs new file mode 100644 index 00000000000000..d2e2aebd50ae3f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Int32.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_Int32() + { + var test = new StoreUnaryOpTest__Store_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_Int32 testClass) + { + AdvSimd.Store((Int32*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Int32*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((Int32*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int32*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int32*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int32*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int32*)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int32*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_Int32(); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int32*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int32*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int32*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Int64.cs new file mode 100644 index 00000000000000..8cfa92632a40a3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Int64.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_Int64() + { + var test = new StoreUnaryOpTest__Store_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_Int64 testClass) + { + AdvSimd.Store((Int64*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Int64*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((Int64*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int64*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int64*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int64*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int64*)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int64*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_Int64(); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int64*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int64*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Int64*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.SByte.cs new file mode 100644 index 00000000000000..77aa5d0679564f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.SByte.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_SByte() + { + var test = new StoreUnaryOpTest__Store_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_SByte testClass) + { + AdvSimd.Store((SByte*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((SByte*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((SByte*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(SByte*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(SByte*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(SByte*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(SByte*)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((SByte*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_SByte(); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((SByte*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((SByte*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((SByte*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Single.cs new file mode 100644 index 00000000000000..9aaf745259e6c7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.Single.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_Single() + { + var test = new StoreUnaryOpTest__Store_Vector128_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_Single testClass) + { + AdvSimd.Store((Single*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_Single testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Single*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((Single*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Single*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Single*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Single*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Single*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Single*)), + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Single*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Single*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_Single(); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_Single(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Single*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Single*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Single*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((Single*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.UInt16.cs new file mode 100644 index 00000000000000..258cce1e8e58e6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.UInt16.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_UInt16() + { + var test = new StoreUnaryOpTest__Store_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_UInt16 testClass) + { + AdvSimd.Store((UInt16*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((UInt16*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt16*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt16*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt16*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt16*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt16*)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt16*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_UInt16(); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt16*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt16*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt16*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.UInt32.cs new file mode 100644 index 00000000000000..57110a4baa09af --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.UInt32.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_UInt32() + { + var test = new StoreUnaryOpTest__Store_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_UInt32 testClass) + { + AdvSimd.Store((UInt32*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((UInt32*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt32*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt32*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt32*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt32*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt32*)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt32*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_UInt32(); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt32*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt32*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt32*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.UInt64.cs new file mode 100644 index 00000000000000..e766b14b858c24 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector128.UInt64.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector128_UInt64() + { + var test = new StoreUnaryOpTest__Store_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector128_UInt64 testClass) + { + AdvSimd.Store((UInt64*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((UInt64*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt64*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt64*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt64*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt64*), typeof(Vector128) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt64*)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt64*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector128_UInt64(); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + { + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt64*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt64*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector128((UInt64*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Byte.cs new file mode 100644 index 00000000000000..161b1ee50848b1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Byte.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_Byte() + { + var test = new StoreUnaryOpTest__Store_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_Byte testClass) + { + AdvSimd.Store((Byte*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Byte*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((Byte*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Byte*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Byte*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Byte*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Byte*)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Byte*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_Byte(); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Byte*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Byte*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Byte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Byte*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Double.cs new file mode 100644 index 00000000000000..6d70978f2314b0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Double.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_Double() + { + var test = new StoreUnaryOpTest__Store_Vector64_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_Double + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_Double testClass) + { + AdvSimd.Store((Double*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_Double testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Double*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((Double*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_Double() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_Double() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Double*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Double*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Double*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Double*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Double*)), + AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Double*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Double*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Double*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_Double(); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_Double(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Double*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Double*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Double*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Double*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Double*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Int16.cs new file mode 100644 index 00000000000000..8e1c6822fb84ee --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Int16.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_Int16() + { + var test = new StoreUnaryOpTest__Store_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_Int16 testClass) + { + AdvSimd.Store((Int16*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Int16*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((Int16*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int16*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int16*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int16*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int16*)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int16*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_Int16(); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int16*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int16*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int16*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Int32.cs new file mode 100644 index 00000000000000..20c186ff850ffc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Int32.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_Int32() + { + var test = new StoreUnaryOpTest__Store_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_Int32 testClass) + { + AdvSimd.Store((Int32*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Int32*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((Int32*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int32*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int32*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int32*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int32*)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int32*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_Int32(); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int32*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int32*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int32*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Int64.cs new file mode 100644 index 00000000000000..c3109eca07e899 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Int64.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_Int64() + { + var test = new StoreUnaryOpTest__Store_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_Int64 testClass) + { + AdvSimd.Store((Int64*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Int64*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((Int64*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int64*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int64*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Int64*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Int64*)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int64*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_Int64(); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int64*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int64*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Int64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Int64*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.SByte.cs new file mode 100644 index 00000000000000..906e5abd767651 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.SByte.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_SByte() + { + var test = new StoreUnaryOpTest__Store_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_SByte testClass) + { + AdvSimd.Store((SByte*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((SByte*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((SByte*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(SByte*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(SByte*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(SByte*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(SByte*)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((SByte*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_SByte(); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((SByte*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((SByte*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((SByte*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((SByte*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Single.cs new file mode 100644 index 00000000000000..6a13a0d0ece623 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.Single.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_Single() + { + var test = new StoreUnaryOpTest__Store_Vector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_Single + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_Single testClass) + { + AdvSimd.Store((Single*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_Single testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Single*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((Single*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_Single() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_Single() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((Single*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Single*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Single*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(Single*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(Single*)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((Single*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Single*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_Single(); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_Single(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Single*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((Single*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Single*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((Single*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((Single*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.UInt16.cs new file mode 100644 index 00000000000000..3aa4af0c37dbe0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.UInt16.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_UInt16() + { + var test = new StoreUnaryOpTest__Store_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_UInt16 testClass) + { + AdvSimd.Store((UInt16*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((UInt16*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt16*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt16*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt16*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt16*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt16*)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt16*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_UInt16(); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt16*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt16*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt16*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt16*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.UInt32.cs new file mode 100644 index 00000000000000..dc0d73f1c9a373 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.UInt32.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_UInt32() + { + var test = new StoreUnaryOpTest__Store_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_UInt32 testClass) + { + AdvSimd.Store((UInt32*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((UInt32*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt32*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt32*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt32*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt32*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt32*)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt32*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_UInt32(); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt32*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt32*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt32*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt32*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.UInt64.cs new file mode 100644 index 00000000000000..6a2ba8cd05f2d7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Store.Vector64.UInt64.cs @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Store_Vector64_UInt64() + { + var test = new StoreUnaryOpTest__Store_Vector64_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__Store_Vector64_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__Store_Vector64_UInt64 testClass) + { + AdvSimd.Store((UInt64*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__Store_Vector64_UInt64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((UInt64*)testClass._dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt64*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__Store_Vector64_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public StoreUnaryOpTest__Store_Vector64_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, Unsafe.Read>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt64*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt64*)), + Unsafe.Read>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof(AdvSimd).GetMethod(nameof(AdvSimd.Store), new Type[] { typeof(UInt64*), typeof(Vector64) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof(UInt64*)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt64*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__Store_Vector64_UInt64(); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__Store_Vector64_UInt64(); + + fixed (Vector64* pFld1 = &test._fld1) + { + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt64*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt64*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + AdvSimd.Store((UInt64*)_dataTable.outArrayPtr, AdvSimd.LoadVector64((UInt64*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if (firstOp[i] != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Store)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx index 632dc3e2ad8429..53d979ae6c97ef 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx @@ -508,6 +508,26 @@ private static readonly (string templateFileName, Dictionary tem ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "SqrtScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SqrtScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Sqrt(firstOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "SqrtScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SqrtScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Sqrt(firstOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/StoreUnOpTest.template b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/StoreUnOpTest.template new file mode 100644 index 00000000000000..4cc48ea034f008 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/StoreUnOpTest.template @@ -0,0 +1,459 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void {TestName}() + { + var test = new StoreUnaryOpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class StoreUnaryOpTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario(StoreUnaryOpTest__{TestName} testClass) + { + {Isa}.{Method}(({RetBaseType}*)testClass._dataTable.outArrayPtr, _fld1); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(StoreUnaryOpTest__{TestName} testClass) + { + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &_fld1) + { + {Isa}.{Method}(({RetBaseType}*)testClass._dataTable.outArrayPtr, {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pFld1))); + + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + + private static {Op1VectorType}<{Op1BaseType}> _clsVar1; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + + private DataTable _dataTable; + + static StoreUnaryOpTest__{TestName}() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _clsVar1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + } + + public StoreUnaryOpTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + _dataTable = new DataTable(_data1, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr)); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr))); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({RetBaseType}*), typeof({Op1VectorType}<{Op1BaseType}>) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof({RetBaseType}*)), + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr) }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({RetBaseType}*), typeof({Op1VectorType}<{Op1BaseType}>) }) + .Invoke(null, new object[] { + Pointer.Box(_dataTable.outArrayPtr, typeof({RetBaseType}*)), + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, _clsVar1); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pClsVar1 = &_clsVar1) + { + {Isa}.{Method}(({Op1BaseType}*)_dataTable.outArrayPtr, {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pClsVar1))); + + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)); + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, op1); + + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new StoreUnaryOpTest__{TestName}(); + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new StoreUnaryOpTest__{TestName}(); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &test._fld1) + { + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pFld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, _fld1); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &_fld1) + { + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pFld1))); + + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, test._fld1); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + {Isa}.{Method}(({RetBaseType}*)_dataTable.outArrayPtr, {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(&test._fld1))); + + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (int i = 0; i < RetElementCount; i++) + { + if ({ValidateIterResult}) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/addressexposedlocal.cs b/src/coreclr/tests/src/JIT/opt/OSR/addressexposedlocal.cs new file mode 100644 index 00000000000000..897c56b7fec291 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/addressexposedlocal.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// OSR method has address exposed local + +class AddressExposedLocal +{ + // [MethodImpl(MethodImplOptions.NoInlining)] + public static unsafe int I(ref int p) => p; + + [MethodImpl(MethodImplOptions.NoInlining)] + public static unsafe void J(ref int p) {} + + [MethodImpl(MethodImplOptions.NoInlining)] + public static unsafe int F(int from, int to) + { + int result = 0; + J(ref result); + for (int i = from; i < to; i++) + { + result = I(ref result) + i; + } + return result; + } + + public static int Main() + { + Console.WriteLine($"starting sum"); + int result = F(0, 1_000_000); + Console.WriteLine($"done, sum is {result}"); + return (result == 1783293664) ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/addressexposedlocal.csproj b/src/coreclr/tests/src/JIT/opt/OSR/addressexposedlocal.csproj new file mode 100644 index 00000000000000..881e48ea778627 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/addressexposedlocal.csproj @@ -0,0 +1,25 @@ + + + Exe + + True + true + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/doublestackalloc.cs b/src/coreclr/tests/src/JIT/opt/OSR/doublestackalloc.cs new file mode 100644 index 00000000000000..7265d18699cf3d --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/doublestackalloc.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// OSR test case with two stackallocs. +// +// Original method frame is variable sized when we reach patchpoint +// OSR method frame is also variable sized. + +using System; + +class DoubleStackAlloc +{ + static int outerSize = 1000; + static int innerSize = 1; + public static unsafe int Main() + { + long* result = stackalloc long[outerSize]; + *result = 0; + for (int i = 0; i < 1_000_000; i++) + { + if ((i % 8192) == 0) + { + long *nresult = stackalloc long[innerSize]; + *nresult = *result; + result = nresult; + } + *result += i; + } + return *result == 499999500000 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/doublestackalloc.csproj b/src/coreclr/tests/src/JIT/opt/OSR/doublestackalloc.csproj new file mode 100644 index 00000000000000..881e48ea778627 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/doublestackalloc.csproj @@ -0,0 +1,25 @@ + + + Exe + + True + true + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/example.cs b/src/coreclr/tests/src/JIT/opt/OSR/example.cs new file mode 100644 index 00000000000000..1f360eea9562e2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/example.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +// Example from the OSR doc + +class OSR_Example +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static double F(int from, int to) + { + double result = 0; + for (int i = from; i < to; i++) + { + result += (double)i; + } + return result; + } + + public static int Main(string[] args) + { + int final = args.Length <= 0 ? 1_000_000 : Int32.Parse(args[0]); + long frequency = Stopwatch.Frequency; + long nanosecPerTick = (1000L*1000L*1000L) / frequency; + // Console.WriteLine($"computing sum over {final} ints"); + // Get some of the initial jit cost out of the way + Stopwatch s = new Stopwatch(); + s.Start(); + s.Stop(); + + s = new Stopwatch(); + s.Start(); + double result = F(0, final); + s.Stop(); + double elapsedTime = 1000.0 * (double) s.ElapsedTicks / (double) frequency; + Console.WriteLine($"{final} iterations took {elapsedTime:F2}ms"); + return result == 499999500000 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/example.csproj b/src/coreclr/tests/src/JIT/opt/OSR/example.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/example.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/genericmethodpatchpoint.cs b/src/coreclr/tests/src/JIT/opt/OSR/genericmethodpatchpoint.cs new file mode 100644 index 00000000000000..a3f9dea686ceaa --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/genericmethodpatchpoint.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// Patchpoint in generic method + +class GenericMethodPatchpoint +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static int F(T[] data, int from, int to) where T : class + { + int result = 0; + for (int i = from; i < to; i++) + { + if (data[i] == null) result++; + } + return result; + } + + public static int Main() + { + string[] a = new string[1000]; + a[111] = "hello, world"; + int result = F(a, 0, a.Length); + Console.WriteLine($"done, result is {result}"); + return result == 999 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/genericmethodpatchpoint.csproj b/src/coreclr/tests/src/JIT/opt/OSR/genericmethodpatchpoint.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/genericmethodpatchpoint.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/innerloop.cs b/src/coreclr/tests/src/JIT/opt/OSR/innerloop.cs new file mode 100644 index 00000000000000..7dadb6debff9b8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/innerloop.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +class InnerLoop +{ + public static int Main() + { + int[] a = new int[1000]; + a[555] = 1; + + int result = 0; + + for (int i = 0; i < 1000; i++) + { + for (int j = i; j < 1000; j++) + { + result += a[j]; + } + } + + return result - 456; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/innerloop.csproj b/src/coreclr/tests/src/JIT/opt/OSR/innerloop.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/innerloop.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/integersumloop.cs b/src/coreclr/tests/src/JIT/opt/OSR/integersumloop.cs new file mode 100644 index 00000000000000..3742958f768c28 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/integersumloop.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +class IntegerSumLoop +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static int F(int from, int to) + { + int result = 0; + for (int i = from; i < to; i++) + { + result += i; + } + return result; + } + + public static int Main(string[] args) + { + int final = 1_000_000; + long frequency = Stopwatch.Frequency; + long nanosecPerTick = (1000L*1000L*1000L) / frequency; + F(0, 10); + Stopwatch s = new Stopwatch(); + s.Start(); + int result = F(0, final); + s.Stop(); + double elapsedTime = 1000.0 * (double) s.ElapsedTicks / (double) frequency; + Console.WriteLine($"{final} iterations took {elapsedTime:F2}ms"); + return result == 1783293664 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/integersumloop.csproj b/src/coreclr/tests/src/JIT/opt/OSR/integersumloop.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/integersumloop.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/livelocaladdress.cs b/src/coreclr/tests/src/JIT/opt/OSR/livelocaladdress.cs new file mode 100644 index 00000000000000..652475c5814371 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/livelocaladdress.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// An example where OSR must preserve original method addreses for locals + +class LiveLocalAddress +{ + public static unsafe int Main() + { + long result = 0; + int a = 0; + int *c = &a; + int b = 0; + long distance = c - &b; + + for (int i = 0; i < 100_000; i++) + { + result += &a - &b; + } + + return (int)(result / (1000 * distance)); + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/livelocaladdress.csproj b/src/coreclr/tests/src/JIT/opt/OSR/livelocaladdress.csproj new file mode 100644 index 00000000000000..53a9cc32ce5e5c --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/livelocaladdress.csproj @@ -0,0 +1,25 @@ + + + Exe + + True + true + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/livelocalstackalloc.cs b/src/coreclr/tests/src/JIT/opt/OSR/livelocalstackalloc.cs new file mode 100644 index 00000000000000..b6f1ec1950b096 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/livelocalstackalloc.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// Example where local address is live in a stackalloc region + +class LiveLocalStackalloc +{ + static int n = 100; + static int j = 30; + + public static unsafe int Main() + { + int nn = n; + int** ptrs = stackalloc int*[nn]; + int a = 100; + *(ptrs + j) = &a; + int result = 0; + + for (int i = 0; i < nn; i++) + { + int* p = *(ptrs + i); + if (p != null) result += *p; + } + + return result; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/livelocalstackalloc.csproj b/src/coreclr/tests/src/JIT/opt/OSR/livelocalstackalloc.csproj new file mode 100644 index 00000000000000..881e48ea778627 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/livelocalstackalloc.csproj @@ -0,0 +1,25 @@ + + + Exe + + True + true + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainloop.cs b/src/coreclr/tests/src/JIT/opt/OSR/mainloop.cs new file mode 100644 index 00000000000000..e63bdca2b1bb25 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainloop.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// Simple OSR test case -- long running loop in Main + +class MainLoop +{ + public static int Main() + { + long result = 0; + for (int i = 0; i < 1_000_000; i++) + { + result += (long)i; + } + return result == 499999500000 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainloop.csproj b/src/coreclr/tests/src/JIT/opt/OSR/mainloop.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainloop.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainloop2.cs b/src/coreclr/tests/src/JIT/opt/OSR/mainloop2.cs new file mode 100644 index 00000000000000..2654ea3fd0beff --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainloop2.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// Simple OSR test case -- nested loop in Main + +class MainNestedLoop +{ + public static int Main() + { + long result = 0; + for (int i = 0; i < 1_000; i++) + { + for (int j = 0; j < 1_000; j++) + { + result += (long)(i * 1_000 + j); + } + } + + return result == 499999500000 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainloop2.csproj b/src/coreclr/tests/src/JIT/opt/OSR/mainloop2.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainloop2.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry.cs b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry.cs new file mode 100644 index 00000000000000..0fb0b6907ede56 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// OSR entry in a try region + +class MainLoopTry +{ + public static int Main() + { + Console.WriteLine($"starting sum"); + int result = 0; + try + { + for (int i = 0; i < 1_000_000; i++) + { + result += i; + } + } + finally + { + Console.WriteLine($"done, sum is {result}"); + } + return result == 1783293664 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry.csproj b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry2.cs b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry2.cs new file mode 100644 index 00000000000000..2eef5c91c3178d --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry2.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// Multiple patchpoints each in a try + +class MainLoopTry2 +{ + public static int Main() + { + Console.WriteLine($"starting sum"); + int result = 0; + try + { + for (int i = 0; i < 1_000; i++) + { + int temp = result; + try + { + for (int j = 0; j < 1_000; j++) + { + temp += 1000 * i + j; + } + } + finally + { + result = temp; + } + } + } + finally + { + Console.WriteLine($"done, sum is {result}"); + } + return result == 1783293664 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry2.csproj b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry2.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry2.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry3.cs b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry3.cs new file mode 100644 index 00000000000000..0c1469206f18dd --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry3.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// Tricky case for OSR with patchpoint in try region. +// +// If we need to OSR at inner loop head, then both try +// regions need trimming, but they can't trim down to the +// same block, and the branch to the logical trimmed +// entry point is not from the OSR entry. + +using System; + +class MainLoopCloselyNestedTry +{ + public static int Main() + { + Console.WriteLine($"starting sum"); + int result = 0; + try + { + try + { + int temp = 0; + for (int i = 0; i < 1_000; i++) + { + for (int j = 0; j < 1_000; j++) + { + temp += 1000 * i + j; + } + } + result = temp; + } + catch (Exception) + { + + } + } + finally + { + Console.WriteLine($"done, sum is {result}"); + } + return result == 1783293664 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry3.csproj b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry3.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry3.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry4.cs b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry4.cs new file mode 100644 index 00000000000000..8b7afbfa4e9a8a --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry4.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// Tricky case for OSR with patchpoint in try region. +// +// If we need to OSR at inner loop head, then both try +// regions need trimming. +// +// Mutually protective try example. + +using System; + +class E : Exception {} + +class MainLoopMutuallyProtectiveTry +{ + public static int Main() + { + Console.WriteLine($"starting sum"); + int result = 0; + try + { + int temp = 0; + for (int i = 0; i < 1_000; i++) + { + for (int j = 0; j < 1_000; j++) + { + temp += 1000 * i + j; + } + } + result = temp; + } + catch (E) + { + } + catch (Exception) + { + } + Console.WriteLine($"done, sum is {result}"); + return result == 1783293664 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry4.csproj b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry4.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/mainlooptry4.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/memoryargument.cs b/src/coreclr/tests/src/JIT/opt/OSR/memoryargument.cs new file mode 100644 index 00000000000000..7b8045c0146bfa --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/memoryargument.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// OSR method must access memory argument + +class MemoryArgument +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static int F(int a, int b, int c, int d, int from, int to) + { + int result = 0; + for (int i = from; i < to; i++) + { + result += i; + } + return result; + } + + public static int Main(string[] args) + { + int final = 1_000_000; + int result = F(0, 0, 0, 0, 0, final); + return result == 1783293664 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/memoryargument.csproj b/src/coreclr/tests/src/JIT/opt/OSR/memoryargument.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/memoryargument.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/nesteddoloops.cs b/src/coreclr/tests/src/JIT/opt/OSR/nesteddoloops.cs new file mode 100644 index 00000000000000..160aeb5406ad30 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/nesteddoloops.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// Nested do lops + +class NestedDoLoops +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static int F(int inner, int outer, int innerTo, int outerTo) + { + do { + do {} while (inner++ < innerTo); + inner = 0; + } + while (outer++ < outerTo); + + return outer; + } + + public static int Main() + { + Console.WriteLine($"starting sum"); + int result1 = F(0, 10, 0, 100_000); + int result2 = F(0, 100_000, 0, 10); + Console.WriteLine($"done, sum is {result1} and {result2}"); + return (result1 == result2) && (result1 == 100_001) ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/nesteddoloops.csproj b/src/coreclr/tests/src/JIT/opt/OSR/nesteddoloops.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/nesteddoloops.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/originalstackalloc.cs b/src/coreclr/tests/src/JIT/opt/OSR/originalstackalloc.cs new file mode 100644 index 00000000000000..cdb6cbf1baf330 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/originalstackalloc.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// Orignal method has stackalloc, osr does not + +class OriginalStackalloc +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static unsafe int F(int from, int to, int s) + { + int* result = stackalloc int[s]; + *result = 0; + for (int i = from; i < to; i++) + { + *result += i; + } + return *result; + } + + public static int Main() + { + Console.WriteLine($"starting sum"); + int result = F(0, 1_000_000, 1); + Console.WriteLine($"done, sum is {result}"); + return (result == 1783293664) ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/originalstackalloc.csproj b/src/coreclr/tests/src/JIT/opt/OSR/originalstackalloc.csproj new file mode 100644 index 00000000000000..881e48ea778627 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/originalstackalloc.csproj @@ -0,0 +1,25 @@ + + + Exe + + True + true + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/osrcontainstry.cs b/src/coreclr/tests/src/JIT/opt/OSR/osrcontainstry.cs new file mode 100644 index 00000000000000..ce89aefe69eb26 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/osrcontainstry.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// OSR method contains try + +class OSRContainsTry +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static unsafe int I(ref int p) => p; + + [MethodImpl(MethodImplOptions.NoInlining)] + public static unsafe int F(int from, int to) + { + int result = 0; + for (int i = from; i < to; i++) + { + try + { + result = I(ref result) + i; + } + catch (Exception e) + { + } + } + return result; + } + + public static int Main() + { + Console.WriteLine($"starting sum"); + int result = F(0, 1_000_000); + Console.WriteLine($"done, sum is {result}"); + return result == 1783293664 ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/osrcontainstry.csproj b/src/coreclr/tests/src/JIT/opt/OSR/osrcontainstry.csproj new file mode 100644 index 00000000000000..881e48ea778627 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/osrcontainstry.csproj @@ -0,0 +1,25 @@ + + + Exe + + True + true + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/promoted.cs b/src/coreclr/tests/src/JIT/opt/OSR/promoted.cs new file mode 100644 index 00000000000000..0fde778e7cdd7c --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/promoted.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +// OSR complications with promoted structs + +struct Y +{ + public Y(int _a, int _b) + { + a = _a; + b = _b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void Init(int _a, int _b) + { + s_y = new Y(_a, _b); + } + + public static Y s_y; + public int a; + public int b; +} + +class OSRMethodStructPromotion +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static int F(int from, int to) + { + Y.Init(from, to); + Y y = Y.s_y; + int result = 0; + for (int i = y.a; i < y.b; i++) + { + result += i; + } + return result; + } + + public static int Main(string[] args) + { + int final = 1_000_000; + F(0, 10); + int result = F(0, final); + int expected = 1783293664; + return result == expected ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/promoted.csproj b/src/coreclr/tests/src/JIT/opt/OSR/promoted.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/promoted.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/tailrecurse.cs b/src/coreclr/tests/src/JIT/opt/OSR/tailrecurse.cs new file mode 100644 index 00000000000000..61a82945be469b --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/tailrecurse.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// OSR and tail recursion + +class OSRTailRecursion +{ + public static int F(int from, int to, int n, int a) + { + int result = a; + for (int i = from; i < to; i++) + { + result += i; + } + + if (n <= 0) return result; + + int delta = to - from; + + return F(to, to + to - from, n-1, result); + } + + public static int Main() + { + Console.WriteLine($"starting sum"); + int result = F(0, 100_000, 9, 0); + bool ok = (result == 1783293664); + string msg = ok ? "Pass" : "Fail"; + Console.WriteLine($"done, sum is {result}, {msg}"); + return ok ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/tailrecurse.csproj b/src/coreclr/tests/src/JIT/opt/OSR/tailrecurse.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/tailrecurse.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry.cs b/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry.cs new file mode 100644 index 00000000000000..c6481a6fb654d5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// Tail recursion, OSR entry in try region + +class TailRecursionWithOsrEntryInTry +{ + public static int F(int from, int to, int n, int a) + { + int result = a; + + try + { + for (int i = from; i < to; i++) + { + result += i; + } + } + catch(Exception) + { + } + + if (n <= 0) return result; + + int delta = to - from; + + return F(to, to + to - from, n-1, result); + } + + public static int Main() + { + Console.WriteLine($"starting sum"); + int result = F(0, 100_000, 9, 0); + bool ok = (result == 1783293664); + string msg = ok ? "Pass" : "Fail"; + Console.WriteLine($"done, sum is {result}, {msg}"); + return ok ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry.csproj b/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry2.cs b/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry2.cs new file mode 100644 index 00000000000000..dfe13efd797584 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry2.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// Tail recursion candidate with OSR entry in a try region + +class TailRecursionCandidateOSREntryInTry +{ + public unsafe static int F(int from, int to, int n, int result, int *x) + { + try + { + for (int i = from; i < to; i++) + { + result += i; + } + } + catch(Exception) + { + } + + if (n <= 0) return result; + + int delta = to - from; + + // Tail recursive site, but can't tail call + return F(to, to + delta, n-1, result, &result); + } + + public static unsafe int Main() + { + int x = 0; + int result = F(0, 100_000, 9, 0, &x); + bool ok = (result == 1783293664); + string msg = ok ? "Pass" : "Fail"; + Console.WriteLine($"done, sum is {result}, {msg}"); + return ok ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry2.csproj b/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry2.csproj new file mode 100644 index 00000000000000..881e48ea778627 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/tailrecursetry2.csproj @@ -0,0 +1,25 @@ + + + Exe + + True + true + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods.cs b/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods.cs new file mode 100644 index 00000000000000..8128e005c0fbad --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// Method creates has two OSR methods + +class TwoOSRMethods +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static void I(ref int p, int i) => p = p + i; + + [MethodImpl(MethodImplOptions.NoInlining)] + public static int F(int from, int to, bool b) + { + int result = 0; + + if (b) + { + for (int i = from; i < to; i++) + { + I(ref result, i); + } + } + else + { + for (int i = from; i < to; i++) + { + result += i; + } + + } + return result; + } + + public static int Main(string[] args) + { + int final = 1_000_000; + int result1 = F(0, final, true); + int result2 = F(0, final, false); + return (result1 == result2) && (result1 == 1783293664) ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods.csproj b/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods1.cs b/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods1.cs new file mode 100644 index 00000000000000..42eb9dc848dbe6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods1.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// Two OSR methods from one orignal method + +class X +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static int F(int from, int to, bool sumUp) + { + int result = 0; + + if (sumUp) + { + for (int i = from; i < to; i++) + { + result += i; + } + } + else + { + for (int i = to; i > from; i--) + { + result += (i-1); + } + + } + return result; + } + + public static int Main(string[] args) + { + int final = 1_000_000; + int result1 = F(0, final, true); + int result2 = F(0, final, false); + return (result1 == result2) && (result1 == 1783293664) ? 100 : -1; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods1.csproj b/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods1.csproj new file mode 100644 index 00000000000000..9620f75474a935 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/OSR/twoosrmethods1.csproj @@ -0,0 +1,24 @@ + + + Exe + + True + + + + + + + + + diff --git a/src/coreclr/tests/src/readytorun/crossgen2/Program.cs b/src/coreclr/tests/src/readytorun/crossgen2/Program.cs index 00baf301d95883..32121faedec6ca 100644 --- a/src/coreclr/tests/src/readytorun/crossgen2/Program.cs +++ b/src/coreclr/tests/src/readytorun/crossgen2/Program.cs @@ -1211,9 +1211,7 @@ public static int Main(string[] args) RunTest("ChkCast", ChkCast()); RunTest("ChkCastValueType", ChkCastValueType()); RunTest("BoxUnbox", BoxUnbox()); - // TODO: enabling this test requires fixes to IsManagedSequential I'm going to send out - // in a subsequent PR together with removal of this temporary clause [trylek] - // RunTest("NullableWithExplicitLayoutTest", NullableWithExplicitLayoutTest()); + RunTest("NullableWithExplicitLayoutTest", NullableWithExplicitLayoutTest()); RunTest("CastClassWithCharTest", CastClassWithCharTest()); RunTest("TypeHandle", TypeHandle()); RunTest("RuntimeTypeHandle", RuntimeTypeHandle()); diff --git a/src/coreclr/tests/src/readytorun/crossgen2/crossgen2smoke.csproj b/src/coreclr/tests/src/readytorun/crossgen2/crossgen2smoke.csproj index 8a98db7f66eeb2..62fdd0c6634ed0 100644 --- a/src/coreclr/tests/src/readytorun/crossgen2/crossgen2smoke.csproj +++ b/src/coreclr/tests/src/readytorun/crossgen2/crossgen2smoke.csproj @@ -5,8 +5,8 @@ true 0 - - true + + true .ildll diff --git a/src/coreclr/tests/testenvironment.proj b/src/coreclr/tests/testenvironment.proj index b3bfd7aef5985a..caed6ae7e1ee8c 100644 --- a/src/coreclr/tests/testenvironment.proj +++ b/src/coreclr/tests/testenvironment.proj @@ -40,7 +40,14 @@ COMPlus_JitStressRegs; COMPlus_TailcallStress; COMPlus_ReadyToRun; - COMPlus_ZapDisable + COMPlus_ZapDisable; + COMPlus_TC_OnStackReplacement; + COMPlus_TC_QuickJitForLoops; + COMPlus_TC_OnStackReplacement_InitialCounter; + COMPlus_OSR_HitLimit; + COMPlus_JitEnableGuardedDevirtualization; + COMPlus_EnableEHWriteThru; + COMPlus_JitObjectStackAllocation @@ -126,6 +133,11 @@ + + + + + diff --git a/src/installer/settings.cmake b/src/installer/settings.cmake index 6c56313847a686..c43bdbf4fc19ec 100644 --- a/src/installer/settings.cmake +++ b/src/installer/settings.cmake @@ -111,7 +111,10 @@ else() # compiling with -std=c++11. # add_compile_options(-Weverything) endif() - add_compile_options(-Werror) + # Suppress warnings-as-errors in release branches to reduce servicing churn + if (PRERELEASE) + add_compile_options(-Werror) + endif() add_compile_options(-Wno-missing-field-initializers) add_compile_options(-Wno-unused-function) add_compile_options(-Wno-unused-local-typedef) @@ -149,6 +152,10 @@ elseif(CLR_CMAKE_TARGET_FREEBSD) add_compile_options(-fstack-protector) endif() +if(CLR_CMAKE_TARGET_ANDROID) + add_compile_options(-Wno-user-defined-warnings) +endif() + add_definitions(-D_NO_ASYNCRTIMP) add_definitions(-D_NO_PPLXIMP) if(CLR_CMAKE_TARGET_LINUX) diff --git a/src/installer/test/HostActivation.Tests/PortableAppActivation.cs b/src/installer/test/HostActivation.Tests/PortableAppActivation.cs index 0c46e67de869ea..73179af9637f4b 100644 --- a/src/installer/test/HostActivation.Tests/PortableAppActivation.cs +++ b/src/installer/test/HostActivation.Tests/PortableAppActivation.cs @@ -404,6 +404,58 @@ public void MissingFrameworkInRuntimeConfig_Fails(bool useAppHost) .And.HaveStdErrContaining($"'{app.RuntimeConfigJson}' did not specify a framework"); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void AppHost_CLI_FrameworkDependent_MissingRuntimeFramework_ErrorReportedInDialog(bool missingHostfxr) + { + var fixture = sharedTestState.PortableAppFixture_Built + .Copy(); + + string appExe = fixture.TestProject.AppExe; + File.Copy(sharedTestState.BuiltAppHost, appExe, overwrite: true); + AppHostExtensions.BindAppHost(appExe); + + string invalidDotNet = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "cliErrors")); + using (new TestArtifact(invalidDotNet)) + { + Directory.CreateDirectory(invalidDotNet); + + string expectedErrorCode; + string expectedUrlQuery; + string expectedUrlParameter = null; + if (missingHostfxr) + { + expectedErrorCode = Constants.ErrorCode.CoreHostLibMissingFailure.ToString("x"); + expectedUrlQuery = "missing_runtime=true&"; + expectedUrlParameter = $"&apphost_version={sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"; + } + else + { + invalidDotNet = new DotNetBuilder(invalidDotNet, sharedTestState.RepoDirectories.BuiltDotnet, "missingFramework") + .Build() + .BinPath; + expectedErrorCode = Constants.ErrorCode.FrameworkMissingFailure.ToString("x"); + expectedUrlQuery = $"framework={Constants.MicrosoftNETCoreApp}&framework_version={sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"; + } + + Command command = Command.Create(appExe) + .EnableTracingAndCaptureOutputs() + .DotNetRoot(invalidDotNet) + .MultilevelLookup(false) + .Start(); + + var result = command.WaitForExit(true) + .Should().Fail(); + + result.And.HaveStdErrContaining($"- https://aka.ms/dotnet-core-applaunch?{expectedUrlQuery}"); + if (expectedUrlParameter != null) + { + result.And.HaveStdErrContaining(expectedUrlParameter); + } + } + } + [Theory] [InlineData(true)] [InlineData(false)] @@ -430,10 +482,12 @@ public void AppHost_GUI_FrameworkDependent_MissingRuntimeFramework_ErrorReported string expectedErrorCode; string expectedUrlQuery; + string expectedUrlParameter = null; if (missingHostfxr) { expectedErrorCode = Constants.ErrorCode.CoreHostLibMissingFailure.ToString("x"); - expectedUrlQuery = "missing_runtime=true"; + expectedUrlQuery = "missing_runtime=true&"; + expectedUrlParameter = $"&apphost_version={sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"; } else { @@ -453,11 +507,17 @@ public void AppHost_GUI_FrameworkDependent_MissingRuntimeFramework_ErrorReported WaitForPopupFromProcess(command.Process); command.Process.Kill(); - command.WaitForExit(true) - .Should().Fail() - .And.HaveStdErrContaining($"Showing error dialog for application: '{Path.GetFileName(appExe)}' - error code: 0x{expectedErrorCode}") + var result = command.WaitForExit(true) + .Should().Fail(); + + result.And.HaveStdErrContaining($"Showing error dialog for application: '{Path.GetFileName(appExe)}' - error code: 0x{expectedErrorCode}") .And.HaveStdErrContaining($"url: 'https://aka.ms/dotnet-core-applaunch?{expectedUrlQuery}") - .And.HaveStdErrContaining($"apphost_version={sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdErrContaining("&gui=true"); + + if (expectedUrlParameter != null) + { + result.And.HaveStdErrContaining(expectedUrlParameter); + } } } diff --git a/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Der.cs b/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Der.cs index 868547af4ba759..40f035a22baff8 100644 --- a/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Der.cs +++ b/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Der.cs @@ -4,8 +4,6 @@ using System; using System.Diagnostics; -using System.IO; -using System.Numerics; using System.Security.Cryptography; using System.Security.Cryptography.Asn1; @@ -20,45 +18,170 @@ internal static partial class AsymmetricAlgorithmHelpers /// Convert Ieee1363 format of (r, s) to Der format /// public static byte[] ConvertIeee1363ToDer(ReadOnlySpan input) + { + using (AsnWriter writer = WriteIeee1363ToDer(input)) + { + return writer.Encode(); + } + } + + internal static bool TryConvertIeee1363ToDer( + ReadOnlySpan input, + Span destination, + out int bytesWritten) + { + using (AsnWriter writer = WriteIeee1363ToDer(input)) + { + return writer.TryEncode(destination, out bytesWritten); + } + } + + private static AsnWriter WriteIeee1363ToDer(ReadOnlySpan input) { Debug.Assert(input.Length % 2 == 0); Debug.Assert(input.Length > 1); // Input is (r, s), each of them exactly half of the array. - // Output is the DER encoded value of CONSTRUCTEDSEQUENCE(INTEGER(r), INTEGER(s)). + // Output is the DER encoded value of SEQUENCE(INTEGER(r), INTEGER(s)). int halfLength = input.Length / 2; - using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) - { - writer.PushSequence(); - writer.WriteKeyParameterInteger(input.Slice(0, halfLength)); - writer.WriteKeyParameterInteger(input.Slice(halfLength, halfLength)); - writer.PopSequence(); - return writer.Encode(); - } + AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); + writer.PushSequence(); + writer.WriteKeyParameterInteger(input.Slice(0, halfLength)); + writer.WriteKeyParameterInteger(input.Slice(halfLength, halfLength)); + writer.PopSequence(); + return writer; } /// /// Convert Der format of (r, s) to Ieee1363 format /// - public static byte[] ConvertDerToIeee1363(byte[] input, int inputOffset, int inputCount, int fieldSizeBits) + public static byte[] ConvertDerToIeee1363(ReadOnlySpan input, int fieldSizeBits) { - int size = BitsToBytes(fieldSizeBits); + int fieldSizeBytes = BitsToBytes(fieldSizeBits); + int encodedSize = 2 * fieldSizeBytes; + byte[] response = new byte[encodedSize]; - AsnReader reader = new AsnReader(input.AsMemory(inputOffset, inputCount), AsnEncodingRules.DER); - AsnReader sequenceReader = reader.ReadSequence(); + ConvertDerToIeee1363(input, fieldSizeBits, response); + return response; + } + + internal static int ConvertDerToIeee1363(ReadOnlySpan input, int fieldSizeBits, Span destination) + { + int fieldSizeBytes = BitsToBytes(fieldSizeBits); + int encodedSize = 2 * fieldSizeBytes; + + Debug.Assert(destination.Length >= encodedSize); + + AsnValueReader reader = new AsnValueReader(input, AsnEncodingRules.DER); + AsnValueReader sequenceReader = reader.ReadSequence(); reader.ThrowIfNotEmpty(); - ReadOnlySpan rDer = sequenceReader.ReadIntegerBytes().Span; - ReadOnlySpan sDer = sequenceReader.ReadIntegerBytes().Span; + ReadOnlySpan rDer = sequenceReader.ReadIntegerBytes(); + ReadOnlySpan sDer = sequenceReader.ReadIntegerBytes(); sequenceReader.ThrowIfNotEmpty(); - byte[] response = new byte[2 * size]; - CopySignatureField(rDer, response.AsSpan(0, size)); - CopySignatureField(sDer, response.AsSpan(size, size)); + CopySignatureField(rDer, destination.Slice(0, fieldSizeBytes)); + CopySignatureField(sDer, destination.Slice(fieldSizeBytes, fieldSizeBytes)); + return encodedSize; + } - return response; + internal static int GetMaxDerSignatureSize(int fieldSizeBits) + { + // This encoding format is the DER-encoded representation of + // SEQUENCE(INTEGER(r), INTEGER(s)). + // Each of r and s are unsigned fieldSizeBits integers, and if byte-aligned + // then they may gain a padding byte to avoid being a negative number. + // The biggest single-byte length encoding for DER is 0x7F bytes, but we're + // symmetric, so 0x7E (126). + // 63 bytes per half allows for 61 content bytes (prefix 02 3D), which can + // encode up to a ((61 * 8) - 1)-bit integer. + // So, any fieldSizeBits <= 487 maximally needs 2 * fieldSizeBytes + 6 bytes, + // because all lengths fit in one byte. (30 7E 02 3D ... 02 3D ...) + + // Add the padding bit because of unsigned -> signed. + int paddedFieldSizeBytes = BitsToBytes(fieldSizeBits + 1); + + if (paddedFieldSizeBytes <= 61) + { + return 2 * paddedFieldSizeBytes + 6; + } + + // Past this point the sequence length grows (30 81 xx) up until 0xFF payload. + // Per our symmetry, that happens when the integers themselves max out, which is + // when paddedFieldSizeBytes is 0x7F; which covers up to a 1015-bit (before padding) field. + + if (paddedFieldSizeBytes <= 0x7F) + { + return 2 * paddedFieldSizeBytes + 7; + } + + // Beyond here, we'll just do math. + int segmentSize = 2 + GetDerLengthLength(paddedFieldSizeBytes) + paddedFieldSizeBytes; + int payloadSize = 2 * segmentSize; + int sequenceSize = 2 + GetDerLengthLength(payloadSize) + payloadSize; + return sequenceSize; + + static int GetDerLengthLength(int payloadLength) + { + Debug.Assert(payloadLength >= 0); + + if (payloadLength <= 0x7F) + return 0; + + if (payloadLength <= 0xFF) + return 1; + + if (payloadLength <= 0xFFFF) + return 2; + + if (payloadLength <= 0xFFFFFF) + return 3; + + return 4; + } + } + +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + /// + /// Converts IeeeP1363 format to the specified signature format + /// + internal static byte[] ConvertFromIeeeP1363Signature(byte[] signature, DSASignatureFormat targetFormat) + { + switch (targetFormat) + { + case DSASignatureFormat.IeeeP1363FixedFieldConcatenation: + return signature; + case DSASignatureFormat.Rfc3279DerSequence: + return ConvertIeee1363ToDer(signature); + default: + throw new CryptographicException( + SR.Cryptography_UnknownSignatureFormat, + targetFormat.ToString()); + } } + /// + /// Converts signature in the specified signature format to IeeeP1363 + /// + internal static byte[] ConvertSignatureToIeeeP1363( + DSASignatureFormat currentFormat, + ReadOnlySpan signature, + int fieldSizeBits) + { + switch (currentFormat) + { + case DSASignatureFormat.IeeeP1363FixedFieldConcatenation: + return signature.ToArray(); + case DSASignatureFormat.Rfc3279DerSequence: + return ConvertDerToIeee1363(signature, fieldSizeBits); + default: + throw new CryptographicException( + SR.Cryptography_UnknownSignatureFormat, + currentFormat.ToString()); + } + } +#endif + public static int BitsToBytes(int bitLength) { int byteLength = (bitLength + 7) / 8; @@ -69,10 +192,15 @@ private static void CopySignatureField(ReadOnlySpan signatureField, Span response.Length) { - // The only way this should be true is if the value required a zero-byte-pad. - Debug.Assert(signatureField.Length == response.Length + 1, "signatureField.Length == fieldLength + 1"); - Debug.Assert(signatureField[0] == 0, "signatureField[0] == 0"); - Debug.Assert(signatureField[1] > 0x7F, "signatureField[1] > 0x7F"); + if (signatureField.Length != response.Length + 1 || + signatureField[0] != 0 || + signatureField[1] <= 0x7F) + { + // The only way this should be true is if the value required a zero-byte-pad. + Debug.Fail($"A signature field was longer ({signatureField.Length}) than expected ({response.Length})"); + throw new CryptographicException(); + } + signatureField = signatureField.Slice(1); } @@ -80,7 +208,59 @@ private static void CopySignatureField(ReadOnlySpan signatureField, Span signature, + int fieldSizeBits = 0) + { + try + { + if (fieldSizeBits == 0) + { + DSAParameters pars = dsa.ExportParameters(false); + fieldSizeBits = pars.Q!.Length * 8; + } + + return ConvertSignatureToIeeeP1363( + currentFormat, + signature, + fieldSizeBits); + } + catch (CryptographicException) + { + // This method is used only for verification where we want to return false when signature is + // incorrectly formatted. + // We do not want to bubble up the exception anywhere. + return null; + } + } + + internal static byte[]? ConvertSignatureToIeeeP1363( + this ECDsa ecdsa, + DSASignatureFormat currentFormat, + ReadOnlySpan signature) + { + try + { + return ConvertSignatureToIeeeP1363( + currentFormat, + signature, + ecdsa.KeySize); + } + catch (CryptographicException) + { + // This method is used only for verification where we want to return false when signature is + // incorrectly formatted. + // We do not want to bubble up the exception anywhere. + return null; + } + } +#endif } } diff --git a/src/libraries/Common/src/Internal/Cryptography/Helpers.cs b/src/libraries/Common/src/Internal/Cryptography/Helpers.cs index 0959b740cc380a..6e274fe3f8ce78 100644 --- a/src/libraries/Common/src/Internal/Cryptography/Helpers.cs +++ b/src/libraries/Common/src/Internal/Cryptography/Helpers.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. #nullable enable +using System; using System.Diagnostics.CodeAnalysis; namespace Internal.Cryptography @@ -19,5 +20,17 @@ internal static partial class Helpers return (byte[])(src.Clone()); } + + internal static bool TryCopyToDestination(ReadOnlySpan source, Span destination, out int bytesWritten) + { + if (source.TryCopyTo(destination)) + { + bytesWritten = source.Length; + return true; + } + + bytesWritten = 0; + return false; + } } } diff --git a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFProxy.cs b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFProxy.cs index 2ed609b19d9ee3..580a3d87a40a45 100644 --- a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFProxy.cs +++ b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFProxy.cs @@ -50,12 +50,12 @@ internal class CFProxy { private SafeCFDictionaryHandle _dictionary; - internal static readonly string kCFProxyTypeAutoConfigurationURL; - internal static readonly string kCFProxyTypeAutoConfigurationJavaScript; - internal static readonly string kCFProxyTypeFTP; - internal static readonly string kCFProxyTypeHTTP; - internal static readonly string kCFProxyTypeHTTPS; - internal static readonly string kCFProxyTypeSOCKS; + internal static readonly string? kCFProxyTypeAutoConfigurationURL; + internal static readonly string? kCFProxyTypeAutoConfigurationJavaScript; + internal static readonly string? kCFProxyTypeFTP; + internal static readonly string? kCFProxyTypeHTTP; + internal static readonly string? kCFProxyTypeHTTPS; + internal static readonly string? kCFProxyTypeSOCKS; private static readonly IntPtr kCFProxyAutoConfigurationJavaScriptKey; private static readonly IntPtr kCFProxyAutoConfigurationURLKey; @@ -109,7 +109,7 @@ private static string LoadCFStringSymbol(IntPtr lib, string name) } } - private string GetString(IntPtr key) + private string? GetString(IntPtr key) { IntPtr dictValue = CFDictionaryGetValue(_dictionary, key); if (dictValue != IntPtr.Zero) @@ -122,10 +122,10 @@ private string GetString(IntPtr key) return null; } - public string ProxyType => GetString(kCFProxyTypeKey); - public string HostName => GetString(kCFProxyHostNameKey); - public string Username => GetString(kCFProxyUsernameKey); - public string Password => GetString(kCFProxyPasswordKey); + public string? ProxyType => GetString(kCFProxyTypeKey); + public string? HostName => GetString(kCFProxyHostNameKey); + public string? Username => GetString(kCFProxyUsernameKey); + public string? Password => GetString(kCFProxyPasswordKey); public int PortNumber { diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.cs index 5ada0a223dc732..24cab8dbd09fc6 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.cs @@ -10,12 +10,12 @@ internal static partial class Interop { internal static partial class Crypto { - internal static bool EcDsaSign(ReadOnlySpan dgst, Span sig, [In, Out] ref int siglen, SafeEcKeyHandle ecKey) => - EcDsaSign(ref MemoryMarshal.GetReference(dgst), dgst.Length, ref MemoryMarshal.GetReference(sig), ref siglen, ecKey); + internal static bool EcDsaSign(ReadOnlySpan dgst, Span sig, out int siglen, SafeEcKeyHandle ecKey) => + EcDsaSign(ref MemoryMarshal.GetReference(dgst), dgst.Length, ref MemoryMarshal.GetReference(sig), out siglen, ecKey); [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcDsaSign")] [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool EcDsaSign(ref byte dgst, int dlen, ref byte sig, [In, Out] ref int siglen, SafeEcKeyHandle ecKey); + private static extern bool EcDsaSign(ref byte dgst, int dlen, ref byte sig, out int siglen, SafeEcKeyHandle ecKey); internal static int EcDsaVerify(ReadOnlySpan dgst, ReadOnlySpan sigbuf, SafeEcKeyHandle ecKey) { diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs index 3f8daec8964724..e522e7ee6dff62 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs @@ -333,14 +333,11 @@ internal static int Encrypt(SafeSslHandle context, ReadOnlySpan input, ref int retVal; Exception? innerError = null; - lock (context) - { - retVal = Ssl.SslWrite(context, ref MemoryMarshal.GetReference(input), input.Length); + retVal = Ssl.SslWrite(context, ref MemoryMarshal.GetReference(input), input.Length); - if (retVal != input.Length) - { - errorCode = GetSslError(context, retVal, out innerError); - } + if (retVal != input.Length) + { + errorCode = GetSslError(context, retVal, out innerError); } if (retVal != input.Length) @@ -390,30 +387,27 @@ internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, int retVal = BioWrite(context.InputBio!, outBuffer, offset, count); Exception? innerError = null; - lock (context) + if (retVal == count) { - if (retVal == count) + unsafe { - unsafe + fixed (byte* fixedBuffer = outBuffer) { - fixed (byte* fixedBuffer = outBuffer) - { - retVal = Ssl.SslRead(context, fixedBuffer + offset, outBuffer.Length); - } - } - - if (retVal > 0) - { - count = retVal; + retVal = Ssl.SslRead(context, fixedBuffer + offset, outBuffer.Length); } } - if (retVal != count) + if (retVal > 0) { - errorCode = GetSslError(context, retVal, out innerError); + count = retVal; } } + if (retVal != count) + { + errorCode = GetSslError(context, retVal, out innerError); + } + if (retVal != count) { retVal = 0; diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetVersionExW.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetVersionExW.cs deleted file mode 100644 index 5899bdb5259677..00000000000000 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetVersionExW.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.InteropServices; - -internal static partial class Interop -{ - internal static partial class Kernel32 - { - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern bool GetVersionExW(ref OSVERSIONINFOEX osvi); - } -} diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs index 13c56f1687e9e4..608073d36b0504 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs @@ -40,6 +40,10 @@ internal static unsafe partial class Kernel32 internal const uint TIME_NOSECONDS = 0x00000002; + internal const int GEOCLASS_NATION = 16; + internal const int GEO_ISO2 = 4; + internal const int GEOID_NOT_AVAILABLE = -1; + internal const string LOCALE_NAME_USER_DEFAULT = null; internal const string LOCALE_NAME_SYSTEM_DEFAULT = "!x-sys-default-locale"; @@ -133,6 +137,12 @@ internal static extern bool IsNLSDefinedString( [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern int GetCalendarInfoEx(string? lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, IntPtr lpValue); + [DllImport("kernel32.dll")] + internal static extern int GetUserGeoID(int geoClass); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + internal static extern int GetGeoInfo(int location, int geoType, char* lpGeoData, int cchData, int LangId); + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string? lpReserved, uint CalType, void* lParam); diff --git a/src/libraries/Common/src/Interop/Windows/NtDll/Interop.NtStatus.cs b/src/libraries/Common/src/Interop/Windows/NtDll/Interop.NtStatus.cs index 2d51c44f544d42..413efdfbf690a7 100644 --- a/src/libraries/Common/src/Interop/Windows/NtDll/Interop.NtStatus.cs +++ b/src/libraries/Common/src/Interop/Windows/NtDll/Interop.NtStatus.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. // See the LICENSE file in the project root for more information. @@ -7,15 +7,16 @@ internal static partial class Interop internal class StatusOptions { // Error codes from ntstatus.h - internal const uint STATUS_SUCCESS = 0x00000000; - internal const uint STATUS_SOME_NOT_MAPPED = 0x00000107; - internal const uint STATUS_NO_MORE_FILES = 0x80000006; - internal const uint STATUS_INVALID_PARAMETER = 0xC000000D; - internal const uint STATUS_NO_MEMORY = 0xC0000017; - internal const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034; - internal const uint STATUS_NONE_MAPPED = 0xC0000073; + internal const uint STATUS_SUCCESS = 0x00000000; + internal const uint STATUS_SOME_NOT_MAPPED = 0x00000107; + internal const uint STATUS_NO_MORE_FILES = 0x80000006; + internal const uint STATUS_INVALID_PARAMETER = 0xC000000D; + internal const uint STATUS_FILE_NOT_FOUND = 0xC000000F; + internal const uint STATUS_NO_MEMORY = 0xC0000017; + internal const uint STATUS_ACCESS_DENIED = 0xC0000022; + internal const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034; + internal const uint STATUS_ACCOUNT_RESTRICTION = 0xC000006E; + internal const uint STATUS_NONE_MAPPED = 0xC0000073; internal const uint STATUS_INSUFFICIENT_RESOURCES = 0xC000009A; - internal const uint STATUS_ACCESS_DENIED = 0xC0000022; - internal const uint STATUS_ACCOUNT_RESTRICTION = 0xc000006e; } } diff --git a/src/libraries/Common/src/Interop/Windows/NtDll/Interop.RTL_OSVERSIONINFOEX.cs b/src/libraries/Common/src/Interop/Windows/NtDll/Interop.RTL_OSVERSIONINFOEX.cs deleted file mode 100644 index 049a68ca446b16..00000000000000 --- a/src/libraries/Common/src/Interop/Windows/NtDll/Interop.RTL_OSVERSIONINFOEX.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Runtime.InteropServices; - -internal partial class Interop -{ - internal partial class NtDll - { - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal unsafe struct RTL_OSVERSIONINFOEX - { - internal uint dwOSVersionInfoSize; - internal uint dwMajorVersion; - internal uint dwMinorVersion; - internal uint dwBuildNumber; - internal uint dwPlatformId; - internal fixed char szCSDVersion[128]; - } - } -} diff --git a/src/libraries/Common/src/Interop/Windows/NtDll/Interop.RtlGetVersion.cs b/src/libraries/Common/src/Interop/Windows/NtDll/Interop.RtlGetVersion.cs index 17f0521504a657..d01a65913e86a8 100644 --- a/src/libraries/Common/src/Interop/Windows/NtDll/Interop.RtlGetVersion.cs +++ b/src/libraries/Common/src/Interop/Windows/NtDll/Interop.RtlGetVersion.cs @@ -18,19 +18,15 @@ internal static unsafe int RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) return RtlGetVersion(ref osvi); } - internal static unsafe string RtlGetVersion() + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal unsafe struct RTL_OSVERSIONINFOEX { - const string Version = "Microsoft Windows"; - if (RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) == 0) - { - return osvi.szCSDVersion[0] != '\0' ? - string.Format("{0} {1}.{2}.{3} {4}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, new string(&(osvi.szCSDVersion[0]))) : - string.Format("{0} {1}.{2}.{3}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); - } - else - { - return Version; - } + internal uint dwOSVersionInfoSize; + internal uint dwMajorVersion; + internal uint dwMinorVersion; + internal uint dwBuildNumber; + internal uint dwPlatformId; + internal fixed char szCSDVersion[128]; } } } diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.SafeWinHttpHandle.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.SafeWinHttpHandle.cs index 866a0bb9eb5fe6..a2b2e720d3b263 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.SafeWinHttpHandle.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.SafeWinHttpHandle.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Diagnostics; using System.Runtime.InteropServices; @@ -14,13 +15,13 @@ internal partial class WinHttp { internal class SafeWinHttpHandle : SafeHandleZeroOrMinusOneIsInvalid { - private SafeWinHttpHandle _parentHandle = null; + private SafeWinHttpHandle? _parentHandle = null; public SafeWinHttpHandle() : base(true) { } - public static void DisposeAndClearHandle(ref SafeWinHttpHandle safeHandle) + public static void DisposeAndClearHandle(ref SafeWinHttpHandle? safeHandle) { if (safeHandle != null) { diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs index 8f72b74777e01b..3b5429bb9de33f 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Runtime.InteropServices; using System.Text; @@ -189,7 +190,7 @@ public static extern bool WinHttpGetIEProxyConfigForCurrentUser( [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool WinHttpGetProxyForUrl( - SafeWinHttpHandle sessionHandle, string url, + SafeWinHttpHandle? sessionHandle, string url, ref WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, out WINHTTP_PROXY_INFO proxyInfo); diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs index adf182ec33e774..3948b540f6179a 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Runtime.InteropServices; using System.Text; @@ -148,9 +149,11 @@ internal partial class WinHttp public const uint WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS = 111; + public const uint WINHTTP_OPTION_ENABLE_HTTP2_PLUS_CLIENT_CERT = 161; public const uint WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL = 133; public const uint WINHTTP_OPTION_HTTP_PROTOCOL_USED = 134; public const uint WINHTTP_PROTOCOL_FLAG_HTTP2 = 0x1; + public const uint WINHTTP_HTTP2_PLUS_CLIENT_CERT_FLAG = 0x1; public const uint WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET = 114; public const uint WINHTTP_OPTION_WEB_SOCKET_CLOSE_TIMEOUT = 115; @@ -239,7 +242,7 @@ public struct WINHTTP_AUTOPROXY_OPTIONS public uint Flags; public uint AutoDetectFlags; [MarshalAs(UnmanagedType.LPWStr)] - public string AutoConfigUrl; + public string? AutoConfigUrl; public IntPtr Reserved1; public uint Reserved2; [MarshalAs(UnmanagedType.Bool)] diff --git a/src/libraries/Common/src/Interop/Windows/WinInet/Interop.wininet_errors.cs b/src/libraries/Common/src/Interop/Windows/WinInet/Interop.wininet_errors.cs index 5bb5373ba07346..193a03f5b53a7d 100644 --- a/src/libraries/Common/src/Interop/Windows/WinInet/Interop.wininet_errors.cs +++ b/src/libraries/Common/src/Interop/Windows/WinInet/Interop.wininet_errors.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; - namespace System.Net { internal static partial class Interop diff --git a/src/libraries/Common/src/System/Globalization/FormatProvider.Number.cs b/src/libraries/Common/src/System/Globalization/FormatProvider.Number.cs index 77981ef2a5463a..9b7120fb19cedc 100644 --- a/src/libraries/Common/src/System/Globalization/FormatProvider.Number.cs +++ b/src/libraries/Common/src/System/Globalization/FormatProvider.Number.cs @@ -607,7 +607,8 @@ internal static unsafe bool TryStringToNumber(ReadOnlySpan str, NumberStyl "($#)", "-$#", "$-#", "$#-", "(#$)", "-#$", "#-$", "#$-", "-# $", "-$ #", "# $-", "$ #-", - "$ -#", "#- $", "($ #)", "(# $)" + "$ -#", "#- $", "($ #)", "(# $)", + "$- #" }; private static readonly string[] s_posPercentFormats = diff --git a/src/libraries/Common/src/System/IO/ChunkedMemoryStream.cs b/src/libraries/Common/src/System/IO/ChunkedMemoryStream.cs index a7295c4c228065..ceb003f86baeea 100644 --- a/src/libraries/Common/src/System/IO/ChunkedMemoryStream.cs +++ b/src/libraries/Common/src/System/IO/ChunkedMemoryStream.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -11,8 +12,8 @@ namespace System.IO /// Provides an in-memory stream composed of non-contiguous chunks. internal sealed class ChunkedMemoryStream : Stream { - private MemoryChunk _headChunk; - private MemoryChunk _currentChunk; + private MemoryChunk? _headChunk; + private MemoryChunk? _currentChunk; private const int InitialChunkDefaultSize = 1024; private const int MaxChunkSize = 1024 * InitialChunkDefaultSize; @@ -24,7 +25,7 @@ public byte[] ToArray() { byte[] result = new byte[_totalLength]; int offset = 0; - for (MemoryChunk chunk = _headChunk; chunk != null; chunk = chunk._next) + for (MemoryChunk? chunk = _headChunk; chunk != null; chunk = chunk._next) { Debug.Assert(chunk._next == null || chunk._freeOffset == chunk._buffer.Length); Buffer.BlockCopy(chunk._buffer, 0, result, offset, chunk._freeOffset); @@ -109,7 +110,7 @@ private sealed class MemoryChunk { internal readonly byte[] _buffer; internal int _freeOffset; - internal MemoryChunk _next; + internal MemoryChunk? _next; internal MemoryChunk(int bufferSize) { _buffer = new byte[bufferSize]; } } diff --git a/src/libraries/Common/src/System/IO/DelegatingStream.cs b/src/libraries/Common/src/System/IO/DelegatingStream.cs index 889bbb213f913a..cbb3075a1d3327 100644 --- a/src/libraries/Common/src/System/IO/DelegatingStream.cs +++ b/src/libraries/Common/src/System/IO/DelegatingStream.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.IO; using System.Threading; @@ -113,7 +114,7 @@ public override ValueTask ReadAsync(Memory buffer, CancellationToken return _innerStream.ReadAsync(buffer, cancellationToken); } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { return _innerStream.BeginRead(buffer, offset, count, callback, state); } @@ -167,7 +168,7 @@ public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationTo return _innerStream.WriteAsync(buffer, cancellationToken); } - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { return _innerStream.BeginWrite(buffer, offset, count, callback, state); } diff --git a/src/libraries/Common/src/System/IO/ReadOnlyMemoryStream.cs b/src/libraries/Common/src/System/IO/ReadOnlyMemoryStream.cs index 5ec499dc6df599..6c826601aff886 100644 --- a/src/libraries/Common/src/System/IO/ReadOnlyMemoryStream.cs +++ b/src/libraries/Common/src/System/IO/ReadOnlyMemoryStream.cs @@ -105,7 +105,7 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel new ValueTask(Task.FromCanceled(cancellationToken)) : new ValueTask(Read(buffer.Span)); - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => TaskToApm.Begin(ReadAsync(buffer, offset, count), callback, state); public override int EndRead(IAsyncResult asyncResult) => diff --git a/src/libraries/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs b/src/libraries/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs index dd8a2956207b29..de841022113c37 100644 --- a/src/libraries/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs +++ b/src/libraries/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.IO; using System.Threading; @@ -26,7 +27,7 @@ internal NoWriteNoSeekStreamContent(Stream content) _content = content; } - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => SerializeToStreamAsync(stream, context, CancellationToken.None); #if NETCOREAPP @@ -34,7 +35,7 @@ protected override #else internal #endif - Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) + Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) { Debug.Assert(stream != null); @@ -54,7 +55,7 @@ Task SerializeToStreamAsync(Stream stream, TransportContext context, Cancellatio { copyTask = copyTask.ContinueWith((t, s) => { - try { ((Stream)s).Dispose(); } catch { } + try { ((Stream)s!).Dispose(); } catch { } t.GetAwaiter().GetResult(); }, _content, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } diff --git a/src/libraries/Common/src/System/Net/Http/WinInetProxyHelper.cs b/src/libraries/Common/src/System/Net/Http/WinInetProxyHelper.cs index ff1b71e5e9dad5..f597c7d30e0833 100644 --- a/src/libraries/Common/src/System/Net/Http/WinInetProxyHelper.cs +++ b/src/libraries/Common/src/System/Net/Http/WinInetProxyHelper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Runtime.InteropServices; @@ -14,7 +15,7 @@ namespace System.Net.Http internal class WinInetProxyHelper { private const int RecentAutoDetectionInterval = 120_000; // 2 minutes in milliseconds. - private readonly string _autoConfigUrl, _proxy, _proxyBypass; + private readonly string? _autoConfigUrl, _proxy, _proxyBypass; private readonly bool _autoDetect; private readonly bool _useProxy = false; private bool _autoDetectionFailed; @@ -28,10 +29,10 @@ public WinInetProxyHelper() { if (Interop.WinHttp.WinHttpGetIEProxyConfigForCurrentUser(out proxyConfig)) { - _autoConfigUrl = Marshal.PtrToStringUni(proxyConfig.AutoConfigUrl); + _autoConfigUrl = Marshal.PtrToStringUni(proxyConfig.AutoConfigUrl)!; _autoDetect = proxyConfig.AutoDetect; - _proxy = Marshal.PtrToStringUni(proxyConfig.Proxy); - _proxyBypass = Marshal.PtrToStringUni(proxyConfig.ProxyBypass); + _proxy = Marshal.PtrToStringUni(proxyConfig.Proxy)!; + _proxyBypass = Marshal.PtrToStringUni(proxyConfig.ProxyBypass)!; if (NetEventSource.IsEnabled) { @@ -59,7 +60,7 @@ public WinInetProxyHelper() } } - public string AutoConfigUrl => _autoConfigUrl; + public string? AutoConfigUrl => _autoConfigUrl; public bool AutoDetect => _autoDetect; @@ -69,16 +70,16 @@ public WinInetProxyHelper() public bool ManualSettingsOnly => !AutoSettingsUsed && ManualSettingsUsed; - public string Proxy => _proxy; + public string? Proxy => _proxy; - public string ProxyBypass => _proxyBypass; + public string? ProxyBypass => _proxyBypass; public bool RecentAutoDetectionFailure => _autoDetectionFailed && Environment.TickCount - _lastTimeAutoDetectionFailed <= RecentAutoDetectionInterval; public bool GetProxyForUrl( - SafeWinHttpHandle sessionHandle, + SafeWinHttpHandle? sessionHandle, Uri uri, out Interop.WinHttp.WINHTTP_PROXY_INFO proxyInfo) { @@ -123,7 +124,7 @@ public bool GetProxyForUrl( { _autoDetectionFailed = false; if (Interop.WinHttp.WinHttpGetProxyForUrl( - sessionHandle, + sessionHandle!, uri.AbsoluteUri, ref autoProxyOptions, out proxyInfo)) diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs index 41eb1c6938a5fa..3fe3c86243d320 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Buffers; using System.Diagnostics; #if KESTREL @@ -93,7 +94,7 @@ private enum State : byte private byte[] _headerValueOctets; private State _state = State.Ready; - private byte[] _headerName; + private byte[]? _headerName; private int _stringIndex; private int _stringLength; private int _headerNameLength; @@ -129,13 +130,13 @@ public void Decode(in ReadOnlySequence data, bool endHeaders, IHttpHeaders CheckIncompleteHeaderBlock(endHeaders); } - public void Decode(ReadOnlySpan data, bool endHeaders, IHttpHeadersHandler handler) + public void Decode(ReadOnlySpan data, bool endHeaders, IHttpHeadersHandler? handler) { DecodeInternal(data, endHeaders, handler); CheckIncompleteHeaderBlock(endHeaders); } - private void DecodeInternal(ReadOnlySpan data, bool endHeaders, IHttpHeadersHandler handler) + private void DecodeInternal(ReadOnlySpan data, bool endHeaders, IHttpHeadersHandler? handler) { int intResult; @@ -370,7 +371,7 @@ private void CheckIncompleteHeaderBlock(bool endHeaders) } } - private void ProcessHeaderValue(IHttpHeadersHandler handler) + private void ProcessHeaderValue(IHttpHeadersHandler? handler) { OnString(nextState: State.Ready); @@ -394,7 +395,7 @@ public void CompleteDecode() } } - private void OnIndexedHeaderField(int index, IHttpHeadersHandler handler) + private void OnIndexedHeaderField(int index, IHttpHeadersHandler? handler) { HeaderField header = GetHeader(index); handler?.OnHeader(header.Name, header.Value); diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackEncoder.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackEncoder.cs index 15aec6cfa6599a..d09f1841349dda 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackEncoder.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackEncoder.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable +using System.Collections.Generic; using System.Diagnostics; namespace System.Net.Http.HPack @@ -370,7 +372,7 @@ public static bool EncodeStringLiteral(string value, Span destination, out return false; } - public static bool EncodeStringLiterals(ReadOnlySpan values, string separator, Span destination, out int bytesWritten) + public static bool EncodeStringLiterals(ReadOnlySpan values, string? separator, Span destination, out int bytesWritten) { bytesWritten = 0; @@ -393,6 +395,7 @@ public static bool EncodeStringLiterals(ReadOnlySpan values, string sepa valueLength = checked((int)(valueLength + part.Length)); } + Debug.Assert(separator != null); valueLength = checked((int)(valueLength + (values.Length - 1) * separator.Length)); destination[0] = 0; diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs index 958dfac303e8dc..e3b85872ed7555 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Buffers; using System.Diagnostics; using System.Net.Http.HPack; @@ -118,7 +119,7 @@ private enum State private bool _huffman; private int? _index; - private byte[] _headerName; + private byte[]? _headerName; private int _headerNameLength; private int _headerValueLength; private int _stringLength; @@ -130,7 +131,7 @@ private enum State private static void ReturnAndGetNewPooledArray(ref byte[] buffer, int newSize) { byte[] old = buffer; - buffer = null; + buffer = null!; Pool.Return(old, clearArray: true); buffer = Pool.Rent(newSize); @@ -151,19 +152,19 @@ public void Dispose() if (_stringOctets != null) { Pool.Return(_stringOctets, true); - _stringOctets = null; + _stringOctets = null!; } if (_headerNameOctets != null) { Pool.Return(_headerNameOctets, true); - _headerNameOctets = null; + _headerNameOctets = null!; } if (_headerValueOctets != null) { Pool.Return(_headerValueOctets, true); - _headerValueOctets = null; + _headerValueOctets = null!; } } diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackEncoder.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackEncoder.cs index ecf0f1e183abbc..c9560959106276 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackEncoder.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackEncoder.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Collections.Generic; using System.Diagnostics; using System.Net.Http.HPack; @@ -10,7 +11,7 @@ namespace System.Net.Http.QPack { internal class QPackEncoder { - private IEnumerator> _enumerator; + private IEnumerator>? _enumerator; // https://tools.ietf.org/html/draft-ietf-quic-qpack-11#section-4.5.2 // 0 1 2 3 4 5 6 7 @@ -194,7 +195,7 @@ private static bool EncodeValueString(string s, Span buffer, out int lengt /// /// Encodes a value by concatenating a collection of strings, separated by a separator string. /// - public static bool EncodeValueString(ReadOnlySpan values, string separator, Span buffer, out int length) + public static bool EncodeValueString(ReadOnlySpan values, string? separator, Span buffer, out int length) { if (values.Length == 1) { @@ -209,6 +210,7 @@ public static bool EncodeValueString(ReadOnlySpan values, string separat if (buffer.Length > 0) { + Debug.Assert(separator != null); int valueLength = separator.Length * (values.Length - 1); for (int i = 0; i < values.Length; ++i) { @@ -386,7 +388,7 @@ private bool Encode(Span buffer, bool throwIfNoneEncoded, out int length) do { - if (!EncodeLiteralHeaderFieldWithoutNameReference(_enumerator.Current.Key, _enumerator.Current.Value, buffer.Slice(length), out int headerLength)) + if (!EncodeLiteralHeaderFieldWithoutNameReference(_enumerator!.Current.Key, _enumerator.Current.Value, buffer.Slice(length), out int headerLength)) { if (length == 0 && throwIfNoneEncoded) { diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockConnection.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockConnection.cs index d9ab07022e72b3..ae4040621033e2 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockConnection.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockConnection.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Buffers.Binary; using System.Net.Security; using System.Net.Sockets; @@ -14,17 +15,17 @@ internal sealed class MockConnection : QuicConnectionProvider { private readonly bool _isClient; private bool _disposed = false; - private IPEndPoint _remoteEndPoint; - private IPEndPoint _localEndPoint; + private IPEndPoint? _remoteEndPoint; + private IPEndPoint? _localEndPoint; private object _syncObject = new object(); - private Socket _socket = null; - private IPEndPoint _peerListenEndPoint = null; - private TcpListener _inboundListener = null; + private Socket? _socket = null; + private IPEndPoint? _peerListenEndPoint = null; + private TcpListener? _inboundListener = null; private long _nextOutboundBidirectionalStream; private long _nextOutboundUnidirectionalStream; // Constructor for outbound connections - internal MockConnection(IPEndPoint remoteEndPoint, SslClientAuthenticationOptions sslClientAuthenticationOptions, IPEndPoint localEndPoint = null) + internal MockConnection(IPEndPoint? remoteEndPoint, SslClientAuthenticationOptions? sslClientAuthenticationOptions, IPEndPoint? localEndPoint = null) { _remoteEndPoint = remoteEndPoint; _localEndPoint = localEndPoint; @@ -43,8 +44,8 @@ internal MockConnection(Socket socket, IPEndPoint peerListenEndPoint, TcpListene _socket = socket; _peerListenEndPoint = peerListenEndPoint; _inboundListener = inboundListener; - _localEndPoint = (IPEndPoint)socket.LocalEndPoint; - _remoteEndPoint = (IPEndPoint)socket.RemoteEndPoint; + _localEndPoint = (IPEndPoint?)socket.LocalEndPoint; + _remoteEndPoint = (IPEndPoint?)socket.RemoteEndPoint; } internal override bool Connected @@ -57,9 +58,9 @@ internal override bool Connected } } - internal override IPEndPoint LocalEndPoint => new IPEndPoint(_localEndPoint.Address, _localEndPoint.Port); + internal override IPEndPoint LocalEndPoint => new IPEndPoint(_localEndPoint!.Address, _localEndPoint.Port); - internal override IPEndPoint RemoteEndPoint => new IPEndPoint(_remoteEndPoint.Address, _remoteEndPoint.Port); + internal override IPEndPoint RemoteEndPoint => new IPEndPoint(_remoteEndPoint!.Address, _remoteEndPoint.Port); internal override SslApplicationProtocol NegotiatedApplicationProtocol => throw new NotImplementedException(); @@ -73,14 +74,14 @@ internal override async ValueTask ConnectAsync(CancellationToken cancellationTok throw new InvalidOperationException("Already connected"); } - Socket socket = new Socket(_remoteEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + Socket socket = new Socket(_remoteEndPoint!.AddressFamily, SocketType.Stream, ProtocolType.Tcp); await socket.ConnectAsync(_remoteEndPoint).ConfigureAwait(false); socket.NoDelay = true; - _localEndPoint = (IPEndPoint)socket.LocalEndPoint; + _localEndPoint = (IPEndPoint?)socket.LocalEndPoint; // Listen on a new local endpoint for inbound streams - TcpListener inboundListener = new TcpListener(_localEndPoint.Address, 0); + TcpListener inboundListener = new TcpListener(_localEndPoint!.Address, 0); inboundListener.Start(); int inboundListenPort = ((IPEndPoint)inboundListener.LocalEndpoint).Port; @@ -97,7 +98,7 @@ internal override async ValueTask ConnectAsync(CancellationToken cancellationTok } while (bytesRead != buffer.Length); int peerListenPort = BinaryPrimitives.ReadInt32LittleEndian(buffer); - IPEndPoint peerListenEndPoint = new IPEndPoint(((IPEndPoint)socket.RemoteEndPoint).Address, peerListenPort); + IPEndPoint peerListenEndPoint = new IPEndPoint(((IPEndPoint)socket.RemoteEndPoint!).Address, peerListenPort); _socket = socket; _peerListenEndPoint = peerListenEndPoint; @@ -141,7 +142,7 @@ internal override long GetRemoteAvailableBidirectionalStreamCount() internal async Task CreateOutboundMockStreamAsync(long streamId) { Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); - await socket.ConnectAsync(_peerListenEndPoint).ConfigureAwait(false); + await socket.ConnectAsync(_peerListenEndPoint!).ConfigureAwait(false); socket.NoDelay = true; // Write stream ID to socket so server can read it @@ -156,7 +157,7 @@ internal override async ValueTask AcceptStreamAsync(Cancella { CheckDisposed(); - Socket socket = await _inboundListener.AcceptSocketAsync().ConfigureAwait(false); + Socket socket = await _inboundListener!.AcceptSocketAsync().ConfigureAwait(false); // Read first bytes to get stream ID byte[] buffer = new byte[8]; diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockImplementationProvider.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockImplementationProvider.cs index b70a1132848317..56a5a11679630c 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockImplementationProvider.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockImplementationProvider.cs @@ -10,7 +10,7 @@ internal sealed class MockImplementationProvider : QuicImplementationProvider { internal override QuicListenerProvider CreateListener(QuicListenerOptions options) { - return new MockListener(options.ListenEndPoint, options.ServerAuthenticationOptions); + return new MockListener(options.ListenEndPoint!, options.ServerAuthenticationOptions); } internal override QuicConnectionProvider CreateConnection(QuicClientConnectionOptions options) diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockListener.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockListener.cs index 911f1896b16950..88297bdfdd5170 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockListener.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockListener.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Net.Sockets; using System.Net.Security; using System.Threading.Tasks; @@ -13,11 +14,11 @@ namespace System.Net.Quic.Implementations.Mock internal sealed class MockListener : QuicListenerProvider { private bool _disposed = false; - private SslServerAuthenticationOptions _sslOptions; + private SslServerAuthenticationOptions? _sslOptions; private IPEndPoint _listenEndPoint; - private TcpListener _tcpListener = null; + private TcpListener _tcpListener; - internal MockListener(IPEndPoint listenEndPoint, SslServerAuthenticationOptions sslServerAuthenticationOptions) + internal MockListener(IPEndPoint listenEndPoint, SslServerAuthenticationOptions? sslServerAuthenticationOptions) { if (listenEndPoint == null) { @@ -49,7 +50,7 @@ internal override async ValueTask AcceptConnectionAsync( } while (bytesRead != buffer.Length); int peerListenPort = BinaryPrimitives.ReadInt32LittleEndian(buffer); - IPEndPoint peerListenEndPoint = new IPEndPoint(((IPEndPoint)socket.RemoteEndPoint).Address, peerListenPort); + IPEndPoint peerListenEndPoint = new IPEndPoint(((IPEndPoint)socket.RemoteEndPoint!).Address, peerListenPort); // Listen on a new local endpoint for inbound streams TcpListener inboundListener = new TcpListener(_listenEndPoint.Address, 0); @@ -96,7 +97,7 @@ private void Dispose(bool disposing) if (disposing) { _tcpListener?.Stop(); - _tcpListener = null; + _tcpListener = null!; } // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockStream.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockStream.cs index 187ba680e17de4..f367d981bd1016 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockStream.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/Mock/MockStream.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Buffers; using System.Diagnostics; using System.Net.Sockets; @@ -17,9 +18,9 @@ internal sealed class MockStream : QuicStreamProvider private bool _canRead; private bool _canWrite; - private MockConnection _connection; + private MockConnection? _connection; - private Socket _socket = null; + private Socket? _socket = null; // Constructor for outbound streams internal MockStream(MockConnection connection, long streamId, bool bidirectional) @@ -69,7 +70,7 @@ internal override int Read(Span buffer) throw new NotSupportedException(); } - return _socket.Receive(buffer); + return _socket!.Receive(buffer); } internal override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) @@ -86,7 +87,7 @@ internal override async ValueTask ReadAsync(Memory buffer, Cancellati await ConnectAsync(cancellationToken).ConfigureAwait(false); } - return await _socket.ReceiveAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false); + return await _socket!.ReceiveAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false); } internal override bool CanWrite => _canWrite; @@ -100,7 +101,7 @@ internal override void Write(ReadOnlySpan buffer) throw new NotSupportedException(); } - _socket.Send(buffer); + _socket!.Send(buffer); } internal override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) @@ -121,11 +122,11 @@ internal override async ValueTask WriteAsync(ReadOnlyMemory buffer, bool e { await ConnectAsync(cancellationToken).ConfigureAwait(false); } - await _socket.SendAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false); + await _socket!.SendAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false); if (endStream) { - _socket.Shutdown(SocketShutdown.Send); + _socket!.Shutdown(SocketShutdown.Send); } } @@ -149,12 +150,12 @@ internal override async ValueTask WriteAsync(ReadOnlySequence buffers, boo foreach (ReadOnlyMemory buffer in buffers) { - await _socket.SendAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false); + await _socket!.SendAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false); } if (endStream) { - _socket.Shutdown(SocketShutdown.Send); + _socket!.Shutdown(SocketShutdown.Send); } } @@ -178,12 +179,12 @@ internal override async ValueTask WriteAsync(ReadOnlyMemory foreach (ReadOnlyMemory buffer in buffers.ToArray()) { - await _socket.SendAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false); + await _socket!.SendAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false); } if (endStream) { - _socket.Shutdown(SocketShutdown.Send); + _socket!.Shutdown(SocketShutdown.Send); } } @@ -221,7 +222,7 @@ internal override void Shutdown() { CheckDisposed(); - _socket.Shutdown(SocketShutdown.Send); + _socket!.Shutdown(SocketShutdown.Send); } private void CheckDisposed() diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs index 977af1da938708..0b9893333d7156 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.IO; using System.Net.Security; using System.Runtime.InteropServices; @@ -127,7 +128,7 @@ private unsafe MsQuicApi() _registrationContext = ctx; } - internal static MsQuicApi Api { get; } + internal static MsQuicApi Api { get; } = null!; internal static bool IsQuicSupported { get; } @@ -221,10 +222,10 @@ internal unsafe uint UnsafeGetParam( buf); } - public async ValueTask CreateSecurityConfig(X509Certificate certificate, string certFilePath, string privateKeyFilePath) + public async ValueTask CreateSecurityConfig(X509Certificate certificate, string? certFilePath, string? privateKeyFilePath) { - MsQuicSecurityConfig secConfig = null; - var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + MsQuicSecurityConfig? secConfig = null; + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); uint secConfigCreateStatus = MsQuicStatusCodes.InternalError; uint createConfigStatus; IntPtr unmanagedAddr = IntPtr.Zero; diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicSession.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicSession.cs index 89dd99f73c3e9f..0f19506b81a2d5 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicSession.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicSession.cs @@ -22,7 +22,7 @@ public IntPtr ConnectionOpen(QuicClientConnectionOptions options) { if (!_opened) { - OpenSession(options.ClientAuthenticationOptions.ApplicationProtocols[0].Protocol.ToArray(), + OpenSession(options.ClientAuthenticationOptions!.ApplicationProtocols![0].Protocol.ToArray(), (ushort)options.MaxBidirectionalStreams, (ushort)options.MaxUnidirectionalStreams); } @@ -50,7 +50,7 @@ public IntPtr ListenerOpen(QuicListenerOptions options) { if (!_opened) { - OpenSession(options.ServerAuthenticationOptions.ApplicationProtocols[0].Protocol.ToArray(), + OpenSession(options.ServerAuthenticationOptions!.ApplicationProtocols![0].Protocol.ToArray(), (ushort)options.MaxBidirectionalStreams, (ushort)options.MaxUnidirectionalStreams); } diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/QuicExceptionHelpers.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/QuicExceptionHelpers.cs index 1b8ab8ef260660..bca44c017d7057 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/QuicExceptionHelpers.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/QuicExceptionHelpers.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Net.Quic.Implementations.MsQuic.Internal { internal static class QuicExceptionHelpers { - internal static void ThrowIfFailed(uint status, string message = null, Exception innerException = null) + internal static void ThrowIfFailed(uint status, string? message = null, Exception? innerException = null) { if (!MsQuicStatusHelper.SuccessfulStatusCode(status)) { diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/ResettableCompletionSource.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/ResettableCompletionSource.cs index 4bcf0a917a4558..4164663df942f3 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/ResettableCompletionSource.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/ResettableCompletionSource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Threading.Tasks; using System.Threading.Tasks.Sources; @@ -35,7 +36,7 @@ public ValueTaskSourceStatus GetStatus(short token) return _valueTaskSource.GetStatus(token); } - public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) + public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) { _valueTaskSource.OnCompleted(continuation, state, token, flags); } diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicConnection.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicConnection.cs index 1d914c2668e7c4..0fdecc68af8d72 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicConnection.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicConnection.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.IO; using System.Net.Quic.Implementations.MsQuic.Internal; using System.Net.Security; @@ -16,7 +17,7 @@ namespace System.Net.Quic.Implementations.MsQuic { internal sealed class MsQuicConnection : QuicConnectionProvider { - private MsQuicSession _session; + private MsQuicSession? _session; // Pointer to the underlying connection // TODO replace all IntPtr with SafeHandles @@ -27,10 +28,10 @@ internal sealed class MsQuicConnection : QuicConnectionProvider // Delegate that wraps the static function that will be called when receiving an event. // TODO investigate if the delegate can be static instead. - private ConnectionCallbackDelegate _connectionDelegate; + private ConnectionCallbackDelegate? _connectionDelegate; // Endpoint to either connect to or the endpoint already accepted. - private IPEndPoint _localEndPoint; + private IPEndPoint? _localEndPoint; private readonly IPEndPoint _remoteEndPoint; private readonly ResettableCompletionSource _connectTcs = new ResettableCompletionSource(); @@ -38,7 +39,7 @@ internal sealed class MsQuicConnection : QuicConnectionProvider private bool _disposed; private bool _connected; - private MsQuicSecurityConfig _securityConfig; + private MsQuicSecurityConfig? _securityConfig; private long _abortErrorCode = -1; // Queue for accepted streams @@ -70,7 +71,7 @@ public MsQuicConnection(QuicClientConnectionOptions options) // Creating a session per connection isn't ideal. _session = new MsQuicSession(); _ptr = _session.ConnectionOpen(options); - _remoteEndPoint = options.RemoteEndPoint; + _remoteEndPoint = options.RemoteEndPoint!; SetCallbackHandler(); SetIdleTimeout(options.IdleTimeout); @@ -82,15 +83,15 @@ internal override IPEndPoint LocalEndPoint { get { - return new IPEndPoint(_localEndPoint.Address, _localEndPoint.Port); + return new IPEndPoint(_localEndPoint!.Address, _localEndPoint.Port); } } - internal async ValueTask SetSecurityConfigForConnection(X509Certificate cert, string certFilePath, string privateKeyFilePath) + internal async ValueTask SetSecurityConfigForConnection(X509Certificate cert, string? certFilePath, string? privateKeyFilePath) { _securityConfig = await MsQuicApi.Api.CreateSecurityConfig(cert, certFilePath, privateKeyFilePath); // TODO this isn't being set correctly - MsQuicParameterHelpers.SetSecurityConfig(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.SEC_CONFIG, _securityConfig.NativeObjPtr); + MsQuicParameterHelpers.SetSecurityConfig(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.SEC_CONFIG, _securityConfig!.NativeObjPtr); } internal override IPEndPoint RemoteEndPoint => new IPEndPoint(_remoteEndPoint.Address, _remoteEndPoint.Port); @@ -355,7 +356,7 @@ internal static uint NativeCallbackHandler( ref ConnectionEvent connectionEventStruct) { GCHandle handle = GCHandle.FromIntPtr(context); - MsQuicConnection quicConnection = (MsQuicConnection)handle.Target; + MsQuicConnection quicConnection = (MsQuicConnection)handle.Target!; return quicConnection.HandleEvent(ref connectionEventStruct); } diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicListener.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicListener.cs index 14323d963f3e01..e87126b87f0e20 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicListener.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicListener.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Net.Quic.Implementations.MsQuic.Internal; using System.Net.Security; using System.Runtime.InteropServices; @@ -25,7 +26,7 @@ internal sealed class MsQuicListener : QuicListenerProvider, IDisposable private GCHandle _handle; // Delegate that wraps the static function that will be called when receiving an event. - private ListenerCallbackDelegate _listenerDelegate; + private ListenerCallbackDelegate? _listenerDelegate; // Ssl listening options (ALPN, cert, etc) private SslServerAuthenticationOptions _sslOptions; @@ -46,8 +47,8 @@ internal MsQuicListener(QuicListenerOptions options) }); _options = options; - _sslOptions = options.ServerAuthenticationOptions; - _listenEndPoint = options.ListenEndPoint; + _sslOptions = options.ServerAuthenticationOptions!; + _listenEndPoint = options.ListenEndPoint!; _ptr = _session.ListenerOpen(options); } @@ -77,7 +78,7 @@ internal override async ValueTask AcceptConnectionAsync( throw new QuicOperationAbortedException(); } - await connection.SetSecurityConfigForConnection(_sslOptions.ServerCertificate, + await connection.SetSecurityConfigForConnection(_sslOptions.ServerCertificate!, _options.CertificateFilePath, _options.PrivateKeyFilePath); @@ -187,7 +188,7 @@ internal static uint NativeCallbackHandler( ref ListenerEvent connectionEventStruct) { GCHandle handle = GCHandle.FromIntPtr(context); - MsQuicListener quicListener = (MsQuicListener)handle.Target; + MsQuicListener quicListener = (MsQuicListener)handle.Target!; return quicListener.ListenerCallbackHandler(ref connectionEventStruct); } diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicStream.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicStream.cs index 00ca779e3ce7a0..b8b6282a25c137 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicStream.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/MsQuicStream.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Buffers; using System.Collections.Generic; using System.Diagnostics; @@ -23,7 +24,7 @@ internal sealed class MsQuicStream : QuicStreamProvider private GCHandle _handle; // Delegate that wraps the static function that will be called when receiving an event. - private StreamCallbackDelegate _callback; + private StreamCallbackDelegate? _callback; // Backing for StreamId private long _streamId = -1; @@ -424,7 +425,7 @@ internal override Task FlushAsync(CancellationToken cancellationToken = default) { ThrowIfDisposed(); - return default; + return default!; } public override ValueTask DisposeAsync() @@ -500,7 +501,7 @@ internal static uint NativeCallbackHandler( ref StreamEvent streamEvent) { var handle = GCHandle.FromIntPtr(context); - var quicStream = (MsQuicStream)handle.Target; + var quicStream = (MsQuicStream)handle.Target!; return quicStream.HandleEvent(ref streamEvent); } diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Interop/MsQuicNativeMethods.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Interop/MsQuicNativeMethods.cs index 6f7edba173145e..31ab416fbd39fe 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Interop/MsQuicNativeMethods.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Interop/MsQuicNativeMethods.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; @@ -90,7 +91,7 @@ internal delegate uint SecConfigCreateDelegate( IntPtr registrationContext, uint flags, IntPtr certificate, - [MarshalAs(UnmanagedType.LPStr)]string principal, + [MarshalAs(UnmanagedType.LPStr)]string? principal, IntPtr context, SecConfigCreateCompleteDelegate completionHandler); diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicClientConnectionOptions.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicClientConnectionOptions.cs index a9a9b0ec40c450..3e7d10a199a586 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicClientConnectionOptions.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicClientConnectionOptions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Net.Security; namespace System.Net.Quic @@ -14,17 +15,17 @@ internal class QuicClientConnectionOptions /// /// Client authentication options to use when establishing a . /// - public SslClientAuthenticationOptions ClientAuthenticationOptions { get; set; } + public SslClientAuthenticationOptions? ClientAuthenticationOptions { get; set; } /// /// The local endpoint that will be bound to. /// - public IPEndPoint LocalEndPoint { get; set; } + public IPEndPoint? LocalEndPoint { get; set; } /// /// The endpoint to connect to. /// - public IPEndPoint RemoteEndPoint { get; set; } + public IPEndPoint? RemoteEndPoint { get; set; } /// /// Limit on the number of bidirectional streams the peer connection can create diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicConnection.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicConnection.cs index 877421a94f0149..c2bbceb43cdd52 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicConnection.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicConnection.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Net.Quic.Implementations; using System.Net.Quic.Implementations.MsQuic.Internal; using System.Net.Security; @@ -22,13 +23,13 @@ internal sealed class QuicConnection : IDisposable /// The remote endpoint to connect to. /// TLS options /// The local endpoint to connect from. - public QuicConnection(IPEndPoint remoteEndPoint, SslClientAuthenticationOptions sslClientAuthenticationOptions, IPEndPoint localEndPoint = null) + public QuicConnection(IPEndPoint remoteEndPoint, SslClientAuthenticationOptions? sslClientAuthenticationOptions, IPEndPoint? localEndPoint = null) : this(QuicImplementationProviders.Default, remoteEndPoint, sslClientAuthenticationOptions, localEndPoint) { } // !!! TEMPORARY: Remove "implementationProvider" before shipping - public QuicConnection(QuicImplementationProvider implementationProvider, IPEndPoint remoteEndPoint, SslClientAuthenticationOptions sslClientAuthenticationOptions, IPEndPoint localEndPoint = null) + public QuicConnection(QuicImplementationProvider implementationProvider, IPEndPoint remoteEndPoint, SslClientAuthenticationOptions? sslClientAuthenticationOptions, IPEndPoint? localEndPoint = null) : this(implementationProvider, new QuicClientConnectionOptions() { RemoteEndPoint = remoteEndPoint, ClientAuthenticationOptions = sslClientAuthenticationOptions, LocalEndPoint = localEndPoint }) { } diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicListenerOptions.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicListenerOptions.cs index f9eae30c3d5a52..934c7a8e244e47 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicListenerOptions.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicListenerOptions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Net.Security; namespace System.Net.Quic @@ -14,22 +15,22 @@ internal class QuicListenerOptions /// /// Server Ssl options to use for ALPN, SNI, etc. /// - public SslServerAuthenticationOptions ServerAuthenticationOptions { get; set; } + public SslServerAuthenticationOptions? ServerAuthenticationOptions { get; set; } /// /// Optional path to certificate file to configure the security configuration. /// - public string CertificateFilePath { get; set; } + public string? CertificateFilePath { get; set; } /// /// Optional path to private key file to configure the security configuration. /// - public string PrivateKeyFilePath { get; set; } + public string? PrivateKeyFilePath { get; set; } /// /// The endpoint to listen on. /// - public IPEndPoint ListenEndPoint { get; set; } + public IPEndPoint? ListenEndPoint { get; set; } /// /// Number of connections to be held without accepting the connection. diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicStream.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicStream.cs index 6e52bb07530d8e..4e1af6dff60b39 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicStream.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/QuicStream.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Buffers; using System.IO; using System.Net.Quic.Implementations; @@ -29,13 +30,13 @@ internal QuicStream(QuicStreamProvider provider) public override void SetLength(long value) => throw new NotSupportedException(); public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => TaskToApm.Begin(ReadAsync(buffer, offset, count, default), callback, state); public override int EndRead(IAsyncResult asyncResult) => TaskToApm.End(asyncResult); - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => TaskToApm.Begin(WriteAsync(buffer, offset, count, default), callback, state); public override void EndWrite(IAsyncResult asyncResult) => diff --git a/src/libraries/Common/src/System/Net/HttpKnownHeaderNames.TryGetHeaderName.cs b/src/libraries/Common/src/System/Net/HttpKnownHeaderNames.TryGetHeaderName.cs index 22c3cc787963af..b96dbd0a006505 100644 --- a/src/libraries/Common/src/System/Net/HttpKnownHeaderNames.TryGetHeaderName.cs +++ b/src/libraries/Common/src/System/Net/HttpKnownHeaderNames.TryGetHeaderName.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net { @@ -15,7 +17,7 @@ internal static partial class HttpKnownHeaderNames /// Gets a known header name string from a matching char[] array segment, using a case-sensitive /// ordinal comparison. Used to avoid allocating new strings for known header names. /// - public static bool TryGetHeaderName(char[] array, int startIndex, int length, out string name) + public static bool TryGetHeaderName(char[] array, int startIndex, int length, [NotNullWhen(true)] out string? name) { CharArrayHelpers.DebugAssertArrayInputs(array, startIndex, length); @@ -30,7 +32,7 @@ public static bool TryGetHeaderName(char[] array, int startIndex, int length, ou /// Gets a known header name string from a matching IntPtr buffer, using a case-sensitive /// ordinal comparison. Used to avoid allocating new strings for known header names. /// - public static unsafe bool TryGetHeaderName(IntPtr buffer, int length, out string name) + public static unsafe bool TryGetHeaderName(IntPtr buffer, int length, out string? name) { Debug.Assert(length >= 0); @@ -84,7 +86,7 @@ private static bool TryGetHeaderName( T key, int startIndex, int length, Func charAt, Func equals, - out string name) + [NotNullWhen(true)] out string? name) { Debug.Assert(key != null); Debug.Assert(startIndex >= 0); @@ -110,7 +112,7 @@ private static bool TryGetHeaderName( // // Matching is case-sensitive: we only want to return a known header that exactly matches the key. - string potentialHeader = null; + string potentialHeader; switch (length) { @@ -340,7 +342,7 @@ private static bool TryGetHeaderName( /// Returns true if matches the char[] array segment, /// using an ordinal comparison. /// - private static bool TryMatch(string known, T key, int startIndex, int length, Func equals, out string name) + private static bool TryMatch(string known, T key, int startIndex, int length, Func equals, [NotNullWhen(true)] out string? name) { Debug.Assert(known != null); Debug.Assert(known.Length > 0); diff --git a/src/libraries/Common/src/System/Net/HttpStatusDescription.cs b/src/libraries/Common/src/System/Net/HttpStatusDescription.cs index dc13fd0b8973d3..809cffd33ad326 100644 --- a/src/libraries/Common/src/System/Net/HttpStatusDescription.cs +++ b/src/libraries/Common/src/System/Net/HttpStatusDescription.cs @@ -2,14 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Net { internal static class HttpStatusDescription { - internal static string Get(HttpStatusCode code) => + internal static string? Get(HttpStatusCode code) => Get((int)code); - internal static string Get(int code) => + internal static string? Get(int code) => code switch { 100 => "Continue", diff --git a/src/libraries/Common/src/System/Net/LazyAsyncResult.cs b/src/libraries/Common/src/System/Net/LazyAsyncResult.cs index 20d9557c6ea7ae..95c73255094e22 100644 --- a/src/libraries/Common/src/System/Net/LazyAsyncResult.cs +++ b/src/libraries/Common/src/System/Net/LazyAsyncResult.cs @@ -45,7 +45,7 @@ private class ThreadContext private bool _protectState; // Used by ContextAwareResult to prevent some calls. #endif - private readonly object _asyncObject; // Caller's async object. + private readonly object? _asyncObject; // Caller's async object. private readonly object? _asyncState; // Caller's state object. private AsyncCallback? _asyncCallback; // Caller's callback method. private object? _result; // Final IO result to be returned byt the End*() method. @@ -58,7 +58,7 @@ private class ThreadContext private object? _event; // Lazy allocated event to be returned in the IAsyncResult for the client to wait on. - internal LazyAsyncResult(object myObject, object? myState, AsyncCallback? myCallBack) + internal LazyAsyncResult(object? myObject, object? myState, AsyncCallback? myCallBack) { _asyncObject = myObject; _asyncState = myState; @@ -68,7 +68,7 @@ internal LazyAsyncResult(object myObject, object? myState, AsyncCallback? myCall } // Interface method to return the original async object. - internal object AsyncObject + internal object? AsyncObject { get { diff --git a/src/libraries/Common/src/System/Net/Logging/NetEventSource.Common.cs b/src/libraries/Common/src/System/Net/Logging/NetEventSource.Common.cs index 29abfe2c0f8b75..f476d851ba1e60 100644 --- a/src/libraries/Common/src/System/Net/Logging/NetEventSource.Common.cs +++ b/src/libraries/Common/src/System/Net/Logging/NetEventSource.Common.cs @@ -424,7 +424,7 @@ private static void DebugValidateArg(FormattableString? arg) public static string IdOf(object? value) => value != null ? value.GetType().Name + "#" + GetHashCode(value) : NullInstance; [NonEvent] - public static int GetHashCode(object value) => value?.GetHashCode() ?? 0; + public static int GetHashCode(object? value) => value?.GetHashCode() ?? 0; [NonEvent] public static object Format(object? value) diff --git a/src/libraries/Common/src/System/Net/Mail/MailAddress.cs b/src/libraries/Common/src/System/Net/Mail/MailAddress.cs index 6c61c58b4f3a34..c2a943022e9f47 100644 --- a/src/libraries/Common/src/System/Net/Mail/MailAddress.cs +++ b/src/libraries/Common/src/System/Net/Mail/MailAddress.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Text; namespace System.Net.Mail @@ -13,7 +14,7 @@ public MailAddress(string address) MailAddressParser.TryParseAddress(address, out ParseAddressInfo _, throwExceptionIfFail: true); } - internal MailAddress(string displayName, string localPart, string domain, Encoding displayNameEncoding) + internal MailAddress(string displayName, string localPart, string domain, Encoding? displayNameEncoding) { } } diff --git a/src/libraries/Common/src/System/Net/Mail/MailAddressParser.cs b/src/libraries/Common/src/System/Net/Mail/MailAddressParser.cs index 6b1e8e5bb36c64..896cb0312b942e 100644 --- a/src/libraries/Common/src/System/Net/Mail/MailAddressParser.cs +++ b/src/libraries/Common/src/System/Net/Mail/MailAddressParser.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Net.Mime; namespace System.Net.Mail @@ -69,7 +71,7 @@ private static bool TryParseAddress(string data, bool expectMultipleAddresses, r Debug.Assert(index >= 0 && index < data.Length, "Index out of range: " + index + ", " + data.Length); // Parsed components to be assembled as a MailAddress later - string displayName; + string? displayName; // Skip comments and whitespace if (!TryReadCfwsAndThrowIfIncomplete(data, index, out index, throwExceptionIfFail)) @@ -87,7 +89,7 @@ private static bool TryParseAddress(string data, bool expectMultipleAddresses, r index--; } - if (!TryParseDomain(data, ref index, out string domain, throwExceptionIfFail)) + if (!TryParseDomain(data, ref index, out string? domain, throwExceptionIfFail)) { parseAddressInfo = default; return false; @@ -110,7 +112,7 @@ private static bool TryParseAddress(string data, bool expectMultipleAddresses, r // Skip the '@' symbol index--; - if (!TryParseLocalPart(data, ref index, expectAngleBracket, expectMultipleAddresses, out string localPart, throwExceptionIfFail)) + if (!TryParseLocalPart(data, ref index, expectAngleBracket, expectMultipleAddresses, out string? localPart, throwExceptionIfFail)) { parseAddressInfo = default; return false; @@ -206,7 +208,7 @@ private static bool TryReadCfwsAndThrowIfIncomplete(string data, int index, out // Throws a FormatException or returns false: // - For invalid un-escaped chars, including Unicode // - If the start of the data string is reached - private static bool TryParseDomain(string data, ref int index, out string domain, bool throwExceptionIfFail) + private static bool TryParseDomain(string data, ref int index, [NotNullWhen(true)] out string? domain, bool throwExceptionIfFail) { // Skip comments and whitespace if (!TryReadCfwsAndThrowIfIncomplete(data, index, out index, throwExceptionIfFail)) @@ -268,7 +270,7 @@ private static bool TryParseDomain(string data, ref int index, out string domain // - For invalid un-escaped chars, including Unicode // - If the final value of data[index] is not a valid character to precede the local-part private static bool TryParseLocalPart(string data, ref int index, bool expectAngleBracket, - bool expectMultipleAddresses, out string localPart, bool throwExceptionIfFail) + bool expectMultipleAddresses, [NotNullWhen(true)] out string? localPart, bool throwExceptionIfFail) { // Skip comments and whitespace if (!TryReadCfwsAndThrowIfIncomplete(data, index, out index, throwExceptionIfFail)) @@ -354,7 +356,7 @@ private static bool TryParseLocalPart(string data, ref int index, bool expectAng // Throws a FormatException or false is returned: // - For invalid un-escaped chars, except Unicode // - If the postconditions cannot be met. - private static bool TryParseDisplayName(string data, ref int index, bool expectMultipleAddresses, out string displayName, bool throwExceptionIfFail) + private static bool TryParseDisplayName(string data, ref int index, bool expectMultipleAddresses, [NotNullWhen(true)] out string? displayName, bool throwExceptionIfFail) { // Whatever is left over must be the display name. The display name should be a single word/atom or a // quoted string, but for robustness we allow the quotes to be omitted, so long as we can find the comma @@ -432,7 +434,7 @@ private static bool TryParseDisplayName(string data, ref int index, bool expectM return true; } - internal static bool TryNormalizeOrThrow(string input, out string normalizedString, bool throwExceptionIfFail) + internal static bool TryNormalizeOrThrow(string input, [NotNullWhen(true)] out string? normalizedString, bool throwExceptionIfFail) { try { diff --git a/src/libraries/Common/src/System/Net/Mail/MailBnfHelper.cs b/src/libraries/Common/src/System/Net/Mail/MailBnfHelper.cs index 1137a443e1b9db..bd368ce3b20fca 100644 --- a/src/libraries/Common/src/System/Net/Mail/MailBnfHelper.cs +++ b/src/libraries/Common/src/System/Net/Mail/MailBnfHelper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.Text; @@ -189,12 +190,12 @@ internal static void ValidateHeaderName(string data) throw new FormatException(SR.InvalidHeaderName); } - internal static string ReadQuotedString(string data, ref int offset, StringBuilder builder) + internal static string? ReadQuotedString(string data, ref int offset, StringBuilder builder) { return ReadQuotedString(data, ref offset, builder, false, false); } - internal static string ReadQuotedString(string data, ref int offset, StringBuilder builder, bool doesntRequireQuotes, bool permitUnicodeInDisplayName) + internal static string? ReadQuotedString(string data, ref int offset, StringBuilder? builder, bool doesntRequireQuotes, bool permitUnicodeInDisplayName) { // assume first char is the opening quote if (!doesntRequireQuotes) @@ -246,7 +247,7 @@ internal static string ReadQuotedString(string data, ref int offset, StringBuild throw new FormatException(SR.MailHeaderFieldMalformedHeader); } - internal static string ReadParameterAttribute(string data, ref int offset, StringBuilder builder) + internal static string? ReadParameterAttribute(string data, ref int offset, StringBuilder builder) { if (!SkipCFWS(data, ref offset)) return null; // @@ -254,7 +255,7 @@ internal static string ReadParameterAttribute(string data, ref int offset, Strin return ReadToken(data, ref offset, null); } - internal static string ReadToken(string data, ref int offset, StringBuilder builder) + internal static string ReadToken(string data, ref int offset, StringBuilder? builder) { int start = offset; for (; offset < data.Length; offset++) @@ -277,9 +278,9 @@ internal static string ReadToken(string data, ref int offset, StringBuilder buil return data.Substring(start, offset - start); } - private static readonly string[] s_months = new string[] { null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + private static readonly string?[] s_months = new string?[] { null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - internal static string GetDateTimeString(DateTime value, StringBuilder builder) + internal static string? GetDateTimeString(DateTime value, StringBuilder? builder) { StringBuilder localBuilder = (builder != null ? builder : new StringBuilder()); localBuilder.Append(value.Day); diff --git a/src/libraries/Common/src/System/Net/NTAuthentication.Common.cs b/src/libraries/Common/src/System/Net/NTAuthentication.Common.cs index 03a98ef5aef82a..839c96f670785b 100644 --- a/src/libraries/Common/src/System/Net/NTAuthentication.Common.cs +++ b/src/libraries/Common/src/System/Net/NTAuthentication.Common.cs @@ -28,7 +28,7 @@ internal partial class NTAuthentication private string? _protocolName; private string? _clientSpecifiedSpn; - private ChannelBinding _channelBinding = null!; + private ChannelBinding? _channelBinding = null; // If set, no more calls should be made. internal bool IsCompleted => _isCompleted; @@ -92,12 +92,12 @@ internal bool IsKerberos // // This overload does not attempt to impersonate because the caller either did it already or the original thread context is still preserved. // - internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding) + internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlagsPal requestedContextFlags, ChannelBinding? channelBinding) { Initialize(isServer, package, credential, spn, requestedContextFlags, channelBinding); } - private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding) + private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlagsPal requestedContextFlags, ChannelBinding? channelBinding) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this, package, spn, requestedContextFlags); @@ -167,7 +167,7 @@ internal int MakeSignature(byte[] buffer, int offset, int count, ref byte[] outp return NegotiateStreamPal.MakeSignature(_securityContext!, buffer, offset, count, ref output); } - internal string? GetOutgoingBlob(string incomingBlob) + internal string? GetOutgoingBlob(string? incomingBlob) { byte[]? decodedIncomingBlob = null; if (incomingBlob != null && incomingBlob.Length > 0) diff --git a/src/libraries/Common/src/System/Net/Security/CertificateHelper.Unix.cs b/src/libraries/Common/src/System/Net/Security/CertificateHelper.Unix.cs index 1120a042a7db26..d69563e3688304 100644 --- a/src/libraries/Common/src/System/Net/Security/CertificateHelper.Unix.cs +++ b/src/libraries/Common/src/System/Net/Security/CertificateHelper.Unix.cs @@ -8,7 +8,7 @@ namespace System.Net.Security { internal static partial class CertificateHelper { - internal static X509Certificate2 GetEligibleClientCertificate() + internal static X509Certificate2? GetEligibleClientCertificate() { // Get initial list of client certificates from the MY store. X509Certificate2Collection candidateCerts; diff --git a/src/libraries/Common/src/System/Net/Security/CertificateHelper.Windows.cs b/src/libraries/Common/src/System/Net/Security/CertificateHelper.Windows.cs index 7bb5d1042dd02c..fcb49a04b3fa9c 100644 --- a/src/libraries/Common/src/System/Net/Security/CertificateHelper.Windows.cs +++ b/src/libraries/Common/src/System/Net/Security/CertificateHelper.Windows.cs @@ -2,13 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Security.Cryptography.X509Certificates; namespace System.Net.Security { internal static partial class CertificateHelper { - internal static X509Certificate2 GetEligibleClientCertificate() + internal static X509Certificate2? GetEligibleClientCertificate() { // Get initial list of client certificates from the MY store. X509Certificate2Collection candidateCerts; diff --git a/src/libraries/Common/src/System/Net/Security/CertificateHelper.cs b/src/libraries/Common/src/System/Net/Security/CertificateHelper.cs index 84ab203a3b50fb..30c8f9330a33df 100644 --- a/src/libraries/Common/src/System/Net/Security/CertificateHelper.cs +++ b/src/libraries/Common/src/System/Net/Security/CertificateHelper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using Microsoft.Win32.SafeHandles; using System.Diagnostics; using System.Globalization; @@ -14,7 +15,7 @@ internal static partial class CertificateHelper { private const string ClientAuthenticationOID = "1.3.6.1.5.5.7.3.2"; - internal static X509Certificate2 GetEligibleClientCertificate(X509CertificateCollection candidateCerts) + internal static X509Certificate2? GetEligibleClientCertificate(X509CertificateCollection candidateCerts) { if (candidateCerts.Count == 0) { @@ -27,7 +28,7 @@ internal static X509Certificate2 GetEligibleClientCertificate(X509CertificateCol return GetEligibleClientCertificate(certs); } - internal static X509Certificate2 GetEligibleClientCertificate(X509Certificate2Collection candidateCerts) + internal static X509Certificate2? GetEligibleClientCertificate(X509Certificate2Collection candidateCerts) { if (candidateCerts.Count == 0) { diff --git a/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs b/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs index 1fdcd6952254b8..441706c9010417 100644 --- a/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs +++ b/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs @@ -100,7 +100,7 @@ private static bool GssInitSecurityContext( ref SafeGssContextHandle? context, SafeGssCredHandle credential, bool isNtlm, - ChannelBinding channelBinding, + ChannelBinding? channelBinding, SafeGssNameHandle? targetName, Interop.NetSecurityNative.GssFlags inFlags, byte[]? buffer, @@ -279,7 +279,7 @@ Interop.NetSecurityNative.Status status private static SecurityStatusPal EstablishSecurityContext( SafeFreeNegoCredentials credential, ref SafeDeleteContext? context, - ChannelBinding channelBinding, + ChannelBinding? channelBinding, string targetName, ContextFlagsPal inFlags, byte[]? incomingBlob, @@ -361,7 +361,7 @@ internal static SecurityStatusPal InitializeSecurityContext( string spn, ContextFlagsPal requestedContextFlags, byte[]? incomingBlob, - ChannelBinding channelBinding, + ChannelBinding? channelBinding, ref byte[]? resultBlob, ref ContextFlagsPal contextFlags) { @@ -400,7 +400,7 @@ internal static SecurityStatusPal AcceptSecurityContext( ref SafeDeleteContext? securityContext, ContextFlagsPal requestedContextFlags, byte[]? incomingBlob, - ChannelBinding channelBinding, + ChannelBinding? channelBinding, ref byte[] resultBlob, ref ContextFlagsPal contextFlags) { diff --git a/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Windows.cs b/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Windows.cs index a1f306edd44e2d..56a87933e21f6e 100644 --- a/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Windows.cs +++ b/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Windows.cs @@ -77,7 +77,7 @@ internal static SecurityStatusPal InitializeSecurityContext( string spn, ContextFlagsPal requestedContextFlags, byte[]? incomingBlob, - ChannelBinding channelBinding, + ChannelBinding? channelBinding, ref byte[]? resultBlob, ref ContextFlagsPal contextFlags) { @@ -134,7 +134,7 @@ internal static SecurityStatusPal AcceptSecurityContext( ref SafeDeleteContext? securityContext, ContextFlagsPal requestedContextFlags, byte[]? incomingBlob, - ChannelBinding channelBinding, + ChannelBinding? channelBinding, ref byte[]? resultBlob, ref ContextFlagsPal contextFlags) { diff --git a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs index 6b33d1047eb751..fcc2fb94e59abf 100644 --- a/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs +++ b/src/libraries/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs @@ -33,12 +33,12 @@ public static SslClientAuthenticationOptions ShallowClone(this SslClientAuthenti // Try to detect if a property gets added that we're not copying correctly. foreach (PropertyInfo pi in options.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) { - object origValue = pi.GetValue(options); - object cloneValue = pi.GetValue(clone); + object? origValue = pi.GetValue(options); + object? cloneValue = pi.GetValue(clone); if (origValue is IEnumerable origEnumerable) { - IEnumerable cloneEnumerable = cloneValue as IEnumerable; + IEnumerable? cloneEnumerable = cloneValue as IEnumerable; Debug.Assert(cloneEnumerable != null, $"{pi.Name}. Expected enumerable cloned value."); IEnumerator e1 = origEnumerable.GetEnumerator(); diff --git a/src/libraries/Common/src/System/Net/SecurityStatusPal.cs b/src/libraries/Common/src/System/Net/SecurityStatusPal.cs index 595aec0970aba1..d0f7b26c038d5e 100644 --- a/src/libraries/Common/src/System/Net/SecurityStatusPal.cs +++ b/src/libraries/Common/src/System/Net/SecurityStatusPal.cs @@ -35,6 +35,7 @@ internal enum SecurityStatusPalErrorCode ContextExpired, CredentialsNeeded, Renegotiate, + TryAgain, // Errors OutOfMemory, diff --git a/src/libraries/Common/src/System/Net/TlsStream.cs b/src/libraries/Common/src/System/Net/TlsStream.cs index 6076b435b91c06..9be73c9b2ab95e 100644 --- a/src/libraries/Common/src/System/Net/TlsStream.cs +++ b/src/libraries/Common/src/System/Net/TlsStream.cs @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; -using System.Threading.Tasks; namespace System.Net { @@ -32,7 +32,7 @@ public void AuthenticateAsClient() ServicePointManager.CheckCertificateRevocationList); } - public IAsyncResult BeginAuthenticateAsClient(AsyncCallback asyncCallback, object state) + public IAsyncResult BeginAuthenticateAsClient(AsyncCallback? asyncCallback, object? state) { return _sslStream.BeginAuthenticateAsClient( _host, @@ -48,7 +48,7 @@ public void EndAuthenticateAsClient(IAsyncResult asyncResult) _sslStream.EndAuthenticateAsClient(asyncResult); } - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback? callback, object? state) { return _sslStream.BeginWrite(buffer, offset, size, callback, state); } @@ -68,7 +68,7 @@ public override int Read(byte[] buffer, int offset, int size) return _sslStream.Read(buffer, offset, size); } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { return _sslStream.BeginRead(buffer, offset, count, callback, state); } diff --git a/src/libraries/Common/src/System/Runtime/ExceptionServices/ExceptionStackTrace.cs b/src/libraries/Common/src/System/Runtime/ExceptionServices/ExceptionStackTrace.cs index c8b633ca745dba..57647f3ab15af7 100644 --- a/src/libraries/Common/src/System/Runtime/ExceptionServices/ExceptionStackTrace.cs +++ b/src/libraries/Common/src/System/Runtime/ExceptionServices/ExceptionStackTrace.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.Reflection; @@ -16,12 +17,12 @@ public static void AddCurrentStack(Exception exception) Debug.Assert(exception != null, "Expected non-null Exception"); const string ExceptionRemoteStackTraceStringName = "_remoteStackTraceString"; - FieldInfo fi = typeof(Exception).GetField(ExceptionRemoteStackTraceStringName, BindingFlags.NonPublic | BindingFlags.Instance); + FieldInfo? fi = typeof(Exception).GetField(ExceptionRemoteStackTraceStringName, BindingFlags.NonPublic | BindingFlags.Instance); if (fi != null) { string text = - (string)fi.GetValue(exception) + + (string?)fi.GetValue(exception) + Environment.StackTrace + Environment.NewLine + "--- End of stack trace from AddCurrentStack ---" + Environment.NewLine; fi.SetValue(exception, text); diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs index e1bc57cb95f945..06fb623cc81c5a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs @@ -13,11 +13,11 @@ namespace System.Security.Cryptography.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct OaepParamsAsn { - private static readonly byte[] s_defaultHashFunc = { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 }; + private static ReadOnlySpan DefaultHashFunc => new byte[] { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 }; - private static readonly byte[] s_defaultMaskGenFunc = { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 }; + private static ReadOnlySpan DefaultMaskGenFunc => new byte[] { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 }; - private static readonly byte[] s_defaultPSourceFunc = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x09, 0x04, 0x00 }; + private static ReadOnlySpan DefaultPSourceFunc => new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x09, 0x04, 0x00 }; internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashFunc; internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenFunc; @@ -30,15 +30,15 @@ static OaepParamsAsn() ReadOnlyMemory rebind = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultHashFunc, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultHashFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashFunc); reader.ThrowIfNotEmpty(); - reader = new AsnValueReader(s_defaultMaskGenFunc, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultMaskGenFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.MaskGenFunc); reader.ThrowIfNotEmpty(); - reader = new AsnValueReader(s_defaultPSourceFunc, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultPSourceFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.PSourceFunc); reader.ThrowIfNotEmpty(); } @@ -61,7 +61,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) HashFunc.Encode(tmp); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultHashFunc)) + if (!encoded.SequenceEqual(DefaultHashFunc)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); writer.WriteEncodedValue(encoded); @@ -78,7 +78,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) MaskGenFunc.Encode(tmp); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultMaskGenFunc)) + if (!encoded.SequenceEqual(DefaultMaskGenFunc)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); writer.WriteEncodedValue(encoded); @@ -95,7 +95,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) PSourceFunc.Encode(tmp); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultPSourceFunc)) + if (!encoded.SequenceEqual(DefaultPSourceFunc)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2)); writer.WriteEncodedValue(encoded); @@ -142,7 +142,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultHashFunc, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultHashFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashFunc); } @@ -155,7 +155,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultMaskGenFunc, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultMaskGenFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.MaskGenFunc); } @@ -168,7 +168,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultPSourceFunc, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultPSourceFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.PSourceFunc); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs index 67c2cecd73b778..78730906951dd0 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs @@ -13,7 +13,7 @@ namespace System.Security.Cryptography.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct Pbkdf2Params { - private static readonly byte[] s_defaultPrf = { 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00 }; + private static ReadOnlySpan DefaultPrf => new byte[] { 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00 }; internal System.Security.Cryptography.Asn1.Pbkdf2SaltChoice Salt; internal int IterationCount; @@ -27,7 +27,7 @@ static Pbkdf2Params() ReadOnlyMemory rebind = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultPrf, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultPrf, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.Prf); reader.ThrowIfNotEmpty(); } @@ -58,7 +58,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) Prf.Encode(tmp); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultPrf)) + if (!encoded.SequenceEqual(DefaultPrf)) { writer.WriteEncodedValue(encoded); } @@ -122,7 +122,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultPrf, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultPrf, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.Prf); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/MacData.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/MacData.xml.cs index cf059b72be7399..da404561afb879 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/MacData.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/MacData.xml.cs @@ -13,7 +13,7 @@ namespace System.Security.Cryptography.Asn1.Pkcs12 [StructLayout(LayoutKind.Sequential)] internal partial struct MacData { - private static readonly byte[] s_defaultIterationCount = { 0x02, 0x01, 0x01 }; + private static ReadOnlySpan DefaultIterationCount => new byte[] { 0x02, 0x01, 0x01 }; internal System.Security.Cryptography.Asn1.DigestInfoAsn Mac; internal ReadOnlyMemory MacSalt; @@ -25,7 +25,7 @@ static MacData() MacData decoded = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultIterationCount, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultIterationCount, AsnEncodingRules.DER); if (!reader.TryReadInt32(out decoded.IterationCount)) { @@ -55,7 +55,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) tmp.WriteInteger(IterationCount); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultIterationCount)) + if (!encoded.SequenceEqual(DefaultIterationCount)) { writer.WriteEncodedValue(encoded); } @@ -116,7 +116,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultIterationCount, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultIterationCount, AsnEncodingRules.DER); if (!defaultReader.TryReadInt32(out decoded.IterationCount)) { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs index 78985e2b8ca778..6c42acd09a1cc3 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs @@ -13,13 +13,13 @@ namespace System.Security.Cryptography.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct PssParamsAsn { - private static readonly byte[] s_defaultHashAlgorithm = { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 }; + private static ReadOnlySpan DefaultHashAlgorithm => new byte[] { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 }; - private static readonly byte[] s_defaultMaskGenAlgorithm = { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 }; + private static ReadOnlySpan DefaultMaskGenAlgorithm => new byte[] { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 }; - private static readonly byte[] s_defaultSaltLength = { 0x02, 0x01, 0x14 }; + private static ReadOnlySpan DefaultSaltLength => new byte[] { 0x02, 0x01, 0x14 }; - private static readonly byte[] s_defaultTrailerField = { 0x02, 0x01, 0x01 }; + private static ReadOnlySpan DefaultTrailerField => new byte[] { 0x02, 0x01, 0x01 }; internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm; internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenAlgorithm; @@ -33,15 +33,15 @@ static PssParamsAsn() ReadOnlyMemory rebind = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultHashAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashAlgorithm); reader.ThrowIfNotEmpty(); - reader = new AsnValueReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultMaskGenAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.MaskGenAlgorithm); reader.ThrowIfNotEmpty(); - reader = new AsnValueReader(s_defaultSaltLength, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultSaltLength, AsnEncodingRules.DER); if (!reader.TryReadInt32(out decoded.SaltLength)) { @@ -50,7 +50,7 @@ static PssParamsAsn() reader.ThrowIfNotEmpty(); - reader = new AsnValueReader(s_defaultTrailerField, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultTrailerField, AsnEncodingRules.DER); if (!reader.TryReadInt32(out decoded.TrailerField)) { @@ -78,7 +78,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) HashAlgorithm.Encode(tmp); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultHashAlgorithm)) + if (!encoded.SequenceEqual(DefaultHashAlgorithm)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); writer.WriteEncodedValue(encoded); @@ -95,7 +95,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) MaskGenAlgorithm.Encode(tmp); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultMaskGenAlgorithm)) + if (!encoded.SequenceEqual(DefaultMaskGenAlgorithm)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); writer.WriteEncodedValue(encoded); @@ -112,7 +112,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) tmp.WriteInteger(SaltLength); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultSaltLength)) + if (!encoded.SequenceEqual(DefaultSaltLength)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2)); writer.WriteEncodedValue(encoded); @@ -129,7 +129,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) tmp.WriteInteger(TrailerField); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultTrailerField)) + if (!encoded.SequenceEqual(DefaultTrailerField)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 3)); writer.WriteEncodedValue(encoded); @@ -176,7 +176,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultHashAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashAlgorithm); } @@ -189,7 +189,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultMaskGenAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.MaskGenAlgorithm); } @@ -207,7 +207,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultSaltLength, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultSaltLength, AsnEncodingRules.DER); if (!defaultReader.TryReadInt32(out decoded.SaltLength)) { @@ -230,7 +230,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultTrailerField, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultTrailerField, AsnEncodingRules.DER); if (!defaultReader.TryReadInt32(out decoded.TrailerField)) { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs index 0c447e9bf6bf33..45ead32bef0c21 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs @@ -13,7 +13,7 @@ namespace System.Security.Cryptography.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct X509ExtensionAsn { - private static readonly byte[] s_defaultCritical = { 0x01, 0x01, 0x00 }; + private static ReadOnlySpan DefaultCritical => new byte[] { 0x01, 0x01, 0x00 }; internal Oid ExtnId; internal bool Critical; @@ -25,7 +25,7 @@ static X509ExtensionAsn() X509ExtensionAsn decoded = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultCritical, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultCritical, AsnEncodingRules.DER); decoded.Critical = reader.ReadBoolean(); reader.ThrowIfNotEmpty(); } @@ -49,7 +49,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) tmp.WriteBoolean(Critical); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultCritical)) + if (!encoded.SequenceEqual(DefaultCritical)) { writer.WriteEncodedValue(encoded); } @@ -96,7 +96,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultCritical, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultCritical, AsnEncodingRules.DER); decoded.Critical = defaultReader.ReadBoolean(); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/asn.xslt b/src/libraries/Common/src/System/Security/Cryptography/Asn1/asn.xslt index a182bd6ba865b0..b6866081ab6d43 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/asn.xslt +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/asn.xslt @@ -213,7 +213,7 @@ namespace - private static readonly byte[] = { }; + private static ReadOnlySpan<byte> => new byte[] { }; @@ -909,7 +909,7 @@ namespace new Asn1Tag(TagClass.ContextSpecific, ) - s_default + Default else diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs b/src/libraries/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs index 9dc07c411485ae..406d2878fdbe23 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs @@ -41,15 +41,49 @@ public override byte[] CreateSignature(byte[] rgbHash) } } +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + protected override unsafe bool TryCreateSignatureCore( + ReadOnlySpan hash, + Span destination, + DSASignatureFormat signatureFormat, + out int bytesWritten) +#else public override unsafe bool TryCreateSignature(ReadOnlySpan hash, Span destination, out int bytesWritten) +#endif { Span stackBuf = stackalloc byte[WindowsMaxQSize]; ReadOnlySpan source = AdjustHashSizeIfNecessary(hash, stackBuf); using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle()) { - return CngCommon.TrySignHash(keyHandle, source, destination, AsymmetricPaddingMode.None, null, out bytesWritten); + if (!CngCommon.TrySignHash(keyHandle, source, destination, AsymmetricPaddingMode.None, null, out bytesWritten)) + { + bytesWritten = 0; + return false; + } } + +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) + { + return true; + } + + if (signatureFormat != DSASignatureFormat.Rfc3279DerSequence) + { + Debug.Fail($"Missing internal implementation handler for signature format {signatureFormat}"); + throw new CryptographicException( + SR.Cryptography_UnknownSignatureFormat, + signatureFormat.ToString()); + } + + return AsymmetricAlgorithmHelpers.TryConvertIeee1363ToDer( + destination.Slice(0, bytesWritten), + destination, + out bytesWritten); +#else + return true; +#endif } public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) @@ -63,14 +97,41 @@ public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) throw new ArgumentNullException(nameof(rgbSignature)); } +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + return VerifySignatureCore(rgbHash, rgbSignature, DSASignatureFormat.IeeeP1363FixedFieldConcatenation); +#else return VerifySignature((ReadOnlySpan)rgbHash, (ReadOnlySpan)rgbSignature); +#endif } - public override bool VerifySignature(ReadOnlySpan hash, ReadOnlySpan signature) +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + protected override bool VerifySignatureCore( + ReadOnlySpan hash, + ReadOnlySpan signature, + DSASignatureFormat signatureFormat) { Span stackBuf = stackalloc byte[WindowsMaxQSize]; ReadOnlySpan source = AdjustHashSizeIfNecessary(hash, stackBuf); + if (signatureFormat == DSASignatureFormat.Rfc3279DerSequence) + { + // source.Length is the field size, in bytes, so just convert to bits. + int fieldSizeBits = source.Length * 8; + signature = this.ConvertSignatureToIeeeP1363(signatureFormat, signature, fieldSizeBits); + } + else if (signatureFormat != DSASignatureFormat.IeeeP1363FixedFieldConcatenation) + { + Debug.Fail($"Missing internal implementation handler for signature format {signatureFormat}"); + throw new CryptographicException( + SR.Cryptography_UnknownSignatureFormat, + signatureFormat.ToString()); + } +#else + public override bool VerifySignature(ReadOnlySpan hash, ReadOnlySpan signature) + { + Span stackBuf = stackalloc byte[WindowsMaxQSize]; + ReadOnlySpan source = AdjustHashSizeIfNecessary(hash, stackBuf); +#endif using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle()) { unsafe diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs index b2d01c1eb427ba..9a6f96fe669566 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs @@ -24,7 +24,16 @@ internal static partial class DSAImplementation #endif public sealed partial class DSAOpenSsl : DSA { + // The biggest key allowed by FIPS 186-4 has N=256 (bit), which + // maximally produces a 72-byte DER signature. + // If a future version of the standard continues to enhance DSA, + // we may want to bump this limit to allow the max-1 (expected size) + // TryCreateSignature to pass. + // Future updates seem unlikely, though, as FIPS 186-5 October 2019 draft has + // DSA as a no longer supported/updated algorithm. + private const int SignatureStackBufSize = 72; private const int BitsPerByte = 8; + private Lazy _key = null!; public DSAOpenSsl() @@ -210,71 +219,118 @@ public override byte[] CreateSignature(byte[] rgbHash) SafeDsaHandle key = GetKey(); int signatureSize = Interop.Crypto.DsaEncodedSignatureSize(key); - byte[] signature = CryptoPool.Rent(signatureSize); - try - { - bool success = Interop.Crypto.DsaSign(key, rgbHash, new Span(signature, 0, signatureSize), out signatureSize); - if (!success) - { - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } + int signatureFieldSize = Interop.Crypto.DsaSignatureFieldSize(key) * BitsPerByte; + Span signDestination = stackalloc byte[SignatureStackBufSize]; - Debug.Assert( - signatureSize <= signature.Length, - "DSA_sign reported an unexpected signature size", - "DSA_sign reported signatureSize was {0}, when <= {1} was expected", - signatureSize, - signature.Length); + ReadOnlySpan derSignature = SignHash(rgbHash, signDestination, signatureSize, key); + return AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(derSignature, signatureFieldSize); + } - int signatureFieldSize = Interop.Crypto.DsaSignatureFieldSize(key) * BitsPerByte; - return AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(signature, 0, signatureSize, signatureFieldSize); - } - finally - { - CryptoPool.Return(signature, signatureSize); - } +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + public override bool TryCreateSignature( + ReadOnlySpan hash, + Span destination, + out int bytesWritten) + { + return TryCreateSignatureCore( + hash, + destination, + DSASignatureFormat.IeeeP1363FixedFieldConcatenation, + out bytesWritten); } + protected override bool TryCreateSignatureCore( + ReadOnlySpan hash, + Span destination, + DSASignatureFormat signatureFormat, + out int bytesWritten) +#else public override bool TryCreateSignature(ReadOnlySpan hash, Span destination, out int bytesWritten) +#endif { - byte[] converted; SafeDsaHandle key = GetKey(); - int signatureSize = Interop.Crypto.DsaEncodedSignatureSize(key); - byte[] signature = CryptoPool.Rent(signatureSize); - try + int maxSignatureSize = Interop.Crypto.DsaEncodedSignatureSize(key); + Span signDestination = stackalloc byte[SignatureStackBufSize]; + +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) +#endif + { + int fieldSizeBytes = Interop.Crypto.DsaSignatureFieldSize(key); + int p1363SignatureSize = 2 * fieldSizeBytes; + + if (destination.Length < p1363SignatureSize) + { + bytesWritten = 0; + return false; + } + + int fieldSizeBits = fieldSizeBytes * 8; + + ReadOnlySpan derSignature = SignHash(hash, signDestination, maxSignatureSize, key); + bytesWritten = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(derSignature, fieldSizeBits, destination); + Debug.Assert(bytesWritten == p1363SignatureSize); + return true; + } +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + else if (signatureFormat == DSASignatureFormat.Rfc3279DerSequence) { - bool success = Interop.Crypto.DsaSign(key, hash, new Span(signature, 0, signatureSize), out signatureSize); - if (!success) + if (destination.Length >= maxSignatureSize) { - throw Interop.Crypto.CreateOpenSslCryptographicException(); + signDestination = destination; } + else if (maxSignatureSize > signDestination.Length) + { + Debug.Fail($"Stack-based signDestination is insufficient ({maxSignatureSize} needed)"); + bytesWritten = 0; + return false; + } + + ReadOnlySpan derSignature = SignHash(hash, signDestination, maxSignatureSize, key); - Debug.Assert( - signatureSize <= signature.Length, - "DSA_sign reported an unexpected signature size", - "DSA_sign reported signatureSize was {0}, when <= {1} was expected", - signatureSize, - signature.Length); + if (destination == signDestination) + { + bytesWritten = derSignature.Length; + return true; + } - int signatureFieldSize = Interop.Crypto.DsaSignatureFieldSize(key) * BitsPerByte; - converted = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(signature, 0, signatureSize, signatureFieldSize); + return Helpers.TryCopyToDestination(derSignature, destination, out bytesWritten); } - finally + else { - CryptoPool.Return(signature, signatureSize); + Debug.Fail($"Missing internal implementation handler for signature format {signatureFormat}"); + throw new CryptographicException( + SR.Cryptography_UnknownSignatureFormat, + signatureFormat.ToString()); } +#endif + } - if (converted.Length <= destination.Length) + private static ReadOnlySpan SignHash( + ReadOnlySpan hash, + Span destination, + int signatureLength, + SafeDsaHandle key) + { + if (signatureLength > destination.Length) { - new ReadOnlySpan(converted).CopyTo(destination); - bytesWritten = converted.Length; - return true; + Debug.Fail($"Stack-based signDestination is insufficient ({signatureLength} needed)"); + destination = new byte[signatureLength]; } - else + + if (!Interop.Crypto.DsaSign(key, hash, destination, out int actualLength)) { - bytesWritten = 0; - return false; + throw Interop.Crypto.CreateOpenSslCryptographicException(); } + + Debug.Assert( + actualLength <= signatureLength, + "DSA_sign reported an unexpected signature size", + "DSA_sign reported signatureSize was {0}, when <= {1} was expected", + actualLength, + signatureLength); + + return destination.Slice(0, actualLength); } public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) @@ -287,20 +343,44 @@ public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) return VerifySignature((ReadOnlySpan)rgbHash, (ReadOnlySpan)rgbSignature); } +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + + public override bool VerifySignature(ReadOnlySpan hash, ReadOnlySpan signature) => + VerifySignatureCore(hash, signature, DSASignatureFormat.IeeeP1363FixedFieldConcatenation); + + protected override bool VerifySignatureCore( + ReadOnlySpan hash, + ReadOnlySpan signature, + DSASignatureFormat signatureFormat) +#else public override bool VerifySignature(ReadOnlySpan hash, ReadOnlySpan signature) +#endif { SafeDsaHandle key = GetKey(); - int expectedSignatureBytes = Interop.Crypto.DsaSignatureFieldSize(key) * 2; - if (signature.Length != expectedSignatureBytes) +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) { - // The input isn't of the right length (assuming no DER), so we can't sensibly re-encode it with DER. - return false; - } - - byte[] openSslFormat = AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(signature); +#endif + int expectedSignatureBytes = Interop.Crypto.DsaSignatureFieldSize(key) * 2; + if (signature.Length != expectedSignatureBytes) + { + // The input isn't of the right length (assuming no DER), so we can't sensibly re-encode it with DER. + return false; + } - return Interop.Crypto.DsaVerify(key, hash, openSslFormat); + signature = AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(signature); +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + } + else if (signatureFormat != DSASignatureFormat.Rfc3279DerSequence) + { + Debug.Fail($"Missing internal implementation handler for signature format {signatureFormat}"); + throw new CryptographicException( + SR.Cryptography_UnknownSignatureFormat, + signatureFormat.ToString()); + } +#endif + return Interop.Crypto.DsaVerify(key, hash, signature); } private void ThrowIfDisposed() diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs index 6f4e111b1c59c6..0744b81a6e3672 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs @@ -276,9 +276,7 @@ public override byte[] CreateSignature(byte[] rgbHash) // Since the AppleCrypto implementation is limited to FIPS 186-2, signature field sizes // are always 160 bits / 20 bytes (the size of SHA-1, and the only legal length for Q). byte[] ieeeFormatSignature = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363( - derFormatSignature, - 0, - derFormatSignature.Length, + derFormatSignature.AsSpan(0, derFormatSignature.Length), fieldSizeBits: 160); return ieeeFormatSignature; diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.SignVerify.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.SignVerify.cs index bc065dfea08cce..277198b4485219 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.SignVerify.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDsaCng.SignVerify.cs @@ -2,14 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Diagnostics; using Microsoft.Win32.SafeHandles; using Internal.Cryptography; -using ErrorCode = Interop.NCrypt.ErrorCode; using AsymmetricPaddingMode = Interop.NCrypt.AsymmetricPaddingMode; namespace System.Security.Cryptography @@ -48,12 +46,57 @@ public override byte[] SignHash(byte[] hash) } } +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + public override bool TrySignHash(ReadOnlySpan source, Span destination, out int bytesWritten) + { + return TrySignHashCore( + source, + destination, + DSASignatureFormat.IeeeP1363FixedFieldConcatenation, + out bytesWritten); + } + + protected override unsafe bool TrySignHashCore( + ReadOnlySpan hash, + Span destination, + DSASignatureFormat signatureFormat, + out int bytesWritten) + { +#else public override unsafe bool TrySignHash(ReadOnlySpan source, Span destination, out int bytesWritten) { + ReadOnlySpan hash = source; +#endif using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle()) { - return keyHandle.TrySignHash(source, destination, AsymmetricPaddingMode.None, null, out bytesWritten); + if (!keyHandle.TrySignHash(hash, destination, AsymmetricPaddingMode.None, null, out bytesWritten)) + { + bytesWritten = 0; + return false; + } + } + +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) + { + return true; + } + + if (signatureFormat != DSASignatureFormat.Rfc3279DerSequence) + { + Debug.Fail($"Missing internal implementation handler for signature format {signatureFormat}"); + throw new CryptographicException( + SR.Cryptography_UnknownSignatureFormat, + signatureFormat.ToString()); } + + return AsymmetricAlgorithmHelpers.TryConvertIeee1363ToDer( + destination.Slice(0, bytesWritten), + destination, + out bytesWritten); +#else + return true; +#endif } /// @@ -66,14 +109,37 @@ public override bool VerifyHash(byte[] hash, byte[] signature) if (signature == null) throw new ArgumentNullException(nameof(signature)); +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + return VerifyHashCore(hash, signature, DSASignatureFormat.IeeeP1363FixedFieldConcatenation); +#else return VerifyHash((ReadOnlySpan)hash, (ReadOnlySpan)signature); +#endif } - public override unsafe bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan signature) +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan signature) => + VerifyHashCore(hash, signature, DSASignatureFormat.IeeeP1363FixedFieldConcatenation); + + protected override bool VerifyHashCore( + ReadOnlySpan hash, + ReadOnlySpan signature, + DSASignatureFormat signatureFormat) +#else + public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan signature) +#endif { +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + if (signatureFormat != DSASignatureFormat.IeeeP1363FixedFieldConcatenation) + { + signature = this.ConvertSignatureToIeeeP1363(signatureFormat, signature); + } +#endif using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle()) { - return keyHandle.VerifyHash(hash, signature, AsymmetricPaddingMode.None, null); + unsafe + { + return keyHandle.VerifyHash(hash, signature, AsymmetricPaddingMode.None, null); + } } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs index a95b3dbb90142f..e6f2f21ae7a48e 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; using System.IO; using Internal.Cryptography; using Microsoft.Win32.SafeHandles; @@ -14,6 +15,9 @@ internal static partial class ECDsaImplementation #endif public sealed partial class ECDsaOpenSsl : ECDsa { + // secp521r1 maxes out at 139 bytes, so 256 should always be enough + private const int SignatureStackBufSize = 256; + private ECOpenSsl _key; /// @@ -80,48 +84,112 @@ public override byte[] SignHash(byte[] hash) ThrowIfDisposed(); SafeEcKeyHandle key = _key.Value; int signatureLength = Interop.Crypto.EcDsaSize(key); - byte[] signature = new byte[signatureLength]; - if (!Interop.Crypto.EcDsaSign(hash, signature, ref signatureLength, key)) - throw Interop.Crypto.CreateOpenSslCryptographicException(); - byte[] converted = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(signature, 0, signatureLength, KeySize); + Span signDestination = stackalloc byte[SignatureStackBufSize]; + ReadOnlySpan derSignature = SignHash(hash, signDestination, signatureLength, key); + byte[] converted = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(derSignature, KeySize); return converted; } +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS public override bool TrySignHash(ReadOnlySpan hash, Span destination, out int bytesWritten) + { + return TrySignHashCore( + hash, + destination, + DSASignatureFormat.IeeeP1363FixedFieldConcatenation, + out bytesWritten); + } + + protected override bool TrySignHashCore( + ReadOnlySpan hash, + Span destination, + DSASignatureFormat signatureFormat, + out int bytesWritten) +#else + public override bool TrySignHash(ReadOnlySpan hash, Span destination, out int bytesWritten) +#endif { ThrowIfDisposed(); SafeEcKeyHandle key = _key.Value; - byte[] converted; int signatureLength = Interop.Crypto.EcDsaSize(key); - byte[] signature = CryptoPool.Rent(signatureLength); - try + Span signDestination = stackalloc byte[SignatureStackBufSize]; + +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) { - if (!Interop.Crypto.EcDsaSign(hash, new Span(signature, 0, signatureLength), ref signatureLength, key)) +#endif + int encodedSize = 2 * AsymmetricAlgorithmHelpers.BitsToBytes(KeySize); + + if (destination.Length < encodedSize) { - throw Interop.Crypto.CreateOpenSslCryptographicException(); + bytesWritten = 0; + return false; } - converted = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(signature, 0, signatureLength, KeySize); + ReadOnlySpan derSignature = SignHash(hash, signDestination, signatureLength, key); + bytesWritten = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(derSignature, KeySize, destination); + Debug.Assert(bytesWritten == encodedSize); + return true; +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS } - finally + else if (signatureFormat == DSASignatureFormat.Rfc3279DerSequence) { - CryptoPool.Return(signature, signatureLength); + if (destination.Length >= signatureLength) + { + signDestination = destination; + } + else if (signatureLength > signDestination.Length) + { + Debug.Fail($"Stack-based signDestination is insufficient ({signatureLength} needed)"); + bytesWritten = 0; + return false; + } + + ReadOnlySpan derSignature = SignHash(hash, signDestination, signatureLength, key); + + if (destination == signDestination) + { + bytesWritten = derSignature.Length; + return true; + } + + return Helpers.TryCopyToDestination(derSignature, destination, out bytesWritten); } + else + { + throw new ArgumentOutOfRangeException(nameof(signatureFormat)); + } +#endif + } - if (converted.Length <= destination.Length) + private static ReadOnlySpan SignHash( + ReadOnlySpan hash, + Span destination, + int signatureLength, + SafeEcKeyHandle key) + { + if (signatureLength > destination.Length) { - new ReadOnlySpan(converted).CopyTo(destination); - bytesWritten = converted.Length; - return true; + Debug.Fail($"Stack-based signDestination is insufficient ({signatureLength} needed)"); + destination = new byte[signatureLength]; } - else + + if (!Interop.Crypto.EcDsaSign(hash, destination, out int actualLength, key)) { - bytesWritten = 0; - return false; + throw Interop.Crypto.CreateOpenSslCryptographicException(); } + + Debug.Assert( + actualLength <= signatureLength, + "ECDSA_sign reported an unexpected signature size", + "ECDSA_sign reported signatureSize was {0}, when <= {1} was expected", + actualLength, + signatureLength); + + return destination.Slice(0, actualLength); } public override bool VerifyHash(byte[] hash, byte[] signature) @@ -134,24 +202,62 @@ public override bool VerifyHash(byte[] hash, byte[] signature) return VerifyHash((ReadOnlySpan)hash, (ReadOnlySpan)signature); } +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan signature) => + VerifyHashCore(hash, signature, DSASignatureFormat.IeeeP1363FixedFieldConcatenation); + + protected override bool VerifyHashCore( + ReadOnlySpan hash, + ReadOnlySpan signature, + DSASignatureFormat signatureFormat) +#else public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan signature) +#endif { ThrowIfDisposed(); - // The signature format for .NET is r.Concat(s). Each of r and s are of length BitsToBytes(KeySize), even - // when they would have leading zeroes. If it's the correct size, then we need to encode it from - // r.Concat(s) to SEQUENCE(INTEGER(r), INTEGER(s)), because that's the format that OpenSSL expects. - int expectedBytes = 2 * AsymmetricAlgorithmHelpers.BitsToBytes(KeySize); - if (signature.Length != expectedBytes) + Span derSignature = stackalloc byte[SignatureStackBufSize]; + ReadOnlySpan toVerify = derSignature; + +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) { - // The input isn't of the right length, so we can't sensibly re-encode it. - return false; - } +#endif + // The signature format for .NET is r.Concat(s). Each of r and s are of length BitsToBytes(KeySize), even + // when they would have leading zeroes. If it's the correct size, then we need to encode it from + // r.Concat(s) to SEQUENCE(INTEGER(r), INTEGER(s)), because that's the format that OpenSSL expects. + int expectedBytes = 2 * AsymmetricAlgorithmHelpers.BitsToBytes(KeySize); + if (signature.Length != expectedBytes) + { + // The input isn't of the right length, so we can't sensibly re-encode it. + return false; + } - byte[] openSslFormat = AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(signature); + if (AsymmetricAlgorithmHelpers.TryConvertIeee1363ToDer(signature, derSignature, out int derSize)) + { + toVerify = derSignature.Slice(0, derSize); + } + else + { + toVerify = AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(signature); + } +#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS + } + else if (signatureFormat == DSASignatureFormat.Rfc3279DerSequence) + { + toVerify = signature; + } + else + { + Debug.Fail($"Missing internal implementation handler for signature format {signatureFormat}"); + throw new CryptographicException( + SR.Cryptography_UnknownSignatureFormat, + signatureFormat.ToString()); + } +#endif SafeEcKeyHandle key = _key.Value; - int verifyResult = Interop.Crypto.EcDsaVerify(hash, openSslFormat, key); + int verifyResult = Interop.Crypto.EcDsaVerify(hash, toVerify, key); return verifyResult == 1; } diff --git a/src/libraries/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs b/src/libraries/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs index 42bf95927bd8ea..da68d61d336cb9 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs @@ -109,9 +109,7 @@ public override byte[] SignHash(byte[] hash) byte[] derFormatSignature = Interop.AppleCrypto.GenerateSignature(keys.PrivateKey, hash); byte[] ieeeFormatSignature = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363( - derFormatSignature, - 0, - derFormatSignature.Length, + derFormatSignature.AsSpan(0, derFormatSignature.Length), KeySize); return ieeeFormatSignature; @@ -127,9 +125,7 @@ public override bool TrySignHash(ReadOnlySpan source, Span destinati byte[] derFormatSignature = Interop.AppleCrypto.GenerateSignature(keys.PrivateKey, source); byte[] ieeeFormatSignature = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363( - derFormatSignature, - 0, - derFormatSignature.Length, + derFormatSignature.AsSpan(0, derFormatSignature.Length), KeySize); if (ieeeFormatSignature.Length <= destination.Length) diff --git a/src/libraries/Common/src/System/StrongToWeakReference.cs b/src/libraries/Common/src/System/StrongToWeakReference.cs index f49a9f13d73d06..83dfd05dc99492 100644 --- a/src/libraries/Common/src/System/StrongToWeakReference.cs +++ b/src/libraries/Common/src/System/StrongToWeakReference.cs @@ -9,7 +9,7 @@ namespace System /// Provides an object wrapper that can transition between strong and weak references to the object. internal sealed class StrongToWeakReference : WeakReference where T : class { - private T _strongRef; + private T? _strongRef; /// Initializes the instance with a strong reference to the specified object. /// The object to wrap. @@ -30,9 +30,9 @@ public void MakeStrong() } /// Gets the wrapped object. - public new T Target => _strongRef ?? WeakTarget; + public new T? Target => _strongRef ?? WeakTarget; /// Gets the wrapped object via its weak reference. - private T WeakTarget => base.Target as T; + private T? WeakTarget => base.Target as T; } } diff --git a/src/libraries/Common/src/System/Threading/Tasks/RendezvousAwaitable.cs b/src/libraries/Common/src/System/Threading/Tasks/RendezvousAwaitable.cs index 84134884f6fcdc..890c1ab75461b6 100644 --- a/src/libraries/Common/src/System/Threading/Tasks/RendezvousAwaitable.cs +++ b/src/libraries/Common/src/System/Threading/Tasks/RendezvousAwaitable.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; @@ -19,11 +21,11 @@ internal class RendezvousAwaitable : ICriticalNotifyCompletion /// The continuation to invoke when the operation completes, or if the operation /// has completed before OnCompleted is called. /// - private Action _continuation; + private Action? _continuation; /// The exception representing the failed async operation, if it failed. - private ExceptionDispatchInfo _error; + private ExceptionDispatchInfo? _error; /// The result of the async operation, if it succeeded. - private TResult _result; + [AllowNull] private TResult _result = default; #if DEBUG private bool _resultSet; #endif @@ -39,7 +41,7 @@ public bool IsCompleted { get { - Action c = Volatile.Read(ref _continuation); + Action? c = Volatile.Read(ref _continuation); Debug.Assert(c == null || c == s_completionSentinel); return c != null; } @@ -55,7 +57,7 @@ public TResult GetResult() // Propagate any error if there is one, clearing it out first to prepare for reuse. // We don't need to clear a result, as result and error are mutually exclusive. - ExceptionDispatchInfo error = _error; + ExceptionDispatchInfo? error = _error; if (error != null) { _error = null; @@ -101,7 +103,7 @@ public void SetException(Exception exception) /// Alerts any awaiter that the operation has completed. private void NotifyAwaiter() { - Action c = _continuation ?? Interlocked.CompareExchange(ref _continuation, s_completionSentinel, null); + Action? c = _continuation ?? Interlocked.CompareExchange(ref _continuation, s_completionSentinel, null); if (c != null) { Debug.Assert(c != s_completionSentinel); @@ -122,7 +124,7 @@ public void OnCompleted(Action continuation) { Debug.Assert(continuation != null); - Action c = _continuation ?? Interlocked.CompareExchange(ref _continuation, continuation, null); + Action? c = _continuation ?? Interlocked.CompareExchange(ref _continuation, continuation, null); if (c != null) { Debug.Assert(c == s_completionSentinel); diff --git a/src/libraries/Common/tests/Common.Tests.csproj b/src/libraries/Common/tests/Common.Tests.csproj index 85bcb69323bc80..18a311eb4c6d90 100644 --- a/src/libraries/Common/tests/Common.Tests.csproj +++ b/src/libraries/Common/tests/Common.Tests.csproj @@ -4,6 +4,7 @@ false true $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX + annotations diff --git a/src/libraries/Common/tests/CoreFx.Private.TestUtilities/CoreFx.Private.TestUtilities.csproj b/src/libraries/Common/tests/CoreFx.Private.TestUtilities/CoreFx.Private.TestUtilities.csproj index 4d45110d37908f..559cca7f20346b 100644 --- a/src/libraries/Common/tests/CoreFx.Private.TestUtilities/CoreFx.Private.TestUtilities.csproj +++ b/src/libraries/Common/tests/CoreFx.Private.TestUtilities/CoreFx.Private.TestUtilities.csproj @@ -35,9 +35,6 @@ Common\Interop\Windows\Kernel32\Interop.GetCurrentProcess_IntPtr.cs - - Common\Interop\Windows\NtDll\Interop.RTL_OSVERSIONINFOEX.cs - Common\Interop\Windows\NtDll\Interop.RtlGetVersion.cs diff --git a/src/libraries/Common/tests/CoreFx.Private.TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/CoreFx.Private.TestUtilities/System/PlatformDetection.cs index 088f7eed54ec00..3f021d3309cffd 100644 --- a/src/libraries/Common/tests/CoreFx.Private.TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/CoreFx.Private.TestUtilities/System/PlatformDetection.cs @@ -33,6 +33,7 @@ public static partial class PlatformDetection public static bool IsArgIteratorSupported => IsMonoRuntime || (IsWindows && IsNotArmProcess); public static bool IsArgIteratorNotSupported => !IsArgIteratorSupported; public static bool Is32BitProcess => IntPtr.Size == 4; + public static bool IsNotWindows => !IsWindows; // Please make sure that you have the libgdiplus dependency installed. // For details, see https://docs.microsoft.com/dotnet/core/install/dependencies?pivots=os-macos&tabs=netcore31#libgdiplus @@ -206,7 +207,7 @@ private static bool GetSsl3Support() private static bool GetIsRunningOnMonoInterpreter() { // This is a temporary solution because mono does not support interpreter detection - // within the runtime. + // within the runtime. var val = Environment.GetEnvironmentVariable("MONO_ENV_OPTIONS"); return (val != null && val.Contains("--interpreter")); } diff --git a/src/libraries/Common/tests/System/Net/Http/DefaultCredentialsTest.cs b/src/libraries/Common/tests/System/Net/Http/DefaultCredentialsTest.cs index 40686b97bc519f..d5b9e4fb940cb4 100644 --- a/src/libraries/Common/tests/System/Net/Http/DefaultCredentialsTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/DefaultCredentialsTest.cs @@ -335,7 +335,8 @@ private async Task ProcessRequests() // Send a response in the JSON format that the client expects string username = context.User.Identity.Name; - await context.Response.OutputStream.WriteAsync(System.Text.Encoding.UTF8.GetBytes($"{{\"authenticated\": \"true\", \"user\": \"{username}\" }}")); + byte[] bytes = System.Text.Encoding.UTF8.GetBytes($"{{\"authenticated\": \"true\", \"user\": \"{username}\" }}"); + await context.Response.OutputStream.WriteAsync(bytes); context.Response.Close(); } diff --git a/src/libraries/Common/tests/System/Net/Http/GenericLoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/GenericLoopbackServer.cs index 9e505e37314b63..779055b921e4dc 100644 --- a/src/libraries/Common/tests/System/Net/Http/GenericLoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/GenericLoopbackServer.cs @@ -86,7 +86,7 @@ public class GenericLoopbackOptions public IPAddress Address { get; set; } = IPAddress.Loopback; public bool UseSsl { get; set; } = PlatformDetection.SupportsAlpn && !Capability.Http2ForceUnencryptedLoopback(); public SslProtocols SslProtocols { get; set; } = -#if !NETSTANDARD2_0 +#if !NETSTANDARD2_0 && !NETFRAMEWORK SslProtocols.Tls13 | #endif SslProtocols.Tls12; diff --git a/src/libraries/Common/tests/System/Net/Http/Http2Frames.cs b/src/libraries/Common/tests/System/Net/Http/Http2Frames.cs index 4fe0f5bddd9790..af0f245b1b8215 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http2Frames.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http2Frames.cs @@ -548,10 +548,12 @@ public override void WriteTo(Span buffer) BinaryPrimitives.WriteUInt16BigEndian(buffer, checked((ushort)Origin.Length)); buffer = buffer.Slice(2); - Encoding.ASCII.GetBytes(Origin, buffer); + var tmpBuffer = Encoding.ASCII.GetBytes(Origin); + tmpBuffer.CopyTo(buffer); buffer = buffer.Slice(Origin.Length); - Encoding.ASCII.GetBytes(AltSvc, buffer); + tmpBuffer = Encoding.ASCII.GetBytes(AltSvc); + tmpBuffer.CopyTo(buffer); } public override string ToString() => $"{base.ToString()}\n{nameof(Origin)}: {Origin}\n{nameof(AltSvc)}: {AltSvc}"; diff --git a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs index 43be924c03550b..ee774e0f23090c 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; using System.IO; +using System.Linq; using System.Net.Http.Functional.Tests; using System.Net.Security; using System.Net.Sockets; @@ -28,6 +28,7 @@ public class Http2LoopbackConnection : GenericLoopbackConnection private readonly byte[] _prefix; public string PrefixString => Encoding.UTF8.GetString(_prefix, 0, _prefix.Length); public bool IsInvalid => _connectionSocket == null; + public Stream Stream => _connectionStream; public Http2LoopbackConnection(Socket socket, Http2Options httpOptions) { @@ -40,6 +41,7 @@ public Http2LoopbackConnection(Socket socket, Http2Options httpOptions) using (var cert = Configuration.Certificates.GetServerCertificate()) { +#if !NETFRAMEWORK SslServerAuthenticationOptions options = new SslServerAuthenticationOptions(); options.EnabledSslProtocols = httpOptions.SslProtocols; @@ -51,9 +53,12 @@ public Http2LoopbackConnection(Socket socket, Http2Options httpOptions) options.ServerCertificate = cert; - options.ClientCertificateRequired = false; + options.ClientCertificateRequired = httpOptions.ClientCertificateRequired; sslStream.AuthenticateAsServerAsync(options, CancellationToken.None).Wait(); +#else + sslStream.AuthenticateAsServerAsync(cert, httpOptions.ClientCertificateRequired, httpOptions.SslProtocols, checkCertificateRevocation: false).Wait(); +#endif } _connectionStream = sslStream; @@ -64,6 +69,10 @@ public Http2LoopbackConnection(Socket socket, Http2Options httpOptions) { throw new Exception("Connection stream closed while attempting to read connection preface."); } + else if (Text.Encoding.ASCII.GetString(_prefix).Contains("HTTP/1.1")) + { + throw new Exception("HTTP 1.1 request received."); + } } public async Task SendConnectionPrefaceAsync() @@ -331,7 +340,7 @@ private static (int bytesConsumed, string value) DecodeString(ReadOnlySpan } else { - string value = Encoding.ASCII.GetString(headerBlock.Slice(bytesConsumed, stringLength)); + string value = Encoding.ASCII.GetString(headerBlock.Slice(bytesConsumed, stringLength).ToArray()); return (bytesConsumed + stringLength, value); } } diff --git a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackServer.cs index f2aea4cfb4f234..4d3486c3a80c74 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackServer.cs @@ -181,9 +181,14 @@ public override async Task AcceptConnectionAsync(Func clientFunc, Func serverFunc, int timeout = 60_000) + public static Task CreateClientAndServerAsync(Func clientFunc, Func serverFunc, int timeout = 60_000) { - using (var server = Http2LoopbackServer.CreateServer()) + return CreateClientAndServerAsync(clientFunc, serverFunc, null, timeout); + } + + public static async Task CreateClientAndServerAsync(Func clientFunc, Func serverFunc, Http2Options http2Options, int timeout = 60_000) + { + using (var server = Http2LoopbackServer.CreateServer(http2Options ?? new Http2Options())) { Task clientTask = clientFunc(server.Address); Task serverTask = serverFunc(server); @@ -197,6 +202,8 @@ public class Http2Options : GenericLoopbackOptions { public int ListenBacklog { get; set; } = 1; + public bool ClientCertificateRequired { get; set; } + public Http2Options() { UseSsl = PlatformDetection.SupportsAlpn && !Capability.Http2ForceUnencryptedLoopback(); @@ -237,7 +244,7 @@ public override async Task CreateServerAsync(Func HttpVersion.Version20; + public override Version Version => HttpVersion20.Value; } public enum ProtocolErrors @@ -257,4 +264,9 @@ public enum ProtocolErrors INADEQUATE_SECURITY = 0xc, HTTP_1_1_REQUIRED = 0xd } + + public static class HttpVersion20 + { + public static readonly Version Value = new Version(2, 0); + } } diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.AcceptAllCerts.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.AcceptAllCerts.cs index 53d45add78b831..99ef96c4b645bc 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.AcceptAllCerts.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.AcceptAllCerts.cs @@ -39,8 +39,10 @@ public void SingletonReturnsTrue() [InlineData(SslProtocols.Tls, true)] [InlineData(SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, false)] [InlineData(SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, true)] +#if !NETFRAMEWORK [InlineData(SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, false)] [InlineData(SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, true)] +#endif [InlineData(SslProtocols.None, false)] [InlineData(SslProtocols.None, true)] public async Task SetDelegate_ConnectionSucceeds(SslProtocols acceptedProtocol, bool requestOnlyThisProtocol) @@ -64,7 +66,11 @@ public async Task SetDelegate_ConnectionSucceeds(SslProtocols acceptedProtocol, // restrictions on minimum TLS/SSL version // We currently know that some platforms like Debian 10 OpenSSL // will by default block < TLS 1.2 +#if !NETFRAMEWORK handler.SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; +#else + handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; +#endif } var options = new LoopbackServer.Options { UseSsl = true, SslProtocols = acceptedProtocol }; diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs index 3b195350040d97..9c2c1e2c74e53e 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs @@ -602,6 +602,12 @@ public async Task Credentials_ServerUsesWindowsAuthentication_Success(string ser [InlineData("Negotiate")] public async Task Credentials_ServerChallengesWithWindowsAuth_ClientSendsWindowsAuthHeader(string authScheme) { +#if WINHTTPHANDLER_TEST + if (UseVersion > HttpVersion.Version11) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif await LoopbackServerFactory.CreateClientAndServerAsync( async uri => { diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs index d7e519fa202ed4..b248f3470bbdda 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs @@ -28,17 +28,24 @@ public abstract class HttpClientHandler_Cancellation_Test : HttpClientHandlerTes { public HttpClientHandler_Cancellation_Test(ITestOutputHelper output) : base(output) { } - [Theory] + [ConditionalTheory] [InlineData(false, CancellationMode.Token)] [InlineData(true, CancellationMode.Token)] public async Task PostAsync_CancelDuringRequestContentSend_TaskCanceledQuickly(bool chunkedTransfer, CancellationMode mode) { - if (LoopbackServerFactory.Version >= HttpVersion.Version20 && chunkedTransfer) + if (LoopbackServerFactory.Version >= HttpVersion20.Value && chunkedTransfer) { // There is no chunked encoding in HTTP/2 and later return; } +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif + var serverRelease = new TaskCompletionSource(); await LoopbackServerFactory.CreateClientAndServerAsync(async uri => { @@ -76,16 +83,23 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => }); } - [Theory] + [ConditionalTheory] [MemberData(nameof(OneBoolAndCancellationMode))] public async Task GetAsync_CancelDuringResponseHeadersReceived_TaskCanceledQuickly(bool connectionClose, CancellationMode mode) { - if (LoopbackServerFactory.Version >= HttpVersion.Version20 && connectionClose) + if (LoopbackServerFactory.Version >= HttpVersion20.Value && connectionClose) { // There is no Connection header in HTTP/2 and later return; } +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif + using (HttpClient client = CreateHttpClient()) { client.Timeout = Timeout.InfiniteTimeSpan; @@ -130,7 +144,7 @@ await ValidateClientCancellationAsync(async () => [MemberData(nameof(TwoBoolsAndCancellationMode))] public async Task GetAsync_CancelDuringResponseBodyReceived_Buffered_TaskCanceledQuickly(bool chunkedTransfer, bool connectionClose, CancellationMode mode) { - if (LoopbackServerFactory.Version >= HttpVersion.Version20 && (chunkedTransfer || connectionClose)) + if (LoopbackServerFactory.Version >= HttpVersion20.Value && (chunkedTransfer || connectionClose)) { // There is no chunked encoding or connection header in HTTP/2 and later return; @@ -182,16 +196,23 @@ await ValidateClientCancellationAsync(async () => } } - [Theory] + [ConditionalTheory] [MemberData(nameof(ThreeBools))] public async Task GetAsync_CancelDuringResponseBodyReceived_Unbuffered_TaskCanceledQuickly(bool chunkedTransfer, bool connectionClose, bool readOrCopyToAsync) { - if (LoopbackServerFactory.Version >= HttpVersion.Version20 && (chunkedTransfer || connectionClose)) + if (LoopbackServerFactory.Version >= HttpVersion20.Value && (chunkedTransfer || connectionClose)) { // There is no chunked encoding or connection header in HTTP/2 and later return; } +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif + using (HttpClient client = CreateHttpClient()) { client.Timeout = Timeout.InfiniteTimeSpan; @@ -237,14 +258,19 @@ await ValidateClientCancellationAsync(async () => }); } } - - [Theory] + [ConditionalTheory] [InlineData(CancellationMode.CancelPendingRequests, false)] [InlineData(CancellationMode.DisposeHttpClient, false)] [InlineData(CancellationMode.CancelPendingRequests, true)] [InlineData(CancellationMode.DisposeHttpClient, true)] public async Task GetAsync_CancelPendingRequests_DoesntCancelReadAsyncOnResponseStream(CancellationMode mode, bool copyToAsync) { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif using (HttpClient client = CreateHttpClient()) { client.Timeout = Timeout.InfiniteTimeSpan; @@ -312,7 +338,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, url) => [ConditionalFact] public async Task MaxConnectionsPerServer_WaitingConnectionsAreCancelable() { - if (LoopbackServerFactory.Version >= HttpVersion.Version20) + if (LoopbackServerFactory.Version >= HttpVersion20.Value) { // HTTP/2 does not use connection limits. throw new SkipTestException("Not supported on HTTP/2 and later"); @@ -490,11 +516,18 @@ public static IEnumerable PostAsync_Cancel_CancellationTokenPassedToCo } } +#if !NETFRAMEWORK [OuterLoop("Uses Task.Delay")] - [Theory] + [ConditionalTheory] [MemberData(nameof(PostAsync_Cancel_CancellationTokenPassedToContent_MemberData))] public async Task PostAsync_Cancel_CancellationTokenPassedToContent(HttpContent content, CancellationTokenSource cancellationTokenSource) { +#if WINHTTPHANDLER_TEST + if (UseVersion > HttpVersion.Version11) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif await LoopbackServerFactory.CreateClientAndServerAsync( async uri => { @@ -518,6 +551,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync( catch (Exception) { } }); } +#endif private async Task ValidateClientCancellationAsync(Func clientBodyAsync) { diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ClientCertificates.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ClientCertificates.cs index b75156a6f2556c..a17334e247f328 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ClientCertificates.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ClientCertificates.cs @@ -113,7 +113,7 @@ await TestHelper.WhenAllCompletedOrAnyFailed( { _output.WriteLine( "Client cert: {0}", - ((X509Certificate2)sslStream.RemoteCertificate).GetNameInfo(X509NameType.SimpleName, false)); + new X509Certificate2(sslStream.RemoteCertificate.Export(X509ContentType.Cert)).GetNameInfo(X509NameType.SimpleName, false)); Assert.Equal(cert, sslStream.RemoteCertificate); } else diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs index 75f440ac1bcdc9..3fa53fe5a9be21 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs @@ -182,7 +182,11 @@ await LoopbackServerFactory.CreateClientAndServerAsync( private string GetCookieValue(HttpRequestData request) { +#if !NETFRAMEWORK if (LoopbackServerFactory.Version < HttpVersion.Version20) +#else + if (LoopbackServerFactory.Version < HttpVersion20.Value) +#endif { // HTTP/1.x must have only one value. return request.GetSingleHeaderValue("Cookie"); @@ -603,7 +607,9 @@ public static IEnumerable CookieNamesValuesAndUseCookies() yield return new object[] { "ABC", "123", useCookies }; yield return new object[] { "Hello", "World", useCookies }; yield return new object[] { "foo", "bar", useCookies }; +#if !NETFRAMEWORK yield return new object[] { "Hello World", "value", useCookies }; +#endif yield return new object[] { ".AspNetCore.Session", "RAExEmXpoCbueP_QYM", useCookies }; yield return new object[] diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs index 0fb03c3e612b8c..fa0b630594b7f1 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs @@ -22,6 +22,11 @@ namespace System.Net.Http.Functional.Tests public abstract class HttpClientHandler_Decompression_Test : HttpClientHandlerTestBase { +#if !NETFRAMEWORK + private static readonly DecompressionMethods _all = DecompressionMethods.All; +#else + private static readonly DecompressionMethods _all = DecompressionMethods.Deflate | DecompressionMethods.GZip; +#endif public HttpClientHandler_Decompression_Test(ITestOutputHelper output) : base(output) { } public static IEnumerable RemoteServersAndCompressionUris() @@ -41,20 +46,22 @@ public static IEnumerable DecompressedResponse_MethodSpecified_Decompr { "deflate", new Func(s => new DeflateStream(s, CompressionLevel.Optimal, leaveOpen: true)), - specifyAllMethods ? DecompressionMethods.Deflate : DecompressionMethods.All + specifyAllMethods ? DecompressionMethods.Deflate : _all }; yield return new object[] { "gzip", new Func(s => new GZipStream(s, CompressionLevel.Optimal, leaveOpen: true)), - specifyAllMethods ? DecompressionMethods.GZip : DecompressionMethods.All + specifyAllMethods ? DecompressionMethods.GZip : _all }; +#if !NETFRAMEWORK yield return new object[] { "br", new Func(s => new BrotliStream(s, CompressionLevel.Optimal, leaveOpen: true)), - specifyAllMethods ? DecompressionMethods.Brotli : DecompressionMethods.All + specifyAllMethods ? DecompressionMethods.Brotli : _all }; +#endif } } @@ -102,6 +109,7 @@ public static IEnumerable DecompressedResponse_MethodNotSpecified_Orig new Func(s => new DeflateStream(s, CompressionLevel.Optimal, leaveOpen: true)), DecompressionMethods.None }; +#if !NETFRAMEWORK yield return new object[] { "gzip", @@ -114,6 +122,7 @@ public static IEnumerable DecompressedResponse_MethodNotSpecified_Orig new Func(s => new BrotliStream(s, CompressionLevel.Optimal, leaveOpen: true)), DecompressionMethods.Deflate | DecompressionMethods.GZip }; +#endif } [Theory] @@ -189,10 +198,12 @@ public async Task GetAsync_SetAutomaticDecompression_HeadersRemoved(Configuratio } [Theory] +#if NETCORE [InlineData(DecompressionMethods.Brotli, "br", "")] [InlineData(DecompressionMethods.Brotli, "br", "br")] [InlineData(DecompressionMethods.Brotli, "br", "gzip")] [InlineData(DecompressionMethods.Brotli, "br", "gzip, deflate")] +#endif [InlineData(DecompressionMethods.GZip, "gzip", "")] [InlineData(DecompressionMethods.Deflate, "deflate", "")] [InlineData(DecompressionMethods.GZip | DecompressionMethods.Deflate, "gzip, deflate", "")] diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.MaxResponseHeadersLength.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.MaxResponseHeadersLength.cs index 7c6db382a06862..dd6daf3e359576 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.MaxResponseHeadersLength.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.MaxResponseHeadersLength.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.DotNet.XUnitExtensions; using Xunit; using Xunit.Abstractions; @@ -46,9 +47,15 @@ public void ValidValue_SetGet_Roundtrips(int validValue) } } - [Fact] + [ConditionalFact] public async Task SetAfterUse_Throws() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif await LoopbackServerFactory.CreateClientAndServerAsync(async uri => { using HttpClientHandler handler = CreateHttpClientHandler(); diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs index ef7b570d16ce46..80ec9e25b244d6 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs @@ -26,9 +26,15 @@ public abstract class HttpClientHandler_Proxy_Test : HttpClientHandlerTestBase { public HttpClientHandler_Proxy_Test(ITestOutputHelper output) : base(output) { } - [Fact] + [ConditionalFact] public async Task Dispose_HandlerWithProxy_ProxyNotDisposed() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif var proxy = new TrackDisposalProxy(); await LoopbackServerFactory.CreateClientAndServerAsync(async uri => diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs index 2a04997b809539..393c0241a1928e 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs @@ -13,6 +13,7 @@ using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; +using Microsoft.DotNet.XUnitExtensions; using Xunit; using Xunit.Abstractions; @@ -30,9 +31,15 @@ public abstract partial class HttpClientHandler_ServerCertificates_Test : HttpCl public HttpClientHandler_ServerCertificates_Test(ITestOutputHelper output) : base(output) { } - [Fact] + [ConditionalFact] public void Ctor_ExpectedDefaultValues() { +#if WINHTTPHANDLER_TEST + if (UseVersion > HttpVersion.Version11) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif using (HttpClientHandler handler = CreateHttpClientHandler()) { Assert.Null(handler.ServerCertificateCustomValidationCallback); @@ -40,9 +47,16 @@ public void Ctor_ExpectedDefaultValues() } } - [Fact] + [ConditionalFact] public void ServerCertificateCustomValidationCallback_SetGet_Roundtrips() { +#if WINHTTPHANDLER_TEST + if (UseVersion > HttpVersion.Version11) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif + using (HttpClientHandler handler = CreateHttpClientHandler()) { Assert.Null(handler.ServerCertificateCustomValidationCallback); diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs index b6bf8b5143c2cf..b264aa6bc6c5d9 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs @@ -43,11 +43,13 @@ public void DefaultProtocols_MatchesExpected() [InlineData(SslProtocols.Tls11 | SslProtocols.Tls12)] [InlineData(SslProtocols.Tls | SslProtocols.Tls12)] [InlineData(SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12)] +#if !NETFRAMEWORK [InlineData(SslProtocols.Tls13)] [InlineData(SslProtocols.Tls11 | SslProtocols.Tls13)] [InlineData(SslProtocols.Tls12 | SslProtocols.Tls13)] [InlineData(SslProtocols.Tls | SslProtocols.Tls13)] [InlineData(SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13)] +#endif public void SetGetProtocols_Roundtrips(SslProtocols protocols) { using (HttpClientHandler handler = CreateHttpClientHandler()) @@ -90,7 +92,9 @@ public static IEnumerable GetAsync_AllowedSSLVersion_Succeeds_MemberDa #pragma warning disable 0618 if (PlatformDetection.SupportsSsl3) { +#if !NETFRAMEWORK yield return new object[] { SslProtocols.Ssl3, true }; +#endif } if (PlatformDetection.IsWindows && !PlatformDetection.IsWindows10Version1607OrGreater) { @@ -100,8 +104,10 @@ public static IEnumerable GetAsync_AllowedSSLVersion_Succeeds_MemberDa // These protocols are new, and might not be enabled everywhere yet if (PlatformDetection.IsUbuntu1810OrHigher) { +#if !NETFRAMEWORK yield return new object[] { SslProtocols.Tls13, false }; yield return new object[] { SslProtocols.Tls13, true }; +#endif } } @@ -124,7 +130,11 @@ public async Task GetAsync_AllowedSSLVersion_Succeeds(SslProtocols acceptedProto // restrictions on minimum TLS/SSL version // We currently know that some platforms like Debian 10 OpenSSL // will by default block < TLS 1.2 +#if !NETFRAMEWORK handler.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13; +#else + handler.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; +#endif } var options = new LoopbackServer.Options { UseSsl = true, SslProtocols = acceptedProtocol }; diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index 671401f92852cb..a866a5d076a995 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -226,6 +226,12 @@ public async Task SendAsync_SimpleGet_Success(Configuration.Http.RemoteServer re [ConditionalFact] public async Task GetAsync_IPv6LinkLocalAddressUri_Success() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif using (HttpClient client = CreateHttpClient()) { var options = new GenericLoopbackOptions { Address = TestHelper.GetIPv6LinkLocalAddress() }; @@ -244,10 +250,16 @@ await TestHelper.WhenAllCompletedOrAnyFailed( } } - [Theory] + [ConditionalTheory] [MemberData(nameof(GetAsync_IPBasedUri_Success_MemberData))] public async Task GetAsync_IPBasedUri_Success(IPAddress address) { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif using (HttpClient client = CreateHttpClient()) { var options = new GenericLoopbackOptions { Address = address }; @@ -479,7 +491,7 @@ public static IEnumerable SecureAndNonSecure_IPBasedUri_MemberData() = [MemberData(nameof(SecureAndNonSecure_IPBasedUri_MemberData))] public async Task GetAsync_SecureAndNonSecureIPBasedUri_CorrectlyFormatted(IPAddress address, bool useSsl) { - if (LoopbackServerFactory.Version >= HttpVersion.Version20) + if (LoopbackServerFactory.Version >= HttpVersion20.Value) { throw new SkipTestException("Host header is not supported on HTTP/2 and later."); } @@ -556,11 +568,17 @@ public async Task GetAsync_ServerNeedsAuthAndNoCredential_StatusCodeUnauthorized } } - [Theory] + [ConditionalTheory] [InlineData("WWW-Authenticate", "CustomAuth")] [InlineData("", "")] // RFC7235 requires servers to send this header with 401 but some servers don't. public async Task GetAsync_ServerNeedsNonStandardAuthAndSetCredential_StatusCodeUnauthorized(string authHeadrName, string authHeaderValue) { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif await LoopbackServerFactory.CreateServerAsync(async (server, url) => { HttpClientHandler handler = CreateHttpClientHandler(); @@ -735,9 +753,15 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => server.AcceptConnectionSendCustomResponseAndCloseAsync("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhe")); } - [Fact] + [ConditionalFact] public async Task PostAsync_ManyDifferentRequestHeaders_SentCorrectly() { +#if WINHTTPHANDLER_TEST + if (UseVersion > HttpVersion.Version11) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif const string content = "hello world"; // Using examples from https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields @@ -871,7 +895,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.Equal("X-Underscore_Name", requestData.GetSingleHeaderValue("X-Underscore_Name")); Assert.Equal("End", requestData.GetSingleHeaderValue("X-End")); - if (LoopbackServerFactory.Version >= HttpVersion.Version20) + if (LoopbackServerFactory.Version >= HttpVersion20.Value) { // HTTP/2 and later forbids certain headers or values. Assert.Equal("trailers", requestData.GetSingleHeaderValue("TE")); @@ -904,7 +928,7 @@ public static IEnumerable GetAsync_ManyDifferentResponseHeaders_Parsed [MemberData(nameof(GetAsync_ManyDifferentResponseHeaders_ParsedCorrectly_MemberData))] public async Task GetAsync_ManyDifferentResponseHeaders_ParsedCorrectly(string newline, string fold, bool dribble) { - if (LoopbackServerFactory.Version >= HttpVersion.Version20) + if (LoopbackServerFactory.Version >= HttpVersion20.Value) { throw new SkipTestException("Folding is not supported on HTTP/2 and later."); } @@ -1036,7 +1060,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => [ConditionalFact] public async Task GetAsync_NonTraditionalChunkSizes_Accepted() { - if (LoopbackServerFactory.Version >= HttpVersion.Version20) + if (LoopbackServerFactory.Version >= HttpVersion20.Value) { throw new SkipTestException("Chunking is not supported on HTTP/2 and later."); } @@ -1260,7 +1284,13 @@ await connection.ReadRequestHeaderAndSendCustomResponseAsync( [InlineData(null)] public async Task ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream(bool? chunked) { - if (LoopbackServerFactory.Version >= HttpVersion.Version20 && chunked == true) +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif + if (LoopbackServerFactory.Version >= HttpVersion20.Value && chunked == true) { throw new SkipTestException("Chunking is not supported on HTTP/2 and later."); } @@ -1288,8 +1318,10 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.Throws(() => responseStream.Seek(0, SeekOrigin.Begin)); Assert.Throws(() => responseStream.SetLength(0)); Assert.Throws(() => responseStream.Write(new byte[1], 0, 1)); +#if !NETFRAMEWORK Assert.Throws(() => responseStream.Write(new Span(new byte[1]))); Assert.Throws(() => { responseStream.WriteAsync(new Memory(new byte[1])); }); +#endif Assert.Throws(() => { responseStream.WriteAsync(new byte[1], 0, 1); }); Assert.Throws(() => responseStream.WriteByte(1)); @@ -1329,13 +1361,21 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.Equal(1, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null)); Assert.Equal((byte)'e', buffer[0]); +#if !NETFRAMEWORK Assert.Equal(1, await responseStream.ReadAsync(new Memory(buffer))); +#else + Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); +#endif Assert.Equal((byte)'l', buffer[0]); Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); Assert.Equal((byte)'l', buffer[0]); +#if !NETFRAMEWORK Assert.Equal(1, responseStream.Read(new Span(buffer))); +#else + Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); +#endif Assert.Equal((byte)'o', buffer[0]); Assert.Equal(1, responseStream.Read(buffer, 0, 1)); @@ -1343,9 +1383,13 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => // Doing any of these 0-byte reads causes the connection to fail. Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, Array.Empty(), 0, 0, null)); +#if !NETFRAMEWORK Assert.Equal(0, await responseStream.ReadAsync(Memory.Empty)); +#endif Assert.Equal(0, await responseStream.ReadAsync(Array.Empty(), 0, 0)); +#if !NETFRAMEWORK Assert.Equal(0, responseStream.Read(Span.Empty)); +#endif Assert.Equal(0, responseStream.Read(Array.Empty(), 0, 0)); // And copying @@ -1360,9 +1404,13 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.Equal(0, ms.Length); Assert.Equal(-1, responseStream.ReadByte()); Assert.Equal(0, responseStream.Read(buffer, 0, 1)); +#if !NETFRAMEWORK Assert.Equal(0, responseStream.Read(new Span(buffer))); +#endif Assert.Equal(0, await responseStream.ReadAsync(buffer, 0, 1)); +#if !NETFRAMEWORK Assert.Equal(0, await responseStream.ReadAsync(new Memory(buffer))); +#endif Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null)); } } @@ -1392,9 +1440,15 @@ await server.AcceptConnectionAsync(async connection => }); } - [Fact] + [ConditionalFact] public async Task ReadAsStreamAsync_EmptyResponseBody_HandlerProducesWellBehavedResponseStream() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif await LoopbackServerFactory.CreateClientAndServerAsync(async uri => { using (var client = new HttpMessageInvoker(CreateHttpClientHandler())) @@ -1417,8 +1471,10 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.Throws(() => responseStream.Seek(0, SeekOrigin.Begin)); Assert.Throws(() => responseStream.SetLength(0)); Assert.Throws(() => responseStream.Write(new byte[1], 0, 1)); +#if !NETFRAMEWORK Assert.Throws(() => responseStream.Write(new Span(new byte[1]))); await Assert.ThrowsAsync(async () => await responseStream.WriteAsync(new Memory(new byte[1]))); +#endif await Assert.ThrowsAsync(async () => await responseStream.WriteAsync(new byte[1], 0, 1)); Assert.Throws(() => responseStream.WriteByte(1)); @@ -1455,9 +1511,13 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => var buffer = new byte[1]; Assert.Equal(-1, responseStream.ReadByte()); Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null)); +#if !NETFRAMEWORK Assert.Equal(0, await responseStream.ReadAsync(new Memory(buffer))); +#endif Assert.Equal(0, await responseStream.ReadAsync(buffer, 0, 1)); +#if !NETFRAMEWORK Assert.Equal(0, responseStream.Read(new Span(buffer))); +#endif Assert.Equal(0, responseStream.Read(buffer, 0, 1)); // Empty copies @@ -1471,10 +1531,15 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => }, server => server.AcceptConnectionSendResponseAndCloseAsync()); } - - [Fact] + [ConditionalFact] public async Task Dispose_DisposingHandlerCancelsActiveOperationsWithoutResponses() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif await LoopbackServerFactory.CreateServerAsync(async (server1, url1) => { await LoopbackServerFactory.CreateServerAsync(async (server2, url2) => @@ -1837,9 +1902,15 @@ public async Task PostAsync_ExpectContinue_Success(bool? expectContinue, string } } - [Fact] + [ConditionalFact] public async Task GetAsync_ExpectContinueTrue_NoContent_StillSendsHeader() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif const string ExpectedContent = "Hello, expecting and continuing world."; var clientCompleted = new TaskCompletionSource(); await LoopbackServerFactory.CreateClientAndServerAsync(async uri => @@ -1876,10 +1947,16 @@ public static IEnumerable Interim1xxStatusCode() yield return new object[] { (HttpStatusCode) 199 }; } - [Theory] + [ConditionalTheory] [MemberData(nameof(Interim1xxStatusCode))] public async Task SendAsync_1xxResponsesWithHeaders_InterimResponsesHeadersIgnored(HttpStatusCode responseStatusCode) { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif var clientFinished = new TaskCompletionSource(); const string TestString = "test"; const string CookieHeaderExpected = "yummy_cookie=choco"; @@ -1940,10 +2017,16 @@ await server.AcceptConnectionAsync(async connection => }); } - [Theory] + [ConditionalTheory] [MemberData(nameof(Interim1xxStatusCode))] public async Task SendAsync_Unexpected1xxResponses_DropAllInterimResponses(HttpStatusCode responseStatusCode) { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif var clientFinished = new TaskCompletionSource(); const string TestString = "test"; @@ -1980,9 +2063,15 @@ await server.AcceptConnectionAsync(async connection => }); } - [Fact] + [ConditionalFact] public async Task SendAsync_MultipleExpected100Responses_ReceivesCorrectResponse() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif var clientFinished = new TaskCompletionSource(); const string TestString = "test"; @@ -2019,9 +2108,15 @@ await server.AcceptConnectionAsync(async connection => }); } - [Fact] + [ConditionalFact] public async Task SendAsync_No100ContinueReceived_RequestBodySentEventually() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif var clientFinished = new TaskCompletionSource(); const string RequestString = "request"; const string ResponseString = "response"; @@ -2069,7 +2164,7 @@ public async Task SendAsync_101SwitchingProtocolsResponse_Success() return; } - if (LoopbackServerFactory.Version >= HttpVersion.Version20) + if (LoopbackServerFactory.Version >= HttpVersion20.Value) { throw new SkipTestException("Upgrade is not supported on HTTP/2 and later"); } @@ -2215,6 +2310,7 @@ public async Task PostAsync_Redirect_LargePayload_Helper(Configuration.Http.Remo } } +#if !NETFRAMEWORK [OuterLoop("Uses external server")] [Theory, MemberData(nameof(RemoteServersMemberData))] public async Task PostAsync_ReuseRequestContent_Success(Configuration.Http.RemoteServer remoteServer) @@ -2233,13 +2329,14 @@ public async Task PostAsync_ReuseRequestContent_Success(Configuration.Http.Remot } } } +#endif [Theory] [InlineData(HttpStatusCode.MethodNotAllowed, "Custom description")] [InlineData(HttpStatusCode.MethodNotAllowed, "")] public async Task GetAsync_CallMethod_ExpectedStatusLine(HttpStatusCode statusCode, string reasonPhrase) { - if (LoopbackServerFactory.Version >= HttpVersion.Version20) + if (LoopbackServerFactory.Version >= HttpVersion20.Value) { // Custom messages are not supported on HTTP2 and later. return; @@ -2386,6 +2483,12 @@ public async Task SendAsync_SendRequestUsingNoBodyMethodToEchoServerWithContent_ [Fact] public async Task SendAsync_RequestVersion10_ServerReceivesVersion10Request() { + // Test is not supported for WinHttpHandler and HTTP/2 + if(IsWinHttpHandler && UseVersion >= HttpVersion20.Value) + { + return; + } + Version receivedRequestVersion = await SendRequestAndGetRequestVersionAsync(new Version(1, 0)); Assert.Equal(new Version(1, 0), receivedRequestVersion); } @@ -2440,9 +2543,15 @@ public async Task SendAsync_RequestVersion20_ResponseVersion20IfHttp2Supported(U } } - [Fact] + [ConditionalFact] public async Task SendAsync_RequestVersion20_HttpNotHttps_NoUpgradeRequest() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif await LoopbackServerFactory.CreateClientAndServerAsync(async uri => { using (HttpClient client = CreateHttpClient()) @@ -2514,12 +2623,18 @@ await LoopbackServer.CreateServerAsync(async (server, url) => return receivedRequestVersion; } -#endregion + #endregion -#region Uri wire transmission encoding tests - [Fact] + #region Uri wire transmission encoding tests + [ConditionalFact] public async Task SendRequest_UriPathHasReservedChars_ServerReceivedExpectedPath() { +#if WINHTTPHANDLER_TEST + if (UseVersion >= HttpVersion20.Value) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif await LoopbackServerFactory.CreateServerAsync(async (server, rootUrl) => { var uri = new Uri($"{rootUrl.Scheme}://{rootUrl.Host}:{rootUrl.Port}/test[]"); diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTestBase.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTestBase.cs index 83308747801bf0..003e344d74042a 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTestBase.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTestBase.cs @@ -32,13 +32,21 @@ public HttpClientHandlerTestBase(ITestOutputHelper output) protected virtual HttpClient CreateHttpClient() => CreateHttpClient(CreateHttpClientHandler()); protected HttpClient CreateHttpClient(HttpMessageHandler handler) => - new HttpClient(handler) { DefaultRequestVersion = UseVersion }; + new HttpClient(handler) { +#if !NETFRAMEWORK + DefaultRequestVersion = UseVersion +#endif + }; protected static HttpClient CreateHttpClient(string useVersionString) => CreateHttpClient(CreateHttpClientHandler(useVersionString), useVersionString); protected static HttpClient CreateHttpClient(HttpMessageHandler handler, string useVersionString) => - new HttpClient(handler) { DefaultRequestVersion = Version.Parse(useVersionString) }; + new HttpClient(handler) { +#if !NETFRAMEWORK + DefaultRequestVersion = Version.Parse(useVersionString) +#endif + }; protected HttpClientHandler CreateHttpClientHandler() => CreateHttpClientHandler(UseVersion); @@ -51,7 +59,7 @@ protected static LoopbackServerFactory GetFactoryForVersion(Version useVersion) { return useVersion.Major switch { -#if NETCOREAPP +#if NETCOREAPP || WINHTTPHANDLER_TEST #if HTTP3 3 => Http3LoopbackServerFactory.Singleton, #endif @@ -81,7 +89,11 @@ protected HttpClient CreateHttpClientForRemoteServer(Configuration.Http.RemoteSe wrappedHandler = new VersionCheckerHttpHandler(httpClientHandler, remoteServer.HttpVersion); } - return new HttpClient(wrappedHandler) { DefaultRequestVersion = remoteServer.HttpVersion }; + return new HttpClient(wrappedHandler) { +#if !NETFRAMEWORK + DefaultRequestVersion = remoteServer.HttpVersion +#endif + }; } private sealed class VersionCheckerHttpHandler : DelegatingHandler diff --git a/src/libraries/Common/tests/System/Net/Http/HttpProtocolTests.cs b/src/libraries/Common/tests/System/Net/Http/HttpProtocolTests.cs index 62a46c21b0afc5..635cb2bed65c1b 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpProtocolTests.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpProtocolTests.cs @@ -20,9 +20,15 @@ public abstract class HttpProtocolTests : HttpClientHandlerTestBase public HttpProtocolTests(ITestOutputHelper output) : base(output) { } - [Fact] + [ConditionalFact] public async Task GetAsync_RequestVersion10_Success() { +#if WINHTTPHANDLER_TEST + if (UseVersion > HttpVersion.Version11) + { + throw new SkipTestException($"Test doesn't support {UseVersion} protocol."); + } +#endif await LoopbackServer.CreateServerAsync(async (server, url) => { using (HttpClient client = CreateHttpClient()) @@ -454,7 +460,7 @@ public async Task GetAsync_Chunked_VaryingSizeChunks_ReceivedCorrectly(int maxCh await LoopbackServer.CreateClientAndServerAsync(async uri => { using (HttpMessageInvoker client = new HttpMessageInvoker(CreateHttpClientHandler())) - using (HttpResponseMessage resp = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, uri) { Version = UseVersion }, CancellationToken.None)) + using (HttpResponseMessage resp = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, uri) { Version = base.UseVersion }, CancellationToken.None)) using (Stream respStream = await resp.Content.ReadAsStreamAsync()) { var actualData = new MemoryStream(); @@ -467,7 +473,11 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => { byte[] buffer = new byte[4096]; int bytesRead; +#if !NETFRAMEWORK while ((bytesRead = await respStream.ReadAsync(buffer)) > 0) +#else + while ((bytesRead = await respStream.ReadAsync(buffer, 0, buffer.Length)) > 0) +#endif { actualData.Write(buffer, 0, bytesRead); } diff --git a/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs index 6433f539c0dc63..48d75c889b1718 100644 --- a/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs @@ -394,7 +394,7 @@ public Options() { UseSsl = false; SslProtocols = -#if !NETSTANDARD2_0 +#if !NETSTANDARD2_0 && !NETFRAMEWORK SslProtocols.Tls13 | #endif SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; @@ -451,6 +451,11 @@ public async Task ReadAsync(Memory buffer, int offset, int size) } return readLength; +#elif NETFRAMEWORK + var tmpBuffer = new byte[buffer.Length]; + int readBytes = await _stream.ReadAsync(tmpBuffer, offset, size).ConfigureAwait(false); + tmpBuffer.CopyTo(buffer); + return readBytes; #else return await _stream.ReadAsync(buffer.Slice(offset, size)).ConfigureAwait(false); #endif diff --git a/src/libraries/Common/tests/System/Net/Http/PostScenarioTest.cs b/src/libraries/Common/tests/System/Net/Http/PostScenarioTest.cs index 733b29f0c6d6bb..34de8fffac58f2 100644 --- a/src/libraries/Common/tests/System/Net/Http/PostScenarioTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/PostScenarioTest.cs @@ -28,6 +28,7 @@ public abstract class PostScenarioTest : HttpClientHandlerTestBase public PostScenarioTest(ITestOutputHelper output) : base(output) { } +#if !NETFRAMEWORK [OuterLoop("Uses external servers")] [Theory, MemberData(nameof(RemoteServersMemberData))] public async Task PostRewindableStreamContentMultipleTimes_StreamContentFullySent(Configuration.Http.RemoteServer remoteServer) @@ -50,6 +51,7 @@ public async Task PostRewindableStreamContentMultipleTimes_StreamContentFullySen } } } +#endif [OuterLoop("Uses external servers")] [Theory, MemberData(nameof(RemoteServersMemberData))] diff --git a/src/libraries/Common/tests/System/Net/Http/QPackTestDecoder.cs b/src/libraries/Common/tests/System/Net/Http/QPackTestDecoder.cs index da276e1ce9d654..432b868b3352af 100644 --- a/src/libraries/Common/tests/System/Net/Http/QPackTestDecoder.cs +++ b/src/libraries/Common/tests/System/Net/Http/QPackTestDecoder.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Linq; using System.Numerics; using System.Text; @@ -72,7 +73,12 @@ private static (int bytesConsumed, string value) DecodeString(ReadOnlySpan } (int varIntLength, int stringLength) = DecodeInteger(buffer, prefixMask); - string value = Encoding.ASCII.GetString(buffer.Slice(varIntLength, stringLength)); +#if !NETFRAMEWORK + ReadOnlySpan bytes = buffer.Slice(varIntLength, stringLength); +#else + byte[] bytes = buffer.Slice(varIntLength, stringLength).ToArray(); +#endif + string value = Encoding.ASCII.GetString(bytes); return (varIntLength + stringLength, value); } @@ -203,6 +209,32 @@ public static (int bytesConsumed, int value) DecodeInteger(ReadOnlySpan he new HttpHeaderData("x-frame-options", "deny"), new HttpHeaderData("x-frame-options", "sameorigin"), }; - } +#if NETFRAMEWORK + private static class BitOperations + { + public static int LeadingZeroCount(byte value) + { + int count = 0; + while ((value & 0b1000_0000) != 0) + { + count++; + value <<= 1; + } + return count; + } + + public static int TrailingZeroCount(int value) + { + int count = 0; + while ((value & 1) != 0) + { + count++; + value >>= 1; + } + return count; + } + } +#endif + } } diff --git a/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs b/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs index 8df08a7282145c..67812f9cb73f4f 100644 --- a/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs @@ -80,7 +80,11 @@ public async Task GetStreamAsync_ReadToEnd_Success(Configuration.Http.RemoteServ case 4: // Individual calls to Read(Span) +#if !NETFRAMEWORK while ((bytesRead = stream.Read(new Span(buffer))) != 0) +#else + while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0) +#endif { ms.Write(buffer, 0, bytesRead); } @@ -173,7 +177,9 @@ public async Task GetStreamAsync_ReadZeroBytes_Success(Configuration.Http.Remote using (Stream stream = await client.GetStreamAsync(remoteServer.EchoUri)) { Assert.Equal(0, stream.Read(new byte[1], 0, 0)); +#if !NETFRAMEWORK Assert.Equal(0, stream.Read(new Span(new byte[1], 0, 0))); +#endif Assert.Equal(0, await stream.ReadAsync(new byte[1], 0, 0)); } } @@ -221,7 +227,7 @@ await client.GetAsync(remoteServer.EchoUri, HttpCompletionOption.ResponseHeaders } } } - +#if NETCOREAPP [Theory] [InlineData(TransferType.ContentLength, TransferError.ContentLengthTooLarge)] [InlineData(TransferType.Chunked, TransferError.MissingChunkTerminator)] @@ -249,6 +255,7 @@ await StartTransferTypeAndErrorServer(transferType, transferError, async uri => await ReadAsStreamHelper(uri); }); } +#endif public enum TransferType { diff --git a/src/libraries/Common/tests/System/Net/StreamArrayExtensions.cs b/src/libraries/Common/tests/System/Net/StreamArrayExtensions.cs new file mode 100644 index 00000000000000..0d21fd2cab84c0 --- /dev/null +++ b/src/libraries/Common/tests/System/Net/StreamArrayExtensions.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace System.Net +{ + public static class StreamArrayExtensions + { + public static ValueTask WriteAsync(this Stream stream, ReadOnlyMemory memory) + { + bool isArray = MemoryMarshal.TryGetArray(memory, out ArraySegment segment); + Assert.True(isArray); + + return new ValueTask(stream.WriteAsync(segment.Array, segment.Offset, segment.Count)); + } + + public static ValueTask WriteAsync(this StreamWriter writer, string text) + { + return new ValueTask(writer.WriteAsync(text.ToCharArray(), 0, text.Length)); + } + + public static ValueTask ReadAsync(this Stream stream, ReadOnlyMemory buffer, CancellationToken cancellationToken) + { + bool isArray = MemoryMarshal.TryGetArray(buffer, out ArraySegment segment); + Assert.True(isArray); + + return new ValueTask(stream.ReadAsync(segment.Array, segment.Offset, segment.Count, cancellationToken)); + } + } +} diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSASignatureFormatTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSASignatureFormatTests.cs new file mode 100644 index 00000000000000..af4c6da4fefd8e --- /dev/null +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DSASignatureFormatTests.cs @@ -0,0 +1,382 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.Algorithms.Tests; +using Xunit; + +namespace System.Security.Cryptography.Dsa.Tests +{ + public abstract class DSASignatureFormatTests : DsaFamilySignatureFormatTests + { + private static readonly KeyDescription[] s_keys = LocalGenerateTestKeys().ToArray(); + + protected override KeyDescription[] GenerateTestKeys() => s_keys; + protected override bool SupportsSha2 => DSAFactory.SupportsFips186_3; + protected override string HashParameterName => "rgbHash"; + protected override string SignatureParameterName => "rgbSignature"; + + private static KeyDescription CreateKey(int keySize) + { + DSA dsa = DSAFactory.Create(keySize); + int fieldSize; + + if (keySize <= 1024) + { + fieldSize = 160; + } + else if (keySize == 3072) + { + fieldSize = 256; + } + else + { + fieldSize = dsa.ExportParameters(false).Q.Length * 8; + } + + return new KeyDescription( + dsa, + $"{keySize}-bit random key", + fieldSize); + } + + private static KeyDescription OpenKey(in DSAParameters dsaParameters) + { + return new KeyDescription( + DSAFactory.Create(dsaParameters), + $"{dsaParameters.Y.Length * 8}-bit static key", + dsaParameters.Q.Length * 8); + } + + private static IEnumerable LocalGenerateTestKeys() + { + if (DSAFactory.SupportsKeyGeneration) + { + yield return CreateKey(1024); + + if (DSAFactory.SupportsFips186_3) + { + yield return CreateKey(2048); + } + } + + if (DSAFactory.SupportsFips186_3) + { + yield return OpenKey(DSATestData.GetDSA2048Params()); + } + + yield return OpenKey(DSATestData.GetDSA1024Params()); + } + } + + public sealed class DsaArraySignatureFormatTests : DSASignatureFormatTests + { + protected override bool IsArrayBased => true; + + protected override byte[] SignHash( + KeyDescription key, + byte[] hash, + DSASignatureFormat signatureFormat) + { + return ((DSA)key.Key).CreateSignature(hash, signatureFormat); + } + + protected override bool VerifyHash( + KeyDescription key, + byte[] hash, + byte[] signature, + DSASignatureFormat signatureFormat) + { + return ((DSA)key.Key).VerifySignature(hash, signature, signatureFormat); + } + + protected override byte[] SignData( + KeyDescription key, + byte[] data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + return ((DSA)key.Key).SignData(data, hashAlgorithm, signatureFormat); + } + + protected override bool VerifyData( + KeyDescription key, + byte[] data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + return ((DSA)key.Key).VerifyData(data, signature, hashAlgorithm, signatureFormat); + } + } + + public sealed class DsaArrayOffsetSignatureFormatTests : DSASignatureFormatTests + { + protected override bool IsArrayBased => true; + + protected override byte[] SignHash( + KeyDescription key, + byte[] hash, + DSASignatureFormat signatureFormat) + { + return ((DSA)key.Key).CreateSignature(hash, signatureFormat); + } + + protected override bool VerifyHash( + KeyDescription key, + byte[] hash, + byte[] signature, + DSASignatureFormat signatureFormat) + { + return ((DSA)key.Key).VerifySignature(hash, signature, signatureFormat); + } + + protected override byte[] SignData( + KeyDescription key, + byte[] data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + int offset = 0; + int count = 0; + + if (data != null) + { + offset = 2; + count = data.Length; + byte[] bigger = new byte[count + 7]; + Buffer.BlockCopy(data, 0, bigger, offset, count); + data = bigger; + } + + return ((DSA)key.Key).SignData(data, offset, count, hashAlgorithm, signatureFormat); + } + + protected override bool VerifyData( + KeyDescription key, + byte[] data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + int offset = 0; + int count = 0; + + if (data != null) + { + offset = 2; + count = data.Length; + byte[] bigger = new byte[count + 7]; + Buffer.BlockCopy(data, 0, bigger, offset, count); + data = bigger; + } + + return ((DSA)key.Key).VerifyData(data, offset, count, signature, hashAlgorithm, signatureFormat); + } + + [Fact] + public void OffsetAndCountOutOfRange() + { + KeyDescription keyDescription = GetKey(); + DSA key = (DSA)keyDescription.Key; + + HashAlgorithmName hash = HashAlgorithmName.SHA1; + byte[] buffer = new byte[10]; + + foreach (DSASignatureFormat format in Enum.GetValues(typeof(DSASignatureFormat))) + { + AssertExtensions.Throws( + "offset", + () => key.SignData(buffer, -1, buffer.Length, hash, format)); + + AssertExtensions.Throws( + "offset", + () => key.SignData(buffer, buffer.Length + 1, 0, hash, format)); + + AssertExtensions.Throws( + "offset", + () => key.VerifyData(buffer, -1, buffer.Length, buffer, hash, format)); + + AssertExtensions.Throws( + "offset", + () => key.VerifyData(buffer, buffer.Length + 1, 0, buffer, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.SignData(buffer, 1, buffer.Length, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.SignData(buffer, 0, buffer.Length + 1, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.SignData(buffer, buffer.Length, 1, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.VerifyData(buffer, 1, buffer.Length, buffer, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.VerifyData(buffer, 0, buffer.Length + 1, buffer, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.VerifyData(buffer, buffer.Length, 1, buffer, hash, format)); + } + } + } + + public sealed class DsaSpanSignatureFormatTests : DSASignatureFormatTests + { + protected override bool IsArrayBased => false; + + protected override byte[] SignHash( + KeyDescription key, + byte[] hash, + DSASignatureFormat signatureFormat) + { + DSA dsa = (DSA)key.Key; + byte[] predictedMax = new byte[dsa.GetMaxSignatureSize(signatureFormat)]; + + Assert.True( + dsa.TryCreateSignature(hash, predictedMax, signatureFormat, out int written), + "TryCreateSignature with a GetMaxSignatureSize buffer"); + + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) + { + // GetMaxSignatureSize should be exactly accurate for P1363. + Assert.Equal(predictedMax.Length, written); + } + + if (written == predictedMax.Length) + { + return predictedMax; + } + + return predictedMax.AsSpan(0, written).ToArray(); + } + + protected override bool VerifyHash( + KeyDescription key, + byte[] hash, + byte[] signature, + DSASignatureFormat signatureFormat) + { + ReadOnlySpan readOnlyHash = hash; + ReadOnlySpan readOnlySignature = signature; + return ((DSA)key.Key).VerifySignature(readOnlyHash, readOnlySignature, signatureFormat); + } + + protected override byte[] SignData( + KeyDescription key, + byte[] data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + DSA dsa = (DSA)key.Key; + byte[] predictedMax = new byte[dsa.GetMaxSignatureSize(signatureFormat)]; + + Assert.True( + dsa.TrySignData(data, predictedMax, hashAlgorithm, signatureFormat, out int written), + "TrySignData with a GetMaxSignatureSize buffer"); + + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) + { + // GetMaxSignatureSize should be exactly accurate for P1363. + Assert.Equal(predictedMax.Length, written); + } + + if (written == predictedMax.Length) + { + return predictedMax; + } + + return predictedMax.AsSpan(0, written).ToArray(); + } + + protected override bool VerifyData( + KeyDescription key, + byte[] data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + ReadOnlySpan readOnlyData = data; + ReadOnlySpan readOnlySignature = signature; + + return ((DSA)key.Key).VerifyData(readOnlyData, readOnlySignature, hashAlgorithm, signatureFormat); + } + + private static int GetExpectedSize(int fieldSizeInBits) + { + // Assuming FieldSizeInBits is byte-aligned, the odds of a padding byte being required is 50%. + // Two 50% things means that we expect one of them and not the other (on average). + // They only shrink a byte in 1/256, but gain it back 50% of the time, so they shrink in 1/512. + // That's low enough it isn't expected. + // So we expect each of (r) and (s) to be (fieldSizeInBits / 8) + 0.5, then add structure. + // Because DSA is limited to small field sizes (256 bit), the structure overhead is always 6 bytes. + // So, fieldSizeInBits / 4 + return fieldSizeInBits / 4 + 7; + } + + [Fact] + public void Rfc23279TrySignHashUnderMax() + { + KeyDescription keyDescription = GetKey(); + const int RetryCount = 10; + DSA key = (DSA)keyDescription.Key; + + const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; + byte[] hash = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + int expectedSize = GetExpectedSize(keyDescription.FieldSizeInBits); + int maxSize = key.GetMaxSignatureSize(DSASignatureFormat.Rfc3279DerSequence); + Assert.True(expectedSize < maxSize, "expectedSize < maxSize"); + byte[] signature = new byte[expectedSize]; + + for (int i = 0; i < RetryCount; i++) + { + if (key.TryCreateSignature(hash, signature, SignatureFormat, out int written)) + { + return; + } + + Assert.Equal(0, written); + } + + Assert.True(false, $"TryCreateSignature eventually succeeds with a {expectedSize}/{maxSize}-byte destination"); + } + + [Fact] + public void Rfc23279TrySignDataUnderMax() + { + KeyDescription keyDescription = GetKey(); + DSA key = (DSA)keyDescription.Key; + + const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; + const int RetryCount = 10; + HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; + + int expectedSize = GetExpectedSize(keyDescription.FieldSizeInBits); + int maxSize = key.GetMaxSignatureSize(DSASignatureFormat.Rfc3279DerSequence); + Assert.True(expectedSize < maxSize, "expectedSize < maxSize"); + byte[] signature = new byte[expectedSize]; + + for (int i = 0; i < RetryCount; i++) + { + if (key.TrySignData(Array.Empty(), signature, hashAlgorithm, SignatureFormat, out int written)) + { + return; + } + + Assert.Equal(0, written); + } + + Assert.True(false, $"TrySignData eventually succeeds with a {expectedSize}/{maxSize}-byte destination"); + } + } +} diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DsaFamilySignatureFormatTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DsaFamilySignatureFormatTests.cs new file mode 100644 index 00000000000000..d062f7e6e5871d --- /dev/null +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DSA/DsaFamilySignatureFormatTests.cs @@ -0,0 +1,403 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using Xunit; + +namespace System.Security.Cryptography.Algorithms.Tests +{ + public abstract class DsaFamilySignatureFormatTests + { + protected readonly struct KeyDescription + { + public readonly AsymmetricAlgorithm Key; + public readonly string Description; + public readonly int FieldSizeInBits; + + public KeyDescription(AsymmetricAlgorithm key, string description, int fieldSizeInBits) + { + Key = key; + Description = description; + FieldSizeInBits = fieldSizeInBits; + } + + public override string ToString() => Description; + } + + private readonly KeyDescription[] _testKeys; + private readonly byte[] _typeNameBytes; + private readonly int _typeDifferentiator; + + protected DsaFamilySignatureFormatTests() + { + _testKeys = GenerateTestKeys(); + string typeName = GetType().Name; + _typeDifferentiator = typeName.GetHashCode(); + _typeNameBytes = System.Text.Encoding.UTF8.GetBytes(typeName); + } + + public static IEnumerable SignatureFormats { get; } = + new[] + { + new object[] { DSASignatureFormat.Rfc3279DerSequence }, + new object[] { DSASignatureFormat.IeeeP1363FixedFieldConcatenation }, + }; + + protected virtual string HashParameterName => "hash"; + protected virtual string SignatureParameterName => "signature"; + protected abstract bool SupportsSha2 { get; } + protected abstract bool IsArrayBased { get; } + protected bool IsNotArrayBased => !IsArrayBased; + + protected abstract KeyDescription[] GenerateTestKeys(); + + protected abstract byte[] SignHash( + KeyDescription key, + byte[] hash, + DSASignatureFormat signatureFormat); + protected abstract bool VerifyHash( + KeyDescription key, + byte[] hash, + byte[] signature, + DSASignatureFormat signatureFormat); + protected abstract byte[] SignData( + KeyDescription key, + byte[] data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat); + protected abstract bool VerifyData( + KeyDescription key, + byte[] data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat); + + protected KeyDescription GetKey([CallerMemberName]string testMethodName = null) + { + int absoluteKeyId = Math.Abs(_typeDifferentiator + testMethodName.GetHashCode()); + int localKeyId = absoluteKeyId % _testKeys.Length; + return _testKeys[localKeyId]; + } + + protected static int GetDerLengthLength(int payloadLength) + { + if (payloadLength < 0) + throw new ArgumentOutOfRangeException(nameof(payloadLength)); + + if (payloadLength <= 0x7F) + return 0; + + if (payloadLength <= 0xFF) + return 1; + + if (payloadLength <= 0xFFFF) + return 2; + + if (payloadLength <= 0xFFFFFF) + return 3; + + return 4; + } + + private static void CheckLength(KeyDescription key, byte[] signature, DSASignatureFormat signatureFormat) + { + int fieldSizeBytes = (key.FieldSizeInBits + 7) / 8; + + switch (signatureFormat) + { + case DSASignatureFormat.IeeeP1363FixedFieldConcatenation: + + Assert.Equal(2 * fieldSizeBytes, signature.Length); + break; + case DSASignatureFormat.Rfc3279DerSequence: + { + // SEQUENCE(INTEGER, INTEGER) has a minimum length of 8 (30 06 02 01 00 02 01 00) + // The maximum length is a bit more complicated: + int elemSize = fieldSizeBytes + 1; + int integerMax = 2 + GetDerLengthLength(elemSize) + elemSize; + int integersMax = 2 * integerMax; + int sequenceMax = 2 + GetDerLengthLength(integersMax) + integersMax; + + Assert.InRange(signature.Length, 8, sequenceMax); + break; + } + default: + throw new InvalidOperationException($"No handler for format {signatureFormat}"); + } + } + + [Theory] + [MemberData(nameof(SignatureFormats))] + public void SignHashVerifyHash(DSASignatureFormat signatureFormat) + { + KeyDescription key = GetKey(); + byte[] hash = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + byte[] signature = SignHash(key, hash, signatureFormat); + CheckLength(key, signature, signatureFormat); + Assert.True(VerifyHash(key, hash, signature, signatureFormat)); + } + + [Theory] + [MemberData(nameof(SignatureFormats))] + public void SignDataVerifyData_SHA1(DSASignatureFormat signatureFormat) + { + HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; + + KeyDescription key = GetKey(); + byte[] signature = SignData(key, _typeNameBytes, hashAlgorithm, signatureFormat); + CheckLength(key, signature, signatureFormat); + Assert.True(VerifyData(key, _typeNameBytes, signature, hashAlgorithm, signatureFormat)); + } + + [Theory] + [MemberData(nameof(SignatureFormats))] + public void SignDataVerifyHash_SHA1(DSASignatureFormat signatureFormat) + { + HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; + + KeyDescription key = GetKey(); + byte[] signature = SignData(key, _typeNameBytes, hashAlgorithm, signatureFormat); + CheckLength(key, signature, signatureFormat); + + using (IncrementalHash hash = IncrementalHash.CreateHash(hashAlgorithm)) + { + hash.AppendData(_typeNameBytes); + Assert.True(VerifyHash(key, hash.GetHashAndReset(), signature, signatureFormat)); + } + } + + [Theory] + [MemberData(nameof(SignatureFormats))] + public void SignDataVerifyData_SHA256(DSASignatureFormat signatureFormat) + { + if (!SupportsSha2) + return; + + HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA256; + + KeyDescription key = GetKey(); + byte[] signature = SignData(key, _typeNameBytes, hashAlgorithm, signatureFormat); + CheckLength(key, signature, signatureFormat); + Assert.True(VerifyData(key, _typeNameBytes, signature, hashAlgorithm, signatureFormat)); + } + + [Theory] + [MemberData(nameof(SignatureFormats))] + public void SignDataVerifyHash_SHA256(DSASignatureFormat signatureFormat) + { + if (!SupportsSha2) + return; + + HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA256; + + KeyDescription key = GetKey(); + byte[] signature = SignData(key, _typeNameBytes, hashAlgorithm, signatureFormat); + CheckLength(key, signature, signatureFormat); + + using (IncrementalHash hash = IncrementalHash.CreateHash(hashAlgorithm)) + { + hash.AppendData(_typeNameBytes); + Assert.True(VerifyHash(key, hash.GetHashAndReset(), signature, signatureFormat)); + } + } + + [Fact] + public void VerifyInvalidRfc3279Signature() + { + KeyDescription key = GetKey(); + // This is SEQUENCE(INTEGER(1), INTEGER(0)), except the second integer uses + // a length value that exceeds the payload length. + // This ensures that we don't throw exceptions after finding out the leading bytes + // are valid sequence for the payload length. + byte[] invalidSignature = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00 }; + + Assert.False( + VerifyData( + key, + _typeNameBytes, + invalidSignature, + HashAlgorithmName.SHA1, + DSASignatureFormat.Rfc3279DerSequence), + "VerifyData with an illegal DER payload"); + + Assert.False( + VerifyHash( + key, + _typeNameBytes, + invalidSignature, + DSASignatureFormat.Rfc3279DerSequence), + "VerifyHash with an illegal DER payload"); + } + + [Fact] + public void Rfc3279SignatureValidatesLength() + { + KeyDescription key = GetKey(); + HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; + const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; + + byte[] hash = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + byte[] signature = SignHash(key, hash, SignatureFormat); + byte[] rightPadded = signature.Concat(Enumerable.Repeat((byte)0, 4)).ToArray(); + + Assert.True( + VerifyHash(key, hash, signature, SignatureFormat), + "VerifyHash with the unmodified signature"); + + Assert.False( + VerifyHash(key, hash, rightPadded, SignatureFormat), + "VerifyHash with the right-padded signature"); + + signature = SignData(key, hash, hashAlgorithm, SignatureFormat); + rightPadded = signature.Concat(Enumerable.Repeat((byte)0, 4)).ToArray(); + + Assert.True( + VerifyData(key, hash, signature, hashAlgorithm, SignatureFormat), + "VerifyData with the unmodified signature"); + + Assert.False( + VerifyData(key, hash, rightPadded, hashAlgorithm, SignatureFormat), + "VerifyData with the right-padded signature"); + } + + [Theory] + [InlineData(DSASignatureFormat.IeeeP1363FixedFieldConcatenation, DSASignatureFormat.Rfc3279DerSequence)] + [InlineData(DSASignatureFormat.Rfc3279DerSequence, DSASignatureFormat.IeeeP1363FixedFieldConcatenation)] + public void SignatureFormatsAreNotCompatible(DSASignatureFormat signFormat, DSASignatureFormat verifyFormat) + { + if (!SupportsSha2) + return; + + HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; + const int RetryCount = 10; + + KeyDescription key = GetKey(); + byte[] hash; + + using (IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithm)) + { + hasher.AppendData(_typeNameBytes); + hash = hasher.GetHashAndReset(); + } + + for (int i = 0; i < RetryCount; i++) + { + byte[] signature = SignData( + key, + _typeNameBytes, + hashAlgorithm, + signFormat); + + if (!VerifyData(key, _typeNameBytes, signature, hashAlgorithm, verifyFormat)) + { + Assert.False( + VerifyHash(key, hash, signature, verifyFormat), + $"VerifyHash({verifyFormat}) verifies after VerifyData({verifyFormat}) fails"); + + return; + } + } + + Assert.False(true, $"{RetryCount} {signFormat} signatures verified as {verifyFormat} signatures"); + } + + [Fact] + public void BadSignatureFormat() + { + KeyDescription key = GetKey(); + + const DSASignatureFormat SignatureFormat = (DSASignatureFormat)3; + byte[] empty = Array.Empty(); + + AssertExtensions.Throws( + "signatureFormat", + () => SignData(key, empty, HashAlgorithmName.SHA1, SignatureFormat)); + + AssertExtensions.Throws( + "signatureFormat", + () => VerifyData(key, empty, empty, HashAlgorithmName.SHA1, SignatureFormat)); + + AssertExtensions.Throws( + "signatureFormat", + () => SignHash(key, empty, SignatureFormat)); + + AssertExtensions.Throws( + "signatureFormat", + () => VerifyHash(key, empty, empty, SignatureFormat)); + } + + [Fact] + public void EmptyHashAlgorithm() + { + KeyDescription key = GetKey(); + byte[] empty = Array.Empty(); + + foreach (DSASignatureFormat format in Enum.GetValues(typeof(DSASignatureFormat))) + { + AssertExtensions.Throws( + "hashAlgorithm", + () => SignData(key, empty, default, format)); + + AssertExtensions.Throws( + "hashAlgorithm", + () => VerifyData(key, empty, empty, default, format)); + } + } + + [Fact] + public void UnknownHashAlgorithm() + { + KeyDescription key = GetKey(); + byte[] empty = Array.Empty(); + HashAlgorithmName unknown = new HashAlgorithmName(nameof(UnknownHashAlgorithm)); + + foreach (DSASignatureFormat format in Enum.GetValues(typeof(DSASignatureFormat))) + { + Assert.ThrowsAny( + () => SignData(key, empty, unknown, format)); + + Assert.ThrowsAny( + () => VerifyData(key, empty, empty, unknown, format)); + } + } + + [Fact] + public void NullInputs() + { + if (IsNotArrayBased) + return; + + KeyDescription key = GetKey(); + + foreach (DSASignatureFormat format in Enum.GetValues(typeof(DSASignatureFormat))) + { + AssertExtensions.Throws( + "data", + () => SignData(key, null, HashAlgorithmName.SHA1, format)); + + AssertExtensions.Throws( + "data", + () => VerifyData(key, null, Array.Empty(), HashAlgorithmName.SHA1, format)); + + AssertExtensions.Throws( + "signature", + () => VerifyData(key, Array.Empty(), null, HashAlgorithmName.SHA1, format)); + + AssertExtensions.Throws( + HashParameterName, + () => SignHash(key, null, format)); + + AssertExtensions.Throws( + HashParameterName, + () => VerifyHash(key, null, Array.Empty(), format)); + + AssertExtensions.Throws( + SignatureParameterName, + () => VerifyHash(key, Array.Empty(), null, format)); + } + } + } +} diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaSignatureFormatTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaSignatureFormatTests.cs new file mode 100644 index 00000000000000..5451458f117a89 --- /dev/null +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaSignatureFormatTests.cs @@ -0,0 +1,383 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.Algorithms.Tests; +using System.Security.Cryptography.Tests; +using Xunit; + +namespace System.Security.Cryptography.EcDsa.Tests +{ + public abstract class ECDsaSignatureFormatTests : DsaFamilySignatureFormatTests + { + private static readonly KeyDescription[] s_keys = LocalGenerateTestKeys().ToArray(); + + protected override KeyDescription[] GenerateTestKeys() => s_keys; + protected override bool SupportsSha2 => true; + + private static KeyDescription CreateKey(ECCurve curve) + { + ECDsa dsa = ECDsaFactory.Create(curve); + + return new KeyDescription( + dsa, + $"{dsa.KeySize}-bit random key", + dsa.KeySize); + } + + private static KeyDescription OpenKey(in ECParameters ecParameters) + { + ECDsa dsa = ECDsaFactory.Create(); + dsa.ImportParameters(ecParameters); + + return new KeyDescription( + dsa, + $"{dsa.KeySize}-bit static key", + dsa.KeySize); + } + + private static IEnumerable LocalGenerateTestKeys() + { + if (ECDsaFactory.IsCurveValid(EccTestData.BrainpoolP160r1Key1.Curve.Oid)) + { + yield return OpenKey(EccTestData.BrainpoolP160r1Key1); + } + + yield return CreateKey(ECCurve.NamedCurves.nistP384); + + yield return OpenKey(EccTestData.GetNistP521DiminishedCoordsParameters()); + + if (ECDsaFactory.ExplicitCurvesSupported) + { + yield return OpenKey(EccTestData.GetNistP256ReferenceKeyExplicit()); + } + } + } + + public sealed class ECDsaArraySignatureFormatTests : ECDsaSignatureFormatTests + { + protected override bool IsArrayBased => true; + + protected override byte[] SignHash( + KeyDescription key, + byte[] hash, + DSASignatureFormat signatureFormat) + { + return ((ECDsa)key.Key).SignHash(hash, signatureFormat); + } + + protected override bool VerifyHash( + KeyDescription key, + byte[] hash, + byte[] signature, + DSASignatureFormat signatureFormat) + { + return ((ECDsa)key.Key).VerifyHash(hash, signature, signatureFormat); + } + + protected override byte[] SignData( + KeyDescription key, + byte[] data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + return ((ECDsa)key.Key).SignData(data, hashAlgorithm, signatureFormat); + } + + protected override bool VerifyData( + KeyDescription key, + byte[] data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + return ((ECDsa)key.Key).VerifyData(data, signature, hashAlgorithm, signatureFormat); + } + } + + public sealed class ECDsaArrayOffsetSignatureFormatTests : ECDsaSignatureFormatTests + { + protected override bool IsArrayBased => true; + + protected override byte[] SignHash( + KeyDescription key, + byte[] hash, + DSASignatureFormat signatureFormat) + { + return ((ECDsa)key.Key).SignHash(hash, signatureFormat); + } + + protected override bool VerifyHash( + KeyDescription key, + byte[] hash, + byte[] signature, + DSASignatureFormat signatureFormat) + { + return ((ECDsa)key.Key).VerifyHash(hash, signature, signatureFormat); + } + + protected override byte[] SignData( + KeyDescription key, + byte[] data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + int offset = 0; + int count = 0; + + if (data != null) + { + offset = 2; + count = data.Length; + byte[] bigger = new byte[count + 7]; + Buffer.BlockCopy(data, 0, bigger, offset, count); + data = bigger; + } + + return ((ECDsa)key.Key).SignData(data, offset, count, hashAlgorithm, signatureFormat); + } + + protected override bool VerifyData( + KeyDescription key, + byte[] data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + int offset = 0; + int count = 0; + + if (data != null) + { + offset = 2; + count = data.Length; + byte[] bigger = new byte[count + 7]; + Buffer.BlockCopy(data, 0, bigger, offset, count); + data = bigger; + } + + return ((ECDsa)key.Key).VerifyData(data, offset, count, signature, hashAlgorithm, signatureFormat); + } + + [Fact] + public void OffsetAndCountOutOfRange() + { + KeyDescription keyDescription = GetKey(); + ECDsa key = (ECDsa)keyDescription.Key; + + HashAlgorithmName hash = HashAlgorithmName.SHA256; + byte[] buffer = new byte[10]; + + foreach (DSASignatureFormat format in Enum.GetValues(typeof(DSASignatureFormat))) + { + AssertExtensions.Throws( + "offset", + () => key.SignData(buffer, -1, buffer.Length, hash, format)); + + AssertExtensions.Throws( + "offset", + () => key.SignData(buffer, buffer.Length + 1, 0, hash, format)); + + AssertExtensions.Throws( + "offset", + () => key.VerifyData(buffer, -1, buffer.Length, buffer, hash, format)); + + AssertExtensions.Throws( + "offset", + () => key.VerifyData(buffer, buffer.Length + 1, 0, buffer, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.SignData(buffer, 1, buffer.Length, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.SignData(buffer, 0, buffer.Length + 1, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.SignData(buffer, buffer.Length, 1, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.VerifyData(buffer, 1, buffer.Length, buffer, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.VerifyData(buffer, 0, buffer.Length + 1, buffer, hash, format)); + + AssertExtensions.Throws( + "count", + () => key.VerifyData(buffer, buffer.Length, 1, buffer, hash, format)); + } + } + } + + public sealed class ECDsaSpanSignatureFormatTests : ECDsaSignatureFormatTests + { + protected override bool IsArrayBased => false; + + protected override byte[] SignHash( + KeyDescription key, + byte[] hash, + DSASignatureFormat signatureFormat) + { + ECDsa dsa = (ECDsa)key.Key; + byte[] predictedMax = new byte[dsa.GetMaxSignatureSize(signatureFormat)]; + + Assert.True( + dsa.TrySignHash(hash, predictedMax, signatureFormat, out int written), + "TrySignHash with a GetMaxSignatureSize buffer"); + + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) + { + // GetMaxSignatureSize should be exactly accurate for P1363. + Assert.Equal(predictedMax.Length, written); + } + + if (written == predictedMax.Length) + { + return predictedMax; + } + + return predictedMax.AsSpan(0, written).ToArray(); + } + + protected override bool VerifyHash( + KeyDescription key, + byte[] hash, + byte[] signature, + DSASignatureFormat signatureFormat) + { + ReadOnlySpan readOnlyHash = hash; + ReadOnlySpan readOnlySignature = signature; + return ((ECDsa)key.Key).VerifyHash(readOnlyHash, readOnlySignature, signatureFormat); + } + + protected override byte[] SignData( + KeyDescription key, + byte[] data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + ECDsa dsa = (ECDsa)key.Key; + byte[] predictedMax = new byte[dsa.GetMaxSignatureSize(signatureFormat)]; + + Assert.True( + dsa.TrySignData(data, predictedMax, hashAlgorithm, signatureFormat, out int written), + "TrySignData with a GetMaxSignatureSize buffer"); + + if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) + { + // GetMaxSignatureSize should be exactly accurate for P1363. + Assert.Equal(predictedMax.Length, written); + } + + if (written == predictedMax.Length) + { + return predictedMax; + } + + return predictedMax.AsSpan(0, written).ToArray(); + } + + protected override bool VerifyData( + KeyDescription key, + byte[] data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + ReadOnlySpan readOnlyData = data; + ReadOnlySpan readOnlySignature = signature; + + return ((ECDsa)key.Key).VerifyData(readOnlyData, readOnlySignature, hashAlgorithm, signatureFormat); + } + + private static int GetExpectedSize(int fieldSizeInBits) + { + // In ECDSA field sizes aren't always byte-aligned (e.g. secp521r1). + int fullBytes = Math.DivRem(fieldSizeInBits, 8, out int spareBits) + 1; + int wiggle = 0; + + if (spareBits == 1) + { + // If there's only one spare bit (e.g. 521r1), we have a 50% chance to + // drop a byte (then a 50% chance to gain it back), predict a byte loss. + wiggle = -1; + } + else if (spareBits == 0) + { + // If we're byte aligned, then if the high bit is set (~50%) we gain a padding + // byte, so predict a byte gain. + wiggle = 1; + + // Also, as byte aligned, reduce the +1 from the original calculation + fullBytes--; + } + + int field1 = 2 + GetDerLengthLength(fullBytes) + fullBytes; + int field2 = 2 + GetDerLengthLength(fullBytes + wiggle) + fullBytes + wiggle; + int payload = field1 + field2; + return 2 + GetDerLengthLength(payload) + payload; + } + + [Fact] + public void Rfc23279TrySignHashUnderMax() + { + KeyDescription keyDescription = GetKey(); + ECDsa key = (ECDsa)keyDescription.Key; + + const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; + const int RetryCount = 10; + byte[] hash = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + int expectedSize = GetExpectedSize(keyDescription.FieldSizeInBits); + int maxSize = key.GetMaxSignatureSize(DSASignatureFormat.Rfc3279DerSequence); + Assert.True(expectedSize < maxSize, "expectedSize < maxSize"); + byte[] signature = new byte[expectedSize]; + + for (int i = 0; i < RetryCount; i++) + { + if (key.TrySignHash(hash, signature, SignatureFormat, out int written)) + { + return; + } + + Assert.Equal(0, written); + } + + Assert.True(false, $"TrySignHash eventually succeeds with a {expectedSize}/{maxSize}-byte destination"); + } + + [Fact] + public void Rfc23279TrySignDataUnderMax() + { + KeyDescription keyDescription = GetKey(); + ECDsa key = (ECDsa)keyDescription.Key; + + const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; + const int RetryCount = 10; + HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; + + int expectedSize = GetExpectedSize(keyDescription.FieldSizeInBits); + int maxSize = key.GetMaxSignatureSize(DSASignatureFormat.Rfc3279DerSequence); + Assert.True(expectedSize < maxSize, "expectedSize < maxSize"); + byte[] signature = new byte[expectedSize]; + + for (int i = 0; i < RetryCount; i++) + { + if (key.TrySignData(Array.Empty(), signature, hashAlgorithm, SignatureFormat, out int written)) + { + return; + } + + Assert.Equal(0, written); + } + + Assert.True(false, $"TrySignData eventually succeeds with a {expectedSize}/{maxSize}-byte destination"); + } + } +} diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index e7d659d3141aec..dc7b886d9523a2 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -5,21 +5,40 @@ + + + + + + + + + + + + - - + + + + + + + + MicrosoftAspNetCore true - $(NoWarn);SA1129;SA1028;SA1027;SA1121;CA1200;SA1000;CA1507;CA1802;CA1825 - + $(NoWarn);SA1129;SA1028;SA1027;SA1121;CA1200;SA1000;CA1507;CA1802;CA1825;CA1018;SA1648;CA2007;SA1001;SA1026 + $(NoWarn);CS0618 + $(RepoRoot)artifacts\toolset\Common\ diff --git a/src/libraries/Microsoft.Extensions.Caching.Abstractions/pkg/Microsoft.Extensions.Caching.Abstractions.pkgproj b/src/libraries/Microsoft.Extensions.Caching.Abstractions/pkg/Microsoft.Extensions.Caching.Abstractions.pkgproj new file mode 100644 index 00000000000000..1b13b47a2bc4bf --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Caching.Abstractions/pkg/Microsoft.Extensions.Caching.Abstractions.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.netstandard2.0.cs b/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.cs similarity index 93% rename from src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.netstandard2.0.cs rename to src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.cs index 91fc1c18b67398..8e4779f1e987c2 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.netstandard2.0.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.Caching.Distributed { @@ -20,7 +23,6 @@ public DistributedCacheEntryOptions() { } public static partial class DistributedCacheExtensions { public static string GetString(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key) { throw null; } - [System.Diagnostics.DebuggerStepThroughAttribute] public static System.Threading.Tasks.Task GetStringAsync(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } public static void Set(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, byte[] value) { } public static System.Threading.Tasks.Task SetAsync(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, byte[] value, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } @@ -59,7 +61,6 @@ public static partial class CacheEntryExtensions public static partial class CacheExtensions { public static object Get(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key) { throw null; } - [System.Diagnostics.DebuggerStepThroughAttribute] public static System.Threading.Tasks.Task GetOrCreateAsync(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, System.Func> factory) { throw null; } public static TItem GetOrCreate(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, System.Func factory) { throw null; } public static TItem Get(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key) { throw null; } @@ -120,17 +121,17 @@ public partial class MemoryCacheEntryOptions public MemoryCacheEntryOptions() { } public System.DateTimeOffset? AbsoluteExpiration { get { throw null; } set { } } public System.TimeSpan? AbsoluteExpirationRelativeToNow { get { throw null; } set { } } - public System.Collections.Generic.IList ExpirationTokens { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Collections.Generic.IList PostEvictionCallbacks { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public Microsoft.Extensions.Caching.Memory.CacheItemPriority Priority { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public System.Collections.Generic.IList ExpirationTokens { get { throw null; } } + public System.Collections.Generic.IList PostEvictionCallbacks { get { throw null; } } + public Microsoft.Extensions.Caching.Memory.CacheItemPriority Priority { get { throw null; } set { } } public long? Size { get { throw null; } set { } } public System.TimeSpan? SlidingExpiration { get { throw null; } set { } } } public partial class PostEvictionCallbackRegistration { public PostEvictionCallbackRegistration() { } - public Microsoft.Extensions.Caching.Memory.PostEvictionDelegate EvictionCallback { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public object State { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public Microsoft.Extensions.Caching.Memory.PostEvictionDelegate EvictionCallback { get { throw null; } set { } } + public object State { get { throw null; } set { } } } public delegate void PostEvictionDelegate(object key, object value, Microsoft.Extensions.Caching.Memory.EvictionReason reason, object state); } diff --git a/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.csproj index 5a386d5714d4ad..ffcb96718ce0d3 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.csproj @@ -1,14 +1,9 @@ - - netstandard2.0;$(DefaultNetCoreTargetFramework) + netstandard2.0 - - - - - - - + + + diff --git a/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.netcoreapp.cs b/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.netcoreapp.cs deleted file mode 100644 index 91fc1c18b67398..00000000000000 --- a/src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.netcoreapp.cs +++ /dev/null @@ -1,148 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.Caching.Distributed -{ - public static partial class DistributedCacheEntryExtensions - { - public static Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions SetAbsoluteExpiration(this Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions options, System.DateTimeOffset absolute) { throw null; } - public static Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions SetAbsoluteExpiration(this Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions options, System.TimeSpan relative) { throw null; } - public static Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions SetSlidingExpiration(this Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions options, System.TimeSpan offset) { throw null; } - } - public partial class DistributedCacheEntryOptions - { - public DistributedCacheEntryOptions() { } - public System.DateTimeOffset? AbsoluteExpiration { get { throw null; } set { } } - public System.TimeSpan? AbsoluteExpirationRelativeToNow { get { throw null; } set { } } - public System.TimeSpan? SlidingExpiration { get { throw null; } set { } } - } - public static partial class DistributedCacheExtensions - { - public static string GetString(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key) { throw null; } - [System.Diagnostics.DebuggerStepThroughAttribute] - public static System.Threading.Tasks.Task GetStringAsync(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } - public static void Set(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, byte[] value) { } - public static System.Threading.Tasks.Task SetAsync(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, byte[] value, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } - public static void SetString(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, string value) { } - public static void SetString(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, string value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions options) { } - public static System.Threading.Tasks.Task SetStringAsync(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, string value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions options, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } - public static System.Threading.Tasks.Task SetStringAsync(this Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, string key, string value, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } - } - public partial interface IDistributedCache - { - byte[] Get(string key); - System.Threading.Tasks.Task GetAsync(string key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)); - void Refresh(string key); - System.Threading.Tasks.Task RefreshAsync(string key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)); - void Remove(string key); - System.Threading.Tasks.Task RemoveAsync(string key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)); - void Set(string key, byte[] value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions options); - System.Threading.Tasks.Task SetAsync(string key, byte[] value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions options, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)); - } -} -namespace Microsoft.Extensions.Caching.Memory -{ - public static partial class CacheEntryExtensions - { - public static Microsoft.Extensions.Caching.Memory.ICacheEntry AddExpirationToken(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, Microsoft.Extensions.Primitives.IChangeToken expirationToken) { throw null; } - public static Microsoft.Extensions.Caching.Memory.ICacheEntry RegisterPostEvictionCallback(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, Microsoft.Extensions.Caching.Memory.PostEvictionDelegate callback) { throw null; } - public static Microsoft.Extensions.Caching.Memory.ICacheEntry RegisterPostEvictionCallback(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, Microsoft.Extensions.Caching.Memory.PostEvictionDelegate callback, object state) { throw null; } - public static Microsoft.Extensions.Caching.Memory.ICacheEntry SetAbsoluteExpiration(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, System.DateTimeOffset absolute) { throw null; } - public static Microsoft.Extensions.Caching.Memory.ICacheEntry SetAbsoluteExpiration(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, System.TimeSpan relative) { throw null; } - public static Microsoft.Extensions.Caching.Memory.ICacheEntry SetOptions(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options) { throw null; } - public static Microsoft.Extensions.Caching.Memory.ICacheEntry SetPriority(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, Microsoft.Extensions.Caching.Memory.CacheItemPriority priority) { throw null; } - public static Microsoft.Extensions.Caching.Memory.ICacheEntry SetSize(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, long size) { throw null; } - public static Microsoft.Extensions.Caching.Memory.ICacheEntry SetSlidingExpiration(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, System.TimeSpan offset) { throw null; } - public static Microsoft.Extensions.Caching.Memory.ICacheEntry SetValue(this Microsoft.Extensions.Caching.Memory.ICacheEntry entry, object value) { throw null; } - } - public static partial class CacheExtensions - { - public static object Get(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key) { throw null; } - [System.Diagnostics.DebuggerStepThroughAttribute] - public static System.Threading.Tasks.Task GetOrCreateAsync(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, System.Func> factory) { throw null; } - public static TItem GetOrCreate(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, System.Func factory) { throw null; } - public static TItem Get(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key) { throw null; } - public static TItem Set(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, TItem value) { throw null; } - public static TItem Set(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, TItem value, Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options) { throw null; } - public static TItem Set(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, TItem value, Microsoft.Extensions.Primitives.IChangeToken expirationToken) { throw null; } - public static TItem Set(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, TItem value, System.DateTimeOffset absoluteExpiration) { throw null; } - public static TItem Set(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, TItem value, System.TimeSpan absoluteExpirationRelativeToNow) { throw null; } - public static bool TryGetValue(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, out TItem value) { throw null; } - } - public enum CacheItemPriority - { - Low = 0, - Normal = 1, - High = 2, - NeverRemove = 3, - } - public enum EvictionReason - { - None = 0, - Removed = 1, - Replaced = 2, - Expired = 3, - TokenExpired = 4, - Capacity = 5, - } - public partial interface ICacheEntry : System.IDisposable - { - System.DateTimeOffset? AbsoluteExpiration { get; set; } - System.TimeSpan? AbsoluteExpirationRelativeToNow { get; set; } - System.Collections.Generic.IList ExpirationTokens { get; } - object Key { get; } - System.Collections.Generic.IList PostEvictionCallbacks { get; } - Microsoft.Extensions.Caching.Memory.CacheItemPriority Priority { get; set; } - long? Size { get; set; } - System.TimeSpan? SlidingExpiration { get; set; } - object Value { get; set; } - } - public partial interface IMemoryCache : System.IDisposable - { - Microsoft.Extensions.Caching.Memory.ICacheEntry CreateEntry(object key); - void Remove(object key); - bool TryGetValue(object key, out object value); - } - public static partial class MemoryCacheEntryExtensions - { - public static Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions AddExpirationToken(this Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options, Microsoft.Extensions.Primitives.IChangeToken expirationToken) { throw null; } - public static Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions RegisterPostEvictionCallback(this Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options, Microsoft.Extensions.Caching.Memory.PostEvictionDelegate callback) { throw null; } - public static Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions RegisterPostEvictionCallback(this Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options, Microsoft.Extensions.Caching.Memory.PostEvictionDelegate callback, object state) { throw null; } - public static Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions SetAbsoluteExpiration(this Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options, System.DateTimeOffset absolute) { throw null; } - public static Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions SetAbsoluteExpiration(this Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options, System.TimeSpan relative) { throw null; } - public static Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions SetPriority(this Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options, Microsoft.Extensions.Caching.Memory.CacheItemPriority priority) { throw null; } - public static Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions SetSize(this Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options, long size) { throw null; } - public static Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions SetSlidingExpiration(this Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions options, System.TimeSpan offset) { throw null; } - } - public partial class MemoryCacheEntryOptions - { - public MemoryCacheEntryOptions() { } - public System.DateTimeOffset? AbsoluteExpiration { get { throw null; } set { } } - public System.TimeSpan? AbsoluteExpirationRelativeToNow { get { throw null; } set { } } - public System.Collections.Generic.IList ExpirationTokens { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Collections.Generic.IList PostEvictionCallbacks { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public Microsoft.Extensions.Caching.Memory.CacheItemPriority Priority { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public long? Size { get { throw null; } set { } } - public System.TimeSpan? SlidingExpiration { get { throw null; } set { } } - } - public partial class PostEvictionCallbackRegistration - { - public PostEvictionCallbackRegistration() { } - public Microsoft.Extensions.Caching.Memory.PostEvictionDelegate EvictionCallback { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public object State { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - } - public delegate void PostEvictionDelegate(object key, object value, Microsoft.Extensions.Caching.Memory.EvictionReason reason, object state); -} -namespace Microsoft.Extensions.Internal -{ - public partial interface ISystemClock - { - System.DateTimeOffset UtcNow { get; } - } - public partial class SystemClock : Microsoft.Extensions.Internal.ISystemClock - { - public SystemClock() { } - public System.DateTimeOffset UtcNow { get { throw null; } } - } -} diff --git a/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Microsoft.Extensions.Caching.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Microsoft.Extensions.Caching.Abstractions.csproj index 8e9ffd7ea338ff..9633abd2b4f74a 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Microsoft.Extensions.Caching.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Microsoft.Extensions.Caching.Abstractions.csproj @@ -1,22 +1,13 @@  - Caching abstractions for in-memory cache and distributed cache. -Commonly used types: -Microsoft.Extensions.Caching.Distributed.IDistributedCache -Microsoft.Extensions.Caching.Memory.IMemoryCache - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0 $(NoWarn);CS1591 - true - cache;memorycache;distributedcache - true - true + true - diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.netcoreapp.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.netcoreapp.cs rename to src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.cs diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.csproj b/src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.csproj index ea36e245c17e13..e971c59c800809 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.csproj +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.csproj @@ -1,20 +1,13 @@ - netstandard2.0;$(DefaultNetCoreTargetFramework) + netstandard2.0 - - - - - - - - - - - - - + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.netstandard2.0.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.netstandard2.0.cs deleted file mode 100644 index a1d47175fb2943..00000000000000 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.netstandard2.0.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.Caching.Distributed -{ - public partial class MemoryDistributedCache : Microsoft.Extensions.Caching.Distributed.IDistributedCache - { - public MemoryDistributedCache(Microsoft.Extensions.Options.IOptions optionsAccessor) { } - public MemoryDistributedCache(Microsoft.Extensions.Options.IOptions optionsAccessor, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { } - public byte[] Get(string key) { throw null; } - public System.Threading.Tasks.Task GetAsync(string key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } - public void Refresh(string key) { } - public System.Threading.Tasks.Task RefreshAsync(string key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } - public void Remove(string key) { } - public System.Threading.Tasks.Task RemoveAsync(string key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } - public void Set(string key, byte[] value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions options) { } - public System.Threading.Tasks.Task SetAsync(string key, byte[] value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions options, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } - } -} -namespace Microsoft.Extensions.Caching.Memory -{ - public partial class MemoryCache : Microsoft.Extensions.Caching.Memory.IMemoryCache, System.IDisposable - { - public MemoryCache(Microsoft.Extensions.Options.IOptions optionsAccessor) { } - public MemoryCache(Microsoft.Extensions.Options.IOptions optionsAccessor, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { } - public int Count { get { throw null; } } - public void Compact(double percentage) { } - public Microsoft.Extensions.Caching.Memory.ICacheEntry CreateEntry(object key) { throw null; } - public void Dispose() { } - protected virtual void Dispose(bool disposing) { } - ~MemoryCache() { } - public void Remove(object key) { } - public bool TryGetValue(object key, out object result) { throw null; } - } - public partial class MemoryCacheOptions : Microsoft.Extensions.Options.IOptions - { - public MemoryCacheOptions() { } - public Microsoft.Extensions.Internal.ISystemClock Clock { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public double CompactionPercentage { get { throw null; } set { } } - public System.TimeSpan ExpirationScanFrequency { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - Microsoft.Extensions.Caching.Memory.MemoryCacheOptions Microsoft.Extensions.Options.IOptions.Value { get { throw null; } } - public long? SizeLimit { get { throw null; } set { } } - } - public partial class MemoryDistributedCacheOptions : Microsoft.Extensions.Caching.Memory.MemoryCacheOptions - { - public MemoryDistributedCacheOptions() { } - } -} -namespace Microsoft.Extensions.DependencyInjection -{ - public static partial class MemoryCacheServiceCollectionExtensions - { - public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddDistributedMemoryCache(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddDistributedMemoryCache(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action setupAction) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddMemoryCache(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddMemoryCache(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action setupAction) { throw null; } - } -} diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj index 9c9e871ef78b30..d3a007618f5695 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj @@ -1,20 +1,11 @@  - In-memory cache implementation of Microsoft.Extensions.Caching.Memory.IMemoryCache. - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0 $(NoWarn);CS1591 - true - cache;memorycache - true - true + true - - - - diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..8d94a5672f8464 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Caching.Memory.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/pkg/Microsoft.Extensions.Configuration.Abstractions.pkgproj b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/pkg/Microsoft.Extensions.Configuration.Abstractions.pkgproj new file mode 100644 index 00000000000000..b33b49659eb28c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/pkg/Microsoft.Extensions.Configuration.Abstractions.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/ref/Microsoft.Extensions.Configuration.Abstractions.cs b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/ref/Microsoft.Extensions.Configuration.Abstractions.cs index b488394ee9ec68..4c2c27406eddb7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/ref/Microsoft.Extensions.Configuration.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/ref/Microsoft.Extensions.Configuration.Abstractions.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.Configuration { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/ref/Microsoft.Extensions.Configuration.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/ref/Microsoft.Extensions.Configuration.Abstractions.csproj index cd753bd8abeca9..b7895cdb04d2b3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/ref/Microsoft.Extensions.Configuration.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/ref/Microsoft.Extensions.Configuration.Abstractions.csproj @@ -4,6 +4,6 @@ - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/Microsoft.Extensions.Configuration.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/Microsoft.Extensions.Configuration.Abstractions.csproj index 10641f00d8d7fb..d22e391d881975 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/Microsoft.Extensions.Configuration.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/Microsoft.Extensions.Configuration.Abstractions.csproj @@ -1,10 +1,13 @@  - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0 + + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/pkg/Microsoft.Extensions.Configuration.Binder.pkgproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/pkg/Microsoft.Extensions.Configuration.Binder.pkgproj new file mode 100644 index 00000000000000..efc73b15575b52 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/pkg/Microsoft.Extensions.Configuration.Binder.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.cs index b7061cdeb5ee79..041d0e62dfc3c0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.cs @@ -1,13 +1,16 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.Configuration { public partial class BinderOptions { public BinderOptions() { } - public bool BindNonPublicProperties { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public bool BindNonPublicProperties { get { throw null; } set { } } } public static partial class ConfigurationBinder { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.csproj index 46f4aee0bca9a9..4df616e013206b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.csproj @@ -4,6 +4,7 @@ - + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs index bbbba06ddca36b..a7bd00f188fc35 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs @@ -7,7 +7,6 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -using Microsoft.Extensions.Configuration.Binder; namespace Microsoft.Extensions.Configuration { @@ -355,14 +354,14 @@ private static object CreateInstance(Type type) if (typeInfo.IsInterface || typeInfo.IsAbstract) { - throw new InvalidOperationException(Resources.FormatError_CannotActivateAbstractOrInterface(type)); + throw new InvalidOperationException(SR.Format(SR.Error_CannotActivateAbstractOrInterface, type)); } if (type.IsArray) { if (typeInfo.GetArrayRank() > 1) { - throw new InvalidOperationException(Resources.FormatError_UnsupportedMultidimensionalArray(type)); + throw new InvalidOperationException(SR.Format(SR.Error_UnsupportedMultidimensionalArray, type)); } return Array.CreateInstance(typeInfo.GetElementType(), 0); @@ -371,7 +370,7 @@ private static object CreateInstance(Type type) var hasDefaultConstructor = typeInfo.DeclaredConstructors.Any(ctor => ctor.IsPublic && ctor.GetParameters().Length == 0); if (!hasDefaultConstructor) { - throw new InvalidOperationException(Resources.FormatError_MissingParameterlessConstructor(type)); + throw new InvalidOperationException(SR.Format(SR.Error_MissingParameterlessConstructor, type)); } try @@ -380,7 +379,7 @@ private static object CreateInstance(Type type) } catch (Exception ex) { - throw new InvalidOperationException(Resources.FormatError_FailedToActivate(type), ex); + throw new InvalidOperationException(SR.Format(SR.Error_FailedToActivate, type), ex); } } @@ -514,7 +513,7 @@ private static bool TryConvertValue(Type type, string value, string path, out ob } catch (Exception ex) { - error = new InvalidOperationException(Resources.FormatError_FailedBinding(path, type), ex); + error = new InvalidOperationException(SR.Format(SR.Error_FailedBinding, path, type), ex); } return true; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Microsoft.Extensions.Configuration.Binder.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Microsoft.Extensions.Configuration.Binder.csproj index 7e91caf6095377..2c2e03156d12b2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Microsoft.Extensions.Configuration.Binder.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Microsoft.Extensions.Configuration.Binder.csproj @@ -1,16 +1,13 @@  - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0 + true - - - - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..f1ac16c5d801a0 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Configuration.Binder.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs index 6dbff86d9ac3e7..6de2c01dd31b6c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs @@ -399,13 +399,13 @@ public void ConsistentExceptionOnFailedBinding(Type type) Assert.NotNull(exception.InnerException); Assert.NotNull(getException.InnerException); Assert.Equal( - Resources.FormatError_FailedBinding(ConfigKey, type), + SR.Format(SR.Error_FailedBinding, ConfigKey, type), exception.Message); Assert.Equal( - Resources.FormatError_FailedBinding(ConfigKey, type), + SR.Format(SR.Error_FailedBinding, ConfigKey, type), getException.Message); Assert.Equal( - Resources.FormatError_FailedBinding(ConfigKey, type), + SR.Format(SR.Error_FailedBinding, ConfigKey, type), getValueException.Message); } @@ -429,7 +429,7 @@ public void ExceptionOnFailedBindingIncludesPath() var exception = Assert.Throws( () => config.Bind(options)); - Assert.Equal(Resources.FormatError_FailedBinding(ConfigKey, typeof(int)), + Assert.Equal(SR.Format(SR.Error_FailedBinding, ConfigKey, typeof(int)), exception.Message); } @@ -728,7 +728,7 @@ public void ExceptionWhenTryingToBindToInterface() var exception = Assert.Throws( () => config.Bind(new TestOptions())); Assert.Equal( - Resources.FormatError_CannotActivateAbstractOrInterface(typeof(ISomeInterface)), + SR.Format(SR.Error_CannotActivateAbstractOrInterface, typeof(ISomeInterface)), exception.Message); } @@ -747,7 +747,7 @@ public void ExceptionWhenTryingToBindClassWithoutParameterlessConstructor() var exception = Assert.Throws( () => config.Bind(new TestOptions())); Assert.Equal( - Resources.FormatError_MissingParameterlessConstructor(typeof(ClassWithoutPublicConstructor)), + SR.Format(SR.Error_MissingParameterlessConstructor, typeof(ClassWithoutPublicConstructor)), exception.Message); } @@ -767,7 +767,7 @@ public void ExceptionWhenTryingToBindToTypeThrowsWhenActivated() () => config.Bind(new TestOptions())); Assert.NotNull(exception.InnerException); Assert.Equal( - Resources.FormatError_FailedToActivate(typeof(ThrowsWhenActivated)), + SR.Format(SR.Error_FailedToActivate, typeof(ThrowsWhenActivated)), exception.Message); } @@ -786,7 +786,7 @@ public void ExceptionIncludesKeyOfFailedBinding() var exception = Assert.Throws( () => config.Bind(new TestOptions())); Assert.Equal( - Resources.FormatError_CannotActivateAbstractOrInterface(typeof(ISomeInterface)), + SR.Format(SR.Error_CannotActivateAbstractOrInterface, typeof(ISomeInterface)), exception.Message); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs index b66baba664201d..71752590f6c48d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs @@ -810,7 +810,7 @@ public void UnsupportedMultidimensionalArrays() var exception = Assert.Throws( () => config.Bind(options)); Assert.Equal( - Resources.FormatError_UnsupportedMultidimensionalArray(typeof(string[,])), + SR.Format(SR.Error_UnsupportedMultidimensionalArray, typeof(string[,])), exception.Message); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Microsoft.Extensions.Configuration.Binder.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Microsoft.Extensions.Configuration.Binder.Tests.csproj index 5df935b970a25d..df49f6059b5017 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Microsoft.Extensions.Configuration.Binder.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Microsoft.Extensions.Configuration.Binder.Tests.csproj @@ -2,16 +2,20 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true - + + Common\ConfigurationProviderExtensions.cs + + + Common\TestStreamHelpers.cs + - - - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/pkg/Microsoft.Extensions.Configuration.CommandLine.pkgproj b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/pkg/Microsoft.Extensions.Configuration.CommandLine.pkgproj new file mode 100644 index 00000000000000..6bb24130672402 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/pkg/Microsoft.Extensions.Configuration.CommandLine.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/ref/Microsoft.Extensions.Configuration.CommandLine.cs b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/ref/Microsoft.Extensions.Configuration.CommandLine.cs index 454aad7db04000..68dca57765d12f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/ref/Microsoft.Extensions.Configuration.CommandLine.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/ref/Microsoft.Extensions.Configuration.CommandLine.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.Configuration { @@ -16,14 +19,14 @@ namespace Microsoft.Extensions.Configuration.CommandLine public partial class CommandLineConfigurationProvider : Microsoft.Extensions.Configuration.ConfigurationProvider { public CommandLineConfigurationProvider(System.Collections.Generic.IEnumerable args, System.Collections.Generic.IDictionary switchMappings = null) { } - protected System.Collections.Generic.IEnumerable Args { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + protected System.Collections.Generic.IEnumerable Args { get { throw null; } } public override void Load() { } } public partial class CommandLineConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource { public CommandLineConfigurationSource() { } - public System.Collections.Generic.IEnumerable Args { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public System.Collections.Generic.IDictionary SwitchMappings { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public System.Collections.Generic.IEnumerable Args { get { throw null; } set { } } + public System.Collections.Generic.IDictionary SwitchMappings { get { throw null; } set { } } public Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { throw null; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/ref/Microsoft.Extensions.Configuration.CommandLine.csproj b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/ref/Microsoft.Extensions.Configuration.CommandLine.csproj index bfcbf852a60129..152fd02a26577d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/ref/Microsoft.Extensions.Configuration.CommandLine.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/ref/Microsoft.Extensions.Configuration.CommandLine.csproj @@ -4,6 +4,7 @@ - + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/CommandLineConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/CommandLineConfigurationProvider.cs index 45bed3b70458de..a3cb1b9234ed9c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/CommandLineConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/CommandLineConfigurationProvider.cs @@ -113,7 +113,7 @@ public override void Load() // If the switch starts with a single "-" and it isn't in given mappings , it is an invalid usage else if (keyStartIndex == 1) { - throw new FormatException(Resources.FormatError_ShortSwitchNotDefined(currentArg)); + throw new FormatException(SR.Format(SR.Error_ShortSwitchNotDefined, currentArg)); } // Otherwise, use the switch name directly as a key else @@ -144,14 +144,14 @@ private Dictionary GetValidatedSwitchMappingsCopy(IDictionary netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + true - - - - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..6589aea16eeaaf --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Configuration.CommandLine.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/CommandLineTest.cs b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/CommandLineTest.cs index 9bd1e478f9039a..dfcdc44a5907ff 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/CommandLineTest.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/CommandLineTest.cs @@ -139,8 +139,8 @@ public void ThrowExceptionWhenPassingSwitchMappingsWithDuplicatedKeys() set.Add(mapping.Key); } - var expectedMsg = new ArgumentException(Resources. - FormatError_DuplicatedKeyInSwitchMappings(expectedDup), "switchMappings").Message; + var expectedMsg = new ArgumentException(SR. + Format(SR.Error_DuplicatedKeyInSwitchMappings, expectedDup), "switchMappings").Message; // Act var exception = Assert.Throws( @@ -167,7 +167,7 @@ public void ThrowExceptionWhenSwitchMappingsContainInvalidKey() { "--Key2", "SuperLongKey2" }, { "/Key3", "AnotherSuperLongKey3" } }; - var expectedMsg = new ArgumentException(Resources.FormatError_InvalidSwitchMapping("/Key3"), + var expectedMsg = new ArgumentException(SR.Format(SR.Error_InvalidSwitchMapping,"/Key3"), "switchMappings").Message; var exception = Assert.Throws( diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/Microsoft.Extensions.Configuration.CommandLine.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/Microsoft.Extensions.Configuration.CommandLine.Tests.csproj index aab6587e9e3f4a..4b9c4ed4aa1a43 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/Microsoft.Extensions.Configuration.CommandLine.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/Microsoft.Extensions.Configuration.CommandLine.Tests.csproj @@ -2,17 +2,23 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true - - + + Common\ConfigurationProviderTestBase.cs + + + Common\ConfigurationProviderExtensions.cs + + + Common\TestStreamHelpers.cs + - - - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/pkg/Microsoft.Extensions.Configuration.EnvironmentVariables.pkgproj b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/pkg/Microsoft.Extensions.Configuration.EnvironmentVariables.pkgproj new file mode 100644 index 00000000000000..bc1798bad6bea7 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/pkg/Microsoft.Extensions.Configuration.EnvironmentVariables.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/ref/Microsoft.Extensions.Configuration.EnvironmentVariables.cs b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/ref/Microsoft.Extensions.Configuration.EnvironmentVariables.cs index ca46a6aba06ee4..388cccc820f1f3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/ref/Microsoft.Extensions.Configuration.EnvironmentVariables.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/ref/Microsoft.Extensions.Configuration.EnvironmentVariables.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.Configuration { @@ -22,7 +25,7 @@ public override void Load() { } public partial class EnvironmentVariablesConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource { public EnvironmentVariablesConfigurationSource() { } - public string Prefix { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public string Prefix { get { throw null; } set { } } public Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { throw null; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/ref/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/ref/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj index 0073a6482919aa..2cdfea08ba7b95 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/ref/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/ref/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj @@ -4,6 +4,7 @@ - + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj index 6cf4826e8c3028..2c2e03156d12b2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj @@ -1,16 +1,13 @@  - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0 + true - - - - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..9afc9e5fc28c8c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Configuration.EnvironmentVariables.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/tests/Microsoft.Extensions.Configuration.EnvironmentVariables.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/tests/Microsoft.Extensions.Configuration.EnvironmentVariables.Tests.csproj index 827966ebedbe47..74357f4d7bec52 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/tests/Microsoft.Extensions.Configuration.EnvironmentVariables.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/tests/Microsoft.Extensions.Configuration.EnvironmentVariables.Tests.csproj @@ -2,18 +2,23 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true - - + + Common\ConfigurationProviderTestBase.cs + + + Common\ConfigurationProviderExtensions.cs + + + Common\TestStreamHelpers.cs + - - - - + - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/pkg/Microsoft.Extensions.Configuration.FileExtensions.pkgproj b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/pkg/Microsoft.Extensions.Configuration.FileExtensions.pkgproj new file mode 100644 index 00000000000000..29cbf601f3424e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/pkg/Microsoft.Extensions.Configuration.FileExtensions.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/ref/Microsoft.Extensions.Configuration.FileExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/ref/Microsoft.Extensions.Configuration.FileExtensions.cs index e32264923f583d..73515ac5be7380 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/ref/Microsoft.Extensions.Configuration.FileExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/ref/Microsoft.Extensions.Configuration.FileExtensions.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.Configuration { @@ -15,7 +18,7 @@ public static partial class FileConfigurationExtensions public abstract partial class FileConfigurationProvider : Microsoft.Extensions.Configuration.ConfigurationProvider, System.IDisposable { public FileConfigurationProvider(Microsoft.Extensions.Configuration.FileConfigurationSource source) { } - public Microsoft.Extensions.Configuration.FileConfigurationSource Source { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public Microsoft.Extensions.Configuration.FileConfigurationSource Source { get { throw null; } } public void Dispose() { } protected virtual void Dispose(bool disposing) { } public override void Load() { } @@ -25,12 +28,12 @@ public override void Load() { } public abstract partial class FileConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource { protected FileConfigurationSource() { } - public Microsoft.Extensions.FileProviders.IFileProvider FileProvider { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public System.Action OnLoadException { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public bool Optional { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public string Path { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public int ReloadDelay { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public bool ReloadOnChange { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public Microsoft.Extensions.FileProviders.IFileProvider FileProvider { get { throw null; } set { } } + public System.Action OnLoadException { get { throw null; } set { } } + public bool Optional { get { throw null; } set { } } + public string Path { get { throw null; } set { } } + public int ReloadDelay { get { throw null; } set { } } + public bool ReloadOnChange { get { throw null; } set { } } public abstract Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder); public void EnsureDefaults(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { } public void ResolveFileProvider() { } @@ -38,8 +41,8 @@ public void ResolveFileProvider() { } public partial class FileLoadExceptionContext { public FileLoadExceptionContext() { } - public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public bool Ignore { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public Microsoft.Extensions.Configuration.FileConfigurationProvider Provider { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public System.Exception Exception { get { throw null; } set { } } + public bool Ignore { get { throw null; } set { } } + public Microsoft.Extensions.Configuration.FileConfigurationProvider Provider { get { throw null; } set { } } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/ref/Microsoft.Extensions.Configuration.FileExtensions.csproj b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/ref/Microsoft.Extensions.Configuration.FileExtensions.csproj index 9aa9638f9281e5..a40874d8ed4072 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/ref/Microsoft.Extensions.Configuration.FileExtensions.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/ref/Microsoft.Extensions.Configuration.FileExtensions.csproj @@ -4,7 +4,9 @@ - - + + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Microsoft.Extensions.Configuration.FileExtensions.csproj b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Microsoft.Extensions.Configuration.FileExtensions.csproj index 04ad307caecdd4..029fecf1e5f9b0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Microsoft.Extensions.Configuration.FileExtensions.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Microsoft.Extensions.Configuration.FileExtensions.csproj @@ -1,17 +1,16 @@  - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0 + true - - - - + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..fc0a9d4517d77a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Configuration.FileExtensions.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/tests/Microsoft.Extensions.Configuration.FileExtensions.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/tests/Microsoft.Extensions.Configuration.FileExtensions.Tests.csproj index 22c2ae43185234..c7ae00f4a0549d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/tests/Microsoft.Extensions.Configuration.FileExtensions.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/tests/Microsoft.Extensions.Configuration.FileExtensions.Tests.csproj @@ -2,19 +2,17 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true - + + Microsoft.Extensions.Configuration\tests\ConfigurationRootTest.cs + - - - - - - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/pkg/Microsoft.Extensions.Configuration.Ini.pkgproj b/src/libraries/Microsoft.Extensions.Configuration.Ini/pkg/Microsoft.Extensions.Configuration.Ini.pkgproj new file mode 100644 index 00000000000000..a6f6f4b5e09584 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/pkg/Microsoft.Extensions.Configuration.Ini.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/ref/Microsoft.Extensions.Configuration.Ini.cs b/src/libraries/Microsoft.Extensions.Configuration.Ini/ref/Microsoft.Extensions.Configuration.Ini.cs index 19afb20f2a4dbe..6e1970781dc98d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/ref/Microsoft.Extensions.Configuration.Ini.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/ref/Microsoft.Extensions.Configuration.Ini.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.Configuration { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/ref/Microsoft.Extensions.Configuration.Ini.csproj b/src/libraries/Microsoft.Extensions.Configuration.Ini/ref/Microsoft.Extensions.Configuration.Ini.csproj index 1b0be6f2086f95..ea7d7410353542 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/ref/Microsoft.Extensions.Configuration.Ini.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/ref/Microsoft.Extensions.Configuration.Ini.csproj @@ -4,7 +4,9 @@ - - + + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/IniConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/IniConfigurationExtensions.cs index 1fd554ebc6c4ae..93e39ff27ac318 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/IniConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/IniConfigurationExtensions.cs @@ -71,7 +71,7 @@ public static IConfigurationBuilder AddIniFile(this IConfigurationBuilder builde } if (string.IsNullOrEmpty(path)) { - throw new ArgumentException(Resources.Error_InvalidFilePath, nameof(path)); + throw new ArgumentException(SR.Error_InvalidFilePath, nameof(path)); } return builder.AddIniFile(s => diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/IniStreamConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/IniStreamConfigurationProvider.cs index b556b14e49f55d..f748ff8b1e26fb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/IniStreamConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/IniStreamConfigurationProvider.cs @@ -58,7 +58,7 @@ public static IDictionary Read(Stream stream) int separator = line.IndexOf('='); if (separator < 0) { - throw new FormatException(Resources.FormatError_UnrecognizedLineFormat(rawLine)); + throw new FormatException(SR.Format(SR.Error_UnrecognizedLineFormat, rawLine)); } string key = sectionPrefix + line.Substring(0, separator).Trim(); @@ -72,7 +72,7 @@ public static IDictionary Read(Stream stream) if (data.ContainsKey(key)) { - throw new FormatException(Resources.FormatError_KeyIsDuplicated(key)); + throw new FormatException(SR.Format(SR.Error_KeyIsDuplicated, key)); } data[key] = value; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Microsoft.Extensions.Configuration.Ini.csproj b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Microsoft.Extensions.Configuration.Ini.csproj index a8eb8425f2ba1a..08941f9da565da 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Microsoft.Extensions.Configuration.Ini.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Microsoft.Extensions.Configuration.Ini.csproj @@ -1,17 +1,15 @@  - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0 + true - - - - + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..0c17153ae37989 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Configuration.Ini.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/IniConfigurationTest.cs b/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/IniConfigurationTest.cs index 5a6db8855de1a6..bfb25815790ae5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/IniConfigurationTest.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/IniConfigurationTest.cs @@ -168,7 +168,7 @@ public void ThrowExceptionWhenFoundInvalidLine() ConnectionString "; var iniConfigSrc = new IniConfigurationProvider(new IniConfigurationSource()); - var expectedMsg = Resources.FormatError_UnrecognizedLineFormat("ConnectionString"); + var expectedMsg = SR.Format(SR.Error_UnrecognizedLineFormat, "ConnectionString"); var exception = Assert.Throws(() => iniConfigSrc.Load(TestStreamHelpers.StringToStream(ini))); @@ -183,7 +183,7 @@ public void ThrowExceptionWhenFoundBrokenSectionHeader() DefaultConnection=TestConnectionString "; var iniConfigSrc = new IniConfigurationProvider(new IniConfigurationSource()); - var expectedMsg = Resources.FormatError_UnrecognizedLineFormat("[ConnectionString"); + var expectedMsg = SR.Format(SR.Error_UnrecognizedLineFormat, "[ConnectionString"); var exception = Assert.Throws(() => iniConfigSrc.Load(TestStreamHelpers.StringToStream(ini))); @@ -193,7 +193,7 @@ public void ThrowExceptionWhenFoundBrokenSectionHeader() [Fact] public void ThrowExceptionWhenPassingNullAsFilePath() { - var expectedMsg = new ArgumentException(Resources.Error_InvalidFilePath, "path").Message; + var expectedMsg = new ArgumentException(SR.Error_InvalidFilePath, "path").Message; var exception = Assert.Throws(() => new ConfigurationBuilder().AddIniFile(path: null)); @@ -203,7 +203,7 @@ public void ThrowExceptionWhenPassingNullAsFilePath() [Fact] public void ThrowExceptionWhenPassingEmptyStringAsFilePath() { - var expectedMsg = new ArgumentException(Resources.Error_InvalidFilePath, "path").Message; + var expectedMsg = new ArgumentException(SR.Error_InvalidFilePath, "path").Message; var exception = Assert.Throws(() => new ConfigurationBuilder().AddIniFile(string.Empty)); @@ -222,7 +222,7 @@ public void ThrowExceptionWhenKeyIsDuplicated() Provider=MySql "; var iniConfigSrc = new IniConfigurationProvider(new IniConfigurationSource()); - var expectedMsg = Resources.FormatError_KeyIsDuplicated("Data:DefaultConnection:ConnectionString"); + var expectedMsg = SR.Format(SR.Error_KeyIsDuplicated, "Data:DefaultConnection:ConnectionString"); var exception = Assert.Throws(() => iniConfigSrc.Load(TestStreamHelpers.StringToStream(ini))); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/Microsoft.Extensions.Configuration.Ini.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/Microsoft.Extensions.Configuration.Ini.Tests.csproj index 58cecd5c5952fe..52c2140100327a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/Microsoft.Extensions.Configuration.Ini.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/Microsoft.Extensions.Configuration.Ini.Tests.csproj @@ -2,20 +2,23 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true - - + + Microsoft.Extensions.Configuration\tests\ConfigurationProviderTestBase.cs + + + Microsoft.Extensions.Configuration\tests\Common\ConfigurationProviderExtensions.cs + + + Microsoft.Extensions.Configuration\tests\Common\TestStreamHelpers.cs + - - - - - - + diff --git a/src/libraries/Microsoft.Extensions.Configuration/pkg/Microsoft.Extensions.Configuration.pkgproj b/src/libraries/Microsoft.Extensions.Configuration/pkg/Microsoft.Extensions.Configuration.pkgproj new file mode 100644 index 00000000000000..c11ff1e2ecb047 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration/pkg/Microsoft.Extensions.Configuration.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs b/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs index c2305fce390ff0..b77e4887c8ed76 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.Configuration { @@ -22,28 +25,28 @@ public void Set(string key, string value) { } public partial class ChainedConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource { public ChainedConfigurationSource() { } - public Microsoft.Extensions.Configuration.IConfiguration Configuration { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public bool ShouldDisposeConfiguration { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public Microsoft.Extensions.Configuration.IConfiguration Configuration { get { throw null; } set { } } + public bool ShouldDisposeConfiguration { get { throw null; } set { } } public Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { throw null; } } public partial class ConfigurationBuilder : Microsoft.Extensions.Configuration.IConfigurationBuilder { public ConfigurationBuilder() { } - public System.Collections.Generic.IDictionary Properties { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Collections.Generic.IList Sources { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Collections.Generic.IDictionary Properties { get { throw null; } } + public System.Collections.Generic.IList Sources { get { throw null; } } public Microsoft.Extensions.Configuration.IConfigurationBuilder Add(Microsoft.Extensions.Configuration.IConfigurationSource source) { throw null; } public Microsoft.Extensions.Configuration.IConfigurationRoot Build() { throw null; } } public partial class ConfigurationKeyComparer : System.Collections.Generic.IComparer { public ConfigurationKeyComparer() { } - public static Microsoft.Extensions.Configuration.ConfigurationKeyComparer Instance { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public static Microsoft.Extensions.Configuration.ConfigurationKeyComparer Instance { get { throw null; } } public int Compare(string x, string y) { throw null; } } public abstract partial class ConfigurationProvider : Microsoft.Extensions.Configuration.IConfigurationProvider { protected ConfigurationProvider() { } - protected System.Collections.Generic.IDictionary Data { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + protected System.Collections.Generic.IDictionary Data { get { throw null; } set { } } public virtual System.Collections.Generic.IEnumerable GetChildKeys(System.Collections.Generic.IEnumerable earlierKeys, string parentPath) { throw null; } public Microsoft.Extensions.Primitives.IChangeToken GetReloadToken() { throw null; } public virtual void Load() { } @@ -90,14 +93,14 @@ public static partial class MemoryConfigurationBuilderExtensions public abstract partial class StreamConfigurationProvider : Microsoft.Extensions.Configuration.ConfigurationProvider { public StreamConfigurationProvider(Microsoft.Extensions.Configuration.StreamConfigurationSource source) { } - public Microsoft.Extensions.Configuration.StreamConfigurationSource Source { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public Microsoft.Extensions.Configuration.StreamConfigurationSource Source { get { throw null; } } public override void Load() { } public abstract void Load(System.IO.Stream stream); } public abstract partial class StreamConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource { protected StreamConfigurationSource() { } - public System.IO.Stream Stream { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public System.IO.Stream Stream { get { throw null; } set { } } public abstract Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder); } } @@ -113,7 +116,7 @@ public void Add(string key, string value) { } public partial class MemoryConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource { public MemoryConfigurationSource() { } - public System.Collections.Generic.IEnumerable> InitialData { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public System.Collections.Generic.IEnumerable> InitialData { get { throw null; } set { } } public Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { throw null; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.csproj b/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.csproj index ee8f8625ad7bc1..724bfef2ca5b4e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.csproj @@ -4,6 +4,7 @@ - + + diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationRoot.cs b/src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationRoot.cs index 6679290bf99a49..c211a74438b8e1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationRoot.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationRoot.cs @@ -69,7 +69,7 @@ public string this[string key] { if (!_providers.Any()) { - throw new InvalidOperationException(Resources.Error_NoSources); + throw new InvalidOperationException(SR.Error_NoSources); } foreach (var provider in _providers) diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/Microsoft.Extensions.Configuration.csproj b/src/libraries/Microsoft.Extensions.Configuration/src/Microsoft.Extensions.Configuration.csproj index 5ba0399f11ea84..da09e22fc90e3f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/Microsoft.Extensions.Configuration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration/src/Microsoft.Extensions.Configuration.csproj @@ -1,16 +1,13 @@  - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0 + true - - - - + diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Configuration/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..27f7fecc2d80bf --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Configuration.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationTest.cs b/src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationTest.cs index 84be4dcde8771a..3e5af7d129f15c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationTest.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationTest.cs @@ -535,7 +535,7 @@ public void SetValueThrowsExceptionNoSourceRegistered() var configurationBuilder = new ConfigurationBuilder(); var config = configurationBuilder.Build(); - var expectedMsg = Resources.Error_NoSources; + var expectedMsg = SR.Error_NoSources; // Act var ex = Assert.Throws(() => config["Title"] = "Welcome"); diff --git a/src/libraries/Microsoft.Extensions.Configuration/tests/Microsoft.Extensions.Configuration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration/tests/Microsoft.Extensions.Configuration.Tests.csproj index 2745ede6a0f758..ddfc57ce028db5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/tests/Microsoft.Extensions.Configuration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration/tests/Microsoft.Extensions.Configuration.Tests.csproj @@ -5,15 +5,13 @@ - - + + - - - - + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/pkg/Microsoft.Extensions.DependencyInjection.Abstractions.pkgproj b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/pkg/Microsoft.Extensions.DependencyInjection.Abstractions.pkgproj new file mode 100644 index 00000000000000..dc757ca30f0a78 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/pkg/Microsoft.Extensions.DependencyInjection.Abstractions.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs index 79c26110d52560..733838e7e5f223 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.DependencyInjection { @@ -63,17 +66,16 @@ public static partial class ServiceCollectionServiceExtensions public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddTransient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) where TService : class where TImplementation : class, TService { throw null; } public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddTransient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Func implementationFactory) where TService : class where TImplementation : class, TService { throw null; } } - [System.Diagnostics.DebuggerDisplayAttribute("Lifetime = {Lifetime}, ServiceType = {ServiceType}, ImplementationType = {ImplementationType}")] public partial class ServiceDescriptor { public ServiceDescriptor(System.Type serviceType, System.Func factory, Microsoft.Extensions.DependencyInjection.ServiceLifetime lifetime) { } public ServiceDescriptor(System.Type serviceType, object instance) { } public ServiceDescriptor(System.Type serviceType, System.Type implementationType, Microsoft.Extensions.DependencyInjection.ServiceLifetime lifetime) { } - public System.Func ImplementationFactory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public object ImplementationInstance { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Type ImplementationType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public Microsoft.Extensions.DependencyInjection.ServiceLifetime Lifetime { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Type ServiceType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Func ImplementationFactory { get { throw null; } } + public object ImplementationInstance { get { throw null; } } + public System.Type ImplementationType { get { throw null; } } + public Microsoft.Extensions.DependencyInjection.ServiceLifetime Lifetime { get { throw null; } } + public System.Type ServiceType { get { throw null; } } public static Microsoft.Extensions.DependencyInjection.ServiceDescriptor Describe(System.Type serviceType, System.Func implementationFactory, Microsoft.Extensions.DependencyInjection.ServiceLifetime lifetime) { throw null; } public static Microsoft.Extensions.DependencyInjection.ServiceDescriptor Describe(System.Type serviceType, System.Type implementationType, Microsoft.Extensions.DependencyInjection.ServiceLifetime lifetime) { throw null; } public static Microsoft.Extensions.DependencyInjection.ServiceDescriptor Scoped(System.Type service, System.Func implementationFactory) { throw null; } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Extensions/ServiceCollectionDescriptorExtensions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Extensions/ServiceCollectionDescriptorExtensions.cs index 61966fd55dcb9b..ece382a735a99f 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Extensions/ServiceCollectionDescriptorExtensions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Extensions/ServiceCollectionDescriptorExtensions.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.Extensions.DependencyInjection.Abstractions; namespace Microsoft.Extensions.DependencyInjection.Extensions { @@ -603,7 +602,7 @@ public static void TryAddEnumerable( implementationType == descriptor.ServiceType) { throw new ArgumentException( - Resources.FormatTryAddIndistinguishableTypeToEnumerable( + SR.Format(SR.TryAddIndistinguishableTypeToEnumerable, implementationType, descriptor.ServiceType), nameof(descriptor)); diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj index d7263dcedf4ba8..a88b34d985e02a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj @@ -1,17 +1,24 @@  - netstandard2.0 + netstandard2.0 $(DefineConstants);ActivatorUtilities_In_DependencyInjection + true - - - - - - + + Common\src\Extensions\ParameterDefaultValue\ParameterDefaultValue.cs + + + Common\src\Extensions\ActivatorUtilities\ActivatorUtilities.cs + + + Common\src\Extensions\ActivatorUtilities\ActivatorUtilitiesConstructorAttribute.cs + + + Common\src\Extensions\ActivatorUtilities\ObjectFactory.cs + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..43610cd6167f78 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs index 0cf36637503bc5..1a7ffad12ad7d8 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection.Abstractions; namespace Microsoft.Extensions.DependencyInjection { @@ -57,7 +56,7 @@ public static object GetRequiredService(this IServiceProvider provider, Type ser var service = provider.GetService(serviceType); if (service == null) { - throw new InvalidOperationException(Resources.FormatNoServiceRegistered(serviceType)); + throw new InvalidOperationException(SR.Format(SR.NoServiceRegistered, serviceType)); } return service; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/pkg/Microsoft.Extensions.DependencyInjection.pkgproj b/src/libraries/Microsoft.Extensions.DependencyInjection/pkg/Microsoft.Extensions.DependencyInjection.pkgproj new file mode 100644 index 00000000000000..becfee5e2d37ba --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/pkg/Microsoft.Extensions.DependencyInjection.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.csproj index 7c02fba66924f4..d4098d54f3b8d6 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.csproj @@ -4,9 +4,10 @@ - + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj index 038878582d55b0..23dacffd9a7a6f 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj @@ -1,8 +1,7 @@  - $(DefaultNetCoreTargetFramework);net461;netstandard2.0;netstandard2.1 - true + net461;netstandard2.0;netstandard2.1 True $(DefineConstants);IL_EMIT @@ -12,26 +11,34 @@ $(DefineConstants);SAVE_ASSEMBLIES - - - - - + + + + + + + + + - - + + Common\src\Extensions\ParameterDefaultValue\ParameterDefaultValue.cs + + + Common\src\Extensions\TypeNameHelper\TypeNameHelper.cs + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..243928d971686c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] +[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection.Performance, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteChain.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteChain.cs index 7c2bd7a80eea43..e81e90110b25cb 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteChain.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteChain.cs @@ -40,7 +40,7 @@ public void Add(Type serviceType, Type implementationType = null) private string CreateCircularDependencyExceptionMessage(Type type) { var messageBuilder = new StringBuilder(); - messageBuilder.AppendFormat(Resources.CircularDependencyException, TypeNameHelper.GetTypeDisplayName(type)); + messageBuilder.AppendFormat(SR.CircularDependencyException, TypeNameHelper.GetTypeDisplayName(type)); messageBuilder.AppendLine(); AppendResolutionPath(messageBuilder, type); diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs index 2be75fdd56ff36..13f93b99bfbaec 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs @@ -40,14 +40,14 @@ private void Populate() if (implementationTypeInfo == null || !implementationTypeInfo.IsGenericTypeDefinition) { throw new ArgumentException( - Resources.FormatOpenGenericServiceRequiresOpenGenericImplementation(descriptor.ServiceType), + SR.Format(SR.OpenGenericServiceRequiresOpenGenericImplementation, descriptor.ServiceType), "descriptors"); } if (implementationTypeInfo.IsAbstract || implementationTypeInfo.IsInterface) { throw new ArgumentException( - Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType)); + SR.Format(SR.TypeCannotBeActivated, descriptor.ImplementationType, descriptor.ServiceType)); } } else if (descriptor.ImplementationInstance == null && descriptor.ImplementationFactory == null) @@ -60,7 +60,7 @@ private void Populate() implementationTypeInfo.IsInterface) { throw new ArgumentException( - Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType)); + SR.Format(SR.TypeCannotBeActivated, descriptor.ImplementationType, descriptor.ServiceType)); } } @@ -134,7 +134,7 @@ private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain call if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { - var itemType = serviceType.GenericTypeArguments.Single(); + var itemType = serviceType.GenericTypeArguments[0]; var cacheLocation = CallSiteResultCacheLocation.Root; var callSites = new List(); @@ -260,7 +260,7 @@ private ServiceCallSite CreateConstructorCallSite(ResultCache lifetime, Type ser if (constructors.Length == 0) { - throw new InvalidOperationException(Resources.FormatNoConstructorMatch(implementationType)); + throw new InvalidOperationException(SR.Format(SR.NoConstructorMatch, implementationType)); } else if (constructors.Length == 1) { @@ -320,7 +320,7 @@ private ServiceCallSite CreateConstructorCallSite(ResultCache lifetime, Type ser // Ambiguous match exception var message = string.Join( Environment.NewLine, - Resources.FormatAmbiguousConstructorException(implementationType), + SR.Format(SR.AmbiguousConstructorException, implementationType), bestConstructor, constructors[i]); throw new InvalidOperationException(message); @@ -332,7 +332,7 @@ private ServiceCallSite CreateConstructorCallSite(ResultCache lifetime, Type ser if (bestConstructor == null) { throw new InvalidOperationException( - Resources.FormatUnableToActivateTypeException(implementationType)); + SR.Format(SR.UnableToActivateTypeException, implementationType)); } else { @@ -368,7 +368,7 @@ private ServiceCallSite[] CreateArgumentCallSites( { if (throwIfCallSiteNotFound) { - throw new InvalidOperationException(Resources.FormatCannotResolveService( + throw new InvalidOperationException(SR.Format(SR.CannotResolveService, parameterType, implementationType)); } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteValidator.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteValidator.cs index 163d72cd54e2c5..72b94ce4e1a50c 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteValidator.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteValidator.cs @@ -29,12 +29,12 @@ public void ValidateResolution(Type serviceType, IServiceScope scope, IServiceSc if (serviceType == scopedService) { throw new InvalidOperationException( - Resources.FormatDirectScopedResolvedFromRootException(serviceType, + SR.Format(SR.DirectScopedResolvedFromRootException, serviceType, nameof(ServiceLifetime.Scoped).ToLowerInvariant())); } throw new InvalidOperationException( - Resources.FormatScopedResolvedFromRootException( + SR.Format(SR.ScopedResolvedFromRootException, serviceType, scopedService, nameof(ServiceLifetime.Scoped).ToLowerInvariant())); @@ -85,7 +85,7 @@ protected override Type VisitScopeCache(ServiceCallSite scopedCallSite, CallSite } if (state.Singleton != null) { - throw new InvalidOperationException(Resources.FormatScopedInSingletonException( + throw new InvalidOperationException(SR.Format(SR.ScopedInSingletonException, scopedCallSite.ServiceType, state.Singleton.ServiceType, nameof(ServiceLifetime.Scoped).ToLowerInvariant(), diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs index 8557b15618bd3c..b4ff7c075a6277 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs @@ -14,7 +14,7 @@ public ConstantCallSite(Type serviceType, object defaultValue): base(ResultCache { if (defaultValue != null && !serviceType.IsInstanceOfType(defaultValue)) { - throw new ArgumentException(Resources.FormatConstantCantBeConvertedToServiceType(defaultValue.GetType(), serviceType)); + throw new ArgumentException(SR.Format(SR.ConstantCantBeConvertedToServiceType, defaultValue.GetType(), serviceType)); } DefaultValue = defaultValue; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstructorCallSite.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstructorCallSite.cs index 3a5265d3c51411..08e6147b5a05ff 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstructorCallSite.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstructorCallSite.cs @@ -20,7 +20,7 @@ public ConstructorCallSite(ResultCache cache, Type serviceType, ConstructorInfo { if (!serviceType.IsAssignableFrom(constructorInfo.DeclaringType)) { - throw new ArgumentException(Resources.FormatImplementationTypeCantBeConvertedToServiceType(constructorInfo.DeclaringType, serviceType)); + throw new ArgumentException(SR.Format(SR.ImplementationTypeCantBeConvertedToServiceType, constructorInfo.DeclaringType, serviceType)); } ServiceType = serviceType; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs index f765ac650d1666..a60bfbad4bc1bd 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs @@ -77,7 +77,7 @@ public void Dispose() } else { - throw new InvalidOperationException(Resources.FormatAsyncDisposableServiceDispose(TypeNameHelper.GetTypeDisplayName(toDispose[i]))); + throw new InvalidOperationException(SR.Format(SR.AsyncDisposableServiceDispose, TypeNameHelper.GetTypeDisplayName(toDispose[i]))); } } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs new file mode 100644 index 00000000000000..d653a671f1ce91 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs @@ -0,0 +1,399 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection.Specification.Fakes; +using Xunit; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public abstract partial class DependencyInjectionSpecificationTests + { + public delegate object CreateInstanceFunc(IServiceProvider provider, Type type, object[] args); + + private static object CreateInstanceDirectly(IServiceProvider provider, Type type, object[] args) + { + return ActivatorUtilities.CreateInstance(provider, type, args); + } + + private static object CreateInstanceFromFactory(IServiceProvider provider, Type type, object[] args) + { + var factory = ActivatorUtilities.CreateFactory(type, args.Select(a => a.GetType()).ToArray()); + return factory(provider, args); + } + + private static T CreateInstance(CreateInstanceFunc func, IServiceProvider provider, params object[] args) + { + return (T)func(provider, typeof(T), args); + } + + public static IEnumerable CreateInstanceFuncs + { + get + { + yield return new[] { (CreateInstanceFunc)CreateInstanceDirectly }; + yield return new[] { (CreateInstanceFunc)CreateInstanceFromFactory }; + } + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorEnablesYouToCreateAnyTypeWithServicesEvenWhenNotInIocContainer(CreateInstanceFunc createFunc) + { + // Arrange + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + var anotherClass = CreateInstance(createFunc, serviceProvider); + + Assert.NotNull(anotherClass.FakeService); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorAcceptsAnyNumberOfAdditionalConstructorParametersToProvide(CreateInstanceFunc createFunc) + { + // Arrange + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act + var anotherClass = CreateInstance(createFunc, serviceProvider, "1", "2"); + + // Assert + Assert.NotNull(anotherClass.FakeService); + Assert.Equal("1", anotherClass.One); + Assert.Equal("2", anotherClass.Two); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorWorksWithStaticCtor(CreateInstanceFunc createFunc) + { + // Act + var anotherClass = CreateInstance(createFunc, provider: null); + + // Assert + Assert.NotNull(anotherClass); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorWorksWithCtorWithOptionalArgs(CreateInstanceFunc createFunc) + { + // Arrange + var provider = new TestServiceCollection(); + var serviceProvider = CreateServiceProvider(provider); + + // Act + var anotherClass = CreateInstance(createFunc, serviceProvider); + + // Assert + Assert.NotNull(anotherClass); + Assert.Equal("BLARGH", anotherClass.Whatever); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorWorksWithCtorWithOptionalArgs_WithStructDefaults(CreateInstanceFunc createFunc) + { + // Arrange + var provider = new TestServiceCollection(); + var serviceProvider = CreateServiceProvider(provider); + + // Act + var anotherClass = CreateInstance(createFunc, serviceProvider); + + // Assert + Assert.NotNull(anotherClass); + Assert.Equal(ConsoleColor.DarkGreen, anotherClass.Color); + Assert.Null(anotherClass.ColorNull); + Assert.Equal(12, anotherClass.Integer); + Assert.Null(anotherClass.IntegerNull); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorCanDisambiguateConstructorsWithUniqueArguments(CreateInstanceFunc createFunc) + { + // Arrange + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act + var instance = CreateInstance(createFunc, serviceProvider, "1", 2); + + // Assert + Assert.NotNull(instance); + Assert.NotNull(instance.FakeService); + Assert.Equal("1", instance.Data1); + Assert.Equal(2, instance.Data2); + } + + public static IEnumerable TypesWithNonPublicConstructorData => + CreateInstanceFuncs.Zip( + new[] { typeof(ClassWithPrivateCtor), typeof(ClassWithInternalConstructor), typeof(ClassWithProtectedConstructor) }, + (a, b) => new object[] { a[0], b }); + + [Theory] + [MemberData(nameof(TypesWithNonPublicConstructorData))] + public void TypeActivatorRequiresPublicConstructor(CreateInstanceFunc createFunc, Type type) + { + // Arrange + var expectedMessage = $"A suitable constructor for type '{type}' could not be located. " + + "Ensure the type is concrete and services are registered for all parameters of a public constructor."; + + // Act and Assert + var ex = Assert.Throws(() => + createFunc(provider: null, type: type, args: new object[0])); + + Assert.Equal(expectedMessage, ex.Message); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorRequiresAllArgumentsCanBeAccepted(CreateInstanceFunc createFunc) + { + // Arrange + var expectedMessage = $"A suitable constructor for type '{typeof(AnotherClassAcceptingData).FullName}' could not be located. " + + "Ensure the type is concrete and services are registered for all parameters of a public constructor."; + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + var ex1 = Assert.Throws(() => + CreateInstance(createFunc, serviceProvider, "1", "2", "3")); + var ex2 = Assert.Throws(() => + CreateInstance(createFunc, serviceProvider, 1, 2)); + + Assert.Equal(expectedMessage, ex1.Message); + Assert.Equal(expectedMessage, ex2.Message); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorRethrowsOriginalExceptionFromConstructor(CreateInstanceFunc createFunc) + { + // Act + var ex1 = Assert.Throws(() => + CreateInstance(createFunc, provider: null)); + + var ex2 = Assert.Throws(() => + CreateInstance(createFunc, provider: null, args: new[] { new FakeService() })); + + // Assert + Assert.Equal(nameof(ClassWithThrowingEmptyCtor), ex1.Message); + Assert.Equal(nameof(ClassWithThrowingCtor), ex2.Message); + } + + [Theory] + [InlineData(typeof(string))] + [InlineData(typeof(int))] + public void TypeActivatorCreateFactoryDoesNotAllowForAmbiguousConstructorMatches(Type paramType) + { + // Arrange + var type = typeof(ClassWithAmbiguousCtors); + var expectedMessage = $"Multiple constructors accepting all given argument types have been found in type '{type}'. " + + "There should only be one applicable constructor."; + + // Act + var ex = Assert.Throws(() => + ActivatorUtilities.CreateFactory(type, new[] { paramType })); + + // Assert + Assert.Equal(expectedMessage, ex.Message); + } + + [Theory] + [InlineData("", "string")] + [InlineData(5, "IFakeService, int")] + public void TypeActivatorCreateInstanceUsesFirstMathchedConstructor(object value, string ctor) + { + // Arrange + var serviceCollection = new TestServiceCollection(); + serviceCollection.AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + var type = typeof(ClassWithAmbiguousCtors); + + // Act + var instance = ActivatorUtilities.CreateInstance(serviceProvider, type, value); + + // Assert + Assert.Equal(ctor, ((ClassWithAmbiguousCtors)instance).CtorUsed); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorUsesMarkedConstructor(CreateInstanceFunc createFunc) + { + // Arrange + var serviceCollection = new TestServiceCollection(); + serviceCollection.AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act + var instance = CreateInstance(createFunc, serviceProvider, "hello"); + + // Assert + Assert.Equal("IFakeService, string", instance.CtorUsed); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorThrowsOnMultipleMarkedCtors(CreateInstanceFunc createFunc) + { + // Act + var exception = Assert.Throws(() => CreateInstance(createFunc, null, "hello")); + + // Assert + Assert.Equal("Multiple constructors were marked with ActivatorUtilitiesConstructorAttribute.", exception.Message); + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void TypeActivatorThrowsWhenMarkedCtorDoesntAcceptArguments(CreateInstanceFunc createFunc) + { + // Act + var exception = Assert.Throws(() => CreateInstance(createFunc, null, 0, "hello")); + + // Assert + Assert.Equal("Constructor marked with ActivatorUtilitiesConstructorAttribute does not accept all given argument types.", exception.Message); + } + + [Fact] + public void GetServiceOrCreateInstanceRegisteredServiceTransient() + { + // Reset the count because test order is not guaranteed + lock (CreationCountFakeService.InstanceLock) + { + CreationCountFakeService.InstanceCount = 0; + + var serviceCollection = new TestServiceCollection() + .AddTransient() + .AddTransient(); + + var serviceProvider = CreateServiceProvider(serviceCollection); + + var service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(1, service.InstanceId); + Assert.Equal(1, CreationCountFakeService.InstanceCount); + + service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(2, service.InstanceId); + Assert.Equal(2, CreationCountFakeService.InstanceCount); + } + } + + [Fact] + public void GetServiceOrCreateInstanceRegisteredServiceSingleton() + { + lock (CreationCountFakeService.InstanceLock) + { + // Arrange + // Reset the count because test order is not guaranteed + CreationCountFakeService.InstanceCount = 0; + + var serviceCollection = new TestServiceCollection() + .AddTransient() + .AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act and Assert + var service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(1, service.InstanceId); + Assert.Equal(1, CreationCountFakeService.InstanceCount); + + service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(1, service.InstanceId); + Assert.Equal(1, CreationCountFakeService.InstanceCount); + } + } + + [Fact] + public void GetServiceOrCreateInstanceUnregisteredService() + { + lock (CreationCountFakeService.InstanceLock) + { + // Arrange + // Reset the count because test order is not guaranteed + CreationCountFakeService.InstanceCount = 0; + + var serviceCollection = new TestServiceCollection() + .AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act and Assert + var service = (CreationCountFakeService)ActivatorUtilities.GetServiceOrCreateInstance( + serviceProvider, + typeof(CreationCountFakeService)); + Assert.NotNull(service); + Assert.Equal(1, service.InstanceId); + Assert.Equal(1, CreationCountFakeService.InstanceCount); + + service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); + Assert.NotNull(service); + Assert.Equal(2, service.InstanceId); + Assert.Equal(2, CreationCountFakeService.InstanceCount); + } + } + + [Theory] + [MemberData(nameof(CreateInstanceFuncs))] + public void UnRegisteredServiceAsConstructorParameterThrowsException(CreateInstanceFunc createFunc) + { + var serviceCollection = new TestServiceCollection() + .AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + var ex = Assert.Throws(() => + CreateInstance(createFunc, serviceProvider)); + Assert.Equal($"Unable to resolve service for type '{typeof(IFakeService)}' while attempting" + + $" to activate '{typeof(CreationCountFakeService)}'.", + ex.Message); + } + + [Fact] + public void CreateInstance_WithAbstractTypeAndPublicConstructor_ThrowsCorrectException() + { + // Act & Assert + var ex = Assert.Throws(() => ActivatorUtilities.CreateInstance(default(IServiceProvider), typeof(AbstractFoo))); + var msg = "A suitable constructor for type 'Microsoft.Extensions.DependencyInjection.Specification.DependencyInjectionSpecificationTests+AbstractFoo' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor."; + Assert.Equal(msg, ex.Message); + } + + [Fact] + public void CreateInstance_CapturesInnerException_OfTargetInvocationException() + { + // Act & Assert + var ex = Assert.Throws(() => ActivatorUtilities.CreateInstance(default(IServiceProvider), typeof(Bar))); + var msg = "some error"; + Assert.Equal(msg, ex.Message); + } + + abstract class AbstractFoo + { + // The constructor should be public, since that is checked as well. + public AbstractFoo() + { + } + } + + class Bar + { + public Bar() + { + throw new InvalidOperationException("some error"); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs new file mode 100644 index 00000000000000..beed0c8661e4b8 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs @@ -0,0 +1,779 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection.Specification.Fakes; +using Xunit; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public abstract partial class DependencyInjectionSpecificationTests + { + protected abstract IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection); + + [Fact] + public void ServicesRegisteredWithImplementationTypeCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.NotNull(service); + Assert.IsType(service); + } + + [Fact] + public void ServicesRegisteredWithImplementationType_ReturnDifferentInstancesPerResolution_ForTransientServices() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.IsType(service1); + Assert.IsType(service2); + Assert.NotSame(service1, service2); + } + + [Fact] + public void ServicesRegisteredWithImplementationType_ReturnSameInstancesPerResolution_ForSingletons() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.IsType(service1); + Assert.IsType(service2); + Assert.Same(service1, service2); + } + + [Fact] + public void ServiceInstanceCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + var instance = new FakeService(); + collection.AddSingleton(typeof(IFakeServiceInstance), instance); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.Same(instance, service); + } + + [Fact] + public void TransientServiceCanBeResolvedFromProvider() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.NotNull(service1); + Assert.NotSame(service1, service2); + } + + [Fact] + public void TransientServiceCanBeResolvedFromScope() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + + using (var scope = provider.CreateScope()) + { + var scopedService1 = scope.ServiceProvider.GetService(); + var scopedService2 = scope.ServiceProvider.GetService(); + + // Assert + Assert.NotSame(service1, scopedService1); + Assert.NotSame(service1, scopedService2); + Assert.NotSame(scopedService1, scopedService2); + } + } + + [Fact] + public void SingletonServiceCanBeResolvedFromScope() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + + // Act + IServiceProvider scopedSp1 = null; + IServiceProvider scopedSp2 = null; + ClassWithServiceProvider instance1 = null; + ClassWithServiceProvider instance2 = null; + + using (var scope1 = provider.CreateScope()) + { + scopedSp1 = scope1.ServiceProvider; + instance1 = scope1.ServiceProvider.GetRequiredService(); + } + + using (var scope2 = provider.CreateScope()) + { + scopedSp2 = scope2.ServiceProvider; + instance2 = scope2.ServiceProvider.GetRequiredService(); + } + + // Assert + Assert.Same(instance1.ServiceProvider, instance2.ServiceProvider); + Assert.NotSame(instance1.ServiceProvider, scopedSp1); + Assert.NotSame(instance2.ServiceProvider, scopedSp2); + } + + [Fact] + public void SingleServiceCanBeIEnumerableResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeService), typeof(FakeService)); + var provider = CreateServiceProvider(collection); + + // Act + var services = provider.GetService>(); + + // Assert + Assert.NotNull(services); + var service = Assert.Single(services); + Assert.IsType(service); + } + + [Fact] + public void MultipleServiceCanBeIEnumerableResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeMultipleService), typeof(FakeOneMultipleService)); + collection.AddTransient(typeof(IFakeMultipleService), typeof(FakeTwoMultipleService)); + var provider = CreateServiceProvider(collection); + + // Act + var services = provider.GetService>(); + + // Assert + Assert.Collection(services.OrderBy(s => s.GetType().FullName), + service => Assert.IsType(service), + service => Assert.IsType(service)); + } + + [Fact] + public void RegistrationOrderIsPreservedWhenServicesAreIEnumerableResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeMultipleService), typeof(FakeOneMultipleService)); + collection.AddTransient(typeof(IFakeMultipleService), typeof(FakeTwoMultipleService)); + + var provider = CreateServiceProvider(collection); + + collection.Reverse(); + var providerReversed = CreateServiceProvider(collection); + + // Act + var services = provider.GetService>(); + var servicesReversed = providerReversed.GetService>(); + + // Assert + Assert.Collection(services, + service => Assert.IsType(service), + service => Assert.IsType(service)); + + Assert.Collection(servicesReversed, + service => Assert.IsType(service), + service => Assert.IsType(service)); + } + + [Fact] + public void OuterServiceCanHaveOtherServicesInjected() + { + // Arrange + var collection = new TestServiceCollection(); + var fakeService = new FakeService(); + collection.AddTransient(); + collection.AddSingleton(fakeService); + collection.AddTransient(); + collection.AddTransient(); + var provider = CreateServiceProvider(collection); + + // Act + var services = provider.GetService(); + + // Assert + Assert.Same(fakeService, services.SingleService); + Assert.Collection(services.MultipleServices.OrderBy(s => s.GetType().FullName), + service => Assert.IsType(service), + service => Assert.IsType(service)); + } + + [Fact] + public void FactoryServicesCanBeCreatedByGetService() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(); + collection.AddTransient(p => + { + var fakeService = p.GetRequiredService(); + return new TransientFactoryService + { + FakeService = fakeService, + Value = 42 + }; + }); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.NotNull(service); + Assert.Equal(42, service.Value); + Assert.NotNull(service.FakeService); + Assert.IsType(service.FakeService); + } + + [Fact] + public void FactoryServicesAreCreatedAsPartOfCreatingObjectGraph() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(); + collection.AddTransient(p => + { + var fakeService = p.GetService(); + return new TransientFactoryService + { + FakeService = fakeService, + Value = 42 + }; + }); + collection.AddScoped(p => + { + var fakeService = p.GetService(); + return new ScopedFactoryService + { + FakeService = fakeService, + }; + }); + collection.AddTransient(); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.Equal(42, service1.TransientService.Value); + Assert.NotNull(service1.TransientService.FakeService); + + Assert.Equal(42, service2.TransientService.Value); + Assert.NotNull(service2.TransientService.FakeService); + + Assert.NotNull(service1.ScopedService.FakeService); + + // Verify scoping works + Assert.NotSame(service1.TransientService, service2.TransientService); + Assert.Same(service1.ScopedService, service2.ScopedService); + } + + [Fact] + public void LastServiceReplacesPreviousServices() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(); + collection.AddTransient(); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.IsType(service); + } + + [Fact] + public void SingletonServiceCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + + // Act + var service1 = provider.GetService(); + var service2 = provider.GetService(); + + // Assert + Assert.NotNull(service1); + Assert.Same(service1, service2); + } + + [Fact] + public void ServiceProviderRegistersServiceScopeFactory() + { + // Arrange + var collection = new TestServiceCollection(); + var provider = CreateServiceProvider(collection); + + // Act + var scopeFactory = provider.GetService(); + + // Assert + Assert.NotNull(scopeFactory); + } + + [Fact] + public void ScopedServiceCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddScoped(); + var provider = CreateServiceProvider(collection); + + // Act + using (var scope = provider.CreateScope()) + { + var providerScopedService = provider.GetService(); + var scopedService1 = scope.ServiceProvider.GetService(); + var scopedService2 = scope.ServiceProvider.GetService(); + + // Assert + Assert.NotSame(providerScopedService, scopedService1); + Assert.Same(scopedService1, scopedService2); + } + } + + [Fact] + public void NestedScopedServiceCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddScoped(); + var provider = CreateServiceProvider(collection); + + // Act + using (var outerScope = provider.CreateScope()) + using (var innerScope = outerScope.ServiceProvider.CreateScope()) + { + var outerScopedService = outerScope.ServiceProvider.GetService(); + var innerScopedService = innerScope.ServiceProvider.GetService(); + + // Assert + Assert.NotNull(outerScopedService); + Assert.NotNull(innerScopedService); + Assert.NotSame(outerScopedService, innerScopedService); + } + } + + [Fact] + public void ScopedServices_FromCachedScopeFactory_CanBeResolvedAndDisposed() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddScoped(); + var provider = CreateServiceProvider(collection); + var cachedScopeFactory = provider.GetService(); + + // Act + for (var i = 0; i < 3; i++) + { + FakeService outerScopedService; + using (var outerScope = cachedScopeFactory.CreateScope()) + { + FakeService innerScopedService; + using (var innerScope = outerScope.ServiceProvider.CreateScope()) + { + outerScopedService = outerScope.ServiceProvider.GetService() as FakeService; + innerScopedService = innerScope.ServiceProvider.GetService() as FakeService; + + // Assert + Assert.NotNull(outerScopedService); + Assert.NotNull(innerScopedService); + Assert.NotSame(outerScopedService, innerScopedService); + } + + Assert.False(outerScopedService.Disposed); + Assert.True(innerScopedService.Disposed); + } + + Assert.True(outerScopedService.Disposed); + } + } + + [Fact] + public void DisposingScopeDisposesService() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(); + collection.AddScoped(); + collection.AddTransient(); + + var provider = CreateServiceProvider(collection); + FakeService disposableService; + FakeService transient1; + FakeService transient2; + FakeService singleton; + + // Act and Assert + var transient3 = Assert.IsType(provider.GetService()); + using (var scope = provider.CreateScope()) + { + disposableService = (FakeService)scope.ServiceProvider.GetService(); + transient1 = (FakeService)scope.ServiceProvider.GetService(); + transient2 = (FakeService)scope.ServiceProvider.GetService(); + singleton = (FakeService)scope.ServiceProvider.GetService(); + + Assert.False(disposableService.Disposed); + Assert.False(transient1.Disposed); + Assert.False(transient2.Disposed); + Assert.False(singleton.Disposed); + } + + Assert.True(disposableService.Disposed); + Assert.True(transient1.Disposed); + Assert.True(transient2.Disposed); + Assert.False(singleton.Disposed); + + var disposableProvider = provider as IDisposable; + if (disposableProvider != null) + { + disposableProvider.Dispose(); + Assert.True(singleton.Disposed); + Assert.True(transient3.Disposed); + } + } + + [Fact] + public void SelfResolveThenDispose() + { + // Arrange + var collection = new TestServiceCollection(); + var provider = CreateServiceProvider(collection); + + // Act + var serviceProvider = provider.GetService(); + + // Assert + Assert.NotNull(serviceProvider); + (provider as IDisposable)?.Dispose(); + } + + [Fact] + public void SafelyDisposeNestedProviderReferences() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(); + var provider = CreateServiceProvider(collection); + + // Act + var nester = provider.GetService(); + + // Assert + Assert.NotNull(nester); + nester.Dispose(); + } + + [Fact] + public void SingletonServicesComeFromRootProvider() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + FakeService disposableService1; + FakeService disposableService2; + + // Act and Assert + using (var scope = provider.CreateScope()) + { + var service = scope.ServiceProvider.GetService(); + disposableService1 = Assert.IsType(service); + Assert.False(disposableService1.Disposed); + } + + Assert.False(disposableService1.Disposed); + + using (var scope = provider.CreateScope()) + { + var service = scope.ServiceProvider.GetService(); + disposableService2 = Assert.IsType(service); + Assert.False(disposableService2.Disposed); + } + + Assert.False(disposableService2.Disposed); + Assert.Same(disposableService1, disposableService2); + } + + [Fact] + public void NestedScopedServiceCanBeResolvedWithNoFallbackProvider() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddScoped(); + var provider = CreateServiceProvider(collection); + + // Act + using (var outerScope = provider.CreateScope()) + using (var innerScope = outerScope.ServiceProvider.CreateScope()) + { + var outerScopedService = outerScope.ServiceProvider.GetService(); + var innerScopedService = innerScope.ServiceProvider.GetService(); + + // Assert + Assert.NotSame(outerScopedService, innerScopedService); + } + } + + [Fact] + public void OpenGenericServicesCanBeResolved() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + + // Act + var genericService = provider.GetService>(); + var singletonService = provider.GetService(); + + // Assert + Assert.Same(singletonService, genericService.Value); + } + + [Fact] + public void ClosedServicesPreferredOverOpenGenericServices() + { + // Arrange + var collection = new TestServiceCollection(); + collection.AddTransient(typeof(IFakeOpenGenericService), typeof(FakeService)); + collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); + collection.AddSingleton(); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService>(); + + // Assert + Assert.IsType(service); + } + + [Fact] + public void AttemptingToResolveNonexistentServiceReturnsNull() + { + // Arrange + var collection = new TestServiceCollection(); + var provider = CreateServiceProvider(collection); + + // Act + var service = provider.GetService(); + + // Assert + Assert.Null(service); + } + + [Fact] + public void NonexistentServiceCanBeIEnumerableResolved() + { + // Arrange + var collection = new TestServiceCollection(); + var provider = CreateServiceProvider(collection); + + // Act + var services = provider.GetService>(); + + // Assert + Assert.Empty(services); + } + + public static TheoryData ServiceContainerPicksConstructorWithLongestMatchesData + { + get + { + var fakeService = new FakeService(); + var multipleService = new FakeService(); + var factoryService = new TransientFactoryService(); + var scopedService = new FakeService(); + + return new TheoryData + { + { + new TestServiceCollection() + .AddSingleton(fakeService), + new TypeWithSupersetConstructors(fakeService) + }, + { + new TestServiceCollection() + .AddSingleton(factoryService), + new TypeWithSupersetConstructors(factoryService) + }, + { + new TestServiceCollection() + .AddSingleton(fakeService) + .AddSingleton(factoryService), + new TypeWithSupersetConstructors(fakeService, factoryService) + }, + { + new TestServiceCollection() + .AddSingleton(fakeService) + .AddSingleton(multipleService) + .AddSingleton(factoryService), + new TypeWithSupersetConstructors(fakeService, multipleService, factoryService) + }, + { + new TestServiceCollection() + .AddSingleton(fakeService) + .AddSingleton(multipleService) + .AddSingleton(scopedService) + .AddSingleton(factoryService), + new TypeWithSupersetConstructors(multipleService, factoryService, fakeService, scopedService) + } + }; + } + } + + [Theory] + [MemberData(nameof(ServiceContainerPicksConstructorWithLongestMatchesData))] + public void ServiceContainerPicksConstructorWithLongestMatches( + IServiceCollection serviceCollection, + TypeWithSupersetConstructors expected) + { + // Arrange + serviceCollection.AddTransient(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + // Act + var actual = serviceProvider.GetService(); + + // Assert + Assert.NotNull(actual); + Assert.Same(expected.Service, actual.Service); + Assert.Same(expected.FactoryService, actual.FactoryService); + Assert.Same(expected.MultipleService, actual.MultipleService); + Assert.Same(expected.ScopedService, actual.ScopedService); + } + + [Fact] + public void DisposesInReverseOrderOfCreation() + { + // Arrange + var serviceCollection = new TestServiceCollection(); + serviceCollection.AddSingleton(); + serviceCollection.AddTransient(); + serviceCollection.AddSingleton(); + serviceCollection.AddScoped(); + serviceCollection.AddTransient(); + serviceCollection.AddSingleton(); + var serviceProvider = CreateServiceProvider(serviceCollection); + + var callback = serviceProvider.GetService(); + var outer = serviceProvider.GetService(); + var multipleServices = outer.MultipleServices.ToArray(); + + // Act + ((IDisposable)serviceProvider).Dispose(); + + // Assert + Assert.Equal(outer, callback.Disposed[0]); + Assert.Equal(multipleServices.Reverse(), callback.Disposed.Skip(1).Take(3).OfType()); + Assert.Equal(outer.SingleService, callback.Disposed[4]); + } + + [Fact] + public void ResolvesMixedOpenClosedGenericsAsEnumerable() + { + // Arrange + var serviceCollection = new TestServiceCollection(); + var instance = new FakeOpenGenericService(null); + + serviceCollection.AddTransient(); + serviceCollection.AddSingleton(typeof(IFakeOpenGenericService), typeof(FakeService)); + serviceCollection.AddSingleton(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); + serviceCollection.AddSingleton>(instance); + + var serviceProvider = CreateServiceProvider(serviceCollection); + + var enumerable = serviceProvider.GetService>>().ToArray(); + + // Assert + Assert.Equal(3, enumerable.Length); + Assert.NotNull(enumerable[0]); + Assert.NotNull(enumerable[1]); + Assert.NotNull(enumerable[2]); + + Assert.Equal(instance, enumerable[2]); + Assert.IsType(enumerable[0]); + } + + [Theory] + [InlineData(typeof(IFakeService), typeof(FakeService), typeof(IFakeService), ServiceLifetime.Scoped)] + [InlineData(typeof(IFakeService), typeof(FakeService), typeof(IFakeService), ServiceLifetime.Singleton)] + [InlineData(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>), typeof(IFakeOpenGenericService), ServiceLifetime.Scoped)] + [InlineData(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>), typeof(IFakeOpenGenericService), ServiceLifetime.Singleton)] + public void ResolvesDifferentInstancesForServiceWhenResolvingEnumerable(Type serviceType, Type implementation, Type resolve, ServiceLifetime lifetime) + { + // Arrange + var serviceCollection = new TestServiceCollection + { + ServiceDescriptor.Describe(serviceType, implementation, lifetime), + ServiceDescriptor.Describe(serviceType, implementation, lifetime), + ServiceDescriptor.Describe(serviceType, implementation, lifetime) + }; + + var serviceProvider = CreateServiceProvider(serviceCollection); + using (var scope = serviceProvider.CreateScope()) + { + var enumerable = (scope.ServiceProvider.GetService(typeof(IEnumerable<>).MakeGenericType(resolve)) as IEnumerable) + .OfType().ToArray(); + var service = scope.ServiceProvider.GetService(resolve); + + // Assert + Assert.Equal(3, enumerable.Length); + Assert.NotNull(enumerable[0]); + Assert.NotNull(enumerable[1]); + Assert.NotNull(enumerable[2]); + + Assert.NotEqual(enumerable[0], enumerable[1]); + Assert.NotEqual(enumerable[1], enumerable[2]); + Assert.Equal(service, enumerable[2]); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClass.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClass.cs new file mode 100644 index 00000000000000..40a92237bfbe6f --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClass.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class AnotherClass + { + public AnotherClass(IFakeService fakeService) + { + FakeService = fakeService; + } + + public IFakeService FakeService { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClassAcceptingData.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClassAcceptingData.cs new file mode 100644 index 00000000000000..4f9dcda0ae303a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AnotherClassAcceptingData.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class AnotherClassAcceptingData + { + public AnotherClassAcceptingData(IFakeService fakeService, string one, string two) + { + FakeService = fakeService; + One = one; + Two = two; + } + + public IFakeService FakeService { get; } + + public string One { get; } + + public string Two { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtors.cs new file mode 100644 index 00000000000000..55ec934be20b42 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtors.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithAmbiguousCtors + { + public ClassWithAmbiguousCtors(string data) + { + CtorUsed = "string"; + } + + public ClassWithAmbiguousCtors(IFakeService service, string data) + { + CtorUsed = "IFakeService, string"; + } + + public ClassWithAmbiguousCtors(IFakeService service, int data) + { + CtorUsed = "IFakeService, int"; + } + + public ClassWithAmbiguousCtors(IFakeService service, string data1, int data2) + { + FakeService = service; + Data1 = data1; + Data2 = data2; + + CtorUsed = "IFakeService, string, string"; + } + + public IFakeService FakeService { get; } + + public string Data1 { get; } + + public int Data2 { get; } + public string CtorUsed { get; set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtorsAndAttribute.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtorsAndAttribute.cs new file mode 100644 index 00000000000000..b0e7d2284cdedf --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAmbiguousCtorsAndAttribute.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithAmbiguousCtorsAndAttribute + { + public ClassWithAmbiguousCtorsAndAttribute(string data) + { + CtorUsed = "string"; + } + + [ActivatorUtilitiesConstructor] + public ClassWithAmbiguousCtorsAndAttribute(IFakeService service, string data) + { + CtorUsed = "IFakeService, string"; + } + + public ClassWithAmbiguousCtorsAndAttribute(IFakeService service, IFakeOuterService service2, string data) + { + CtorUsed = "IFakeService, IFakeService, string"; + } + + public string CtorUsed { get; set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInternalConstructor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInternalConstructor.cs new file mode 100644 index 00000000000000..220d3e86d39b20 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInternalConstructor.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection +{ + public class ClassWithInternalConstructor + { + internal ClassWithInternalConstructor() + { + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithMultipleMarkedCtors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithMultipleMarkedCtors.cs new file mode 100644 index 00000000000000..9cb04aafd63a6f --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithMultipleMarkedCtors.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithMultipleMarkedCtors + { + [ActivatorUtilitiesConstructor] + public ClassWithMultipleMarkedCtors(string data) + { + } + + [ActivatorUtilitiesConstructor] + public ClassWithMultipleMarkedCtors(IFakeService service, string data) + { + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNestedReferencesToProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNestedReferencesToProvider.cs new file mode 100644 index 00000000000000..1813db134fa962 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNestedReferencesToProvider.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithNestedReferencesToProvider : IDisposable + { + private IServiceProvider _serviceProvider; + private ClassWithNestedReferencesToProvider _nested; + + public ClassWithNestedReferencesToProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + _nested = new ClassWithNestedReferencesToProvider(_serviceProvider, 0); + } + + private ClassWithNestedReferencesToProvider(IServiceProvider serviceProvider, int level) + { + _serviceProvider = serviceProvider; + if (level > 1) + { + _nested = new ClassWithNestedReferencesToProvider(_serviceProvider, level + 1); + } + } + + public void Dispose() + { + _nested?.Dispose(); + (_serviceProvider as IDisposable)?.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtor.cs new file mode 100644 index 00000000000000..810804bafccc76 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtor.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class ClassWithOptionalArgsCtor + { + public ClassWithOptionalArgsCtor(string whatever = "BLARGH") + { + Whatever = whatever; + } + + public string Whatever { get; set; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs new file mode 100644 index 00000000000000..d0b2588211e461 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class ClassWithOptionalArgsCtorWithStructs + { + public ConsoleColor? Color { get; } + public ConsoleColor? ColorNull { get; } + + public int? Integer { get; } + public int? IntegerNull { get; } + + public ClassWithOptionalArgsCtorWithStructs( + DateTime dateTime = new DateTime(), + DateTime dateTimeDefault = default(DateTime), + TimeSpan timeSpan = new TimeSpan(), + TimeSpan timeSpanDefault = default(TimeSpan), + DateTimeOffset dateTimeOffset = new DateTimeOffset(), + DateTimeOffset dateTimeOffsetDefault = default(DateTimeOffset), + Guid guid = new Guid(), + Guid guidDefault = default(Guid), + CustomStruct customStruct = new CustomStruct(), + CustomStruct customStructDefault = default(CustomStruct), + ConsoleColor? color = ConsoleColor.DarkGreen, + ConsoleColor? colorNull = null, + int? integer = 12, + int? integerNull = null + ) + { + Color = color; + ColorNull = colorNull; + Integer = integer; + IntegerNull = integerNull; + } + + public struct CustomStruct { } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithPrivateCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithPrivateCtor.cs new file mode 100644 index 00000000000000..f0ef2a678c7377 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithPrivateCtor.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithPrivateCtor + { + private ClassWithPrivateCtor() + { + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithProtectedConstructor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithProtectedConstructor.cs new file mode 100644 index 00000000000000..d3098dcd09b6c5 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithProtectedConstructor.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithProtectedConstructor + { + internal ClassWithProtectedConstructor() + { + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithServiceProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithServiceProvider.cs new file mode 100644 index 00000000000000..1003e9976580ae --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithServiceProvider.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithServiceProvider + { + public ClassWithServiceProvider(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public IServiceProvider ServiceProvider { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStaticCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStaticCtor.cs new file mode 100644 index 00000000000000..ebd631b17e9ddb --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStaticCtor.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithStaticCtor + { + static ClassWithStaticCtor() + { + + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingCtor.cs new file mode 100644 index 00000000000000..575d18117113b9 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingCtor.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithThrowingCtor + { + public ClassWithThrowingCtor(IFakeService service) + { + throw new Exception(nameof(ClassWithThrowingCtor)); + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingEmptyCtor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingEmptyCtor.cs new file mode 100644 index 00000000000000..9ecc4b233244bb --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithThrowingEmptyCtor.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ClassWithThrowingEmptyCtor + { + public ClassWithThrowingEmptyCtor() + { + throw new Exception(nameof(ClassWithThrowingEmptyCtor)); + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/CreationCountFakeService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/CreationCountFakeService.cs new file mode 100644 index 00000000000000..8c9a21912b051e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/CreationCountFakeService.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class CreationCountFakeService + { + public static readonly object InstanceLock = new object(); + + public CreationCountFakeService(IFakeService dependency) + { + InstanceCount++; + InstanceId = InstanceCount; + } + + public static int InstanceCount { get; set; } + + public int InstanceId { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackInnerService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackInnerService.cs new file mode 100644 index 00000000000000..2acc2204591536 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackInnerService.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeDisposableCallbackInnerService : FakeDisposableCallbackService, IFakeMultipleService + { + public FakeDisposableCallbackInnerService(FakeDisposeCallback callback) : base(callback) + { + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackOuterService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackOuterService.cs new file mode 100644 index 00000000000000..7ef95a854b051b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackOuterService.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeDisposableCallbackOuterService : FakeDisposableCallbackService, IFakeOuterService + { + public FakeDisposableCallbackOuterService( + IFakeService singleService, + IEnumerable multipleServices, + FakeDisposeCallback callback) : base(callback) + { + SingleService = singleService; + MultipleServices = multipleServices.ToArray(); + } + + public IFakeService SingleService { get; } + public IEnumerable MultipleServices { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackService.cs new file mode 100644 index 00000000000000..5f29aa01ed1c15 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposableCallbackService.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeDisposableCallbackService: IDisposable + { + private static int _globalId; + private readonly int _id; + private readonly FakeDisposeCallback _callback; + + public FakeDisposableCallbackService(FakeDisposeCallback callback) + { + _id = _globalId++; + _callback = callback; + } + + public void Dispose() + { + _callback.Disposed.Add(this); + } + + public override string ToString() + { + return _id.ToString(); + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposeCallback.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposeCallback.cs new file mode 100644 index 00000000000000..8d0ca9f446f605 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeDisposeCallback.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeDisposeCallback + { + public List Disposed { get; } = new List(); + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOneMultipleService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOneMultipleService.cs new file mode 100644 index 00000000000000..a5d3cd1451c224 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOneMultipleService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeOneMultipleService : IFakeMultipleService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOpenGenericService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOpenGenericService.cs new file mode 100644 index 00000000000000..c2be6bc4c1b43b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOpenGenericService.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeOpenGenericService : IFakeOpenGenericService + { + public FakeOpenGenericService(TVal value) + { + Value = value; + } + + public TVal Value { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOuterService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOuterService.cs new file mode 100644 index 00000000000000..667f911557e8b1 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeOuterService.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeOuterService : IFakeOuterService + { + public FakeOuterService( + IFakeService singleService, + IEnumerable multipleServices) + { + SingleService = singleService; + MultipleServices = multipleServices; + } + + public IFakeService SingleService { get; } + + public IEnumerable MultipleServices { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeService.cs new file mode 100644 index 00000000000000..3fccf3de00b37d --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeService.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeService : IFakeEveryService, IDisposable + { + public PocoClass Value { get; set; } + + public bool Disposed { get; private set; } + + public void Dispose() + { + if (Disposed) + { + throw new ObjectDisposedException(nameof(FakeService)); + } + + Disposed = true; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeTwoMultipleService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeTwoMultipleService.cs new file mode 100644 index 00000000000000..89fcab70108407 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/FakeTwoMultipleService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class FakeTwoMultipleService : IFakeMultipleService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFactoryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFactoryService.cs new file mode 100644 index 00000000000000..ddbc44f20fb79e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFactoryService.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFactoryService + { + IFakeService FakeService { get; } + + int Value { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeEveryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeEveryService.cs new file mode 100644 index 00000000000000..9e24521a65ab5a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeEveryService.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeEveryService : + IFakeService, + IFakeMultipleService, + IFakeScopedService, + IFakeServiceInstance, + IFakeSingletonService, + IFakeOpenGenericService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeMultipleService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeMultipleService.cs new file mode 100644 index 00000000000000..a38394c665f870 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeMultipleService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeMultipleService : IFakeService + { + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs new file mode 100644 index 00000000000000..12dc7142557384 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeOpenGenericService + { + TValue Value { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOuterService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOuterService.cs new file mode 100644 index 00000000000000..f4bd3e3a2dae27 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOuterService.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeOuterService + { + IFakeService SingleService { get; } + + IEnumerable MultipleServices { get; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeScopedService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeScopedService.cs new file mode 100644 index 00000000000000..9f3f4f000df1aa --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeScopedService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeScopedService : IFakeService + { + } +} diff --git a/src/libraries/System.Reflection.Emit/tests/AssemblyInfo.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeService.cs similarity index 62% rename from src/libraries/System.Reflection.Emit/tests/AssemblyInfo.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeService.cs index 74d2d9248d204f..391bf2edf3d4a7 100644 --- a/src/libraries/System.Reflection.Emit/tests/AssemblyInfo.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeService.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Xunit; - -[assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/32177", TestRuntimes.Mono)] // Test hangs \ No newline at end of file +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeService + { + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeServiceInstance.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeServiceInstance.cs new file mode 100644 index 00000000000000..e6ed4019e37bbd --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeServiceInstance.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeServiceInstance : IFakeService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeSingletonService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeSingletonService.cs new file mode 100644 index 00000000000000..3f341ce204de4e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeSingletonService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface IFakeSingletonService : IFakeService + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/INonexistentService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/INonexistentService.cs new file mode 100644 index 00000000000000..54661e3cd970cd --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/INonexistentService.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public interface INonexistentService + { + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/PocoClass.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/PocoClass.cs new file mode 100644 index 00000000000000..75bd28ae9f745c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/PocoClass.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class PocoClass + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ScopedFactoryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ScopedFactoryService.cs new file mode 100644 index 00000000000000..298ad076c1adb1 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ScopedFactoryService.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ScopedFactoryService + { + public IFakeService FakeService { get; set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ServiceAcceptingFactoryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ServiceAcceptingFactoryService.cs new file mode 100644 index 00000000000000..c016eaeeca7cfe --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ServiceAcceptingFactoryService.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class ServiceAcceptingFactoryService + { + public ServiceAcceptingFactoryService( + ScopedFactoryService scopedService, + IFactoryService transientService) + { + ScopedService = scopedService; + TransientService = transientService; + } + + public ScopedFactoryService ScopedService { get; private set; } + + public IFactoryService TransientService { get; private set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TransientFactoryService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TransientFactoryService.cs new file mode 100644 index 00000000000000..1915f3fda0a385 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TransientFactoryService.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class TransientFactoryService : IFactoryService + { + public IFakeService FakeService { get; set; } + + public int Value { get; set; } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TypeWithSupersetConstructors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TypeWithSupersetConstructors.cs new file mode 100644 index 00000000000000..c378883701547b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/TypeWithSupersetConstructors.cs @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes +{ + public class TypeWithSupersetConstructors + { + public TypeWithSupersetConstructors(IFactoryService factoryService) + : this( + fakeService: null, + factoryService: factoryService) + { + } + + public TypeWithSupersetConstructors(IFakeService fakeService) + : this( + fakeService, + factoryService: null) + { + } + + public TypeWithSupersetConstructors( + IFakeService fakeService, + IFactoryService factoryService) + : this( + fakeService, + multipleService: null, + factoryService: factoryService) + { + } + + public TypeWithSupersetConstructors( + IFakeService fakeService, + IFakeMultipleService multipleService, + IFactoryService factoryService) + : this( + multipleService, + factoryService, + fakeService, + scopedService: null) + { + } + + public TypeWithSupersetConstructors( + IFakeMultipleService multipleService, + IFactoryService factoryService, + IFakeService fakeService, + IFakeScopedService scopedService) + { + MultipleService = multipleService; + FactoryService = factoryService; + Service = fakeService; + ScopedService = scopedService; + } + + public IFakeService Service { get; } + + public IFactoryService FactoryService { get; } + + public IFakeMultipleService MultipleService { get; } + + public IFakeScopedService ScopedService { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ServiceCollection.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ServiceCollection.cs new file mode 100644 index 00000000000000..b4501e76319e92 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ServiceCollection.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + internal class TestServiceCollection : List, IServiceCollection + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Utils/MultiServiceHelpers.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Utils/MultiServiceHelpers.cs index c1ab996e9dd9d5..ab44b14269be1f 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Utils/MultiServiceHelpers.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Utils/MultiServiceHelpers.cs @@ -5,7 +5,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Reflection; namespace Microsoft.Extensions.DependencyInjection.Tests @@ -43,7 +42,7 @@ private static bool IsGenericIEnumerable(Type type) private static Type FirstGenericArgument(Type type) { - return type.GetTypeInfo().GenericTypeArguments.Single(); + return type.GetTypeInfo().GenericTypeArguments[0]; } private static IList CreateEmptyList(Type innerType) diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/Microsoft.Extensions.FileProviders.Abstractions.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/Microsoft.Extensions.FileProviders.Abstractions.csproj index f4b7aae8743bed..6f7344c8ff8cfa 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/Microsoft.Extensions.FileProviders.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/Microsoft.Extensions.FileProviders.Abstractions.csproj @@ -3,13 +3,13 @@ Microsoft.Extensions.FileProviders netstandard2.0 + true Common\src\Extensions\EmptyDisposable.cs - diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/Microsoft.Extensions.FileProviders.Composite.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/Microsoft.Extensions.FileProviders.Composite.csproj index 134d041f29c9fe..75718c41b115be 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/Microsoft.Extensions.FileProviders.Composite.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/Microsoft.Extensions.FileProviders.Composite.csproj @@ -3,12 +3,9 @@ Microsoft.Extensions.FileProviders netstandard2.0 + true - - - - diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Composite/tests/Microsoft.Extensions.FileProviders.Composite.Tests.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Composite/tests/Microsoft.Extensions.FileProviders.Composite.Tests.csproj index 7f73088dfe4885..ecb606a8b719e8 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Composite/tests/Microsoft.Extensions.FileProviders.Composite.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Composite/tests/Microsoft.Extensions.FileProviders.Composite.Tests.csproj @@ -3,20 +3,11 @@ Microsoft.Extensions.FileProviders.Composite $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true - - - - - - - - - - diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj index da32c8db673752..5f23ebcc600ad6 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj @@ -4,6 +4,7 @@ Microsoft.Extensions.FileProviders netstandard2.0 true + true @@ -13,7 +14,6 @@ Common\src\Extensions\NonCapturingTimer\NonCapturingTimer.cs - diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/Microsoft.Extensions.FileProviders.Physical.Tests.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/Microsoft.Extensions.FileProviders.Physical.Tests.csproj index 95fc496fd614dd..8cb5229c139d3e 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/Microsoft.Extensions.FileProviders.Physical.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/Microsoft.Extensions.FileProviders.Physical.Tests.csproj @@ -3,10 +3,10 @@ Microsoft.Extensions.FileProviders.Physical $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\xunit\ITestCondition.cs @@ -17,19 +17,7 @@ - - - - - - - - - - - - diff --git a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/Microsoft.Extensions.FileSystemGlobbing.csproj b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/Microsoft.Extensions.FileSystemGlobbing.csproj index 0b0c85d73935e4..00d510d0cede57 100644 --- a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/Microsoft.Extensions.FileSystemGlobbing.csproj +++ b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/Microsoft.Extensions.FileSystemGlobbing.csproj @@ -3,13 +3,13 @@ netstandard2.0 $(NoWarn);CS1591 + true Common\src\Extensions\HashCodeCombiner\HashCodeCombiner.cs - diff --git a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/Microsoft.Extensions.FileSystemGlobbing.Tests.csproj b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/Microsoft.Extensions.FileSystemGlobbing.Tests.csproj index bb2be1175ca05b..ec30023fd0ec80 100644 --- a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/Microsoft.Extensions.FileSystemGlobbing.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/Microsoft.Extensions.FileSystemGlobbing.Tests.csproj @@ -2,14 +2,7 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true - - - - - - - - diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/pkg/Microsoft.Extensions.Hosting.Abstractions.pkgproj b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/pkg/Microsoft.Extensions.Hosting.Abstractions.pkgproj new file mode 100644 index 00000000000000..13333274e7b1b6 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/pkg/Microsoft.Extensions.Hosting.Abstractions.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs index 880dff83911420..0f26a6bf6de097 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.DependencyInjection { @@ -18,7 +21,6 @@ protected BackgroundService() { } public virtual void Dispose() { } protected abstract System.Threading.Tasks.Task ExecuteAsync(System.Threading.CancellationToken stoppingToken); public virtual System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken) { throw null; } - [System.Diagnostics.DebuggerStepThroughAttribute] public virtual System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken) { throw null; } } [System.ObsoleteAttribute("This type is obsolete and will be removed in a future version. The recommended alternative is Microsoft.Extensions.Hosting.Environments.", false)] @@ -37,9 +39,9 @@ public static partial class Environments public partial class HostBuilderContext { public HostBuilderContext(System.Collections.Generic.IDictionary properties) { } - public Microsoft.Extensions.Configuration.IConfiguration Configuration { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public Microsoft.Extensions.Hosting.IHostEnvironment HostingEnvironment { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public System.Collections.Generic.IDictionary Properties { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public Microsoft.Extensions.Configuration.IConfiguration Configuration { get { throw null; } set { } } + public Microsoft.Extensions.Hosting.IHostEnvironment HostingEnvironment { get { throw null; } set { } } + public System.Collections.Generic.IDictionary Properties { get { throw null; } } } public static partial class HostDefaults { @@ -57,18 +59,15 @@ public static partial class HostEnvironmentEnvExtensions public static partial class HostingAbstractionsHostBuilderExtensions { public static Microsoft.Extensions.Hosting.IHost Start(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder) { throw null; } - [System.Diagnostics.DebuggerStepThroughAttribute] public static System.Threading.Tasks.Task StartAsync(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } } public static partial class HostingAbstractionsHostExtensions { public static void Run(this Microsoft.Extensions.Hosting.IHost host) { } - [System.Diagnostics.DebuggerStepThroughAttribute] public static System.Threading.Tasks.Task RunAsync(this Microsoft.Extensions.Hosting.IHost host, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } public static void Start(this Microsoft.Extensions.Hosting.IHost host) { } public static System.Threading.Tasks.Task StopAsync(this Microsoft.Extensions.Hosting.IHost host, System.TimeSpan timeout) { throw null; } public static void WaitForShutdown(this Microsoft.Extensions.Hosting.IHost host) { } - [System.Diagnostics.DebuggerStepThroughAttribute] public static System.Threading.Tasks.Task WaitForShutdownAsync(this Microsoft.Extensions.Hosting.IHost host, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) { throw null; } } public static partial class HostingEnvironmentExtensions diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.csproj index 84664b981272f7..3220cd20db6e89 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.csproj @@ -1,11 +1,15 @@ - netstandard2.0 + netstandard2.0;netstandard2.1 + + + + diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Microsoft.Extensions.Hosting.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Microsoft.Extensions.Hosting.Abstractions.csproj index 5a9396d8471a08..1996b8d4effcb2 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Microsoft.Extensions.Hosting.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Microsoft.Extensions.Hosting.Abstractions.csproj @@ -1,10 +1,10 @@ - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0;$(NetCoreAppCurrent) $(NoWarn);CS1591 Microsoft.Extensions.Hosting + true @@ -12,10 +12,13 @@ + + + diff --git a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.netcoreapp.cs b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.netcoreapp.cs rename to src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs diff --git a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.csproj b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.csproj index 097173637ff1cf..46164f9d0127a4 100644 --- a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.csproj +++ b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.csproj @@ -1,18 +1,11 @@ - - netstandard2.0;$(DefaultNetCoreTargetFramework) + netstandard2.0 - - - - - - - - - - - + + + + + diff --git a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.netstandard2.0.cs b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.netstandard2.0.cs deleted file mode 100644 index 3348637e8fd871..00000000000000 --- a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.netstandard2.0.cs +++ /dev/null @@ -1,120 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.DependencyInjection -{ - public static partial class HttpClientBuilderExtensions - { - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpMessageHandler(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Func configureHandler) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpMessageHandler(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Func configureHandler) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpMessageHandler(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder) where THandler : System.Net.Http.DelegatingHandler { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddTypedClient(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder) where TClient : class { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddTypedClient(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Func factory) where TClient : class { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddTypedClient(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Func factory) where TClient : class { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddTypedClient(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder ConfigureHttpClient(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Action configureClient) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder ConfigureHttpClient(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Action configureClient) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder ConfigureHttpMessageHandlerBuilder(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Action configureBuilder) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder ConfigurePrimaryHttpMessageHandler(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Func configureHandler) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder ConfigurePrimaryHttpMessageHandler(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Func configureHandler) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder ConfigurePrimaryHttpMessageHandler(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder) where THandler : System.Net.Http.HttpMessageHandler { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder RedactLoggedHeaders(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Collections.Generic.IEnumerable redactedLoggedHeaderNames) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder RedactLoggedHeaders(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Func shouldRedactHeaderValue) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder SetHandlerLifetime(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.TimeSpan handlerLifetime) { throw null; } - } - public static partial class HttpClientFactoryServiceCollectionExtensions - { - public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action configureClient) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action configureClient) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) where TClient : class { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configureClient) where TClient : class { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configureClient) where TClient : class { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name) where TClient : class { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action configureClient) where TClient : class { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action configureClient) where TClient : class { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configureClient) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configureClient) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Func factory) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Func factory) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action configureClient) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action configureClient) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Func factory) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Func factory) where TClient : class where TImplementation : class, TClient { throw null; } - } - public partial interface IHttpClientBuilder - { - string Name { get; } - Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; } - } -} -namespace Microsoft.Extensions.Http -{ - public partial class HttpClientFactoryOptions - { - public HttpClientFactoryOptions() { } - public System.TimeSpan HandlerLifetime { get { throw null; } set { } } - public System.Collections.Generic.IList> HttpClientActions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Collections.Generic.IList> HttpMessageHandlerBuilderActions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Func ShouldRedactHeaderValue { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public bool SuppressHandlerScope { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - } - public abstract partial class HttpMessageHandlerBuilder - { - protected HttpMessageHandlerBuilder() { } - public abstract System.Collections.Generic.IList AdditionalHandlers { get; } - public abstract string Name { get; set; } - public abstract System.Net.Http.HttpMessageHandler PrimaryHandler { get; set; } - public virtual System.IServiceProvider Services { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public abstract System.Net.Http.HttpMessageHandler Build(); - protected internal static System.Net.Http.HttpMessageHandler CreateHandlerPipeline(System.Net.Http.HttpMessageHandler primaryHandler, System.Collections.Generic.IEnumerable additionalHandlers) { throw null; } - } - public partial interface IHttpMessageHandlerBuilderFilter - { - System.Action Configure(System.Action next); - } - public partial interface ITypedHttpClientFactory - { - TClient CreateClient(System.Net.Http.HttpClient httpClient); - } -} -namespace Microsoft.Extensions.Http.Logging -{ - public partial class LoggingHttpMessageHandler : System.Net.Http.DelegatingHandler - { - public LoggingHttpMessageHandler(Microsoft.Extensions.Logging.ILogger logger) { } - public LoggingHttpMessageHandler(Microsoft.Extensions.Logging.ILogger logger, Microsoft.Extensions.Http.HttpClientFactoryOptions options) { } - [System.Diagnostics.DebuggerStepThroughAttribute] - protected override System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; } - } - public partial class LoggingScopeHttpMessageHandler : System.Net.Http.DelegatingHandler - { - public LoggingScopeHttpMessageHandler(Microsoft.Extensions.Logging.ILogger logger) { } - public LoggingScopeHttpMessageHandler(Microsoft.Extensions.Logging.ILogger logger, Microsoft.Extensions.Http.HttpClientFactoryOptions options) { } - [System.Diagnostics.DebuggerStepThroughAttribute] - protected override System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; } - } -} -namespace System.Net.Http -{ - public static partial class HttpClientFactoryExtensions - { - public static System.Net.Http.HttpClient CreateClient(this System.Net.Http.IHttpClientFactory factory) { throw null; } - } - public static partial class HttpMessageHandlerFactoryExtensions - { - public static System.Net.Http.HttpMessageHandler CreateHandler(this System.Net.Http.IHttpMessageHandlerFactory factory) { throw null; } - } - public partial interface IHttpClientFactory - { - System.Net.Http.HttpClient CreateClient(string name); - } - public partial interface IHttpMessageHandlerFactory - { - System.Net.Http.HttpMessageHandler CreateHandler(string name); - } -} diff --git a/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj b/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj index b7c800e035ec61..208cae23f9c305 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj +++ b/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj @@ -1,29 +1,21 @@  - - The HttpClient factory is a pattern for configuring and retrieving named HttpClients in a composable way. The HttpClient factory provides extensibility to plug in DelegatingHandlers that address cross-cutting concerns such as service location, load balancing, and reliability. The default HttpClient factory provides built-in diagnostics and logging and manages the lifetimes of connections in a performant way. - Commonly used types: - System.Net.Http.IHttpClientFactory - - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0 $(NoWarn);CS1591 - true - aspnetcore;httpclient - true - true + true - - - - - - - - + + Common\src\Extensions\NonCapturingTimer\NonCapturingTimer.cs + + + Common\src\Extensions\TypeNameHelper.cs + + + Common\src\Extensions\ValueStopwatch\ValueStopwatch.cs + diff --git a/src/libraries/Microsoft.Extensions.Http/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Http/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..665c90dba1e02a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Http/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Http.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/pkg/Microsoft.Extensions.Logging.Abstractions.pkgproj b/src/libraries/Microsoft.Extensions.Logging.Abstractions/pkg/Microsoft.Extensions.Logging.Abstractions.pkgproj new file mode 100644 index 00000000000000..748c29f6212db4 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/pkg/Microsoft.Extensions.Logging.Abstractions.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/ref/Microsoft.Extensions.Logging.Abstractions.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/ref/Microsoft.Extensions.Logging.Abstractions.cs index dcbf6da13a5ea7..878f0c4cba03a1 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/ref/Microsoft.Extensions.Logging.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/ref/Microsoft.Extensions.Logging.Abstractions.cs @@ -1,17 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.Logging { - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] public readonly partial struct EventId { private readonly object _dummy; private readonly int _dummyPrimitive; public EventId(int id, string name = null) { throw null; } - public int Id { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public int Id { get { throw null; } } + public string Name { get { throw null; } } public bool Equals(Microsoft.Extensions.Logging.EventId other) { throw null; } public override bool Equals(object obj) { throw null; } public override int GetHashCode() { throw null; } @@ -127,7 +129,7 @@ namespace Microsoft.Extensions.Logging.Abstractions public partial class NullLogger : Microsoft.Extensions.Logging.ILogger { internal NullLogger() { } - public static Microsoft.Extensions.Logging.Abstractions.NullLogger Instance { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public static Microsoft.Extensions.Logging.Abstractions.NullLogger Instance { get { throw null; } } public System.IDisposable BeginScope(TState state) { throw null; } public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) { throw null; } public void Log(Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.Extensions.Logging.EventId eventId, TState state, System.Exception exception, System.Func formatter) { } @@ -143,7 +145,7 @@ public void Dispose() { } public partial class NullLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, System.IDisposable { internal NullLoggerProvider() { } - public static Microsoft.Extensions.Logging.Abstractions.NullLoggerProvider Instance { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public static Microsoft.Extensions.Logging.Abstractions.NullLoggerProvider Instance { get { throw null; } } public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { throw null; } public void Dispose() { } } diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LoggerMessage.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LoggerMessage.cs index 81177f20ca0c3d..7101c09d986f58 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LoggerMessage.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LoggerMessage.cs @@ -259,7 +259,7 @@ private static LogValuesFormatter CreateLogValuesFormatter(string formatString, if (actualCount != expectedNamedParameterCount) { throw new ArgumentException( - Resource.FormatUnexpectedNumberOfNamedParameters(formatString, expectedNamedParameterCount, actualCount)); + SR.Format(SR.UnexpectedNumberOfNamedParameters, expectedNamedParameterCount, actualCount)); } return logValuesFormatter; diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj index 34bc1818a72fdc..247ee6768e7a8d 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj @@ -1,17 +1,21 @@ - netstandard2.0 + netstandard2.0 $(NoWarn);CS1591 + true - - - - - - + + Common\src\Extensions\TypeNameHelper\TypeNameHelper.cs + + + Common\src\Extensions\Logging\NullExternalScopeProvider.cs + + + Common\src\Extensions\Logging\NullScope.cs + diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..a3841254b41bb5 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Logging.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/pkg/Microsoft.Extensions.Options.ConfigurationExtensions.pkgproj b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/pkg/Microsoft.Extensions.Options.ConfigurationExtensions.pkgproj new file mode 100644 index 00000000000000..a0b57f23c3c5b1 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/pkg/Microsoft.Extensions.Options.ConfigurationExtensions.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/ref/Microsoft.Extensions.Options.ConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/ref/Microsoft.Extensions.Options.ConfigurationExtensions.cs index e66c32090379a5..42b3ae6d7c4949 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/ref/Microsoft.Extensions.Options.ConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/ref/Microsoft.Extensions.Options.ConfigurationExtensions.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.DependencyInjection { @@ -23,7 +26,7 @@ public partial class ConfigurationChangeTokenSource : Microsoft.Extens { public ConfigurationChangeTokenSource(Microsoft.Extensions.Configuration.IConfiguration config) { } public ConfigurationChangeTokenSource(string name, Microsoft.Extensions.Configuration.IConfiguration config) { } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public string Name { get { throw null; } } public Microsoft.Extensions.Primitives.IChangeToken GetChangeToken() { throw null; } } public partial class ConfigureFromConfigurationOptions : Microsoft.Extensions.Options.ConfigureOptions where TOptions : class diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/ref/Microsoft.Extensions.Options.ConfigurationExtensions.csproj b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/ref/Microsoft.Extensions.Options.ConfigurationExtensions.csproj index fe70d4f69ca309..be66538ec516b3 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/ref/Microsoft.Extensions.Options.ConfigurationExtensions.csproj +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/ref/Microsoft.Extensions.Options.ConfigurationExtensions.csproj @@ -4,9 +4,10 @@ - - - - + + + + + diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/Microsoft.Extensions.Options.ConfigurationExtensions.csproj b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/Microsoft.Extensions.Options.ConfigurationExtensions.csproj index 5a83d1492919f0..de569c7bd8fd90 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/Microsoft.Extensions.Options.ConfigurationExtensions.csproj +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/Microsoft.Extensions.Options.ConfigurationExtensions.csproj @@ -1,8 +1,8 @@  - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0;$(NetCoreAppCurrent) + true @@ -10,6 +10,12 @@ + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/pkg/Microsoft.Extensions.Options.DataAnnotations.pkgproj b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/pkg/Microsoft.Extensions.Options.DataAnnotations.pkgproj new file mode 100644 index 00000000000000..de950358cd2e93 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/pkg/Microsoft.Extensions.Options.DataAnnotations.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/ref/Microsoft.Extensions.Options.DataAnnotations.cs b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/ref/Microsoft.Extensions.Options.DataAnnotations.cs index 13fdbc84780657..0839723b9a2b10 100644 --- a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/ref/Microsoft.Extensions.Options.DataAnnotations.cs +++ b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/ref/Microsoft.Extensions.Options.DataAnnotations.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.DependencyInjection { @@ -14,7 +17,7 @@ namespace Microsoft.Extensions.Options public partial class DataAnnotationValidateOptions : Microsoft.Extensions.Options.IValidateOptions where TOptions : class { public DataAnnotationValidateOptions(string name) { } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public string Name { get { throw null; } } public Microsoft.Extensions.Options.ValidateOptionsResult Validate(string name, TOptions options) { throw null; } } } diff --git a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/ref/Microsoft.Extensions.Options.DataAnnotations.csproj b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/ref/Microsoft.Extensions.Options.DataAnnotations.csproj index c8291cba6676f2..b8dd59bff6fe78 100644 --- a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/ref/Microsoft.Extensions.Options.DataAnnotations.csproj +++ b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/ref/Microsoft.Extensions.Options.DataAnnotations.csproj @@ -1,13 +1,10 @@ - netstandard2.0 + netstandard2.0;netstandard2.1 - - - - - + + diff --git a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/Microsoft.Extensions.Options.DataAnnotations.csproj b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/Microsoft.Extensions.Options.DataAnnotations.csproj index e848318f76e6f9..18a3307bfe228f 100644 --- a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/Microsoft.Extensions.Options.DataAnnotations.csproj +++ b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/Microsoft.Extensions.Options.DataAnnotations.csproj @@ -1,8 +1,8 @@  - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0;$(NetCoreAppCurrent) + true @@ -10,8 +10,14 @@ - + + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Options/pkg/Microsoft.Extensions.Options.pkgproj b/src/libraries/Microsoft.Extensions.Options/pkg/Microsoft.Extensions.Options.pkgproj new file mode 100644 index 00000000000000..f50e78baa3f9f3 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options/pkg/Microsoft.Extensions.Options.pkgproj @@ -0,0 +1,9 @@ + + + + + net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) + + + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.cs b/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.cs index 76e96b817796f7..b10fa502425485 100644 --- a/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.cs +++ b/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ namespace Microsoft.Extensions.DependencyInjection { @@ -25,70 +28,70 @@ namespace Microsoft.Extensions.Options public partial class ConfigureNamedOptions : Microsoft.Extensions.Options.IConfigureNamedOptions, Microsoft.Extensions.Options.IConfigureOptions where TOptions : class { public ConfigureNamedOptions(string name, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public string Name { get { throw null; } } public virtual void Configure(string name, TOptions options) { } public void Configure(TOptions options) { } } public partial class ConfigureNamedOptions : Microsoft.Extensions.Options.IConfigureNamedOptions, Microsoft.Extensions.Options.IConfigureOptions where TOptions : class where TDep : class { public ConfigureNamedOptions(string name, TDep dependency, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep Dependency { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep Dependency { get { throw null; } } + public string Name { get { throw null; } } public virtual void Configure(string name, TOptions options) { } public void Configure(TOptions options) { } } public partial class ConfigureNamedOptions : Microsoft.Extensions.Options.IConfigureNamedOptions, Microsoft.Extensions.Options.IConfigureOptions where TOptions : class where TDep1 : class where TDep2 : class { public ConfigureNamedOptions(string name, TDep1 dependency, TDep2 dependency2, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public string Name { get { throw null; } } public virtual void Configure(string name, TOptions options) { } public void Configure(TOptions options) { } } public partial class ConfigureNamedOptions : Microsoft.Extensions.Options.IConfigureNamedOptions, Microsoft.Extensions.Options.IConfigureOptions where TOptions : class where TDep1 : class where TDep2 : class where TDep3 : class { public ConfigureNamedOptions(string name, TDep1 dependency, TDep2 dependency2, TDep3 dependency3, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep3 Dependency3 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public TDep3 Dependency3 { get { throw null; } } + public string Name { get { throw null; } } public virtual void Configure(string name, TOptions options) { } public void Configure(TOptions options) { } } public partial class ConfigureNamedOptions : Microsoft.Extensions.Options.IConfigureNamedOptions, Microsoft.Extensions.Options.IConfigureOptions where TOptions : class where TDep1 : class where TDep2 : class where TDep3 : class where TDep4 : class { public ConfigureNamedOptions(string name, TDep1 dependency1, TDep2 dependency2, TDep3 dependency3, TDep4 dependency4, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep3 Dependency3 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep4 Dependency4 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public TDep3 Dependency3 { get { throw null; } } + public TDep4 Dependency4 { get { throw null; } } + public string Name { get { throw null; } } public virtual void Configure(string name, TOptions options) { } public void Configure(TOptions options) { } } public partial class ConfigureNamedOptions : Microsoft.Extensions.Options.IConfigureNamedOptions, Microsoft.Extensions.Options.IConfigureOptions where TOptions : class where TDep1 : class where TDep2 : class where TDep3 : class where TDep4 : class where TDep5 : class { public ConfigureNamedOptions(string name, TDep1 dependency1, TDep2 dependency2, TDep3 dependency3, TDep4 dependency4, TDep5 dependency5, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep3 Dependency3 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep4 Dependency4 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep5 Dependency5 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public TDep3 Dependency3 { get { throw null; } } + public TDep4 Dependency4 { get { throw null; } } + public TDep5 Dependency5 { get { throw null; } } + public string Name { get { throw null; } } public virtual void Configure(string name, TOptions options) { } public void Configure(TOptions options) { } } public partial class ConfigureOptions : Microsoft.Extensions.Options.IConfigureOptions where TOptions : class { public ConfigureOptions(System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } public virtual void Configure(TOptions options) { } } public partial interface IConfigureNamedOptions : Microsoft.Extensions.Options.IConfigureOptions where TOptions : class @@ -145,8 +148,8 @@ public static partial class Options public partial class OptionsBuilder where TOptions : class { public OptionsBuilder(Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name) { } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public Microsoft.Extensions.DependencyInjection.IServiceCollection Services { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public string Name { get { throw null; } } + public Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get { throw null; } } public virtual Microsoft.Extensions.Options.OptionsBuilder Configure(System.Action configureOptions) { throw null; } public virtual Microsoft.Extensions.Options.OptionsBuilder Configure(System.Action configureOptions) where TDep : class { throw null; } public virtual Microsoft.Extensions.Options.OptionsBuilder Configure(System.Action configureOptions) where TDep1 : class where TDep2 : class { throw null; } @@ -208,75 +211,75 @@ public void Dispose() { } public partial class OptionsValidationException : System.Exception { public OptionsValidationException(string optionsName, System.Type optionsType, System.Collections.Generic.IEnumerable failureMessages) { } - public System.Collections.Generic.IEnumerable Failures { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Collections.Generic.IEnumerable Failures { get { throw null; } } public override string Message { get { throw null; } } - public string OptionsName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Type OptionsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public string OptionsName { get { throw null; } } + public System.Type OptionsType { get { throw null; } } } public partial class OptionsWrapper : Microsoft.Extensions.Options.IOptions where TOptions : class { public OptionsWrapper(TOptions options) { } - public TOptions Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public TOptions Value { get { throw null; } } } public partial class PostConfigureOptions : Microsoft.Extensions.Options.IPostConfigureOptions where TOptions : class { public PostConfigureOptions(string name, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public string Name { get { throw null; } } public virtual void PostConfigure(string name, TOptions options) { } } public partial class PostConfigureOptions : Microsoft.Extensions.Options.IPostConfigureOptions where TOptions : class where TDep : class { public PostConfigureOptions(string name, TDep dependency, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep Dependency { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep Dependency { get { throw null; } } + public string Name { get { throw null; } } public virtual void PostConfigure(string name, TOptions options) { } public void PostConfigure(TOptions options) { } } public partial class PostConfigureOptions : Microsoft.Extensions.Options.IPostConfigureOptions where TOptions : class where TDep1 : class where TDep2 : class { public PostConfigureOptions(string name, TDep1 dependency, TDep2 dependency2, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public string Name { get { throw null; } } public virtual void PostConfigure(string name, TOptions options) { } public void PostConfigure(TOptions options) { } } public partial class PostConfigureOptions : Microsoft.Extensions.Options.IPostConfigureOptions where TOptions : class where TDep1 : class where TDep2 : class where TDep3 : class { public PostConfigureOptions(string name, TDep1 dependency, TDep2 dependency2, TDep3 dependency3, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep3 Dependency3 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public TDep3 Dependency3 { get { throw null; } } + public string Name { get { throw null; } } public virtual void PostConfigure(string name, TOptions options) { } public void PostConfigure(TOptions options) { } } public partial class PostConfigureOptions : Microsoft.Extensions.Options.IPostConfigureOptions where TOptions : class where TDep1 : class where TDep2 : class where TDep3 : class where TDep4 : class { public PostConfigureOptions(string name, TDep1 dependency1, TDep2 dependency2, TDep3 dependency3, TDep4 dependency4, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep3 Dependency3 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep4 Dependency4 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public TDep3 Dependency3 { get { throw null; } } + public TDep4 Dependency4 { get { throw null; } } + public string Name { get { throw null; } } public virtual void PostConfigure(string name, TOptions options) { } public void PostConfigure(TOptions options) { } } public partial class PostConfigureOptions : Microsoft.Extensions.Options.IPostConfigureOptions where TOptions : class where TDep1 : class where TDep2 : class where TDep3 : class where TDep4 : class where TDep5 : class { public PostConfigureOptions(string name, TDep1 dependency1, TDep2 dependency2, TDep3 dependency3, TDep4 dependency4, TDep5 dependency5, System.Action action) { } - public System.Action Action { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep3 Dependency3 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep4 Dependency4 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep5 Dependency5 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public System.Action Action { get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public TDep3 Dependency3 { get { throw null; } } + public TDep4 Dependency4 { get { throw null; } } + public TDep5 Dependency5 { get { throw null; } } + public string Name { get { throw null; } } public virtual void PostConfigure(string name, TOptions options) { } public void PostConfigure(TOptions options) { } } @@ -285,75 +288,75 @@ public partial class ValidateOptionsResult public static readonly Microsoft.Extensions.Options.ValidateOptionsResult Skip; public static readonly Microsoft.Extensions.Options.ValidateOptionsResult Success; public ValidateOptionsResult() { } - public bool Failed { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] protected set { } } - public string FailureMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] protected set { } } - public System.Collections.Generic.IEnumerable Failures { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] protected set { } } - public bool Skipped { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] protected set { } } - public bool Succeeded { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] protected set { } } + public bool Failed { get { throw null; } protected set { } } + public string FailureMessage { get { throw null; } protected set { } } + public System.Collections.Generic.IEnumerable Failures { get { throw null; } protected set { } } + public bool Skipped { get { throw null; } protected set { } } + public bool Succeeded { get { throw null; } protected set { } } public static Microsoft.Extensions.Options.ValidateOptionsResult Fail(System.Collections.Generic.IEnumerable failures) { throw null; } public static Microsoft.Extensions.Options.ValidateOptionsResult Fail(string failureMessage) { throw null; } } public partial class ValidateOptions : Microsoft.Extensions.Options.IValidateOptions where TOptions : class { public ValidateOptions(string name, System.Func validation, string failureMessage) { } - public string FailureMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Func Validation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public string FailureMessage { get { throw null; } } + public string Name { get { throw null; } } + public System.Func Validation { get { throw null; } } public Microsoft.Extensions.Options.ValidateOptionsResult Validate(string name, TOptions options) { throw null; } } public partial class ValidateOptions : Microsoft.Extensions.Options.IValidateOptions where TOptions : class { public ValidateOptions(string name, TDep dependency, System.Func validation, string failureMessage) { } - public TDep Dependency { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string FailureMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Func Validation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public TDep Dependency { get { throw null; } } + public string FailureMessage { get { throw null; } } + public string Name { get { throw null; } } + public System.Func Validation { get { throw null; } } public Microsoft.Extensions.Options.ValidateOptionsResult Validate(string name, TOptions options) { throw null; } } public partial class ValidateOptions : Microsoft.Extensions.Options.IValidateOptions where TOptions : class { public ValidateOptions(string name, TDep1 dependency1, TDep2 dependency2, System.Func validation, string failureMessage) { } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string FailureMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Func Validation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public string FailureMessage { get { throw null; } } + public string Name { get { throw null; } } + public System.Func Validation { get { throw null; } } public Microsoft.Extensions.Options.ValidateOptionsResult Validate(string name, TOptions options) { throw null; } } public partial class ValidateOptions : Microsoft.Extensions.Options.IValidateOptions where TOptions : class { public ValidateOptions(string name, TDep1 dependency1, TDep2 dependency2, TDep3 dependency3, System.Func validation, string failureMessage) { } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep3 Dependency3 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string FailureMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Func Validation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public TDep3 Dependency3 { get { throw null; } } + public string FailureMessage { get { throw null; } } + public string Name { get { throw null; } } + public System.Func Validation { get { throw null; } } public Microsoft.Extensions.Options.ValidateOptionsResult Validate(string name, TOptions options) { throw null; } } public partial class ValidateOptions : Microsoft.Extensions.Options.IValidateOptions where TOptions : class { public ValidateOptions(string name, TDep1 dependency1, TDep2 dependency2, TDep3 dependency3, TDep4 dependency4, System.Func validation, string failureMessage) { } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep3 Dependency3 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep4 Dependency4 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string FailureMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Func Validation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public TDep3 Dependency3 { get { throw null; } } + public TDep4 Dependency4 { get { throw null; } } + public string FailureMessage { get { throw null; } } + public string Name { get { throw null; } } + public System.Func Validation { get { throw null; } } public Microsoft.Extensions.Options.ValidateOptionsResult Validate(string name, TOptions options) { throw null; } } public partial class ValidateOptions : Microsoft.Extensions.Options.IValidateOptions where TOptions : class { public ValidateOptions(string name, TDep1 dependency1, TDep2 dependency2, TDep3 dependency3, TDep4 dependency4, TDep5 dependency5, System.Func validation, string failureMessage) { } - public TDep1 Dependency1 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep2 Dependency2 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep3 Dependency3 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep4 Dependency4 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public TDep5 Dependency5 { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string FailureMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } - public System.Func Validation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } + public TDep1 Dependency1 { get { throw null; } } + public TDep2 Dependency2 { get { throw null; } } + public TDep3 Dependency3 { get { throw null; } } + public TDep4 Dependency4 { get { throw null; } } + public TDep5 Dependency5 { get { throw null; } } + public string FailureMessage { get { throw null; } } + public string Name { get { throw null; } } + public System.Func Validation { get { throw null; } } public Microsoft.Extensions.Options.ValidateOptionsResult Validate(string name, TOptions options) { throw null; } } } diff --git a/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.csproj b/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.csproj index df0de680df1f81..a119724225afd6 100644 --- a/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.csproj +++ b/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.csproj @@ -3,11 +3,11 @@ netstandard2.0;netstandard2.1 - + - - + + diff --git a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj index 3d3c2ae30473ab..a2fb7384785946 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj +++ b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj @@ -1,19 +1,24 @@ - netstandard2.0;$(DefaultNetCoreTargetFramework) - $(DefaultNetCoreTargetFramework) + netstandard2.0;$(NetCoreAppCurrent) + true - - - - + + + + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs index 457b5218eacfa0..164fc84c935197 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs @@ -155,8 +155,8 @@ private static IEnumerable FindIConfigureOptions(Type type) { throw new InvalidOperationException( IsAction(type) - ? Resources.Error_NoIConfigureOptionsAndAction - : Resources.Error_NoIConfigureOptions); + ? SR.Error_NoIConfigureOptionsAndAction + : SR.Error_NoIConfigureOptions); } return serviceTypes; } diff --git a/src/libraries/Microsoft.Extensions.Options/src/Properties/InternalsVisibleTo.cs b/src/libraries/Microsoft.Extensions.Options/src/Properties/InternalsVisibleTo.cs new file mode 100644 index 00000000000000..20cf4cac86329e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options/src/Properties/InternalsVisibleTo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.Options.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj index ea3f5bbdba2662..c4f7c1a92fd6fa 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj @@ -2,6 +2,7 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index 37f8f8a869baf7..c75aa6129cb365 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -37,6 +37,7 @@ public partial interface IChangeToken bool HasChanged { get; } System.IDisposable RegisterChangeCallback(System.Action callback, object state); } + [System.ObsoleteAttribute("This type is obsolete and will be removed in a future version.")] public partial struct InplaceStringBuilder { private object _dummy; diff --git a/src/libraries/Microsoft.Extensions.Primitives/tests/Microsoft.Extensions.Primitives.Tests.csproj b/src/libraries/Microsoft.Extensions.Primitives/tests/Microsoft.Extensions.Primitives.Tests.csproj index 09e032e80f957d..224c54a8cedf89 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/tests/Microsoft.Extensions.Primitives.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Primitives/tests/Microsoft.Extensions.Primitives.Tests.csproj @@ -16,9 +16,5 @@ - - - - diff --git a/src/libraries/Native/Unix/CMakeLists.txt b/src/libraries/Native/Unix/CMakeLists.txt index ef99465e3c77e6..f32da9d6563471 100644 --- a/src/libraries/Native/Unix/CMakeLists.txt +++ b/src/libraries/Native/Unix/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_policy(SET CMP0042 NEW) project(CoreFX C) -include(${CLR_ENG_NATIVE_DIR}/configureplatform.cmake) +include(${CLR_ENG_NATIVE_DIR}/configuretools.cmake) if(CLR_CMAKE_TARGET_IOS) cmake_minimum_required(VERSION 3.14.5) @@ -36,7 +36,11 @@ if(CMAKE_C_COMPILER_ID STREQUAL Clang) add_compile_options(-Wthread-safety) add_compile_options(-Wno-thread-safety-analysis) endif() -add_compile_options(-Werror) + +# Suppress warnings-as-errors in release branches to reduce servicing churn +if (PRERELEASE) + add_compile_options(-Werror) +endif() if(CLR_CMAKE_TARGET_ARCH_WASM) add_definitions(-D_WASM_) @@ -84,6 +88,11 @@ elseif (CLR_CMAKE_TARGET_ARCH_ARM) endif() endif () +if(CLR_CMAKE_TARGET_ANDROID) + add_definitions(-DTARGET_ANDROID) + include_directories(SYSTEM "${CROSS_ROOTFS}/usr/include") +endif() + string(TOUPPER ${CMAKE_BUILD_TYPE} UPPERCASE_CMAKE_BUILD_TYPE) if (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG) add_compile_options(-O0) @@ -195,7 +204,6 @@ function(install_library_and_symbols targetName) endfunction() include(configure.cmake) -include(${CLR_ENG_NATIVE_DIR}/configuretools.cmake) add_subdirectory(System.IO.Compression.Native) diff --git a/src/libraries/Native/Unix/Common/pal_config.h.in b/src/libraries/Native/Unix/Common/pal_config.h.in index 08e9fe7fd9f3ef..e1b4a3f9625593 100644 --- a/src/libraries/Native/Unix/Common/pal_config.h.in +++ b/src/libraries/Native/Unix/Common/pal_config.h.in @@ -100,6 +100,7 @@ #cmakedefine01 HAVE_TCP_H_TCP_KEEPALIVE #cmakedefine01 HAVE_BUILTIN_MUL_OVERFLOW #cmakedefine01 HAVE_DISCONNECTX +#cmakedefine01 HAVE_PTHREAD_SETCANCELSTATE // Mac OS X has stat64, but it is deprecated since plain stat now // provides the same 64-bit aware struct when targeting OS X > 10.5 diff --git a/src/libraries/Native/Unix/System.Globalization.Native/configure.cmake b/src/libraries/Native/Unix/System.Globalization.Native/configure.cmake index 75388ab621136a..6114a1bb31ed67 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/configure.cmake +++ b/src/libraries/Native/Unix/System.Globalization.Native/configure.cmake @@ -3,6 +3,11 @@ include(CheckSymbolExists) set(CMAKE_REQUIRED_INCLUDES ${UTYPES_H} ${ICU_HOMEBREW_INC_PATH}) +if(CLR_CMAKE_TARGET_ANDROID) + string(REPLACE ";" ":" ANDROID_RPATHS "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}:${CMAKE_SYSTEM_LIBRARY_PATH}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rpath ${ANDROID_RPATHS}") +endif() + CHECK_C_SOURCE_COMPILES(" #include int main(void) { enum UDateFormatSymbolType e = UDAT_STANDALONE_SHORTER_WEEKDAYS; } diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_localeNumberData.c b/src/libraries/Native/Unix/System.Globalization.Native/pal_localeNumberData.c index 0beae272c7aff7..b05ae709a278d5 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_localeNumberData.c +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_localeNumberData.c @@ -19,6 +19,7 @@ #define UCHAR_PERCENT ((UChar)0x0025) // '%' #define UCHAR_OPENPAREN ((UChar)0x0028) // '(' #define UCHAR_CLOSEPAREN ((UChar)0x0029) // ')' +#define UCHAR_ZERO ((UChar)0x0030) // '0' #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) @@ -101,6 +102,7 @@ static char* NormalizeNumericPattern(const UChar* srcPattern, int isNegative) switch (ch) { case UCHAR_DIGIT: + case UCHAR_ZERO: if (!digitAdded) { digitAdded = TRUE; @@ -123,10 +125,6 @@ static char* NormalizeNumericPattern(const UChar* srcPattern, int isNegative) spaceAdded = TRUE; destPattern[index++] = ' '; } - else - { - assert(FALSE); - } break; case UCHAR_MINUS: @@ -200,8 +198,7 @@ static int GetNumericPattern(const UNumberFormat* pNumberFormat, } } - // TODO: https://github.com/dotnet/runtime/issues/946 - // assert(FALSE); // should have found a valid pattern + assert(FALSE); // should have found a valid pattern free(normalizedPattern); return INVALID_FORMAT; @@ -232,7 +229,8 @@ static int GetCurrencyNegativePattern(const char* locale) "C -n", "n- C", "(C n)", - "(n C)"}; + "(n C)", + "C- n" }; UErrorCode status = U_ZERO_ERROR; UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status); diff --git a/src/libraries/Native/Unix/System.Native/pal_console.c b/src/libraries/Native/Unix/System.Native/pal_console.c index e2f15174001fbb..00ca624c1b840b 100644 --- a/src/libraries/Native/Unix/System.Native/pal_console.c +++ b/src/libraries/Native/Unix/System.Native/pal_console.c @@ -34,6 +34,7 @@ int32_t SystemNative_GetWindowSize(WinSize* windowSize) return error; #else + (void)windowSize; // unused errno = ENOTSUP; return -1; #endif diff --git a/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c b/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c index 1a6986845c8173..4d090d3d9686a5 100644 --- a/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c +++ b/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c @@ -114,7 +114,7 @@ int32_t SystemNative_EnumerateInterfaceAddresses(IPv4AddressFound onIpv4Found, freeifaddrs(headAddr); return -1; } - + assert(result == actualName); int family = current->ifa_addr->sa_family; if (family == AF_INET) @@ -377,7 +377,11 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter ecmd.cmd = ETHTOOL_GSET; if (ioctl(socketfd, SIOCETHTOOL, &ifr) == 0) { +#ifdef TARGET_ANDROID + nii->Speed = (int64_t)ecmd.speed; +#else nii->Speed = (int64_t)ethtool_cmd_speed(&ecmd); +#endif if (nii->Speed > 0) { // If we did not get -1 diff --git a/src/libraries/Native/Unix/System.Native/pal_io.c b/src/libraries/Native/Unix/System.Native/pal_io.c index 5a8ecbab53a1d6..8706e136425fbb 100644 --- a/src/libraries/Native/Unix/System.Native/pal_io.c +++ b/src/libraries/Native/Unix/System.Native/pal_io.c @@ -913,18 +913,20 @@ int32_t SystemNative_Poll(PollEvent* pollEvents, uint32_t eventCount, int32_t mi return Error_EINVAL; } - size_t bufferSize; - if (!multiply_s(sizeof(struct pollfd), (size_t)eventCount, &bufferSize)) + struct pollfd stackBuffer[(uint32_t)(2048/sizeof(struct pollfd))]; + int useStackBuffer = eventCount <= (sizeof(stackBuffer)/sizeof(stackBuffer[0])); + struct pollfd* pollfds = NULL; + if (useStackBuffer) { - return SystemNative_ConvertErrorPlatformToPal(EOVERFLOW); + pollfds = (struct pollfd*)&stackBuffer[0]; } - - - int useStackBuffer = bufferSize <= 2048; - struct pollfd* pollfds = (struct pollfd*)(useStackBuffer ? alloca(bufferSize) : malloc(bufferSize)); - if (pollfds == NULL) + else { - return Error_ENOMEM; + pollfds = (struct pollfd*)calloc(eventCount, sizeof(*pollfds)); + if (pollfds == NULL) + { + return Error_ENOMEM; + } } for (uint32_t i = 0; i < eventCount; i++) diff --git a/src/libraries/Native/Unix/System.Native/pal_networking.c b/src/libraries/Native/Unix/System.Native/pal_networking.c index 426b831bae4680..f036fe98029909 100644 --- a/src/libraries/Native/Unix/System.Native/pal_networking.c +++ b/src/libraries/Native/Unix/System.Native/pal_networking.c @@ -394,7 +394,7 @@ int32_t SystemNative_GetHostEntryForName(const uint8_t* address, HostEntry* entr } // Skip loopback addresses if at least one interface has non-loopback one. - if ((!includeIPv4Loopback && ifa->ifa_addr->sa_family == AF_INET && (ifa->ifa_flags & IFF_LOOPBACK) != 0) || + if ((!includeIPv4Loopback && ifa->ifa_addr->sa_family == AF_INET && (ifa->ifa_flags & IFF_LOOPBACK) != 0) || (!includeIPv6Loopback && ifa->ifa_addr->sa_family == AF_INET6 && (ifa->ifa_flags & IFF_LOOPBACK) != 0)) { entry->IPAddressCount--; @@ -904,7 +904,7 @@ static void ConvertMessageHeaderToMsghdr(struct msghdr* header, const MessageHea iovlen = (int)IOV_MAX; } header->msg_name = messageHeader->SocketAddress; - header->msg_namelen = (unsigned int)messageHeader->SocketAddressLen; + header->msg_namelen = (socklen_t)messageHeader->SocketAddressLen; header->msg_iov = (struct iovec*)messageHeader->IOVectors; header->msg_iovlen = (__typeof__(header->msg_iovlen))iovlen; header->msg_control = messageHeader->ControlBuffer; @@ -1474,7 +1474,7 @@ int32_t SystemNative_Bind(intptr_t socket, int32_t protocolType, uint8_t* socket if (socketAddress == NULL || socketAddressLen < 0) { return Error_EFAULT; - } + } int fd = ToFileDescriptor(socket); diff --git a/src/libraries/Native/Unix/System.Native/pal_process.c b/src/libraries/Native/Unix/System.Native/pal_process.c index 529be7d428c52e..641ac120a3269a 100644 --- a/src/libraries/Native/Unix/System.Native/pal_process.c +++ b/src/libraries/Native/Unix/System.Native/pal_process.c @@ -227,12 +227,15 @@ int32_t SystemNative_ForkAndExecProcess(const char* filename, int stdinFds[2] = {-1, -1}, stdoutFds[2] = {-1, -1}, stderrFds[2] = {-1, -1}, waitForChildToExecPipe[2] = {-1, -1}; pid_t processId = -1; uint32_t* getGroupsBuffer = NULL; - int thread_cancel_state; sigset_t signal_set; sigset_t old_signal_set; +#ifndef HAVE_PTHREAD_SETCANCELSTATE + int thread_cancel_state; + // None of this code can be canceled without leaking handles, so just don't allow it pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &thread_cancel_state); +#endif // Validate arguments if (NULL == filename || NULL == argv || NULL == envp || NULL == stdinFd || NULL == stdoutFd || @@ -498,9 +501,11 @@ done:; errno = priorErrno; } +#ifndef HAVE_PTHREAD_SETCANCELSTATE // Restore thread cancel state pthread_setcancelstate(thread_cancel_state, &thread_cancel_state); - +#endif + free(getGroupsBuffer); return success ? 0 : -1; @@ -593,7 +598,7 @@ static void ConvertFromPalRLimitToManaged(const struct rlimit* native, RLimit* p pal->MaximumLimit = ConvertFromNativeRLimitInfinityToManagedIfNecessary(native->rlim_max); } -#if defined __USE_GNU && !defined __cplusplus +#if defined(__USE_GNU) && !defined(__cplusplus) && !defined(TARGET_ANDROID) typedef __rlimit_resource_t rlimitResource; typedef __priority_which_t priorityWhich; #else @@ -788,7 +793,7 @@ int32_t SystemNative_SchedSetAffinity(int32_t pid, intptr_t* mask) cpu_set_t set; CPU_ZERO(&set); - intptr_t bits = *mask; + intptr_t bits = *mask; for (int cpu = 0; cpu < maxCpu; cpu++) { if ((bits & (((intptr_t)1u) << cpu)) != 0) @@ -796,7 +801,7 @@ int32_t SystemNative_SchedSetAffinity(int32_t pid, intptr_t* mask) CPU_SET(cpu, &set); } } - + return sched_setaffinity(pid, sizeof(cpu_set_t), &set); } #endif diff --git a/src/libraries/Native/Unix/System.Native/pal_time.c b/src/libraries/Native/Unix/System.Native/pal_time.c index ce22f91ff2e6df..924f3a63e04861 100644 --- a/src/libraries/Native/Unix/System.Native/pal_time.c +++ b/src/libraries/Native/Unix/System.Native/pal_time.c @@ -117,7 +117,7 @@ int32_t SystemNative_GetCpuUtilization(ProcessCpuInformation* previousCpuInfo) uint64_t resolution = SystemNative_GetTimestampResolution(); uint64_t timestamp = SystemNative_GetTimestamp(); - uint64_t currentTime = (uint64_t)(timestamp * ((double)SecondsToNanoSeconds / resolution)); + uint64_t currentTime = (uint64_t)((double)timestamp * ((double)SecondsToNanoSeconds / (double)resolution)); uint64_t lastRecordedCurrentTime = previousCpuInfo->lastRecordedCurrentTime; uint64_t lastRecordedKernelTime = previousCpuInfo->lastRecordedKernelTime; diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ecdsa.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ecdsa.c index 27889bbf901cdd..46d1abc6e95f84 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ecdsa.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_ecdsa.c @@ -13,7 +13,7 @@ CryptoNative_EcDsaSign(const uint8_t* dgst, int32_t dgstlen, uint8_t* sig, int32 return 0; } - unsigned int unsignedSigLength = Int32ToUint32(*siglen); + unsigned int unsignedSigLength = 0; int ret = ECDSA_sign(0, dgst, dgstlen, sig, &unsignedSigLength, key); *siglen = Uint32ToInt32(unsignedSigLength); return ret; diff --git a/src/libraries/Native/Unix/configure.cmake b/src/libraries/Native/Unix/configure.cmake index 473157178a2c2c..6641104a99fdfc 100644 --- a/src/libraries/Native/Unix/configure.cmake +++ b/src/libraries/Native/Unix/configure.cmake @@ -6,6 +6,7 @@ include(CheckPrototypeDefinition) include(CheckStructHasMember) include(CheckSymbolExists) include(CheckTypeSize) +include(CheckFunctionExists) if (CLR_CMAKE_TARGET_LINUX) set(PAL_UNIX_NAME \"LINUX\") @@ -899,6 +900,8 @@ check_c_source_compiles( " HAVE_BUILTIN_MUL_OVERFLOW) +check_function_exists(pthread_setcancelstate HAVE_PTHREAD_SETCANCELSTATE) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/Common/pal_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/Common/pal_config.h) diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs index 6e05c9b7c7e86a..4c91c651b28e43 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.cs @@ -2105,6 +2105,9 @@ public sealed partial class Encoder public static readonly System.Drawing.Imaging.Encoder ScanMethod; public static readonly System.Drawing.Imaging.Encoder Transformation; public static readonly System.Drawing.Imaging.Encoder Version; + public static readonly System.Drawing.Imaging.Encoder ColorSpace; + public static readonly System.Drawing.Imaging.Encoder ImageItems; + public static readonly System.Drawing.Imaging.Encoder SaveAsCmyk; public Encoder(System.Guid guid) { } public System.Guid Guid { get { throw null; } } } @@ -2152,6 +2155,7 @@ public enum EncoderParameterValueType ValueTypeLongRange = 6, ValueTypeUndefined = 7, ValueTypeRationalRange = 8, + ValueTypePointer = 9, } public enum EncoderValue { diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Encoder.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Encoder.cs index 30b92a8a34c103..a9c401cdb81d50 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Encoder.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Encoder.cs @@ -17,6 +17,21 @@ public sealed class Encoder public static readonly Encoder ChrominanceTable = new Encoder(new Guid(unchecked((int)0xf2e455dc), unchecked((short)0x09b3), unchecked((short)0x4316), new byte[] { 0x82, 0x60, 0x67, 0x6a, 0xda, 0x32, 0x48, 0x1c })); public static readonly Encoder SaveFlag = new Encoder(new Guid(unchecked((int)0x292266fc), unchecked((short)0xac40), unchecked((short)0x47bf), new byte[] { 0x8c, 0xfc, 0xa8, 0x5b, 0x89, 0xa6, 0x55, 0xde })); + /// + /// An object that is initialized with the globally unique identifier for the color space category. + /// + public static readonly Encoder ColorSpace = new Encoder(new Guid(unchecked((int)0xae7a62a0), unchecked((short)0xee2c), unchecked((short)0x49d8), new byte[] { 0x9d, 0x07, 0x1b, 0xa8, 0xa9, 0x27, 0x59, 0x6e })); + + /// + /// An object that is initialized with the globally unique identifier for the image items category. + /// + public static readonly Encoder ImageItems = new Encoder(new Guid(unchecked((int)0x63875e13), unchecked((short)0x1f1d), unchecked((short)0x45ab), new byte[] { 0x91, 0x95, 0xa2, 0x9b, 0x60, 0x66, 0xa6, 0x50 })); + + /// + /// An object that is initialized with the globally unique identifier for the save as CMYK category. + /// + public static readonly Encoder SaveAsCmyk = new Encoder(new Guid(unchecked((int)0xa219bbc9), unchecked((short)0x0a9d), unchecked((short)0x4005), new byte[] { 0xa3, 0xee, 0x3a, 0x42, 0x1b, 0x8b, 0xb0, 0x6c })); + private Guid _guid; public Encoder(Guid guid) diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/EncoderParameter.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/EncoderParameter.cs index 55a04fe2b6b8d5..51011d5557d8fb 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/EncoderParameter.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/EncoderParameter.cs @@ -381,6 +381,9 @@ public EncoderParameter(Encoder encoder, int numberValues, EncoderParameterValue case EncoderParameterValueType.ValueTypeRationalRange: size = 2 * 2 * 4; break; + case EncoderParameterValueType.ValueTypePointer: + size = IntPtr.Size; + break; default: throw Gdip.StatusException(Gdip.WrongState); } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/EncoderParameterValueType.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/EncoderParameterValueType.cs index 9b9f073d63032b..78950e22ce8e60 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/EncoderParameterValueType.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/EncoderParameterValueType.cs @@ -44,6 +44,10 @@ public enum EncoderParameterValueType /// Two Rationals. The first Rational specifies the lower end and the second specifies the higher end. /// All values are inclusive at both ends /// - ValueTypeRationalRange = 8 + ValueTypeRationalRange = 8, + /// + /// The parameter is a pointer to a block of custom metadata. + /// + ValueTypePointer = 9, } } diff --git a/src/libraries/System.Drawing.Common/tests/ImageTests.cs b/src/libraries/System.Drawing.Common/tests/ImageTests.cs index c9147dc81b216c..ebf65b2235a23c 100644 --- a/src/libraries/System.Drawing.Common/tests/ImageTests.cs +++ b/src/libraries/System.Drawing.Common/tests/ImageTests.cs @@ -157,6 +157,23 @@ public static IEnumerable GetEncoderParameterList_ReturnsExpected_Test new Guid(unchecked((int)0xa219bbc9), unchecked((short)0x0a9d), unchecked((short)0x4005), new byte[] { 0xa3, 0xee, 0x3a, 0x42, 0x1b, 0x8b, 0xb0, 0x6c }) /* Encoder.SaveAsCmyk.Guid */ } }; + +#if !NETFRAMEWORK + // NetFX doesn't support pointer-type encoder parameters, and doesn't define Encoder.ImageItems. Skip this test + // on NetFX. + yield return new object[] + { + ImageFormat.Jpeg, + new Guid[] + { + Encoder.Transformation.Guid, + Encoder.Quality.Guid, + Encoder.LuminanceTable.Guid, + Encoder.ChrominanceTable.Guid, + Encoder.ImageItems.Guid + } + }; +#endif } [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] diff --git a/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoAll.cs b/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoAll.cs index f20cecc147156d..028cf71e49780a 100644 --- a/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoAll.cs +++ b/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoAll.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +using Microsoft.DotNet.RemoteExecutor; using System.Text; using Xunit; @@ -631,10 +632,13 @@ public void GetCulturesTest(string cultureName, int lcid, string specificCulture [Fact] public void ClearCachedDataTest() { - CultureInfo ci = CultureInfo.GetCultureInfo("ja-JP"); - Assert.True((object) ci == (object) CultureInfo.GetCultureInfo("ja-JP"), "Expected getting same object reference"); - ci.ClearCachedData(); - Assert.False((object) ci == (object) CultureInfo.GetCultureInfo("ja-JP"), "expected to get a new object reference"); + RemoteExecutor.Invoke(() => + { + CultureInfo ci = CultureInfo.GetCultureInfo("ja-JP"); + Assert.True((object) ci == (object) CultureInfo.GetCultureInfo("ja-JP"), "Expected getting same object reference"); + ci.ClearCachedData(); + Assert.False((object) ci == (object) CultureInfo.GetCultureInfo("ja-JP"), "expected to get a new object reference"); + }).Dispose(); } [Fact] diff --git a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoTests.cs b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoTests.cs index 4602ca86526baa..a6cfb1becc01c5 100644 --- a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoTests.cs +++ b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoTests.cs @@ -87,6 +87,20 @@ public void NativeDigitsTest() Assert.Equal(newDigits, nfi.NativeDigits); } + [Fact] + public void TestNFIFormatLimits() + { + foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures)) + { + NumberFormatInfo nfi = ci.NumberFormat; + Assert.InRange(nfi.CurrencyNegativePattern, 0, 16); + Assert.InRange(nfi.CurrencyPositivePattern, 0, 3); + Assert.InRange(nfi.PercentNegativePattern, 0, 11); + Assert.InRange(nfi.PercentPositivePattern, 0, 3); + Assert.InRange(nfi.NumberNegativePattern, 0, 4); + } + } + [Theory] [MemberData(nameof(DigitSubstitution_TestData))] public void DigitSubstitutionListTest(string cultureName, DigitShapes shape) diff --git a/src/libraries/System.Globalization/tests/System/Globalization/RegionInfoTests.cs b/src/libraries/System.Globalization/tests/System/Globalization/RegionInfoTests.cs index 204365e4da4346..f7295268e97f4d 100644 --- a/src/libraries/System.Globalization/tests/System/Globalization/RegionInfoTests.cs +++ b/src/libraries/System.Globalization/tests/System/Globalization/RegionInfoTests.cs @@ -52,7 +52,7 @@ public void Ctor_InvalidName_ThrowsArgumentException(string name) AssertExtensions.Throws("name", () => new RegionInfo(name)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows))] public void CurrentRegion() { using (new ThreadCultureChange("en-US")) @@ -63,6 +63,21 @@ public void CurrentRegion() } } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + public void TestCurrentRegion() + { + RemoteExecutor.Invoke(() => + { + RegionInfo ri = RegionInfo.CurrentRegion; + CultureInfo.CurrentCulture.ClearCachedData(); // clear the current region cached data + + CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("ja-JP"); + + // Changing the current culture shouldn't affect the default current region as we get it from Windows settings. + Assert.Equal(ri.TwoLetterISORegionName, RegionInfo.CurrentRegion.TwoLetterISORegionName); + }).Dispose(); + } + [Theory] [InlineData("en-US", "United States")] [OuterLoop("May fail on machines with multiple language packs installed")] // see https://github.com/dotnet/runtime/issues/30132 diff --git a/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Win32.cs b/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Win32.cs index 2fa89c0b0efc5a..b0cf0b347ef6ee 100644 --- a/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Win32.cs +++ b/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Win32.cs @@ -42,6 +42,10 @@ private unsafe bool GetData() case Interop.StatusOptions.STATUS_SUCCESS: Debug.Assert(statusBlock.Information.ToInt64() != 0); return true; + // FILE_NOT_FOUND can occur when there are NO files in a volume root (usually there are hidden system files). + case Interop.StatusOptions.STATUS_FILE_NOT_FOUND: + DirectoryFinished(); + return false; default: int error = (int)Interop.NtDll.RtlNtStatusToDosError(status); diff --git a/src/libraries/System.Linq.Parallel/src/System/Linq/Parallel/QueryOperators/Unary/SingleQueryOperator.cs b/src/libraries/System.Linq.Parallel/src/System/Linq/Parallel/QueryOperators/Unary/SingleQueryOperator.cs index 519b6e2e297678..d1b30d954a51ef 100644 --- a/src/libraries/System.Linq.Parallel/src/System/Linq/Parallel/QueryOperators/Unary/SingleQueryOperator.cs +++ b/src/libraries/System.Linq.Parallel/src/System/Linq/Parallel/QueryOperators/Unary/SingleQueryOperator.cs @@ -123,7 +123,7 @@ internal SingleQueryOperatorEnumerator(QueryOperatorEnumerator so // Straightforward IEnumerator methods. // - internal override bool MoveNext([MaybeNullWhen(false), AllowNull] ref TSource currentElement, ref int currentKey) + internal override bool MoveNext([AllowNull] ref TSource currentElement, ref int currentKey) { Debug.Assert(_source != null); diff --git a/src/libraries/System.Management/src/System/Management/ManagementScope.cs b/src/libraries/System.Management/src/System/Management/ManagementScope.cs index a0710354a11807..54abbc5b3b2fb0 100644 --- a/src/libraries/System.Management/src/System/Management/ManagementScope.cs +++ b/src/libraries/System.Management/src/System/Management/ManagementScope.cs @@ -1178,11 +1178,8 @@ internal int QueryObjectSink_(int lFlags, ref IWbemObjectSink ppResponseHandler) } internal int GetObject_(string strObjectPath, int lFlags, IWbemContext pCtx, ref IWbemClassObjectFreeThreaded ppObject, IntPtr ppCallResult) { - //It is assumed that caller always passes ppCallResult as IntPtr.Zero. - //If it changes let this call go through wminet_utils.dll. Check implementation of CreateInstanceEnum_ for more information. int status = (int)tag_WBEMSTATUS.WBEM_E_FAILED; - if (!object.ReferenceEquals(ppCallResult, IntPtr.Zero)) - status = pWbemServiecsSecurityHelper.GetObject_(strObjectPath, lFlags, pCtx, out ppObject, ppCallResult); + status = pWbemServiecsSecurityHelper.GetObject_(strObjectPath, lFlags, pCtx, out ppObject, ppCallResult); return status; } @@ -1220,11 +1217,8 @@ internal int PutClassAsync_(IWbemClassObjectFreeThreaded pObject, int lFlags, IW } internal int DeleteClass_(string strClass, int lFlags, IWbemContext pCtx, IntPtr ppCallResult) { - //It is assumed that caller always passes ppCallResult as IntPtr.Zero. - //If it changes let this call go through wminet_utils.dll. Check implementation of CreateInstanceEnum_ for more information. int status = (int)tag_WBEMSTATUS.WBEM_E_FAILED; - if (!object.ReferenceEquals(ppCallResult, IntPtr.Zero)) - status = pWbemServiecsSecurityHelper.DeleteClass_(strClass, lFlags, pCtx, ppCallResult); + status = pWbemServiecsSecurityHelper.DeleteClass_(strClass, lFlags, pCtx, ppCallResult); return status; } internal int DeleteClassAsync_(string strClass, int lFlags, IWbemContext pCtx, IWbemObjectSink pResponseHandler) @@ -1287,11 +1281,8 @@ internal int PutInstanceAsync_(IWbemClassObjectFreeThreaded pInst, int lFlags, I } internal int DeleteInstance_(string strObjectPath, int lFlags, IWbemContext pCtx, IntPtr ppCallResult) { - //It is assumed that caller always passes ppCallResult as IntPtr.Zero. - //If it changes let this call go through wminet_utils.dll. Check implementation of CreateInstanceEnum_ for more information. int status = (int)tag_WBEMSTATUS.WBEM_E_FAILED; - if (!object.ReferenceEquals(ppCallResult, IntPtr.Zero)) - status = pWbemServiecsSecurityHelper.DeleteInstance_(strObjectPath, lFlags, pCtx, ppCallResult); + status = pWbemServiecsSecurityHelper.DeleteInstance_(strObjectPath, lFlags, pCtx, ppCallResult); return status; } internal int DeleteInstanceAsync_(string strObjectPath, int lFlags, IWbemContext pCtx, IWbemObjectSink pResponseHandler) @@ -1383,11 +1374,8 @@ internal int ExecNotificationQueryAsync_(string strQueryLanguage, string strQuer } internal int ExecMethod_(string strObjectPath, string strMethodName, int lFlags, IWbemContext pCtx, IWbemClassObjectFreeThreaded pInParams, ref IWbemClassObjectFreeThreaded ppOutParams, IntPtr ppCallResult) { - //It is assumed that caller always passes ppCallResult as IntPtr.Zero. - //If it changes let this call go through wminet_utils.dll. Check implementation of CreateInstanceEnum_ for more information. int status = (int)tag_WBEMSTATUS.WBEM_E_FAILED; - if (!object.ReferenceEquals(ppCallResult, IntPtr.Zero)) - status = pWbemServiecsSecurityHelper.ExecMethod_(strObjectPath, strMethodName, lFlags, pCtx, pInParams, out ppOutParams, ppCallResult); + status = pWbemServiecsSecurityHelper.ExecMethod_(strObjectPath, strMethodName, lFlags, pCtx, pInParams, out ppOutParams, ppCallResult); return status; } internal int ExecMethodAsync_(string strObjectPath, string strMethodName, int lFlags, IWbemContext pCtx, IWbemClassObjectFreeThreaded pInParams, IWbemObjectSink pResponseHandler) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.Helpers.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.Helpers.cs index 56afdd32e4e8e6..7ba580de25817e 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.Helpers.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.Helpers.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; @@ -517,7 +518,7 @@ private long GetLength() return endIndex - startIndex; } - internal bool TryGetReadOnlySequenceSegment(out ReadOnlySequenceSegment? startSegment, out int startIndex, out ReadOnlySequenceSegment? endSegment, out int endIndex) + internal bool TryGetReadOnlySequenceSegment([NotNullWhen(true)] out ReadOnlySequenceSegment? startSegment, out int startIndex, [NotNullWhen(true)] out ReadOnlySequenceSegment? endSegment, out int endIndex) { object? startObject = _startObject; @@ -555,7 +556,7 @@ internal bool TryGetArray(out ArraySegment segment) return true; } - internal bool TryGetString(out string? text, out int start, out int length) + internal bool TryGetString([NotNullWhen(true)] out string? text, out int start, out int length) { if (typeof(T) != typeof(char) || GetSequenceType() != SequenceType.String) { diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj b/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj index e4c330fa57a30b..c402b8d09db8af 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj @@ -7,6 +7,7 @@ true true $(DefineConstants);WINHTTPHANDLER_DLL + annotations diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs index 6913359c608e59..8219a438e72be7 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs @@ -786,6 +786,8 @@ private async Task StartRequestAsync(WinHttpRequestState state) { EnsureSessionHandleExists(state); + SetEnableHttp2PlusClientCertificate(state.RequestMessage.RequestUri, state.RequestMessage.Version); + // Specify an HTTP server. connectHandle = Interop.WinHttp.WinHttpConnect( _sessionHandle, @@ -996,7 +998,7 @@ private void SetRequestHandleOptions(WinHttpRequestState state) SetRequestHandleRedirectionOptions(state.RequestHandle); SetRequestHandleCookieOptions(state.RequestHandle); SetRequestHandleTlsOptions(state.RequestHandle); - SetRequestHandleClientCertificateOptions(state.RequestHandle, state.RequestMessage.RequestUri); + SetRequestHandleClientCertificateOptions(state.RequestHandle, state.RequestMessage.RequestUri, state.RequestMessage.Version); SetRequestHandleCredentialsOptions(state); SetRequestHandleBufferingOptions(state.RequestHandle); SetRequestHandleHttp2Options(state.RequestHandle, state.RequestMessage.Version); @@ -1153,7 +1155,7 @@ private void SetRequestHandleTlsOptions(SafeWinHttpHandle requestHandle) } } - private void SetRequestHandleClientCertificateOptions(SafeWinHttpHandle requestHandle, Uri requestUri) + private void SetRequestHandleClientCertificateOptions(SafeWinHttpHandle requestHandle, Uri requestUri, Version requestVersion) { if (requestUri.Scheme != UriScheme.Https) { @@ -1184,6 +1186,29 @@ private void SetRequestHandleClientCertificateOptions(SafeWinHttpHandle requestH } } + private void SetEnableHttp2PlusClientCertificate(Uri requestUri, Version requestVersion) + { + if (requestUri.Scheme != UriScheme.Https || requestVersion != HttpVersion20) + { + return; + } + + // Newer versions of WinHTTP fully support HTTP/2 with TLS client certificates. + // But the support must be opted in. + uint optionData = Interop.WinHttp.WINHTTP_HTTP2_PLUS_CLIENT_CERT_FLAG; + if (Interop.WinHttp.WinHttpSetOption( + _sessionHandle, + Interop.WinHttp.WINHTTP_OPTION_ENABLE_HTTP2_PLUS_CLIENT_CERT, + ref optionData)) + { + if (NetEventSource.IsEnabled) NetEventSource.Info(this, "HTTP/2 with TLS client cert supported"); + } + else + { + if (NetEventSource.IsEnabled) NetEventSource.Info(this, "HTTP/2 with TLS client cert not supported"); + } + } + internal static void SetNoClientCertificate(SafeWinHttpHandle requestHandle) { SetWinHttpOption( diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BaseCertificateTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BaseCertificateTest.cs new file mode 100644 index 00000000000000..58ebefb99dc540 --- /dev/null +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BaseCertificateTest.cs @@ -0,0 +1,89 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Http.WinHttpHandlerFunctional.Tests +{ + public abstract class BaseCertificateTest + { + private readonly ITestOutputHelper _output; + + protected readonly ValidationCallbackHistory _validationCallbackHistory; + + public BaseCertificateTest(ITestOutputHelper output) + { + _output = output; + _validationCallbackHistory = new ValidationCallbackHistory(); + } + + public class ValidationCallbackHistory + { + public bool ThrowException; + public bool ReturnFailure; + public bool WasCalled; + public SslPolicyErrors SslPolicyErrors; + public string CertificateSubject; + public X509CertificateCollection CertificateChain; + public X509ChainStatus[] ChainStatus; + + public ValidationCallbackHistory() + { + ThrowException = false; + ReturnFailure = false; + WasCalled = false; + SslPolicyErrors = SslPolicyErrors.None; + CertificateSubject = null; + CertificateChain = new X509CertificateCollection(); + ChainStatus = null; + } + } + + protected bool CustomServerCertificateValidationCallback( + HttpRequestMessage sender, + X509Certificate2 certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + _validationCallbackHistory.WasCalled = true; + _validationCallbackHistory.CertificateSubject = certificate.Subject; + foreach (var element in chain.ChainElements) + { + _validationCallbackHistory.CertificateChain.Add(element.Certificate); + } + _validationCallbackHistory.ChainStatus = chain.ChainStatus; + _validationCallbackHistory.SslPolicyErrors = sslPolicyErrors; + + if (_validationCallbackHistory.ThrowException) + { + throw new CustomException(); + } + + if (_validationCallbackHistory.ReturnFailure) + { + return false; + } + + return true; + } + + protected void ConfirmValidCertificate(string expectedHostName) + { + Assert.Equal(SslPolicyErrors.None, _validationCallbackHistory.SslPolicyErrors); + Assert.True(_validationCallbackHistory.CertificateChain.Count > 0); + _output.WriteLine("Certificate.Subject: {0}", _validationCallbackHistory.CertificateSubject); + _output.WriteLine("Expected HostName: {0}", expectedHostName); + } + + public class CustomException : Exception + { + public CustomException() + { + } + } + } +} diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/ClientCertificateTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/ClientCertificateTest.cs new file mode 100644 index 00000000000000..9dfdeefe8a9a9f --- /dev/null +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/ClientCertificateTest.cs @@ -0,0 +1,119 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Net.Security; +using System.Net.Test.Common; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Http.WinHttpHandlerFunctional.Tests +{ + public class ClientCertificateTest : BaseCertificateTest + { + public static bool DowngradeToHTTP1IfClientCertSet => PlatformDetection.WindowsVersion < 2004; + + public ClientCertificateTest(ITestOutputHelper output) : base(output) + { } + + [ConditionalFact(typeof(ServerCertificateTest), nameof(DowngradeToHTTP1IfClientCertSet))] + public async Task UseClientCertOnHttp2_DowngradedToHttp1MutualAuth_Success() + { + using X509Certificate2 clientCert = Test.Common.Configuration.Certificates.GetClientCertificate(); + await LoopbackServer.CreateClientAndServerAsync( + async address => + { + var handler = new WinHttpHandler(); + handler.ServerCertificateValidationCallback = CustomServerCertificateValidationCallback; + handler.ClientCertificates.Add(clientCert); + handler.ClientCertificateOption = ClientCertificateOption.Manual; + using (var client = new HttpClient(handler)) + using (HttpResponseMessage response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, address) { Version = HttpVersion20.Value })) + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(_validationCallbackHistory.WasCalled); + Assert.NotEmpty(_validationCallbackHistory.CertificateChain); + Assert.Equal(Test.Common.Configuration.Certificates.GetServerCertificate(), _validationCallbackHistory.CertificateChain[0]); + } + }, + async s => + { + using (LoopbackServer.Connection connection = await s.EstablishConnectionAsync().ConfigureAwait(false)) + { + SslStream sslStream = connection.Stream as SslStream; + Assert.NotNull(sslStream); + Assert.True(sslStream.IsMutuallyAuthenticated); + Assert.Equal(clientCert, sslStream.RemoteCertificate); + await connection.ReadRequestHeaderAndSendResponseAsync(HttpStatusCode.OK); + } + }, new LoopbackServer.Options { UseSsl = true }); + } + +// Disabling it for full .Net Framework due to a missing ALPN API which leads to a protocol downgrade +#if !NETFRAMEWORK + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version2004OrGreater))] + public async Task UseClientCertOnHttp2_OSSupportsIt_Success() + { + using X509Certificate2 clientCert = Test.Common.Configuration.Certificates.GetClientCertificate(); + await Http2LoopbackServer.CreateClientAndServerAsync( + async address => + { + var handler = new WinHttpHandler(); + handler.ServerCertificateValidationCallback = CustomServerCertificateValidationCallback; + handler.ClientCertificates.Add(clientCert); + handler.ClientCertificateOption = ClientCertificateOption.Manual; + using (var client = new HttpClient(handler)) + using (HttpResponseMessage response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, address) { Version = HttpVersion20.Value })) + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(_validationCallbackHistory.WasCalled); + Assert.NotEmpty(_validationCallbackHistory.CertificateChain); + Assert.Equal(Test.Common.Configuration.Certificates.GetServerCertificate(), _validationCallbackHistory.CertificateChain[0]); + } + }, + async s => + { + using (Http2LoopbackConnection connection = await s.EstablishConnectionAsync().ConfigureAwait(false)) + { + SslStream sslStream = connection.Stream as SslStream; + Assert.NotNull(sslStream); + Assert.True(sslStream.IsMutuallyAuthenticated); + Assert.Equal(clientCert, sslStream.RemoteCertificate); + + int streamId = await connection.ReadRequestHeaderAsync(); + await connection.SendDefaultResponseAsync(streamId); + } + }, new Http2Options { ClientCertificateRequired = true }); + } +#endif + [OuterLoop] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version1607OrGreater))] + public async Task UseClientCertOnHttp2_OSSupportsItButCertNotSet_SuccessWithOneWayAuth() + { + WinHttpHandler handler = new WinHttpHandler(); + handler.ServerCertificateValidationCallback = CustomServerCertificateValidationCallback; + string payload = "Mutual Authentication Test"; + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Test.Common.Configuration.Http.Http2RemoteEchoServer) { Version = HttpVersion20.Value }; + request.Content = new StringContent(payload); + using (var client = new HttpClient(handler)) + using (HttpResponseMessage response = await client.SendAsync(request)) + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(HttpVersion20.Value, response.Version); + string responsePayload = await response.Content.ReadAsStringAsync(); + var responseContent = JsonConvert.DeserializeAnonymousType(responsePayload, new { Method = "_", BodyContent = "_", ClientCertificatePresent = "_", ClientCertificate = "_" }); + Assert.Equal("POST", responseContent.Method); + Assert.Equal(payload, responseContent.BodyContent); + Assert.Equal("false", responseContent.ClientCertificatePresent); + Assert.Null(responseContent.ClientCertificate); + Assert.True(_validationCallbackHistory.WasCalled); + Assert.NotEmpty(_validationCallbackHistory.CertificateChain); + ConfirmValidCertificate("*.azurewebsites.net"); + }; + } + } +} diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/HttpClientHandlerTestBase.WinHttpHandler.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/HttpClientHandlerTestBase.WinHttpHandler.cs index d1798cdf032571..516e9f7d3508b8 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/HttpClientHandlerTestBase.WinHttpHandler.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/HttpClientHandlerTestBase.WinHttpHandler.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Net.Test.Common; using System.IO; namespace System.Net.Http.Functional.Tests @@ -10,13 +11,15 @@ public abstract partial class HttpClientHandlerTestBase : FileCleanupTestBase { protected static bool IsWinHttpHandler => true; + protected static bool AllowAllCertificates { get; set; } = true; + protected static WinHttpClientHandler CreateHttpClientHandler(Version useVersion = null) { useVersion ??= HttpVersion.Version11; - WinHttpClientHandler handler = new WinHttpClientHandler(); + WinHttpClientHandler handler = new WinHttpClientHandler(useVersion); - if (useVersion >= HttpVersion.Version20) + if (useVersion >= HttpVersion20.Value && AllowAllCertificates) { handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/PlatformHandlerTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/PlatformHandlerTest.cs index a871abc502df40..3bd5bc40488ff8 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/PlatformHandlerTest.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/PlatformHandlerTest.cs @@ -192,16 +192,192 @@ public sealed class PlatformHandler_HttpClientHandler_Authentication_Test : Http public PlatformHandler_HttpClientHandler_Authentication_Test(ITestOutputHelper output) : base(output) { } } - // Enable this to run HTTP2 tests on platform handler -#if PLATFORM_HANDLER_HTTP2_TESTS - public sealed class PlatformHandlerTest_Http2 : HttpClientHandlerTest_Http2 +#if NETCOREAPP + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version1607OrGreater))] + public sealed class PlatformHandlerTest_Cookies_Http2 : HttpClientHandlerTest_Cookies { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandlerTest_Cookies_Http2(ITestOutputHelper output) : base(output) { } } - - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))] - public sealed class PlatformHandlerTest_Cookies_Http2 : HttpClientHandlerTest_Cookies + + public sealed class PlatformHandler_HttpClientHandler_Asynchrony_Http2_Test : HttpClientHandler_Asynchrony_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_Asynchrony_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpProtocol_Http2_Tests : HttpProtocolTests + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpProtocol_Http2_Tests(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpProtocolTests_Http2_Dribble : HttpProtocolTests_Dribble + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpProtocolTests_Http2_Dribble(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClient_SelectedSites_Http2_Test : HttpClient_SelectedSites_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClient_SelectedSites_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientEKU_Http2_Test : HttpClientEKUTest + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientEKU_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_Decompression_Http2_Tests : HttpClientHandler_Decompression_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_Decompression_Http2_Tests(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Http2_Test : HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_ClientCertificates_Http2_Test : HttpClientHandler_ClientCertificates_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_ClientCertificates_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_DefaultProxyCredentials_Http2_Test : HttpClientHandler_DefaultProxyCredentials_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_DefaultProxyCredentials_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_MaxConnectionsPerServer_Http2_Test : HttpClientHandler_MaxConnectionsPerServer_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_MaxConnectionsPerServer_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_ServerCertificates_Http2_Test : HttpClientHandler_ServerCertificates_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_ServerCertificates_Http2_Test(ITestOutputHelper output) : base(output) { + AllowAllCertificates = false; + } + } + + public sealed class PlatformHandler_PostScenario_Http2_Test : PostScenarioTest + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_PostScenario_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_SslProtocols_Http2_Test : HttpClientHandler_SslProtocols_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_SslProtocols_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_Proxy_Http2_Test : HttpClientHandler_Proxy_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_Proxy_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_SchSendAuxRecordHttp_Http2_Test : SchSendAuxRecordHttpTest + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_SchSendAuxRecordHttp_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version1607OrGreater))] + public sealed class PlatformHandler_HttpClientHandler_Http2_Test : HttpClientHandlerTest + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandlerTest_AutoRedirect_Http2 : HttpClientHandlerTest_AutoRedirect + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandlerTest_AutoRedirect_Http2(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_DefaultCredentials_Http2_Test : DefaultCredentialsTest + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_DefaultCredentials_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_IdnaProtocol_Http2_Tests : IdnaProtocolTests { - protected override bool UseHttp2LoopbackServer => true; + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_IdnaProtocol_Http2_Tests(ITestOutputHelper output) : base(output) { } + // WinHttp on Win7 does not support IDNA + protected override bool SupportsIdna => !PlatformDetection.IsWindows7; + } + + public sealed class PlatformHandler_HttpRetryProtocol_Http2_Tests : HttpRetryProtocolTests + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpRetryProtocol_Http2_Tests(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandlerTest_Cookies_Http11_Http2 : HttpClientHandlerTest_Cookies_Http11 + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandlerTest_Cookies_Http11_Http2(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_MaxResponseHeadersLength_Http2_Test : HttpClientHandler_MaxResponseHeadersLength_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_MaxResponseHeadersLength_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_Cancellation_Http2_Test : HttpClientHandler_Cancellation_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_Cancellation_Http2_Test(ITestOutputHelper output) : base(output) { } + } + + public sealed class PlatformHandler_HttpClientHandler_Authentication_Http2_Test : HttpClientHandler_Authentication_Test + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_HttpClientHandler_Authentication_Http2_Test(ITestOutputHelper output) : base(output) { } } #endif + public sealed class PlatformHandler_ResponseStream_Http2_Test : ResponseStreamTest + { + protected override Version UseVersion => HttpVersion20.Value; + + public PlatformHandler_ResponseStream_Http2_Test(ITestOutputHelper output) : base(output) { } + } } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/ServerCertificateTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/ServerCertificateTest.cs index 5ad5587abb0c93..f459c2957d2149 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/ServerCertificateTest.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/ServerCertificateTest.cs @@ -2,31 +2,21 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.ComponentModel; -using System.Net; -using System.Net.Http; using System.Net.Security; -using System.Net.Test.Common; -using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; - using Xunit; using Xunit.Abstractions; namespace System.Net.Http.WinHttpHandlerFunctional.Tests { - public class ServerCertificateTest + public class ServerCertificateTest : BaseCertificateTest { - private readonly ITestOutputHelper _output; - private readonly ValidationCallbackHistory _validationCallbackHistory; + public ServerCertificateTest(ITestOutputHelper output) : base(output) + { } - public ServerCertificateTest(ITestOutputHelper output) - { - _output = output; - _validationCallbackHistory = new ValidationCallbackHistory(); - } + public static bool DowngradeToHTTP1IfClientCertSet => PlatformDetection.WindowsVersion < 2004; [OuterLoop] [Fact] @@ -34,7 +24,7 @@ public async Task NoCallback_ValidCertificate_CallbackNotCalled() { var handler = new WinHttpHandler(); using (var client = new HttpClient(handler)) - using (HttpResponseMessage response = await client.GetAsync(System.Net.Test.Common.Configuration.Http.SecureRemoteEchoServer)) + using (HttpResponseMessage response = await client.GetAsync(Test.Common.Configuration.Http.SecureRemoteEchoServer)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.False(_validationCallbackHistory.WasCalled); @@ -48,7 +38,7 @@ public async Task UseCallback_NotSecureConnection_CallbackNotCalled() var handler = new WinHttpHandler(); handler.ServerCertificateValidationCallback = CustomServerCertificateValidationCallback; using (var client = new HttpClient(handler)) - using (HttpResponseMessage response = await client.GetAsync(System.Net.Test.Common.Configuration.Http.RemoteEchoServer)) + using (HttpResponseMessage response = await client.GetAsync(Test.Common.Configuration.Http.RemoteEchoServer)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.False(_validationCallbackHistory.WasCalled); @@ -67,7 +57,7 @@ public async Task UseCallback_ValidCertificate_ExpectedValuesDuringCallback() Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.True(_validationCallbackHistory.WasCalled); - ConfirmValidCertificate(System.Net.Test.Common.Configuration.Http.Host); + ConfirmValidCertificate(Test.Common.Configuration.Http.Host); } } @@ -75,7 +65,7 @@ public async Task UseCallback_ValidCertificate_ExpectedValuesDuringCallback() [Fact] public async Task UseCallback_RedirectandValidCertificate_ExpectedValuesDuringCallback() { - Uri uri = System.Net.Test.Common.Configuration.Http.RemoteSecureHttp11Server.RedirectUriForDestinationUri(302, System.Net.Test.Common.Configuration.Http.SecureRemoteEchoServer, 1); + Uri uri = Test.Common.Configuration.Http.RemoteSecureHttp11Server.RedirectUriForDestinationUri(302, System.Net.Test.Common.Configuration.Http.SecureRemoteEchoServer, 1); var handler = new WinHttpHandler(); handler.ServerCertificateValidationCallback = CustomServerCertificateValidationCallback; @@ -85,7 +75,7 @@ public async Task UseCallback_RedirectandValidCertificate_ExpectedValuesDuringCa Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.True(_validationCallbackHistory.WasCalled); - ConfirmValidCertificate(System.Net.Test.Common.Configuration.Http.Host); + ConfirmValidCertificate(Test.Common.Configuration.Http.Host); } } @@ -99,7 +89,7 @@ public async Task UseCallback_CallbackReturnsFailure_ThrowsInnerSecurityFailureE handler.ServerCertificateValidationCallback = CustomServerCertificateValidationCallback; using (var client = new HttpClient(handler)) { - var request = new HttpRequestMessage(HttpMethod.Get, System.Net.Test.Common.Configuration.Http.SecureRemoteEchoServer); + var request = new HttpRequestMessage(HttpMethod.Get, Test.Common.Configuration.Http.SecureRemoteEchoServer); _validationCallbackHistory.ReturnFailure = true; HttpRequestException ex = await Assert.ThrowsAsync(() => client.GetAsync(System.Net.Test.Common.Configuration.Http.SecureRemoteEchoServer)); @@ -122,70 +112,5 @@ public async Task UseCallback_CallbackThrowsSpecificException_SpecificExceptionP Assert.True(ex.GetBaseException() is CustomException); } } - - private void ConfirmValidCertificate(string expectedHostName) - { - Assert.Equal(SslPolicyErrors.None, _validationCallbackHistory.SslPolicyErrors); - Assert.True(_validationCallbackHistory.CertificateChain.Count > 0); - _output.WriteLine("Certificate.Subject: {0}", _validationCallbackHistory.CertificateSubject); - _output.WriteLine("Expected HostName: {0}", expectedHostName); - } - - private bool CustomServerCertificateValidationCallback( - HttpRequestMessage sender, - X509Certificate2 certificate, - X509Chain chain, - SslPolicyErrors sslPolicyErrors) - { - _validationCallbackHistory.WasCalled = true; - _validationCallbackHistory.CertificateSubject = certificate.Subject; - foreach (var element in chain.ChainElements) - { - _validationCallbackHistory.CertificateChain.Add(element.Certificate); - } - _validationCallbackHistory.ChainStatus = chain.ChainStatus; - _validationCallbackHistory.SslPolicyErrors = sslPolicyErrors; - - if (_validationCallbackHistory.ThrowException) - { - throw new CustomException(); - } - - if (_validationCallbackHistory.ReturnFailure) - { - return false; - } - - return true; - } - - public class CustomException : Exception - { - public CustomException() - { - } - } - - public class ValidationCallbackHistory - { - public bool ThrowException; - public bool ReturnFailure; - public bool WasCalled; - public SslPolicyErrors SslPolicyErrors; - public string CertificateSubject; - public X509CertificateCollection CertificateChain; - public X509ChainStatus[] ChainStatus; - - public ValidationCallbackHistory() - { - ThrowException = false; - ReturnFailure = false; - WasCalled = false; - SslPolicyErrors = SslPolicyErrors.None; - CertificateSubject = null; - CertificateChain = new X509CertificateCollection(); - ChainStatus = null; - } - } } } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj index 82e2835aa8995b..599da9a519e917 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj @@ -1,8 +1,9 @@ - + $(NetCoreAppCurrent)-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true $(DefineConstants);WINHTTPHANDLER_TEST + 8.0 @@ -11,11 +12,10 @@ Common\System\Net\Configuration.Http.cs + - - - + Common\System\Net\Http\HttpHandlerDefaults.cs @@ -52,6 +52,9 @@ Common\System\Net\TestWebProxies.cs + + Common\System\Net\StreamArrayExtensions.cs + Common\System\Net\Http\ByteAtATimeContent.cs @@ -193,6 +196,7 @@ + diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpClientHandler.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpClientHandler.cs index 2f8ccd311a3d02..611e6c510a7c4b 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpClientHandler.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpClientHandler.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Net.Security; +using System.Net.Test.Common; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading; @@ -18,8 +19,9 @@ namespace System.Net.Http public class WinHttpClientHandler : WinHttpHandler { private bool _useProxy; + private readonly Version _requestVersion; - public WinHttpClientHandler() + public WinHttpClientHandler(Version requestVersion) { // Adjust defaults to match current .NET Desktop HttpClientHandler (based on HWR stack). AllowAutoRedirect = true; @@ -41,6 +43,8 @@ public WinHttpClientHandler() ReceiveHeadersTimeout = Timeout.InfiniteTimeSpan; ReceiveDataTimeout = Timeout.InfiniteTimeSpan; SendTimeout = Timeout.InfiniteTimeSpan; + + _requestVersion = requestVersion; } public virtual bool SupportsAutomaticDecompression => true; @@ -178,6 +182,11 @@ protected override Task SendAsync(HttpRequestMessage reques } } + if(_requestVersion >= HttpVersion20.Value) + { + request.Version = _requestVersion; + } + return base.SendAsync(request, cancellationToken); } } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs index 5c728fced2eeff..0519437ca296e2 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs @@ -3,9 +3,10 @@ // See the LICENSE file in the project root for more information. using System; -using System.Net; -using System.Net.Http; +using System.Collections.Generic; +using System.Linq; using System.Net.Test.Common; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -131,6 +132,46 @@ public async Task SendAsync_GetUsingChunkedEncoding_ThrowsHttpRequestException() } } + [OuterLoop] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version1607OrGreater))] + public async Task GetAsync_SetCookieContainerMultipleCookies_CookiesSent() + { + var cookies = new Cookie[] + { + new Cookie("hello", "world"), + new Cookie("foo", "bar"), + new Cookie("ABC", "123") + }; + + WinHttpHandler handler = new WinHttpHandler(); + var cookieContainer = new CookieContainer(); + + foreach (Cookie c in cookies) + { + cookieContainer.Add(Configuration.Http.Http2RemoteEchoServer, c); + } + + handler.CookieContainer = cookieContainer; + handler.CookieUsePolicy = CookieUsePolicy.UseSpecifiedCookieContainer; + handler.ServerCertificateValidationCallback = (m, cert, chain, err) => true; + string payload = "Cookie Test"; + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Configuration.Http.Http2RemoteEchoServer) { Version = HttpVersion20.Value }; + request.Content = new StringContent(payload); + using (var client = new HttpClient(handler)) + using (HttpResponseMessage response = await client.SendAsync(request)) + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(HttpVersion20.Value, response.Version); + string responsePayload = await response.Content.ReadAsStringAsync(); + var responseContent = Newtonsoft.Json.JsonConvert + .DeserializeAnonymousType(responsePayload, new { Method = "_", BodyContent = "_", Cookies = new Dictionary() }); + Assert.Equal("POST", responseContent.Method); + Assert.Equal(payload, responseContent.BodyContent); + Assert.Equal(cookies.ToDictionary(c => c.Name, c => c.Value), responseContent.Cookies); + + }; + } + public static bool JsonMessageContainsKeyValue(string message, string key, string value) { string pattern = string.Format(@"""{0}"": ""{1}""", key, value); diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj index 4ed356e87e8813..9d1e3ba1e79cff 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj @@ -5,6 +5,7 @@ ../../src/Resources/Strings.resx $(NetCoreAppCurrent)-Windows_NT $(DefineConstants);WINHTTPHANDLER_DLL + annotations diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index b1c02bb8efe1da..131f048c0d847f 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -12,8 +12,8 @@ public partial class ByteArrayContent : System.Net.Http.HttpContent public ByteArrayContent(byte[] content) { } public ByteArrayContent(byte[] content, int offset, int count) { } protected override System.Threading.Tasks.Task CreateContentReadStreamAsync() { throw null; } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context) { throw null; } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context, System.Threading.CancellationToken cancellationToken) { throw null; } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context) { throw null; } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } protected internal override bool TryComputeLength(out long length) { throw null; } } public enum ClientCertificateOption @@ -25,64 +25,65 @@ public abstract partial class DelegatingHandler : System.Net.Http.HttpMessageHan { protected DelegatingHandler() { } protected DelegatingHandler(System.Net.Http.HttpMessageHandler innerHandler) { } - public System.Net.Http.HttpMessageHandler InnerHandler { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.DisallowNullAttribute] + public System.Net.Http.HttpMessageHandler? InnerHandler { get { throw null; } set { } } protected override void Dispose(bool disposing) { } protected internal override System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; } } public partial class FormUrlEncodedContent : System.Net.Http.ByteArrayContent { - public FormUrlEncodedContent(System.Collections.Generic.IEnumerable> nameValueCollection) : base (default(byte[])) { } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context, System.Threading.CancellationToken cancellationToken) { throw null; } + public FormUrlEncodedContent(System.Collections.Generic.IEnumerable> nameValueCollection) : base (default(byte[])) { } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } } public partial class HttpClient : System.Net.Http.HttpMessageInvoker { public HttpClient() : base (default(System.Net.Http.HttpMessageHandler)) { } public HttpClient(System.Net.Http.HttpMessageHandler handler) : base (default(System.Net.Http.HttpMessageHandler)) { } public HttpClient(System.Net.Http.HttpMessageHandler handler, bool disposeHandler) : base (default(System.Net.Http.HttpMessageHandler)) { } - public System.Uri BaseAddress { get { throw null; } set { } } + public System.Uri? BaseAddress { get { throw null; } set { } } public static System.Net.IWebProxy DefaultProxy { get { throw null; } set { } } public System.Net.Http.Headers.HttpRequestHeaders DefaultRequestHeaders { get { throw null; } } public System.Version DefaultRequestVersion { get { throw null; } set { } } public long MaxResponseContentBufferSize { get { throw null; } set { } } public System.TimeSpan Timeout { get { throw null; } set { } } public void CancelPendingRequests() { } - public System.Threading.Tasks.Task DeleteAsync(string requestUri) { throw null; } - public System.Threading.Tasks.Task DeleteAsync(string requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task DeleteAsync(System.Uri requestUri) { throw null; } - public System.Threading.Tasks.Task DeleteAsync(System.Uri requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task DeleteAsync(string? requestUri) { throw null; } + public System.Threading.Tasks.Task DeleteAsync(string? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task DeleteAsync(System.Uri? requestUri) { throw null; } + public System.Threading.Tasks.Task DeleteAsync(System.Uri? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } protected override void Dispose(bool disposing) { } - public System.Threading.Tasks.Task GetAsync(string requestUri) { throw null; } - public System.Threading.Tasks.Task GetAsync(string requestUri, System.Net.Http.HttpCompletionOption completionOption) { throw null; } - public System.Threading.Tasks.Task GetAsync(string requestUri, System.Net.Http.HttpCompletionOption completionOption, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task GetAsync(string requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task GetAsync(System.Uri requestUri) { throw null; } - public System.Threading.Tasks.Task GetAsync(System.Uri requestUri, System.Net.Http.HttpCompletionOption completionOption) { throw null; } - public System.Threading.Tasks.Task GetAsync(System.Uri requestUri, System.Net.Http.HttpCompletionOption completionOption, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task GetAsync(System.Uri requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task GetByteArrayAsync(string requestUri) { throw null; } - public System.Threading.Tasks.Task GetByteArrayAsync(string requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task GetByteArrayAsync(System.Uri requestUri) { throw null; } - public System.Threading.Tasks.Task GetByteArrayAsync(System.Uri requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task GetStreamAsync(string requestUri) { throw null; } - public System.Threading.Tasks.Task GetStreamAsync(string requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task GetStreamAsync(System.Uri requestUri) { throw null; } - public System.Threading.Tasks.Task GetStreamAsync(System.Uri requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task GetStringAsync(string requestUri) { throw null; } - public System.Threading.Tasks.Task GetStringAsync(string requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task GetStringAsync(System.Uri requestUri) { throw null; } - public System.Threading.Tasks.Task GetStringAsync(System.Uri requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PatchAsync(string requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PatchAsync(string requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PatchAsync(System.Uri requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PatchAsync(System.Uri requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PostAsync(string requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PostAsync(string requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PostAsync(System.Uri requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PostAsync(System.Uri requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PutAsync(string requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PutAsync(string requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PutAsync(System.Uri requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PutAsync(System.Uri requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetAsync(string? requestUri) { throw null; } + public System.Threading.Tasks.Task GetAsync(string? requestUri, System.Net.Http.HttpCompletionOption completionOption) { throw null; } + public System.Threading.Tasks.Task GetAsync(string? requestUri, System.Net.Http.HttpCompletionOption completionOption, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetAsync(string? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetAsync(System.Uri? requestUri) { throw null; } + public System.Threading.Tasks.Task GetAsync(System.Uri? requestUri, System.Net.Http.HttpCompletionOption completionOption) { throw null; } + public System.Threading.Tasks.Task GetAsync(System.Uri? requestUri, System.Net.Http.HttpCompletionOption completionOption, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetAsync(System.Uri? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetByteArrayAsync(string? requestUri) { throw null; } + public System.Threading.Tasks.Task GetByteArrayAsync(string? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetByteArrayAsync(System.Uri? requestUri) { throw null; } + public System.Threading.Tasks.Task GetByteArrayAsync(System.Uri? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetStreamAsync(string? requestUri) { throw null; } + public System.Threading.Tasks.Task GetStreamAsync(string? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetStreamAsync(System.Uri? requestUri) { throw null; } + public System.Threading.Tasks.Task GetStreamAsync(System.Uri? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetStringAsync(string? requestUri) { throw null; } + public System.Threading.Tasks.Task GetStringAsync(string? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task GetStringAsync(System.Uri? requestUri) { throw null; } + public System.Threading.Tasks.Task GetStringAsync(System.Uri? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PatchAsync(string? requestUri, System.Net.Http.HttpContent content) { throw null; } + public System.Threading.Tasks.Task PatchAsync(string? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PatchAsync(System.Uri? requestUri, System.Net.Http.HttpContent content) { throw null; } + public System.Threading.Tasks.Task PatchAsync(System.Uri? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PostAsync(string? requestUri, System.Net.Http.HttpContent content) { throw null; } + public System.Threading.Tasks.Task PostAsync(string? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PostAsync(System.Uri? requestUri, System.Net.Http.HttpContent content) { throw null; } + public System.Threading.Tasks.Task PostAsync(System.Uri? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PutAsync(string? requestUri, System.Net.Http.HttpContent content) { throw null; } + public System.Threading.Tasks.Task PutAsync(string? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PutAsync(System.Uri? requestUri, System.Net.Http.HttpContent content) { throw null; } + public System.Threading.Tasks.Task PutAsync(System.Uri? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } public System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request) { throw null; } public System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpCompletionOption completionOption) { throw null; } public System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpCompletionOption completionOption, System.Threading.CancellationToken cancellationToken) { throw null; } @@ -97,17 +98,17 @@ public HttpClientHandler() { } public System.Net.Http.ClientCertificateOption ClientCertificateOptions { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509CertificateCollection ClientCertificates { get { throw null; } } public System.Net.CookieContainer CookieContainer { get { throw null; } set { } } - public System.Net.ICredentials Credentials { get { throw null; } set { } } + public System.Net.ICredentials? Credentials { get { throw null; } set { } } public static System.Func DangerousAcceptAnyServerCertificateValidator { get { throw null; } } - public System.Net.ICredentials DefaultProxyCredentials { get { throw null; } set { } } + public System.Net.ICredentials? DefaultProxyCredentials { get { throw null; } set { } } public int MaxAutomaticRedirections { get { throw null; } set { } } public int MaxConnectionsPerServer { get { throw null; } set { } } public long MaxRequestContentBufferSize { get { throw null; } set { } } public int MaxResponseHeadersLength { get { throw null; } set { } } public bool PreAuthenticate { get { throw null; } set { } } - public System.Collections.Generic.IDictionary Properties { get { throw null; } } - public System.Net.IWebProxy Proxy { get { throw null; } set { } } - public System.Func ServerCertificateCustomValidationCallback { get { throw null; } set { } } + public System.Collections.Generic.IDictionary Properties { get { throw null; } } + public System.Net.IWebProxy? Proxy { get { throw null; } set { } } + public System.Func? ServerCertificateCustomValidationCallback { get { throw null; } set { } } public System.Security.Authentication.SslProtocols SslProtocols { get { throw null; } set { } } public virtual bool SupportsAutomaticDecompression { get { throw null; } } public virtual bool SupportsProxy { get { throw null; } } @@ -128,8 +129,8 @@ public abstract partial class HttpContent : System.IDisposable protected HttpContent() { } public System.Net.Http.Headers.HttpContentHeaders Headers { get { throw null; } } public System.Threading.Tasks.Task CopyToAsync(System.IO.Stream stream) { throw null; } - public System.Threading.Tasks.Task CopyToAsync(System.IO.Stream stream, System.Net.TransportContext context) { throw null; } - public System.Threading.Tasks.Task CopyToAsync(System.IO.Stream stream, System.Net.TransportContext context, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task CopyToAsync(System.IO.Stream stream, System.Net.TransportContext? context) { throw null; } + public System.Threading.Tasks.Task CopyToAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } public System.Threading.Tasks.Task CopyToAsync(System.IO.Stream stream, System.Threading.CancellationToken cancellationToken) { throw null; } protected virtual System.Threading.Tasks.Task CreateContentReadStreamAsync() { throw null; } protected virtual System.Threading.Tasks.Task CreateContentReadStreamAsync(System.Threading.CancellationToken cancellationToken) { throw null; } @@ -143,8 +144,8 @@ protected virtual void Dispose(bool disposing) { } public System.Threading.Tasks.Task ReadAsStreamAsync(System.Threading.CancellationToken cancellationToken) { throw null; } public System.Threading.Tasks.Task ReadAsStringAsync() { throw null; } public System.Threading.Tasks.Task ReadAsStringAsync(System.Threading.CancellationToken cancellationToken) { throw null; } - protected abstract System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context); - protected virtual System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context, System.Threading.CancellationToken cancellationToken) { throw null; } + protected abstract System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context); + protected virtual System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } protected internal abstract bool TryComputeLength(out long length); } public abstract partial class HttpMessageHandler : System.IDisposable @@ -174,31 +175,31 @@ public HttpMethod(string method) { } public static System.Net.Http.HttpMethod Post { get { throw null; } } public static System.Net.Http.HttpMethod Put { get { throw null; } } public static System.Net.Http.HttpMethod Trace { get { throw null; } } - public bool Equals(System.Net.Http.HttpMethod other) { throw null; } - public override bool Equals(object obj) { throw null; } + public bool Equals(System.Net.Http.HttpMethod? other) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static bool operator ==(System.Net.Http.HttpMethod left, System.Net.Http.HttpMethod right) { throw null; } - public static bool operator !=(System.Net.Http.HttpMethod left, System.Net.Http.HttpMethod right) { throw null; } + public static bool operator ==(System.Net.Http.HttpMethod? left, System.Net.Http.HttpMethod? right) { throw null; } + public static bool operator !=(System.Net.Http.HttpMethod? left, System.Net.Http.HttpMethod? right) { throw null; } public override string ToString() { throw null; } } public partial class HttpRequestException : System.Exception { public HttpRequestException() { } - public HttpRequestException(string message) { } - public HttpRequestException(string message, System.Exception inner) { } - public HttpRequestException(string message, System.Exception inner, System.Net.HttpStatusCode? statusCode) { } + public HttpRequestException(string? message) { } + public HttpRequestException(string? message, System.Exception? inner) { } + public HttpRequestException(string? message, System.Exception? inner, System.Net.HttpStatusCode? statusCode) { } public System.Net.HttpStatusCode? StatusCode { get { throw null; } } } public partial class HttpRequestMessage : System.IDisposable { public HttpRequestMessage() { } - public HttpRequestMessage(System.Net.Http.HttpMethod method, string requestUri) { } - public HttpRequestMessage(System.Net.Http.HttpMethod method, System.Uri requestUri) { } - public System.Net.Http.HttpContent Content { get { throw null; } set { } } + public HttpRequestMessage(System.Net.Http.HttpMethod method, string? requestUri) { } + public HttpRequestMessage(System.Net.Http.HttpMethod method, System.Uri? requestUri) { } + public System.Net.Http.HttpContent? Content { get { throw null; } set { } } public System.Net.Http.Headers.HttpRequestHeaders Headers { get { throw null; } } public System.Net.Http.HttpMethod Method { get { throw null; } set { } } - public System.Collections.Generic.IDictionary Properties { get { throw null; } } - public System.Uri RequestUri { get { throw null; } set { } } + public System.Collections.Generic.IDictionary Properties { get { throw null; } } + public System.Uri? RequestUri { get { throw null; } set { } } public System.Version Version { get { throw null; } set { } } public void Dispose() { } protected virtual void Dispose(bool disposing) { } @@ -208,11 +209,11 @@ public partial class HttpResponseMessage : System.IDisposable { public HttpResponseMessage() { } public HttpResponseMessage(System.Net.HttpStatusCode statusCode) { } - public System.Net.Http.HttpContent Content { get { throw null; } set { } } + public System.Net.Http.HttpContent? Content { get { throw null; } set { } } public System.Net.Http.Headers.HttpResponseHeaders Headers { get { throw null; } } public bool IsSuccessStatusCode { get { throw null; } } - public string ReasonPhrase { get { throw null; } set { } } - public System.Net.Http.HttpRequestMessage RequestMessage { get { throw null; } set { } } + public string? ReasonPhrase { get { throw null; } set { } } + public System.Net.Http.HttpRequestMessage? RequestMessage { get { throw null; } set { } } public System.Net.HttpStatusCode StatusCode { get { throw null; } set { } } public System.Net.Http.Headers.HttpResponseHeaders TrailingHeaders { get { throw null; } } public System.Version Version { get { throw null; } set { } } @@ -239,8 +240,8 @@ public virtual void Add(System.Net.Http.HttpContent content) { } protected override System.Threading.Tasks.Task CreateContentReadStreamAsync(System.Threading.CancellationToken cancellationToken) { throw null; } protected override void Dispose(bool disposing) { } public System.Collections.Generic.IEnumerator GetEnumerator() { throw null; } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context) { throw null; } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context, System.Threading.CancellationToken cancellationToken) { throw null; } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context) { throw null; } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } protected internal override bool TryComputeLength(out long length) { throw null; } } @@ -251,14 +252,14 @@ public MultipartFormDataContent(string boundary) { } public override void Add(System.Net.Http.HttpContent content) { } public void Add(System.Net.Http.HttpContent content, string name) { } public void Add(System.Net.Http.HttpContent content, string name, string fileName) { } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context, System.Threading.CancellationToken cancellationToken) { throw null; } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } } public sealed partial class ReadOnlyMemoryContent : System.Net.Http.HttpContent { public ReadOnlyMemoryContent(System.ReadOnlyMemory content) { } protected override System.Threading.Tasks.Task CreateContentReadStreamAsync() { throw null; } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context) { throw null; } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context, System.Threading.CancellationToken cancellationToken) { throw null; } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context) { throw null; } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } protected internal override bool TryComputeLength(out long length) { throw null; } } public sealed partial class SocketsHttpHandler : System.Net.Http.HttpMessageHandler @@ -267,9 +268,10 @@ public SocketsHttpHandler() { } public bool AllowAutoRedirect { get { throw null; } set { } } public System.Net.DecompressionMethods AutomaticDecompression { get { throw null; } set { } } public System.TimeSpan ConnectTimeout { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.AllowNull] public System.Net.CookieContainer CookieContainer { get { throw null; } set { } } - public System.Net.ICredentials Credentials { get { throw null; } set { } } - public System.Net.ICredentials DefaultProxyCredentials { get { throw null; } set { } } + public System.Net.ICredentials? Credentials { get { throw null; } set { } } + public System.Net.ICredentials? DefaultProxyCredentials { get { throw null; } set { } } public System.TimeSpan Expect100ContinueTimeout { get { throw null; } set { } } public int MaxAutomaticRedirections { get { throw null; } set { } } public int MaxConnectionsPerServer { get { throw null; } set { } } @@ -278,9 +280,10 @@ public SocketsHttpHandler() { } public System.TimeSpan PooledConnectionIdleTimeout { get { throw null; } set { } } public System.TimeSpan PooledConnectionLifetime { get { throw null; } set { } } public bool PreAuthenticate { get { throw null; } set { } } - public System.Collections.Generic.IDictionary Properties { get { throw null; } } - public System.Net.IWebProxy Proxy { get { throw null; } set { } } + public System.Collections.Generic.IDictionary Properties { get { throw null; } } + public System.Net.IWebProxy? Proxy { get { throw null; } set { } } public System.TimeSpan ResponseDrainTimeout { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.AllowNullAttribute] public System.Net.Security.SslClientAuthenticationOptions SslOptions { get { throw null; } set { } } public bool UseCookies { get { throw null; } set { } } public bool UseProxy { get { throw null; } set { } } @@ -293,16 +296,16 @@ public StreamContent(System.IO.Stream content) { } public StreamContent(System.IO.Stream content, int bufferSize) { } protected override System.Threading.Tasks.Task CreateContentReadStreamAsync() { throw null; } protected override void Dispose(bool disposing) { } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context) { throw null; } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context, System.Threading.CancellationToken cancellationToken) { throw null; } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context) { throw null; } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } protected internal override bool TryComputeLength(out long length) { throw null; } } public partial class StringContent : System.Net.Http.ByteArrayContent { public StringContent(string content) : base (default(byte[])) { } - public StringContent(string content, System.Text.Encoding encoding) : base (default(byte[])) { } - public StringContent(string content, System.Text.Encoding encoding, string mediaType) : base (default(byte[])) { } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context, System.Threading.CancellationToken cancellationToken) { throw null; } + public StringContent(string content, System.Text.Encoding? encoding) : base (default(byte[])) { } + public StringContent(string content, System.Text.Encoding? encoding, string? mediaType) : base (default(byte[])) { } + protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } } } namespace System.Net.Http.Headers @@ -310,15 +313,15 @@ namespace System.Net.Http.Headers public partial class AuthenticationHeaderValue : System.ICloneable { public AuthenticationHeaderValue(string scheme) { } - public AuthenticationHeaderValue(string scheme, string parameter) { } - public string Parameter { get { throw null; } } + public AuthenticationHeaderValue(string scheme, string? parameter) { } + public string? Parameter { get { throw null; } } public string Scheme { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.AuthenticationHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.AuthenticationHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.AuthenticationHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.AuthenticationHeaderValue? parsedValue) { throw null; } } public partial class CacheControlHeaderValue : System.ICloneable { @@ -339,12 +342,12 @@ public CacheControlHeaderValue() { } public bool ProxyRevalidate { get { throw null; } set { } } public bool Public { get { throw null; } set { } } public System.TimeSpan? SharedMaxAge { get { throw null; } set { } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.CacheControlHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.CacheControlHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.CacheControlHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.CacheControlHeaderValue? parsedValue) { throw null; } } public partial class ContentDispositionHeaderValue : System.ICloneable { @@ -352,19 +355,19 @@ protected ContentDispositionHeaderValue(System.Net.Http.Headers.ContentDispositi public ContentDispositionHeaderValue(string dispositionType) { } public System.DateTimeOffset? CreationDate { get { throw null; } set { } } public string DispositionType { get { throw null; } set { } } - public string FileName { get { throw null; } set { } } - public string FileNameStar { get { throw null; } set { } } + public string? FileName { get { throw null; } set { } } + public string? FileNameStar { get { throw null; } set { } } public System.DateTimeOffset? ModificationDate { get { throw null; } set { } } - public string Name { get { throw null; } set { } } + public string? Name { get { throw null; } set { } } public System.Collections.Generic.ICollection Parameters { get { throw null; } } public System.DateTimeOffset? ReadDate { get { throw null; } set { } } public long? Size { get { throw null; } set { } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.ContentDispositionHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.ContentDispositionHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.ContentDispositionHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ContentDispositionHeaderValue? parsedValue) { throw null; } } public partial class ContentRangeHeaderValue : System.ICloneable { @@ -377,12 +380,12 @@ public ContentRangeHeaderValue(long from, long to, long length) { } public long? Length { get { throw null; } } public long? To { get { throw null; } } public string Unit { get { throw null; } set { } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.ContentRangeHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.ContentRangeHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.ContentRangeHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ContentRangeHeaderValue? parsedValue) { throw null; } } public partial class EntityTagHeaderValue : System.ICloneable { @@ -391,33 +394,33 @@ public EntityTagHeaderValue(string tag, bool isWeak) { } public static System.Net.Http.Headers.EntityTagHeaderValue Any { get { throw null; } } public bool IsWeak { get { throw null; } } public string Tag { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.EntityTagHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.EntityTagHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.EntityTagHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.EntityTagHeaderValue? parsedValue) { throw null; } } public sealed partial class HttpContentHeaders : System.Net.Http.Headers.HttpHeaders { internal HttpContentHeaders() { } public System.Collections.Generic.ICollection Allow { get { throw null; } } - public System.Net.Http.Headers.ContentDispositionHeaderValue ContentDisposition { get { throw null; } set { } } + public System.Net.Http.Headers.ContentDispositionHeaderValue? ContentDisposition { get { throw null; } set { } } public System.Collections.Generic.ICollection ContentEncoding { get { throw null; } } public System.Collections.Generic.ICollection ContentLanguage { get { throw null; } } public long? ContentLength { get { throw null; } set { } } - public System.Uri ContentLocation { get { throw null; } set { } } - public byte[] ContentMD5 { get { throw null; } set { } } - public System.Net.Http.Headers.ContentRangeHeaderValue ContentRange { get { throw null; } set { } } - public System.Net.Http.Headers.MediaTypeHeaderValue ContentType { get { throw null; } set { } } + public System.Uri? ContentLocation { get { throw null; } set { } } + public byte[]? ContentMD5 { get { throw null; } set { } } + public System.Net.Http.Headers.ContentRangeHeaderValue? ContentRange { get { throw null; } set { } } + public System.Net.Http.Headers.MediaTypeHeaderValue? ContentType { get { throw null; } set { } } public System.DateTimeOffset? Expires { get { throw null; } set { } } public System.DateTimeOffset? LastModified { get { throw null; } set { } } } public abstract partial class HttpHeaders : System.Collections.Generic.IEnumerable>>, System.Collections.IEnumerable { protected HttpHeaders() { } - public void Add(string name, System.Collections.Generic.IEnumerable values) { } - public void Add(string name, string value) { } + public void Add(string name, System.Collections.Generic.IEnumerable values) { } + public void Add(string name, string? value) { } public void Clear() { } public bool Contains(string name) { throw null; } public System.Collections.Generic.IEnumerator>> GetEnumerator() { throw null; } @@ -425,9 +428,9 @@ public void Clear() { } public bool Remove(string name) { throw null; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } public override string ToString() { throw null; } - public bool TryAddWithoutValidation(string name, System.Collections.Generic.IEnumerable values) { throw null; } - public bool TryAddWithoutValidation(string name, string value) { throw null; } - public bool TryGetValues(string name, out System.Collections.Generic.IEnumerable values) { throw null; } + public bool TryAddWithoutValidation(string name, System.Collections.Generic.IEnumerable values) { throw null; } + public bool TryAddWithoutValidation(string name, string? value) { throw null; } + public bool TryGetValues(string name, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Collections.Generic.IEnumerable? values) { throw null; } } public sealed partial class HttpHeaderValueCollection : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable where T : class { @@ -439,11 +442,11 @@ public void Clear() { } public bool Contains(T item) { throw null; } public void CopyTo(T[] array, int arrayIndex) { } public System.Collections.Generic.IEnumerator GetEnumerator() { throw null; } - public void ParseAdd(string input) { } + public void ParseAdd(string? input) { } public bool Remove(T item) { throw null; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } public override string ToString() { throw null; } - public bool TryParseAdd(string input) { throw null; } + public bool TryParseAdd(string? input) { throw null; } } public sealed partial class HttpRequestHeaders : System.Net.Http.Headers.HttpHeaders { @@ -452,25 +455,25 @@ internal HttpRequestHeaders() { } public System.Net.Http.Headers.HttpHeaderValueCollection AcceptCharset { get { throw null; } } public System.Net.Http.Headers.HttpHeaderValueCollection AcceptEncoding { get { throw null; } } public System.Net.Http.Headers.HttpHeaderValueCollection AcceptLanguage { get { throw null; } } - public System.Net.Http.Headers.AuthenticationHeaderValue Authorization { get { throw null; } set { } } - public System.Net.Http.Headers.CacheControlHeaderValue CacheControl { get { throw null; } set { } } + public System.Net.Http.Headers.AuthenticationHeaderValue? Authorization { get { throw null; } set { } } + public System.Net.Http.Headers.CacheControlHeaderValue? CacheControl { get { throw null; } set { } } public System.Net.Http.Headers.HttpHeaderValueCollection Connection { get { throw null; } } public bool? ConnectionClose { get { throw null; } set { } } public System.DateTimeOffset? Date { get { throw null; } set { } } public System.Net.Http.Headers.HttpHeaderValueCollection Expect { get { throw null; } } public bool? ExpectContinue { get { throw null; } set { } } - public string From { get { throw null; } set { } } - public string Host { get { throw null; } set { } } + public string? From { get { throw null; } set { } } + public string? Host { get { throw null; } set { } } public System.Net.Http.Headers.HttpHeaderValueCollection IfMatch { get { throw null; } } public System.DateTimeOffset? IfModifiedSince { get { throw null; } set { } } public System.Net.Http.Headers.HttpHeaderValueCollection IfNoneMatch { get { throw null; } } - public System.Net.Http.Headers.RangeConditionHeaderValue IfRange { get { throw null; } set { } } + public System.Net.Http.Headers.RangeConditionHeaderValue? IfRange { get { throw null; } set { } } public System.DateTimeOffset? IfUnmodifiedSince { get { throw null; } set { } } public int? MaxForwards { get { throw null; } set { } } public System.Net.Http.Headers.HttpHeaderValueCollection Pragma { get { throw null; } } - public System.Net.Http.Headers.AuthenticationHeaderValue ProxyAuthorization { get { throw null; } set { } } - public System.Net.Http.Headers.RangeHeaderValue Range { get { throw null; } set { } } - public System.Uri Referrer { get { throw null; } set { } } + public System.Net.Http.Headers.AuthenticationHeaderValue? ProxyAuthorization { get { throw null; } set { } } + public System.Net.Http.Headers.RangeHeaderValue? Range { get { throw null; } set { } } + public System.Uri? Referrer { get { throw null; } set { } } public System.Net.Http.Headers.HttpHeaderValueCollection TE { get { throw null; } } public System.Net.Http.Headers.HttpHeaderValueCollection Trailer { get { throw null; } } public System.Net.Http.Headers.HttpHeaderValueCollection TransferEncoding { get { throw null; } } @@ -485,15 +488,15 @@ public sealed partial class HttpResponseHeaders : System.Net.Http.Headers.HttpHe internal HttpResponseHeaders() { } public System.Net.Http.Headers.HttpHeaderValueCollection AcceptRanges { get { throw null; } } public System.TimeSpan? Age { get { throw null; } set { } } - public System.Net.Http.Headers.CacheControlHeaderValue CacheControl { get { throw null; } set { } } + public System.Net.Http.Headers.CacheControlHeaderValue? CacheControl { get { throw null; } set { } } public System.Net.Http.Headers.HttpHeaderValueCollection Connection { get { throw null; } } public bool? ConnectionClose { get { throw null; } set { } } public System.DateTimeOffset? Date { get { throw null; } set { } } - public System.Net.Http.Headers.EntityTagHeaderValue ETag { get { throw null; } set { } } - public System.Uri Location { get { throw null; } set { } } + public System.Net.Http.Headers.EntityTagHeaderValue? ETag { get { throw null; } set { } } + public System.Uri? Location { get { throw null; } set { } } public System.Net.Http.Headers.HttpHeaderValueCollection Pragma { get { throw null; } } public System.Net.Http.Headers.HttpHeaderValueCollection ProxyAuthenticate { get { throw null; } } - public System.Net.Http.Headers.RetryConditionHeaderValue RetryAfter { get { throw null; } set { } } + public System.Net.Http.Headers.RetryConditionHeaderValue? RetryAfter { get { throw null; } set { } } public System.Net.Http.Headers.HttpHeaderValueCollection Server { get { throw null; } } public System.Net.Http.Headers.HttpHeaderValueCollection Trailer { get { throw null; } } public System.Net.Http.Headers.HttpHeaderValueCollection TransferEncoding { get { throw null; } } @@ -508,78 +511,79 @@ public partial class MediaTypeHeaderValue : System.ICloneable { protected MediaTypeHeaderValue(System.Net.Http.Headers.MediaTypeHeaderValue source) { } public MediaTypeHeaderValue(string mediaType) { } - public string CharSet { get { throw null; } set { } } - public string MediaType { get { throw null; } set { } } + public string? CharSet { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.DisallowNullAttribute] + public string? MediaType { get { throw null; } set { } } public System.Collections.Generic.ICollection Parameters { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.MediaTypeHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.MediaTypeHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.MediaTypeHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.MediaTypeHeaderValue? parsedValue) { throw null; } } public sealed partial class MediaTypeWithQualityHeaderValue : System.Net.Http.Headers.MediaTypeHeaderValue, System.ICloneable { public MediaTypeWithQualityHeaderValue(string mediaType) : base (default(System.Net.Http.Headers.MediaTypeHeaderValue)) { } public MediaTypeWithQualityHeaderValue(string mediaType, double quality) : base (default(System.Net.Http.Headers.MediaTypeHeaderValue)) { } public double? Quality { get { throw null; } set { } } - public static new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue Parse(string input) { throw null; } + public static new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.MediaTypeWithQualityHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.MediaTypeWithQualityHeaderValue? parsedValue) { throw null; } } public partial class NameValueHeaderValue : System.ICloneable { protected NameValueHeaderValue(System.Net.Http.Headers.NameValueHeaderValue source) { } public NameValueHeaderValue(string name) { } - public NameValueHeaderValue(string name, string value) { } + public NameValueHeaderValue(string name, string? value) { } public string Name { get { throw null; } } - public string Value { get { throw null; } set { } } - public override bool Equals(object obj) { throw null; } + public string? Value { get { throw null; } set { } } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.NameValueHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.NameValueHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.NameValueHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.NameValueHeaderValue? parsedValue) { throw null; } } public partial class NameValueWithParametersHeaderValue : System.Net.Http.Headers.NameValueHeaderValue, System.ICloneable { protected NameValueWithParametersHeaderValue(System.Net.Http.Headers.NameValueWithParametersHeaderValue source) : base (default(string)) { } public NameValueWithParametersHeaderValue(string name) : base (default(string)) { } - public NameValueWithParametersHeaderValue(string name, string value) : base (default(string)) { } + public NameValueWithParametersHeaderValue(string name, string? value) : base (default(string)) { } public System.Collections.Generic.ICollection Parameters { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static new System.Net.Http.Headers.NameValueWithParametersHeaderValue Parse(string input) { throw null; } + public static new System.Net.Http.Headers.NameValueWithParametersHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.NameValueWithParametersHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.NameValueWithParametersHeaderValue? parsedValue) { throw null; } } public partial class ProductHeaderValue : System.ICloneable { public ProductHeaderValue(string name) { } - public ProductHeaderValue(string name, string version) { } + public ProductHeaderValue(string name, string? version) { } public string Name { get { throw null; } } - public string Version { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public string? Version { get { throw null; } } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.ProductHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.ProductHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.ProductHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, out System.Net.Http.Headers.ProductHeaderValue? parsedValue) { throw null; } } public partial class ProductInfoHeaderValue : System.ICloneable { public ProductInfoHeaderValue(System.Net.Http.Headers.ProductHeaderValue product) { } public ProductInfoHeaderValue(string comment) { } - public ProductInfoHeaderValue(string productName, string productVersion) { } - public string Comment { get { throw null; } } - public System.Net.Http.Headers.ProductHeaderValue Product { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public ProductInfoHeaderValue(string productName, string? productVersion) { } + public string? Comment { get { throw null; } } + public System.Net.Http.Headers.ProductHeaderValue? Product { get { throw null; } } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } public static System.Net.Http.Headers.ProductInfoHeaderValue Parse(string input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.ProductInfoHeaderValue parsedValue) { throw null; } + public static bool TryParse(string input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ProductInfoHeaderValue? parsedValue) { throw null; } } public partial class RangeConditionHeaderValue : System.ICloneable { @@ -587,13 +591,13 @@ public RangeConditionHeaderValue(System.DateTimeOffset date) { } public RangeConditionHeaderValue(System.Net.Http.Headers.EntityTagHeaderValue entityTag) { } public RangeConditionHeaderValue(string entityTag) { } public System.DateTimeOffset? Date { get { throw null; } } - public System.Net.Http.Headers.EntityTagHeaderValue EntityTag { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public System.Net.Http.Headers.EntityTagHeaderValue? EntityTag { get { throw null; } } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.RangeConditionHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.RangeConditionHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.RangeConditionHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.RangeConditionHeaderValue? parsedValue) { throw null; } } public partial class RangeHeaderValue : System.ICloneable { @@ -601,19 +605,19 @@ public RangeHeaderValue() { } public RangeHeaderValue(long? from, long? to) { } public System.Collections.Generic.ICollection Ranges { get { throw null; } } public string Unit { get { throw null; } set { } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.RangeHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.RangeHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.RangeHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.RangeHeaderValue? parsedValue) { throw null; } } public partial class RangeItemHeaderValue : System.ICloneable { public RangeItemHeaderValue(long? from, long? to) { } public long? From { get { throw null; } } public long? To { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } @@ -624,12 +628,12 @@ public RetryConditionHeaderValue(System.DateTimeOffset date) { } public RetryConditionHeaderValue(System.TimeSpan delta) { } public System.DateTimeOffset? Date { get { throw null; } } public System.TimeSpan? Delta { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.RetryConditionHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.RetryConditionHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.RetryConditionHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.RetryConditionHeaderValue? parsedValue) { throw null; } } public partial class StringWithQualityHeaderValue : System.ICloneable { @@ -637,12 +641,12 @@ public StringWithQualityHeaderValue(string value) { } public StringWithQualityHeaderValue(string value, double quality) { } public double? Quality { get { throw null; } } public string Value { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.StringWithQualityHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.StringWithQualityHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.StringWithQualityHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.StringWithQualityHeaderValue? parsedValue) { throw null; } } public partial class TransferCodingHeaderValue : System.ICloneable { @@ -650,37 +654,37 @@ protected TransferCodingHeaderValue(System.Net.Http.Headers.TransferCodingHeader public TransferCodingHeaderValue(string value) { } public System.Collections.Generic.ICollection Parameters { get { throw null; } } public string Value { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.TransferCodingHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.TransferCodingHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.TransferCodingHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.TransferCodingHeaderValue? parsedValue) { throw null; } } public sealed partial class TransferCodingWithQualityHeaderValue : System.Net.Http.Headers.TransferCodingHeaderValue, System.ICloneable { public TransferCodingWithQualityHeaderValue(string value) : base (default(System.Net.Http.Headers.TransferCodingHeaderValue)) { } public TransferCodingWithQualityHeaderValue(string value, double quality) : base (default(System.Net.Http.Headers.TransferCodingHeaderValue)) { } public double? Quality { get { throw null; } set { } } - public static new System.Net.Http.Headers.TransferCodingWithQualityHeaderValue Parse(string input) { throw null; } + public static new System.Net.Http.Headers.TransferCodingWithQualityHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.TransferCodingWithQualityHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.TransferCodingWithQualityHeaderValue? parsedValue) { throw null; } } public partial class ViaHeaderValue : System.ICloneable { public ViaHeaderValue(string protocolVersion, string receivedBy) { } - public ViaHeaderValue(string protocolVersion, string receivedBy, string protocolName) { } - public ViaHeaderValue(string protocolVersion, string receivedBy, string protocolName, string comment) { } - public string Comment { get { throw null; } } - public string ProtocolName { get { throw null; } } + public ViaHeaderValue(string protocolVersion, string receivedBy, string? protocolName) { } + public ViaHeaderValue(string protocolVersion, string receivedBy, string? protocolName, string? comment) { } + public string? Comment { get { throw null; } } + public string? ProtocolName { get { throw null; } } public string ProtocolVersion { get { throw null; } } public string ReceivedBy { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.ViaHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.ViaHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.ViaHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ViaHeaderValue? parsedValue) { throw null; } } public partial class WarningHeaderValue : System.ICloneable { @@ -690,11 +694,11 @@ public WarningHeaderValue(int code, string agent, string text, System.DateTimeOf public int Code { get { throw null; } } public System.DateTimeOffset? Date { get { throw null; } } public string Text { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - public static System.Net.Http.Headers.WarningHeaderValue Parse(string input) { throw null; } + public static System.Net.Http.Headers.WarningHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, out System.Net.Http.Headers.WarningHeaderValue parsedValue) { throw null; } + public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.WarningHeaderValue? parsedValue) { throw null; } } } diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.csproj b/src/libraries/System.Net.Http/ref/System.Net.Http.csproj index 0a4ab505cc5c84..9f96fca1d9e605 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent) + enable diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index 98aa3953608d41..669571d8e63fba 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -8,6 +8,7 @@ true $(DefineConstants);HTTP_DLL $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS + enable $(DefineConstants);SYSNETHTTP_NO_OPENSSL diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/ByteArrayContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/ByteArrayContent.cs index c6e85c0db157db..9b1e9b0e86dfe2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/ByteArrayContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/ByteArrayContent.cs @@ -51,10 +51,10 @@ public ByteArrayContent(byte[] content, int offset, int count) SetBuffer(_content, _offset, _count); } - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => SerializeToStreamAsyncCore(stream, default); - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => // Only skip the original protected virtual SerializeToStreamAsync if this // isn't a derived type that may have overridden the behavior. GetType() == typeof(ByteArrayContent) ? SerializeToStreamAsyncCore(stream, cancellationToken) : @@ -72,7 +72,7 @@ protected internal override bool TryComputeLength(out long length) protected override Task CreateContentReadStreamAsync() => Task.FromResult(CreateMemoryStreamForByteArray()); - internal override Stream TryCreateContentReadStream() => + internal override Stream? TryCreateContentReadStream() => GetType() == typeof(ByteArrayContent) ? CreateMemoryStreamForByteArray() : // type check ensures we use possible derived type's CreateContentReadStreamAsync override null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DelegatingHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DelegatingHandler.cs index eb3651b5f76960..7fb7b5e395936a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DelegatingHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DelegatingHandler.cs @@ -7,16 +7,18 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http { public abstract class DelegatingHandler : HttpMessageHandler { - private HttpMessageHandler _innerHandler; + private HttpMessageHandler? _innerHandler; private volatile bool _operationStarted = false; private volatile bool _disposed = false; - public HttpMessageHandler InnerHandler + [DisallowNull] + public HttpMessageHandler? InnerHandler { get { @@ -51,7 +53,7 @@ protected internal override Task SendAsync(HttpRequestMessa throw new ArgumentNullException(nameof(request), SR.net_http_handler_norequest); } SetOperationStarted(); - return _innerHandler.SendAsync(request, cancellationToken); + return _innerHandler!.SendAsync(request, cancellationToken); } protected override void Dispose(bool disposing) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs index 682e91c7ecbd88..3e4cf7f2cffb19 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs @@ -45,7 +45,7 @@ protected internal override async Task SendAsync(HttpReques throw new ArgumentNullException(nameof(request), SR.net_http_handler_norequest); } - Activity activity = null; + Activity? activity = null; // if there is no listener, but propagation is enabled (with previous IsEnabled() check) // do not write any events just start/stop Activity and propagate Ids @@ -92,13 +92,13 @@ protected internal override async Task SendAsync(HttpReques } // If we are on at all, we propagate current activity information - Activity currentActivity = Activity.Current; + Activity? currentActivity = Activity.Current; if (currentActivity != null) { InjectHeaders(currentActivity, request); } - Task responseTask = null; + Task? responseTask = null; try { responseTask = base.SendAsync(request, cancellationToken); @@ -164,14 +164,14 @@ internal ActivityStartData(HttpRequestMessage request) private sealed class ActivityStopData { - internal ActivityStopData(HttpResponseMessage response, HttpRequestMessage request, TaskStatus requestTaskStatus) + internal ActivityStopData(HttpResponseMessage? response, HttpRequestMessage request, TaskStatus requestTaskStatus) { Response = response; Request = request; RequestTaskStatus = requestTaskStatus; } - public HttpResponseMessage Response { get; } + public HttpResponseMessage? Response { get; } public HttpRequestMessage Request { get; } public TaskStatus RequestTaskStatus { get; } @@ -210,7 +210,7 @@ internal RequestData(HttpRequestMessage request, Guid loggingRequestId, long tim private sealed class ResponseData { - internal ResponseData(HttpResponseMessage response, Guid loggingRequestId, long timestamp, TaskStatus requestTaskStatus) + internal ResponseData(HttpResponseMessage? response, Guid loggingRequestId, long timestamp, TaskStatus requestTaskStatus) { Response = response; LoggingRequestId = loggingRequestId; @@ -218,7 +218,7 @@ internal ResponseData(HttpResponseMessage response, Guid loggingRequestId, long RequestTaskStatus = requestTaskStatus; } - public HttpResponseMessage Response { get; } + public HttpResponseMessage? Response { get; } public Guid LoggingRequestId { get; } public long Timestamp { get; } public TaskStatus RequestTaskStatus { get; } @@ -240,7 +240,7 @@ private static bool GetEnableActivityPropagationValue() } // AppContext switch wasn't used. Check the environment variable to determine which handler should be used. - string envVar = Environment.GetEnvironmentVariable(EnableActivityPropagationEnvironmentVariableSettingName); + string? envVar = Environment.GetEnvironmentVariable(EnableActivityPropagationEnvironmentVariableSettingName); if (envVar != null && (envVar.Equals("false", StringComparison.OrdinalIgnoreCase) || envVar.Equals("0"))) { // Suppress Activity propagation. @@ -273,14 +273,14 @@ private static void InjectHeaders(Activity currentActivity, HttpRequestMessage r } // we expect baggage to be empty or contain a few items - using (IEnumerator> e = currentActivity.Baggage.GetEnumerator()) + using (IEnumerator> e = currentActivity.Baggage.GetEnumerator()) { if (e.MoveNext()) { var baggage = new List(); do { - KeyValuePair item = e.Current; + KeyValuePair item = e.Current; baggage.Add(new NameValueHeaderValue(WebUtility.UrlEncode(item.Key), WebUtility.UrlEncode(item.Value)).ToString()); } while (e.MoveNext()); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/FormUrlEncodedContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/FormUrlEncodedContent.cs index 85051d1260894d..7ca4a99a1fd125 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/FormUrlEncodedContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/FormUrlEncodedContent.cs @@ -13,13 +13,13 @@ namespace System.Net.Http { public class FormUrlEncodedContent : ByteArrayContent { - public FormUrlEncodedContent(IEnumerable> nameValueCollection) + public FormUrlEncodedContent(IEnumerable> nameValueCollection) : base(GetContentByteArray(nameValueCollection)) { Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); } - private static byte[] GetContentByteArray(IEnumerable> nameValueCollection) + private static byte[] GetContentByteArray(IEnumerable> nameValueCollection) { if (nameValueCollection == null) { @@ -28,7 +28,7 @@ private static byte[] GetContentByteArray(IEnumerable pair in nameValueCollection) + foreach (KeyValuePair pair in nameValueCollection) { if (builder.Length > 0) { @@ -43,7 +43,7 @@ private static byte[] GetContentByteArray(IEnumerable + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => // Only skip the original protected virtual SerializeToStreamAsync if this // isn't a derived type that may have overridden the behavior. GetType() == typeof(FormUrlEncodedContent) ? SerializeToStreamAsyncCore(stream, cancellationToken) : base.SerializeToStreamAsync(stream, context, cancellationToken); - internal override Stream TryCreateContentReadStream() => + internal override Stream? TryCreateContentReadStream() => GetType() == typeof(FormUrlEncodedContent) ? CreateMemoryStreamForByteArray() : // type check ensures we use possible derived type's CreateContentReadStreamAsync override null; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderParser.cs index b51ff21a8607c9..9990f4824251c1 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderParser.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Resources; using System.Text; @@ -27,8 +28,8 @@ private AltSvcHeaderParser() { } - protected override int GetParsedValueLength(string value, int startIndex, object storeValue, - out object parsedValue) + protected override int GetParsedValueLength(string value, int startIndex, object? storeValue, + out object? parsedValue) { Debug.Assert(startIndex >= 0); Debug.Assert(startIndex < value.Length); @@ -41,7 +42,7 @@ protected override int GetParsedValueLength(string value, int startIndex, object int idx = startIndex; - if (!TryReadPercentEncodedAlpnProtocolName(value, idx, out string alpnProtocolName, out int alpnProtocolNameLength)) + if (!TryReadPercentEncodedAlpnProtocolName(value, idx, out string? alpnProtocolName, out int alpnProtocolNameLength)) { parsedValue = null; return 0; @@ -68,7 +69,7 @@ protected override int GetParsedValueLength(string value, int startIndex, object return 0; } - if (!TryReadQuotedAltAuthority(value, idx, out string altAuthorityHost, out int altAuthorityPort, out int altAuthorityLength)) + if (!TryReadQuotedAltAuthority(value, idx, out string? altAuthorityHost, out int altAuthorityPort, out int altAuthorityLength)) { parsedValue = null; return 0; @@ -189,7 +190,7 @@ private static bool IsOptionalWhiteSpace(char ch) return ch == ' ' || ch == '\t'; } - private static bool TryReadPercentEncodedAlpnProtocolName(string value, int startIndex, out string result, out int readLength) + private static bool TryReadPercentEncodedAlpnProtocolName(string value, int startIndex, [NotNullWhen(true)] out string? result, out int readLength) { int tokenLength = HttpRuleParser.GetTokenLength(value, startIndex); @@ -260,7 +261,7 @@ private static bool TryReadPercentEncodedAlpnProtocolName(string value, int star return TryReadUnknownPercentEncodedAlpnProtocolName(span, out result); } - private static bool TryReadUnknownPercentEncodedAlpnProtocolName(ReadOnlySpan value, out string result) + private static bool TryReadUnknownPercentEncodedAlpnProtocolName(ReadOnlySpan value, [NotNullWhen(true)] out string? result) { int idx = value.IndexOf('%'); @@ -322,7 +323,7 @@ private static bool TryReadAlpnHexDigit(char ch, out int nibble) return false; } - private static bool TryReadQuotedAltAuthority(string value, int startIndex, out string host, out int port, out int readLength) + private static bool TryReadQuotedAltAuthority(string value, int startIndex, out string? host, out int port, out int readLength) { if (HttpRuleParser.GetQuotedStringLength(value, startIndex, out int quotedLength) != HttpParseResult.Parsed) { @@ -364,7 +365,7 @@ private static bool TryReadQuotedAltAuthority(string value, int startIndex, out return false; } - private static bool TryReadQuotedValue(ReadOnlySpan value, out string result) + private static bool TryReadQuotedValue(ReadOnlySpan value, out string? result) { int idx = value.IndexOf('\\'); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderValue.cs index f6d84bf6320f4e..39dfed8b3cf014 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderValue.cs @@ -13,7 +13,7 @@ internal sealed class AltSvcHeaderValue { public static AltSvcHeaderValue Clear { get; } = new AltSvcHeaderValue("clear", host: null, port: 0, maxAge: TimeSpan.Zero, persist: false); - public AltSvcHeaderValue(string alpnProtocolName, string host, int port, TimeSpan maxAge, bool persist) + public AltSvcHeaderValue(string alpnProtocolName, string? host, int port, TimeSpan maxAge, bool persist) { AlpnProtocolName = alpnProtocolName; Host = host; @@ -28,7 +28,7 @@ public AltSvcHeaderValue(string alpnProtocolName, string host, int port, TimeSpa /// The name of the host serving this alternate service. /// If null, the alternate service is on the same host this header was received from. /// - public string Host { get; } + public string? Host { get; } public int Port { get; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs index 5eaa82274ca3ea..069e59c0731f03 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs @@ -3,13 +3,14 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { public class AuthenticationHeaderValue : ICloneable { - private string _scheme; - private string _parameter; + private string _scheme = null!; + private string? _parameter; public string Scheme { @@ -25,7 +26,7 @@ public string Scheme // Due to Base64 encoding we have two final "=". The value is neither a token nor a quoted-string, so it must // be an auth-param according to the RFC definition. But that's also incorrect: auth-param means that we // consider the value before the first "=" as "name" and the final "=" as "value". - public string Parameter + public string? Parameter { get { return _parameter; } } @@ -35,7 +36,7 @@ public AuthenticationHeaderValue(string scheme) { } - public AuthenticationHeaderValue(string scheme, string parameter) + public AuthenticationHeaderValue(string scheme, string? parameter) { HeaderUtilities.CheckValidToken(scheme, nameof(scheme)); _scheme = scheme; @@ -63,9 +64,9 @@ public override string ToString() return _scheme + " " + _parameter; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - AuthenticationHeaderValue other = obj as AuthenticationHeaderValue; + AuthenticationHeaderValue? other = obj as AuthenticationHeaderValue; if (other == null) { @@ -96,28 +97,27 @@ public override int GetHashCode() return result; } - public static AuthenticationHeaderValue Parse(string input) + public static AuthenticationHeaderValue Parse(string? input) { int index = 0; return (AuthenticationHeaderValue)GenericHeaderParser.SingleValueAuthenticationParser.ParseValue( input, null, ref index); } - public static bool TryParse(string input, out AuthenticationHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out AuthenticationHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.SingleValueAuthenticationParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.SingleValueAuthenticationParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (AuthenticationHeaderValue)output; + parsedValue = (AuthenticationHeaderValue)output!; return true; } return false; } - internal static int GetAuthenticationLength(string input, int startIndex, out object parsedValue) + internal static int GetAuthenticationLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); @@ -137,7 +137,7 @@ internal static int GetAuthenticationLength(string input, int startIndex, out ob } var result = new AuthenticationHeaderValue(); - string targetScheme = null; + string? targetScheme = null; switch (schemeLength) { // Avoid allocating a scheme string for the most common cases. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/BaseHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/BaseHeaderParser.cs index 0b4162c5b10eaa..f3d9ef5e902026 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/BaseHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/BaseHeaderParser.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { @@ -21,11 +22,13 @@ protected BaseHeaderParser(bool supportsMultipleValues) /// /// The resulting value parsed. /// If a value could be parsed, the number of characters used to parse that value. Otherwise, 0. - protected abstract int GetParsedValueLength(string value, int startIndex, object storeValue, - out object parsedValue); + protected abstract int GetParsedValueLength(string value, int startIndex, object? storeValue, + out object? parsedValue); - public sealed override bool TryParseValue(string value, object storeValue, ref int index, - out object parsedValue) +#pragma warning disable CS8765 // Doesn't match overriden member nullable attribute on out parameter + public sealed override bool TryParseValue(string? value, object? storeValue, ref int index, + out object? parsedValue) +#pragma warning restore CS8765 { parsedValue = null; @@ -57,8 +60,7 @@ public sealed override bool TryParseValue(string value, object storeValue, ref i return SupportsMultipleValues; } - object result = null; - int length = GetParsedValueLength(value, current, storeValue, out result); + int length = GetParsedValueLength(value, current, storeValue, out object? result); if (length == 0) { @@ -76,7 +78,7 @@ public sealed override bool TryParseValue(string value, object storeValue, ref i } index = current; - parsedValue = result; + parsedValue = result!; return true; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ByteArrayHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ByteArrayHeaderParser.cs index b4e24e4f3c0918..3519356e64b693 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ByteArrayHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ByteArrayHeaderParser.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { @@ -24,7 +25,7 @@ public override string ToString(object value) return Convert.ToBase64String((byte[])value); } - public override bool TryParseValue(string value, object storeValue, ref int index, out object parsedValue) + public override bool TryParseValue(string? value, object? storeValue, ref int index, [NotNullWhen(true)] out object? parsedValue) { parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderParser.cs index b3f6ed2bc14b88..6c312dc238c2bd 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderParser.cs @@ -20,10 +20,10 @@ private CacheControlHeaderParser() { } - protected override int GetParsedValueLength(string value, int startIndex, object storeValue, - out object parsedValue) + protected override int GetParsedValueLength(string value, int startIndex, object? storeValue, + out object? parsedValue) { - CacheControlHeaderValue temp = storeValue as CacheControlHeaderValue; + CacheControlHeaderValue? temp = storeValue as CacheControlHeaderValue; Debug.Assert(storeValue == null || temp != null, "'storeValue' is not of type CacheControlHeaderValue"); int resultLength = CacheControlHeaderValue.GetCacheControlLength(value, startIndex, temp, out temp); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderValue.cs index 83b3cb213c88a8..e73adeb9b2bc86 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderValue.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Text; @@ -29,7 +30,7 @@ public class CacheControlHeaderValue : ICloneable private static readonly Action s_checkIsValidToken = CheckIsValidToken; private bool _noCache; - private ObjectCollection _noCacheHeaders; + private ObjectCollection? _noCacheHeaders; private bool _noStore; private TimeSpan? _maxAge; private TimeSpan? _sharedMaxAge; @@ -40,10 +41,10 @@ public class CacheControlHeaderValue : ICloneable private bool _onlyIfCached; private bool _publicField; private bool _privateField; - private ObjectCollection _privateHeaders; + private ObjectCollection? _privateHeaders; private bool _mustRevalidate; private bool _proxyRevalidate; - private ObjectCollection _extensions; + private ObjectCollection? _extensions; public bool NoCache { @@ -315,9 +316,9 @@ public override string ToString() return StringBuilderCache.GetStringAndRelease(sb); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - CacheControlHeaderValue other = obj as CacheControlHeaderValue; + CacheControlHeaderValue? other = obj as CacheControlHeaderValue; if (other == null) { @@ -398,28 +399,27 @@ public override int GetHashCode() return result; } - public static CacheControlHeaderValue Parse(string input) + public static CacheControlHeaderValue Parse(string? input) { int index = 0; return (CacheControlHeaderValue)CacheControlHeaderParser.Parser.ParseValue(input, null, ref index); } - public static bool TryParse(string input, out CacheControlHeaderValue parsedValue) + public static bool TryParse(string? input, out CacheControlHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (CacheControlHeaderParser.Parser.TryParseValue(input, null, ref index, out output)) + if (CacheControlHeaderParser.Parser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (CacheControlHeaderValue)output; + parsedValue = (CacheControlHeaderValue?)output; return true; } return false; } - internal static int GetCacheControlLength(string input, int startIndex, CacheControlHeaderValue storeValue, - out CacheControlHeaderValue parsedValue) + internal static int GetCacheControlLength(string? input, int startIndex, CacheControlHeaderValue? storeValue, + out CacheControlHeaderValue? parsedValue) { Debug.Assert(startIndex >= 0); @@ -433,7 +433,7 @@ internal static int GetCacheControlLength(string input, int startIndex, CacheCon // Cache-Control header consists of a list of name/value pairs, where the value is optional. So use an // instance of NameValueHeaderParser to parse the string. int current = startIndex; - object nameValue = null; + object? nameValue; List nameValueList = new List(); while (current < input.Length) { @@ -442,7 +442,7 @@ internal static int GetCacheControlLength(string input, int startIndex, CacheCon return 0; } - nameValueList.Add(nameValue as NameValueHeaderValue); + nameValueList.Add((NameValueHeaderValue)nameValue); } // If we get here, we were able to successfully parse the string as list of name/value pairs. Now analyze @@ -451,7 +451,7 @@ internal static int GetCacheControlLength(string input, int startIndex, CacheCon // Cache-Control is a header supporting lists of values. However, expose the header as an instance of // CacheControlHeaderValue. So if we already have an instance of CacheControlHeaderValue, add the values // from this string to the existing instances. - CacheControlHeaderValue result = storeValue; + CacheControlHeaderValue? result = storeValue; if (result == null) { result = new CacheControlHeaderValue(); @@ -562,7 +562,7 @@ private static bool TrySetTokenOnlyValue(NameValueHeaderValue nameValue, ref boo } private static bool TrySetOptionalTokenList(NameValueHeaderValue nameValue, ref bool boolField, - ref ObjectCollection destination) + ref ObjectCollection? destination) { Debug.Assert(nameValue != null); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs index a999f77fab4a65..f52e6602844ece 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text; @@ -22,8 +23,8 @@ public class ContentDispositionHeaderValue : ICloneable private const string size = "size"; // Use ObjectCollection since we may have multiple parameters with the same name. - private ObjectCollection _parameters; - private string _dispositionType; + private ObjectCollection? _parameters; + private string _dispositionType = null!; #endregion Fields @@ -51,19 +52,19 @@ public ICollection Parameters } } - public string Name + public string? Name { get { return GetName(name); } set { SetName(name, value); } } - public string FileName + public string? FileName { get { return GetName(fileName); } set { SetName(fileName, value); } } - public string FileNameStar + public string? FileNameStar { get { return GetName(fileNameStar); } set { SetName(fileNameStar, value); } @@ -91,11 +92,11 @@ public long? Size { get { - NameValueHeaderValue sizeParameter = NameValueHeaderValue.Find(_parameters, size); + NameValueHeaderValue? sizeParameter = NameValueHeaderValue.Find(_parameters, size); ulong value; if (sizeParameter != null) { - string sizeString = sizeParameter.Value; + string? sizeString = sizeParameter.Value; if (ulong.TryParse(sizeString, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) { return (long)value; @@ -105,13 +106,13 @@ public long? Size } set { - NameValueHeaderValue sizeParameter = NameValueHeaderValue.Find(_parameters, size); + NameValueHeaderValue? sizeParameter = NameValueHeaderValue.Find(_parameters, size); if (value == null) { // Remove parameter. if (sizeParameter != null) { - _parameters.Remove(sizeParameter); + _parameters!.Remove(sizeParameter); } } else if (value < 0) @@ -172,9 +173,9 @@ public override string ToString() return StringBuilderCache.GetStringAndRelease(sb); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - ContentDispositionHeaderValue other = obj as ContentDispositionHeaderValue; + ContentDispositionHeaderValue? other = obj as ContentDispositionHeaderValue; if (other == null) { @@ -201,28 +202,27 @@ object ICloneable.Clone() #region Parsing - public static ContentDispositionHeaderValue Parse(string input) + public static ContentDispositionHeaderValue Parse(string? input) { int index = 0; return (ContentDispositionHeaderValue)GenericHeaderParser.ContentDispositionParser.ParseValue(input, null, ref index); } - public static bool TryParse(string input, out ContentDispositionHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out ContentDispositionHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.ContentDispositionParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.ContentDispositionParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (ContentDispositionHeaderValue)output; + parsedValue = (ContentDispositionHeaderValue)output!; return true; } return false; } - internal static int GetDispositionTypeLength(string input, int startIndex, out object parsedValue) + internal static int GetDispositionTypeLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); @@ -234,7 +234,7 @@ internal static int GetDispositionTypeLength(string input, int startIndex, out o } // Caller must remove leading whitespace. If not, we'll return 0. - string dispositionType = null; + string? dispositionType; int dispositionTypeLength = GetDispositionTypeExpressionLength(input, startIndex, out dispositionType); if (dispositionTypeLength == 0) @@ -245,7 +245,7 @@ internal static int GetDispositionTypeLength(string input, int startIndex, out o int current = startIndex + dispositionTypeLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); ContentDispositionHeaderValue contentDispositionHeader = new ContentDispositionHeaderValue(); - contentDispositionHeader._dispositionType = dispositionType; + contentDispositionHeader._dispositionType = dispositionType!; // If we're not done and we have a parameter delimiter, then we have a list of parameters. if ((current < input.Length) && (input[current] == ';')) @@ -268,7 +268,7 @@ internal static int GetDispositionTypeLength(string input, int startIndex, out o return current - startIndex; } - private static int GetDispositionTypeExpressionLength(string input, int startIndex, out string dispositionType) + private static int GetDispositionTypeExpressionLength(string input, int startIndex, out string? dispositionType) { Debug.Assert((input != null) && (input.Length > 0) && (startIndex < input.Length)); @@ -296,9 +296,8 @@ private static void CheckDispositionTypeFormat(string dispositionType, string pa } // When adding values using strongly typed objects, no leading/trailing LWS (whitespace) are allowed. - string tempDispositionType; - int dispositionTypeLength = GetDispositionTypeExpressionLength(dispositionType, 0, out tempDispositionType); - if ((dispositionTypeLength == 0) || (tempDispositionType.Length != dispositionType.Length)) + int dispositionTypeLength = GetDispositionTypeExpressionLength(dispositionType, 0, out string? tempDispositionType); + if ((dispositionTypeLength == 0) || (tempDispositionType!.Length != dispositionType.Length)) { throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_headers_invalid_value, dispositionType)); @@ -313,7 +312,7 @@ private static void CheckDispositionTypeFormat(string dispositionType, string pa // Returns null if the parameter is not present or the format is incorrect. private DateTimeOffset? GetDate(string parameter) { - NameValueHeaderValue dateParameter = NameValueHeaderValue.Find(_parameters, parameter); + NameValueHeaderValue? dateParameter = NameValueHeaderValue.Find(_parameters, parameter); DateTimeOffset date; if (dateParameter != null) { @@ -334,13 +333,13 @@ private static void CheckDispositionTypeFormat(string dispositionType, string pa // Add the given parameter to the list. Remove if date is null. private void SetDate(string parameter, DateTimeOffset? date) { - NameValueHeaderValue dateParameter = NameValueHeaderValue.Find(_parameters, parameter); + NameValueHeaderValue? dateParameter = NameValueHeaderValue.Find(_parameters, parameter); if (date == null) { // Remove parameter. if (dateParameter != null) { - _parameters.Remove(dateParameter); + _parameters!.Remove(dateParameter); } } else @@ -360,15 +359,16 @@ private void SetDate(string parameter, DateTimeOffset? date) // Gets a parameter of the given name and attempts to decode it if necessary. // Returns null if the parameter is not present or the raw value if the encoding is incorrect. - private string GetName(string parameter) + private string? GetName(string parameter) { - NameValueHeaderValue nameParameter = NameValueHeaderValue.Find(_parameters, parameter); + NameValueHeaderValue? nameParameter = NameValueHeaderValue.Find(_parameters, parameter); if (nameParameter != null) { - string result; + string? result; // filename*=utf-8'lang'%7FMyString if (parameter.EndsWith('*')) { + Debug.Assert(nameParameter.Value != null); if (TryDecode5987(nameParameter.Value, out result)) { return result; @@ -389,15 +389,15 @@ private string GetName(string parameter) // Add/update the given parameter in the list, encoding if necessary. // Remove if value is null/Empty - private void SetName(string parameter, string value) + private void SetName(string parameter, string? value) { - NameValueHeaderValue nameParameter = NameValueHeaderValue.Find(_parameters, parameter); + NameValueHeaderValue? nameParameter = NameValueHeaderValue.Find(_parameters, parameter); if (string.IsNullOrEmpty(value)) { // Remove parameter. if (nameParameter != null) { - _parameters.Remove(nameParameter); + _parameters!.Remove(nameParameter); } } else @@ -476,12 +476,12 @@ private static string EncodeMime(string input) } // Attempt to decode MIME encoded strings. - private static bool TryDecodeMime(string input, out string output) + private static bool TryDecodeMime(string? input, [NotNullWhen(true)] out string? output) { Debug.Assert(input != null); output = null; - string processedInput = input; + string? processedInput = input; // Require quotes, min of "=?e?b??=" if (!IsQuoted(processedInput) || processedInput.Length < 10) { @@ -519,7 +519,7 @@ private static bool TryDecodeMime(string input, out string output) // Attempt to decode using RFC 5987 encoding. // encoding'language'my%20string - private static bool TryDecode5987(string input, out string output) + private static bool TryDecode5987(string input, out string? output) { output = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentRangeHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentRangeHeaderValue.cs index 05362b0fc502f2..ecb3f51aca7393 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentRangeHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentRangeHeaderValue.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Text; @@ -11,7 +12,7 @@ namespace System.Net.Http.Headers { public class ContentRangeHeaderValue : ICloneable { - private string _unit; + private string _unit = null!; private long? _from; private long? _to; private long? _length; @@ -119,9 +120,9 @@ private ContentRangeHeaderValue(ContentRangeHeaderValue source) _unit = source._unit; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - ContentRangeHeaderValue other = obj as ContentRangeHeaderValue; + ContentRangeHeaderValue? other = obj as ContentRangeHeaderValue; if (other == null) { @@ -157,8 +158,9 @@ public override string ToString() if (HasRange) { - sb.Append(_from.Value); + sb.Append(_from!.Value); sb.Append('-'); + Debug.Assert(_to.HasValue); sb.Append(_to.Value); } else @@ -169,7 +171,7 @@ public override string ToString() sb.Append('/'); if (HasLength) { - sb.Append(_length.Value); + sb.Append(_length!.Value); } else { @@ -179,27 +181,26 @@ public override string ToString() return StringBuilderCache.GetStringAndRelease(sb); } - public static ContentRangeHeaderValue Parse(string input) + public static ContentRangeHeaderValue Parse(string? input) { int index = 0; return (ContentRangeHeaderValue)GenericHeaderParser.ContentRangeParser.ParseValue(input, null, ref index); } - public static bool TryParse(string input, out ContentRangeHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out ContentRangeHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.ContentRangeParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.ContentRangeParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (ContentRangeHeaderValue)output; + parsedValue = (ContentRangeHeaderValue)output!; return true; } return false; } - internal static int GetContentRangeLength(string input, int startIndex, out object parsedValue) + internal static int GetContentRangeLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); @@ -358,7 +359,7 @@ private static bool TryGetRangeLength(string input, ref int current, out int fro } private static bool TryCreateContentRange(string input, string unit, int fromStartIndex, int fromLength, - int toStartIndex, int toLength, int lengthStartIndex, int lengthLength, out object parsedValue) + int toStartIndex, int toLength, int lengthStartIndex, int lengthLength, [NotNullWhen(true)] out object? parsedValue) { parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/DateHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/DateHeaderParser.cs index 9fc560ae840335..cb3e5ad126015e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/DateHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/DateHeaderParser.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { @@ -24,7 +25,7 @@ public override string ToString(object value) return HttpDateParser.DateToString((DateTimeOffset)value); } - public override bool TryParseValue(string value, object storeValue, ref int index, out object parsedValue) + public override bool TryParseValue(string? value, object? storeValue, ref int index, [NotNullWhen(true)] out object? parsedValue) { parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs index 57f893e354c364..46abb6a7f58b3c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs @@ -3,14 +3,15 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { public class EntityTagHeaderValue : ICloneable { - private static EntityTagHeaderValue s_any; + private static EntityTagHeaderValue? s_any; - private string _tag; + private string _tag = null!; private bool _isWeak; public string Tag @@ -82,9 +83,9 @@ public override string ToString() return _tag; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - EntityTagHeaderValue other = obj as EntityTagHeaderValue; + EntityTagHeaderValue? other = obj as EntityTagHeaderValue; if (other == null) { @@ -101,28 +102,27 @@ public override int GetHashCode() return _tag.GetHashCode() ^ _isWeak.GetHashCode(); } - public static EntityTagHeaderValue Parse(string input) + public static EntityTagHeaderValue Parse(string? input) { int index = 0; return (EntityTagHeaderValue)GenericHeaderParser.SingleValueEntityTagParser.ParseValue( input, null, ref index); } - public static bool TryParse(string input, out EntityTagHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out EntityTagHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.SingleValueEntityTagParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.SingleValueEntityTagParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (EntityTagHeaderValue)output; + parsedValue = (EntityTagHeaderValue)output!; return true; } return false; } - internal static int GetEntityTagLength(string input, int startIndex, out EntityTagHeaderValue parsedValue) + internal static int GetEntityTagLength(string? input, int startIndex, out EntityTagHeaderValue? parsedValue) { Debug.Assert(startIndex >= 0); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/GenericHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/GenericHeaderParser.cs index bf891844a814d6..c8cbe3536344bf 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/GenericHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/GenericHeaderParser.cs @@ -9,7 +9,7 @@ namespace System.Net.Http.Headers { internal sealed class GenericHeaderParser : BaseHeaderParser { - private delegate int GetParsedValueLengthDelegate(string value, int startIndex, out object parsedValue); + private delegate int GetParsedValueLengthDelegate(string value, int startIndex, out object? parsedValue); #region Parser instances @@ -41,9 +41,9 @@ internal sealed class GenericHeaderParser : BaseHeaderParser #endregion private readonly GetParsedValueLengthDelegate _getParsedValueLength; - private readonly IEqualityComparer _comparer; + private readonly IEqualityComparer? _comparer; - public override IEqualityComparer Comparer + public override IEqualityComparer? Comparer { get { return _comparer; } } @@ -54,7 +54,7 @@ private GenericHeaderParser(bool supportsMultipleValues, GetParsedValueLengthDel } private GenericHeaderParser(bool supportsMultipleValues, GetParsedValueLengthDelegate getParsedValueLength, - IEqualityComparer comparer) + IEqualityComparer? comparer) : base(supportsMultipleValues) { Debug.Assert(getParsedValueLength != null); @@ -63,38 +63,35 @@ private GenericHeaderParser(bool supportsMultipleValues, GetParsedValueLengthDel _comparer = comparer; } - protected override int GetParsedValueLength(string value, int startIndex, object storeValue, - out object parsedValue) + protected override int GetParsedValueLength(string value, int startIndex, object? storeValue, + out object? parsedValue) { return _getParsedValueLength(value, startIndex, out parsedValue); } #region Parse methods - private static int ParseNameValue(string value, int startIndex, out object parsedValue) + private static int ParseNameValue(string value, int startIndex, out object? parsedValue) { - NameValueHeaderValue temp = null; - int resultLength = NameValueHeaderValue.GetNameValueLength(value, startIndex, out temp); + int resultLength = NameValueHeaderValue.GetNameValueLength(value, startIndex, out NameValueHeaderValue? temp); parsedValue = temp; return resultLength; } - private static int ParseProduct(string value, int startIndex, out object parsedValue) + private static int ParseProduct(string value, int startIndex, out object? parsedValue) { - ProductHeaderValue temp = null; - int resultLength = ProductHeaderValue.GetProductLength(value, startIndex, out temp); + int resultLength = ProductHeaderValue.GetProductLength(value, startIndex, out ProductHeaderValue? temp); parsedValue = temp; return resultLength; } - private static int ParseSingleEntityTag(string value, int startIndex, out object parsedValue) + private static int ParseSingleEntityTag(string value, int startIndex, out object? parsedValue) { - EntityTagHeaderValue temp = null; parsedValue = null; - int resultLength = EntityTagHeaderValue.GetEntityTagLength(value, startIndex, out temp); + int resultLength = EntityTagHeaderValue.GetEntityTagLength(value, startIndex, out EntityTagHeaderValue? temp); // If we don't allow '*' ("Any") as valid ETag value, return false (e.g. 'ETag' header) if (temp == EntityTagHeaderValue.Any) @@ -110,16 +107,15 @@ private static int ParseSingleEntityTag(string value, int startIndex, out object // the value must either be '*' or a list of ETag values. It's not allowed to have both '*' and a list of // ETag values. We're not that strict: We allow both '*' and ETag values in a list. If the server sends such // an invalid list, we want to be able to represent it using the corresponding header property. - private static int ParseMultipleEntityTags(string value, int startIndex, out object parsedValue) + private static int ParseMultipleEntityTags(string value, int startIndex, out object? parsedValue) { - EntityTagHeaderValue temp = null; - int resultLength = EntityTagHeaderValue.GetEntityTagLength(value, startIndex, out temp); + int resultLength = EntityTagHeaderValue.GetEntityTagLength(value, startIndex, out EntityTagHeaderValue? temp); parsedValue = temp; return resultLength; } - private static int ParseMailAddress(string value, int startIndex, out object parsedValue) + private static int ParseMailAddress(string value, int startIndex, out object? parsedValue) { parsedValue = null; @@ -139,10 +135,9 @@ private static int ParseMailAddress(string value, int startIndex, out object par return result.Length; } - private static int ParseHost(string value, int startIndex, out object parsedValue) + private static int ParseHost(string value, int startIndex, out object? parsedValue) { - string host = null; - int hostLength = HttpRuleParser.GetHostLength(value, startIndex, false, out host); + int hostLength = HttpRuleParser.GetHostLength(value, startIndex, false, out string? host); parsedValue = host; return hostLength; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs index e33a5d6f65e0a1..2b955dbd10774c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Text.Unicode; namespace System.Net.Http.Headers @@ -15,7 +16,7 @@ namespace System.Net.Http.Headers internal readonly struct HeaderDescriptor : IEquatable { private readonly string _headerName; - private readonly KnownHeader _knownHeader; + private readonly KnownHeader? _knownHeader; public HeaderDescriptor(KnownHeader knownHeader) { @@ -31,23 +32,23 @@ private HeaderDescriptor(string headerName) } public string Name => _headerName; - public HttpHeaderParser Parser => _knownHeader?.Parser; + public HttpHeaderParser? Parser => _knownHeader?.Parser; public HttpHeaderType HeaderType => _knownHeader == null ? HttpHeaderType.Custom : _knownHeader.HeaderType; - public KnownHeader KnownHeader => _knownHeader; + public KnownHeader? KnownHeader => _knownHeader; public bool Equals(HeaderDescriptor other) => _knownHeader == null ? string.Equals(_headerName, other._headerName, StringComparison.OrdinalIgnoreCase) : _knownHeader == other._knownHeader; public override int GetHashCode() => _knownHeader?.GetHashCode() ?? StringComparer.OrdinalIgnoreCase.GetHashCode(_headerName); - public override bool Equals(object obj) => throw new InvalidOperationException(); // Ensure this is never called, to avoid boxing + public override bool Equals(object? obj) => throw new InvalidOperationException(); // Ensure this is never called, to avoid boxing // Returns false for invalid header name. public static bool TryGet(string headerName, out HeaderDescriptor descriptor) { Debug.Assert(!string.IsNullOrEmpty(headerName)); - KnownHeader knownHeader = KnownHeaders.TryGetKnownHeader(headerName); + KnownHeader? knownHeader = KnownHeaders.TryGetKnownHeader(headerName); if (knownHeader != null) { descriptor = new HeaderDescriptor(knownHeader); @@ -69,7 +70,7 @@ public static bool TryGet(ReadOnlySpan headerName, out HeaderDescriptor de { Debug.Assert(headerName.Length > 0); - KnownHeader knownHeader = KnownHeaders.TryGetKnownHeader(headerName); + KnownHeader? knownHeader = KnownHeaders.TryGetKnownHeader(headerName); if (knownHeader != null) { descriptor = new HeaderDescriptor(knownHeader); @@ -86,7 +87,7 @@ public static bool TryGet(ReadOnlySpan headerName, out HeaderDescriptor de return true; } - internal static bool TryGetStaticQPackHeader(int index, out HeaderDescriptor descriptor, out string knownValue) + internal static bool TryGetStaticQPackHeader(int index, out HeaderDescriptor descriptor, [NotNullWhen(true)] out string? knownValue) { Debug.Assert(index >= 0); Debug.Assert(s_qpackHeaderLookup.Length == 99); @@ -140,7 +141,7 @@ public string GetHeaderValue(ReadOnlySpan headerValue) if (_knownHeader == KnownHeaders.Location) { // Normally Location should be in ISO-8859-1 but occasionally some servers respond with UTF-8. - if (TryDecodeUtf8(headerValue, out string decoded)) + if (TryDecodeUtf8(headerValue, out string? decoded)) { return decoded; } @@ -150,7 +151,7 @@ public string GetHeaderValue(ReadOnlySpan headerValue) return HttpRuleParser.DefaultHttpEncoding.GetString(headerValue); } - private static bool TryDecodeUtf8(ReadOnlySpan input, out string decoded) + private static bool TryDecodeUtf8(ReadOnlySpan input, [NotNullWhen(true)] out string? decoded) { char[] rented = ArrayPool.Shared.Rent(input.Length); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderUtilities.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderUtilities.cs index a8183f11912f36..6e6c78276cae36 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderUtilities.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderUtilities.cs @@ -31,7 +31,7 @@ internal static void SetQuality(ObjectCollection parameter { Debug.Assert(parameters != null); - NameValueHeaderValue qualityParameter = NameValueHeaderValue.Find(parameters, qualityName); + NameValueHeaderValue? qualityParameter = NameValueHeaderValue.Find(parameters, qualityName); if (value.HasValue) { // Note that even if we check the value here, we can't prevent a user from adding an invalid quality @@ -131,7 +131,7 @@ private static void AddHexEscaped(byte c, StringBuilder destination) { Debug.Assert(parameters != null); - NameValueHeaderValue qualityParameter = NameValueHeaderValue.Find(parameters, qualityName); + NameValueHeaderValue? qualityParameter = NameValueHeaderValue.Find(parameters, qualityName); if (qualityParameter != null) { // Note that the RFC requires decimal '.' regardless of the culture. I.e. using ',' as decimal @@ -191,12 +191,12 @@ internal static void CheckValidQuotedString(string value, string parameterName) } } - internal static bool AreEqualCollections(ObjectCollection x, ObjectCollection y) where T : class + internal static bool AreEqualCollections(ObjectCollection? x, ObjectCollection? y) where T : class { return AreEqualCollections(x, y, null); } - internal static bool AreEqualCollections(ObjectCollection x, ObjectCollection y, IEqualityComparer comparer) where T : class + internal static bool AreEqualCollections(ObjectCollection? x, ObjectCollection? y, IEqualityComparer? comparer) where T : class { if (x == null) { @@ -293,7 +293,7 @@ internal static int GetNextNonEmptyOrWhitespaceIndex(string input, int startInde { Debug.Assert(store != null); - object storedValue = store.GetParsedValues(descriptor); + object? storedValue = store.GetParsedValues(descriptor); if (storedValue != null) { return (DateTimeOffset)storedValue; @@ -310,7 +310,7 @@ internal static int GetNextNonEmptyOrWhitespaceIndex(string input, int startInde { Debug.Assert(store != null); - object storedValue = store.GetParsedValues(descriptor); + object? storedValue = store.GetParsedValues(descriptor); if (storedValue != null) { return (TimeSpan)storedValue; @@ -343,7 +343,7 @@ internal static bool TryParseInt64(string value, int offset, int length, out lon return long.TryParse(value.AsSpan(offset, length), NumberStyles.None, provider: null, out result); } - internal static void DumpHeaders(StringBuilder sb, params HttpHeaders[] headers) + internal static void DumpHeaders(StringBuilder sb, params HttpHeaders?[] headers) { // Appends all headers as string similar to: // { @@ -358,7 +358,7 @@ internal static void DumpHeaders(StringBuilder sb, params HttpHeaders[] headers) { if (headers[i] != null) { - foreach (var header in headers[i]) + foreach (var header in headers[i]!) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 { foreach (var headerValue in header.Value) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpContentHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpContentHeaders.cs index 6bb0541910de4a..428632acfa54db 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpContentHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpContentHeaders.cs @@ -13,9 +13,9 @@ public sealed class HttpContentHeaders : HttpHeaders private readonly HttpContent _parent; private bool _contentLengthSet; - private HttpHeaderValueCollection _allow; - private HttpHeaderValueCollection _contentEncoding; - private HttpHeaderValueCollection _contentLanguage; + private HttpHeaderValueCollection? _allow; + private HttpHeaderValueCollection? _contentEncoding; + private HttpHeaderValueCollection? _contentLanguage; public ICollection Allow { @@ -30,9 +30,9 @@ public ICollection Allow } } - public ContentDispositionHeaderValue ContentDisposition + public ContentDispositionHeaderValue? ContentDisposition { - get { return (ContentDispositionHeaderValue)GetParsedValues(KnownHeaders.ContentDisposition.Descriptor); } + get { return (ContentDispositionHeaderValue?)GetParsedValues(KnownHeaders.ContentDisposition.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.ContentDisposition.Descriptor, value); } } @@ -69,7 +69,7 @@ public long? ContentLength get { // 'Content-Length' can only hold one value. So either we get 'null' back or a boxed long value. - object storedValue = GetParsedValues(KnownHeaders.ContentLength.Descriptor); + object? storedValue = GetParsedValues(KnownHeaders.ContentLength.Descriptor); // Only try to calculate the length if the user didn't set the value explicitly using the setter. if (!_contentLengthSet && (storedValue == null)) @@ -103,27 +103,27 @@ public long? ContentLength } } - public Uri ContentLocation + public Uri? ContentLocation { - get { return (Uri)GetParsedValues(KnownHeaders.ContentLocation.Descriptor); } + get { return (Uri?)GetParsedValues(KnownHeaders.ContentLocation.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.ContentLocation.Descriptor, value); } } - public byte[] ContentMD5 + public byte[]? ContentMD5 { - get { return (byte[])GetParsedValues(KnownHeaders.ContentMD5.Descriptor); } + get { return (byte[]?)GetParsedValues(KnownHeaders.ContentMD5.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.ContentMD5.Descriptor, value); } } - public ContentRangeHeaderValue ContentRange + public ContentRangeHeaderValue? ContentRange { - get { return (ContentRangeHeaderValue)GetParsedValues(KnownHeaders.ContentRange.Descriptor); } + get { return (ContentRangeHeaderValue?)GetParsedValues(KnownHeaders.ContentRange.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.ContentRange.Descriptor, value); } } - public MediaTypeHeaderValue ContentType + public MediaTypeHeaderValue? ContentType { - get { return (MediaTypeHeaderValue)GetParsedValues(KnownHeaders.ContentType.Descriptor); } + get { return (MediaTypeHeaderValue?)GetParsedValues(KnownHeaders.ContentType.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.ContentType.Descriptor, value); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpGeneralHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpGeneralHeaders.cs index 550b1117e78a86..9656a0cf0fe421 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpGeneralHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpGeneralHeaders.cs @@ -11,20 +11,20 @@ namespace System.Net.Http.Headers // functionality in both HttpRequestHeaders and HttpResponseHeaders. internal sealed class HttpGeneralHeaders { - private HttpHeaderValueCollection _connection; - private HttpHeaderValueCollection _trailer; - private HttpHeaderValueCollection _transferEncoding; - private HttpHeaderValueCollection _upgrade; - private HttpHeaderValueCollection _via; - private HttpHeaderValueCollection _warning; - private HttpHeaderValueCollection _pragma; + private HttpHeaderValueCollection? _connection; + private HttpHeaderValueCollection? _trailer; + private HttpHeaderValueCollection? _transferEncoding; + private HttpHeaderValueCollection? _upgrade; + private HttpHeaderValueCollection? _via; + private HttpHeaderValueCollection? _warning; + private HttpHeaderValueCollection? _pragma; private readonly HttpHeaders _parent; private bool _transferEncodingChunkedSet; private bool _connectionCloseSet; - public CacheControlHeaderValue CacheControl + public CacheControlHeaderValue? CacheControl { - get { return (CacheControlHeaderValue)_parent.GetParsedValues(KnownHeaders.CacheControl.Descriptor); } + get { return (CacheControlHeaderValue?)_parent.GetParsedValues(KnownHeaders.CacheControl.Descriptor); } set { _parent.SetOrRemoveParsedValue(KnownHeaders.CacheControl.Descriptor, value); } } @@ -57,7 +57,7 @@ public bool? ConnectionClose } } - internal static bool? GetConnectionClose(HttpHeaders parent, HttpGeneralHeaders headers) + internal static bool? GetConnectionClose(HttpHeaders parent, HttpGeneralHeaders? headers) { // If we've already initialized the connection header value collection // and it contains the special value, or if we haven't and the headers contain @@ -117,7 +117,7 @@ public HttpHeaderValueCollection TransferEncoding get { return TransferEncodingCore; } } - internal static bool? GetTransferEncodingChunked(HttpHeaders parent, HttpGeneralHeaders headers) + internal static bool? GetTransferEncodingChunked(HttpHeaders parent, HttpGeneralHeaders? headers) { // If we've already initialized the transfer encoding header value collection // and it contains the special value, or if we haven't and the headers contain diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderParser.cs index 94b64f8199234f..97402f9794a99e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderParser.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { @@ -12,14 +13,14 @@ internal abstract class HttpHeaderParser internal const string DefaultSeparator = ", "; private readonly bool _supportsMultipleValues; - private readonly string _separator; + private readonly string? _separator; public bool SupportsMultipleValues { get { return _supportsMultipleValues; } } - public string Separator + public string? Separator { get { @@ -30,7 +31,7 @@ public string Separator // If ValueType implements Equals() as required, there is no need to provide a comparer. A comparer is needed // e.g. if we want to compare strings using case-insensitive comparison. - public virtual IEqualityComparer Comparer + public virtual IEqualityComparer? Comparer { get { return null; } } @@ -57,9 +58,9 @@ protected HttpHeaderParser(bool supportsMultipleValues, string separator) // pointing to the next non-whitespace character after a delimiter. E.g. if called with a start index of 0 // for string "value , second_value", then after the call completes, 'index' must point to 's', i.e. the first // non-whitespace after the separator ','. - public abstract bool TryParseValue(string value, object storeValue, ref int index, out object parsedValue); + public abstract bool TryParseValue(string? value, object? storeValue, ref int index, [NotNullWhen(true)] out object? parsedValue); - public object ParseValue(string value, object storeValue, ref int index) + public object ParseValue(string? value, object? storeValue, ref int index) { // Index may be value.Length (e.g. both 0). This may be allowed for some headers (e.g. Accept but not // allowed by others (e.g. Content-Length). The parser has to decide if this is valid or not. @@ -67,8 +68,7 @@ public object ParseValue(string value, object storeValue, ref int index) // If a parser returns 'null', it means there was no value, but that's valid (e.g. "Accept: "). The caller // can ignore the value. - object result = null; - if (!TryParseValue(value, storeValue, ref index, out result)) + if (!TryParseValue(value, storeValue, ref index, out object? result)) { throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_headers_invalid_value, value == null ? "" : value.Substring(index))); @@ -80,7 +80,7 @@ public object ParseValue(string value, object storeValue, ref int index) // However for existing types like int, byte[], DateTimeOffset we can't override ToString(). Therefore the // parser provides a ToString() virtual method that can be overridden by derived types to correctly serialize // values (e.g. byte[] to Base64 encoded string). - public virtual string ToString(object value) + public virtual string? ToString(object value) { Debug.Assert(value != null); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderValueCollection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderValueCollection.cs index 02e26a5a576bb3..19534aee7021e4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderValueCollection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderValueCollection.cs @@ -36,8 +36,8 @@ public sealed class HttpHeaderValueCollection : ICollection where T : clas { private readonly HeaderDescriptor _descriptor; private readonly HttpHeaders _store; - private readonly T _specialValue; - private readonly Action, T> _validator; + private readonly T? _specialValue; + private readonly Action, T>? _validator; public int Count { @@ -78,8 +78,8 @@ internal HttpHeaderValueCollection(HeaderDescriptor descriptor, HttpHeaders stor { } - internal HttpHeaderValueCollection(HeaderDescriptor descriptor, HttpHeaders store, T specialValue, - Action, T> validator) + internal HttpHeaderValueCollection(HeaderDescriptor descriptor, HttpHeaders store, T? specialValue, + Action, T>? validator) { Debug.Assert(descriptor.Name != null); Debug.Assert(store != null); @@ -96,12 +96,12 @@ public void Add(T item) _store.AddParsedValue(_descriptor, item); } - public void ParseAdd(string input) + public void ParseAdd(string? input) { _store.Add(_descriptor, input); } - public bool TryParseAdd(string input) + public bool TryParseAdd(string? input) { return _store.TryParseAndAddValue(_descriptor, input); } @@ -129,14 +129,14 @@ public void CopyTo(T[] array, int arrayIndex) throw new ArgumentOutOfRangeException(nameof(arrayIndex)); } - object storeValue = _store.GetParsedValues(_descriptor); + object? storeValue = _store.GetParsedValues(_descriptor); if (storeValue == null) { return; } - List storeValues = storeValue as List; + List? storeValues = storeValue as List; if (storeValues == null) { @@ -147,7 +147,7 @@ public void CopyTo(T[] array, int arrayIndex) { throw new ArgumentException(SR.net_http_copyto_array_too_small); } - array[arrayIndex] = storeValue as T; + array[arrayIndex] = (T)storeValue; } else { @@ -165,19 +165,19 @@ public bool Remove(T item) public IEnumerator GetEnumerator() { - object storeValue = _store.GetParsedValues(_descriptor); + object? storeValue = _store.GetParsedValues(_descriptor); if (storeValue == null) { yield break; } - List storeValues = storeValue as List; + List? storeValues = storeValue as List; if (storeValues == null) { Debug.Assert(storeValue is T); - yield return storeValue as T; + yield return (T)storeValue; } else { @@ -185,7 +185,7 @@ public IEnumerator GetEnumerator() foreach (object item in storeValues) { Debug.Assert(item is T); - yield return item as T; + yield return (T)item; } } } @@ -245,14 +245,14 @@ private int GetCount() { // This is an O(n) operation. - object storeValue = _store.GetParsedValues(_descriptor); + object? storeValue = _store.GetParsedValues(_descriptor); if (storeValue == null) { return 0; } - List storeValues = storeValue as List; + List? storeValues = storeValue as List; if (storeValues == null) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs index 686b0cb5158a27..dfe61faa64ecaa 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs @@ -31,7 +31,7 @@ namespace System.Net.Http.Headers // - HttpResponseHeaders.Via collection will only contain one ViaHeaderValue object with value "1.1 proxy" public abstract class HttpHeaders : IEnumerable>> { - private Dictionary _headerStore; + private Dictionary? _headerStore; private readonly HttpHeaderType _allowedHeaderTypes; private readonly HttpHeaderType _treatAsCustomHeaderTypes; @@ -56,14 +56,14 @@ internal HttpHeaders(HttpHeaderType allowedHeaderTypes, HttpHeaderType treatAsCu _treatAsCustomHeaderTypes = treatAsCustomHeaderTypes & ~HttpHeaderType.NonTrailing; } - internal Dictionary HeaderStore => _headerStore; + internal Dictionary? HeaderStore => _headerStore; - public void Add(string name, string value) + public void Add(string name, string? value) { Add(GetHeaderDescriptor(name), value); } - internal void Add(HeaderDescriptor descriptor, string value) + internal void Add(HeaderDescriptor descriptor, string? value) { // We don't use GetOrCreateHeaderInfo() here, since this would create a new header in the store. If parsing // the value then throws, we would have to remove the header from the store again. So just get a @@ -82,27 +82,25 @@ internal void Add(HeaderDescriptor descriptor, string value) } } - public void Add(string name, IEnumerable values) + public void Add(string name, IEnumerable values) { Add(GetHeaderDescriptor(name), values); } - internal void Add(HeaderDescriptor descriptor, IEnumerable values) + internal void Add(HeaderDescriptor descriptor, IEnumerable values) { if (values == null) { throw new ArgumentNullException(nameof(values)); } - HeaderStoreItemInfo info; - bool addToStore; - PrepareHeaderInfoForAdd(descriptor, out info, out addToStore); + PrepareHeaderInfoForAdd(descriptor, out HeaderStoreItemInfo info, out bool addToStore); try { // Note that if the first couple of values are valid followed by an invalid value, the valid values // will be added to the store before the exception for the invalid value is thrown. - foreach (string value in values) + foreach (string? value in values) { ParseAndAddValue(descriptor, info, value); } @@ -121,11 +119,11 @@ internal void Add(HeaderDescriptor descriptor, IEnumerable values) } } - public bool TryAddWithoutValidation(string name, string value) => + public bool TryAddWithoutValidation(string name, string? value) => TryGetHeaderDescriptor(name, out HeaderDescriptor descriptor) && TryAddWithoutValidation(descriptor, value); - internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, string value) + internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, string? value) { if (value == null) { @@ -141,11 +139,11 @@ internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, string value) return true; } - public bool TryAddWithoutValidation(string name, IEnumerable values) => + public bool TryAddWithoutValidation(string name, IEnumerable values) => TryGetHeaderDescriptor(name, out HeaderDescriptor descriptor) && TryAddWithoutValidation(descriptor, values); - internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, IEnumerable values) + internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, IEnumerable values) { if (values == null) { @@ -153,7 +151,7 @@ internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, IEnumerable GetValues(string name) internal IEnumerable GetValues(HeaderDescriptor descriptor) { - IEnumerable values; - if (!TryGetValues(descriptor, out values)) + if (!TryGetValues(descriptor, out IEnumerable? values)) { throw new InvalidOperationException(SR.net_http_headers_not_found); } @@ -193,7 +190,7 @@ internal IEnumerable GetValues(HeaderDescriptor descriptor) return values; } - public bool TryGetValues(string name, out IEnumerable values) + public bool TryGetValues(string name, [NotNullWhen(true)] out IEnumerable? values) { HeaderDescriptor descriptor; if (!TryGetHeaderDescriptor(name, out descriptor)) @@ -205,7 +202,7 @@ public bool TryGetValues(string name, out IEnumerable values) return TryGetValues(descriptor, out values); } - internal bool TryGetValues(HeaderDescriptor descriptor, out IEnumerable values) + internal bool TryGetValues(HeaderDescriptor descriptor, [NotNullWhen(true)] out IEnumerable? values) { if (_headerStore == null) { @@ -213,8 +210,7 @@ internal bool TryGetValues(HeaderDescriptor descriptor, out IEnumerable return false; } - HeaderStoreItemInfo info = null; - if (TryGetAndParseHeaderInfo(descriptor, out info)) + if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) { values = GetValuesAsStrings(descriptor, info); return true; @@ -239,8 +235,7 @@ internal bool Contains(HeaderDescriptor descriptor) // We can't just call headerStore.ContainsKey() since after parsing the value the header may not exist // anymore (if the value contains invalid newline chars, we remove the header). So try to parse the // header value. - HeaderStoreItemInfo info = null; - return TryGetAndParseHeaderInfo(descriptor, out info); + return TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? _); } public override string ToString() @@ -288,10 +283,9 @@ internal string GetHeaderString(string name) return GetHeaderString(descriptor); } - internal string GetHeaderString(HeaderDescriptor descriptor, object exclude = null) + internal string GetHeaderString(HeaderDescriptor descriptor, object? exclude = null) { - HeaderStoreItemInfo info; - if (!TryGetHeaderInfo(descriptor, out info)) + if (!TryGetHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) { return string.Empty; } @@ -299,7 +293,7 @@ internal string GetHeaderString(HeaderDescriptor descriptor, object exclude = nu return GetHeaderString(descriptor, info, exclude); } - private string GetHeaderString(HeaderDescriptor descriptor, HeaderStoreItemInfo info, object exclude = null) + private string GetHeaderString(HeaderDescriptor descriptor, HeaderStoreItemInfo info, object? exclude = null) { string stringValue; @@ -313,7 +307,7 @@ private string GetHeaderString(HeaderDescriptor descriptor, HeaderStoreItemInfo { // Note that if we get multiple values for a header that doesn't support multiple values, we'll // just separate the values using a comma (default separator). - string separator = HttpHeaderParser.DefaultSeparator; + string? separator = HttpHeaderParser.DefaultSeparator; if ((descriptor.Parser != null) && (descriptor.Parser.SupportsMultipleValues)) { separator = descriptor.Parser.Separator; @@ -335,7 +329,7 @@ public IEnumerator>> GetEnumerator() private IEnumerator>> GetEnumeratorCore() { - foreach (KeyValuePair header in _headerStore) + foreach (KeyValuePair header in _headerStore!) { HeaderDescriptor descriptor = header.Key; HeaderStoreItemInfo info = header.Value; @@ -397,7 +391,7 @@ internal void SetParsedValue(HeaderDescriptor descriptor, object value) AddValue(info, value, StoreLocation.Parsed); } - internal void SetOrRemoveParsedValue(HeaderDescriptor descriptor, object value) + internal void SetOrRemoveParsedValue(HeaderDescriptor descriptor, object? value) { if (value == null) { @@ -430,8 +424,7 @@ internal bool RemoveParsedValue(HeaderDescriptor descriptor, object value) // If we have a value for this header, then verify if we have a single value. If so, compare that // value with 'item'. If we have a list of values, then remove 'item' from the list. - HeaderStoreItemInfo info = null; - if (TryGetAndParseHeaderInfo(descriptor, out info)) + if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) { Debug.Assert(descriptor.Parser != null, "Can't add parsed value if there is no parser available."); Debug.Assert(descriptor.Parser.SupportsMultipleValues, @@ -445,9 +438,9 @@ internal bool RemoveParsedValue(HeaderDescriptor descriptor, object value) return false; } - IEqualityComparer comparer = descriptor.Parser.Comparer; + IEqualityComparer? comparer = descriptor.Parser.Comparer; - List parsedValues = info.ParsedValue as List; + List? parsedValues = info.ParsedValue as List; if (parsedValues == null) { Debug.Assert(info.ParsedValue.GetType() == value.GetType(), @@ -506,8 +499,7 @@ internal bool ContainsParsedValue(HeaderDescriptor descriptor, object value) // If we have a value for this header, then verify if we have a single value. If so, compare that // value with 'item'. If we have a list of values, then compare each item in the list with 'item'. - HeaderStoreItemInfo info = null; - if (TryGetAndParseHeaderInfo(descriptor, out info)) + if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) { Debug.Assert(descriptor.Parser != null, "Can't add parsed value if there is no parser available."); Debug.Assert(descriptor.Parser.SupportsMultipleValues, @@ -519,9 +511,9 @@ internal bool ContainsParsedValue(HeaderDescriptor descriptor, object value) return false; } - List parsedValues = info.ParsedValue as List; + List? parsedValues = info.ParsedValue as List; - IEqualityComparer comparer = descriptor.Parser.Comparer; + IEqualityComparer? comparer = descriptor.Parser.Comparer; if (parsedValues == null) { @@ -609,7 +601,7 @@ private void AddHeaderInfo(HeaderDescriptor descriptor, HeaderStoreItemInfo sour // Now clone and add parsed values (if any). if (sourceInfo.ParsedValue != null) { - List sourceValues = sourceInfo.ParsedValue as List; + List? sourceValues = sourceInfo.ParsedValue as List; if (sourceValues == null) { CloneAndAddValue(destinationInfo, sourceInfo.ParsedValue); @@ -628,9 +620,7 @@ private void AddHeaderInfo(HeaderDescriptor descriptor, HeaderStoreItemInfo sour private static void CloneAndAddValue(HeaderStoreItemInfo destinationInfo, object source) { // We only have one value. Clone it and assign it to the store. - ICloneable cloneableValue = source as ICloneable; - - if (cloneableValue != null) + if (source is ICloneable cloneableValue) { AddValue(destinationInfo, cloneableValue.Clone(), StoreLocation.Parsed); } @@ -641,14 +631,15 @@ private static void CloneAndAddValue(HeaderStoreItemInfo destinationInfo, object } } - private static object CloneStringHeaderInfoValues(object source) + [return: NotNullIfNotNull("source")] + private static object? CloneStringHeaderInfoValues(object? source) { if (source == null) { return null; } - List sourceValues = source as List; + List? sourceValues = source as List; if (sourceValues == null) { // If we just have one value, return the reference to the string (strings are immutable so it's OK @@ -664,7 +655,7 @@ private static object CloneStringHeaderInfoValues(object source) private HeaderStoreItemInfo GetOrCreateHeaderInfo(HeaderDescriptor descriptor, bool parseRawValues) { - HeaderStoreItemInfo result = null; + HeaderStoreItemInfo? result; bool found = false; if (parseRawValues) { @@ -706,7 +697,7 @@ private void AddHeaderToStore(HeaderDescriptor descriptor, HeaderStoreItemInfo i _headerStore.Add(descriptor, info); } - private bool TryGetHeaderInfo(HeaderDescriptor descriptor, out HeaderStoreItemInfo info) + private bool TryGetHeaderInfo(HeaderDescriptor descriptor, [NotNullWhen(true)] out HeaderStoreItemInfo? info) { if (_headerStore == null) { @@ -717,7 +708,7 @@ private bool TryGetHeaderInfo(HeaderDescriptor descriptor, out HeaderStoreItemIn return _headerStore.TryGetValue(descriptor, out info); } - private bool TryGetAndParseHeaderInfo(HeaderDescriptor key, out HeaderStoreItemInfo info) + private bool TryGetAndParseHeaderInfo(HeaderDescriptor key, [NotNullWhen(true)] out HeaderStoreItemInfo? info) { if (TryGetHeaderInfo(key, out info)) { @@ -737,7 +728,7 @@ private bool ParseRawHeaderValues(HeaderDescriptor descriptor, HeaderStoreItemIn // before returning to the caller. if (info.RawValue != null) { - List rawValues = info.RawValue as List; + List? rawValues = info.RawValue as List; if (rawValues == null) { @@ -798,7 +789,7 @@ private static void ParseMultipleRawHeaderValues(HeaderDescriptor descriptor, He private static void ParseSingleRawHeaderValue(HeaderDescriptor descriptor, HeaderStoreItemInfo info) { - string rawValue = info.RawValue as string; + string? rawValue = info.RawValue as string; Debug.Assert(rawValue != null, "RawValue must either be List or string."); if (descriptor.Parser == null) @@ -818,7 +809,7 @@ private static void ParseSingleRawHeaderValue(HeaderDescriptor descriptor, Heade } // See Add(name, string) - internal bool TryParseAndAddValue(HeaderDescriptor descriptor, string value) + internal bool TryParseAndAddValue(HeaderDescriptor descriptor, string? value) { // We don't use GetOrCreateHeaderInfo() here, since this would create a new header in the store. If parsing // the value then throws, we would have to remove the header from the store again. So just get a @@ -840,7 +831,7 @@ internal bool TryParseAndAddValue(HeaderDescriptor descriptor, string value) } // See ParseAndAddValue - private static bool TryParseAndAddRawHeaderValue(HeaderDescriptor descriptor, HeaderStoreItemInfo info, string value, bool addWhenInvalid) + private static bool TryParseAndAddRawHeaderValue(HeaderDescriptor descriptor, HeaderStoreItemInfo info, string? value, bool addWhenInvalid) { Debug.Assert(info != null); Debug.Assert(descriptor.Parser != null); @@ -859,9 +850,8 @@ private static bool TryParseAndAddRawHeaderValue(HeaderDescriptor descriptor, He } int index = 0; - object parsedValue = null; - if (descriptor.Parser.TryParseValue(value, info.ParsedValue, ref index, out parsedValue)) + if (descriptor.Parser.TryParseValue(value, info.ParsedValue, ref index, out object? parsedValue)) { // The raw string only represented one value (which was successfully parsed). Add the value and return. if ((value == null) || (index == value.Length)) @@ -909,6 +899,7 @@ private static bool TryParseAndAddRawHeaderValue(HeaderDescriptor descriptor, He return true; } + Debug.Assert(value != null); if (!ContainsInvalidNewLine(value, descriptor.Name) && addWhenInvalid) { AddValue(info, value ?? string.Empty, StoreLocation.Invalid); @@ -916,7 +907,7 @@ private static bool TryParseAndAddRawHeaderValue(HeaderDescriptor descriptor, He return false; } - private static void AddValue(HeaderStoreItemInfo info, object value, StoreLocation location) + private static void AddValue(HeaderStoreItemInfo info, object? value, StoreLocation location) { // Since we have the same pattern for all three store locations (raw, invalid, parsed), we use // this helper method to deal with adding values: @@ -925,7 +916,7 @@ private static void AddValue(HeaderStoreItemInfo info, object value, StoreLocati // - if 'T', i.e. we have already a value stored (but no list), create a list, add the stored value // to the list and append 'value' at the end of the newly created list. - object currentStoreValue = null; + object? currentStoreValue = null; switch (location) { case StoreLocation.Raw: @@ -955,7 +946,7 @@ private static void AddValue(HeaderStoreItemInfo info, object value, StoreLocati } } - private static void AddValueToStoreValue(object value, ref object currentStoreValue) where T : class + private static void AddValueToStoreValue(object? value, ref object? currentStoreValue) where T : class { // If there is no value set yet, then add current item as value (we don't create a list // if not required). If 'info.Value' is already assigned then make sure 'info.Value' is a @@ -966,28 +957,26 @@ private static void AddValueToStoreValue(object value, ref object currentStor } else { - List storeValues = currentStoreValue as List; + List? storeValues = currentStoreValue as List; if (storeValues == null) { storeValues = new List(2); Debug.Assert(currentStoreValue is T); - storeValues.Add(currentStoreValue as T); + storeValues.Add((T)currentStoreValue); currentStoreValue = storeValues; } Debug.Assert(value is T); - storeValues.Add(value as T); + storeValues.Add((T)value); } } // Since most of the time we just have 1 value, we don't create a List for one value, but we change // the return type to 'object'. The caller has to deal with the return type (object vs. List). This // is to optimize the most common scenario where a header has only one value. - internal object GetParsedValues(HeaderDescriptor descriptor) + internal object? GetParsedValues(HeaderDescriptor descriptor) { - HeaderStoreItemInfo info = null; - - if (!TryGetAndParseHeaderInfo(descriptor, out info)) + if (!TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) { return null; } @@ -1004,16 +993,15 @@ private void PrepareHeaderInfoForAdd(HeaderDescriptor descriptor, out HeaderStor throw new InvalidOperationException(string.Format(SR.net_http_headers_not_allowed_header_name, descriptor.Name)); } - info = null; addToStore = false; - if (!TryGetAndParseHeaderInfo(descriptor, out info)) + if (!TryGetAndParseHeaderInfo(descriptor, out info!)) { info = new HeaderStoreItemInfo(); addToStore = true; } } - private void ParseAndAddValue(HeaderDescriptor descriptor, HeaderStoreItemInfo info, string value) + private void ParseAndAddValue(HeaderDescriptor descriptor, HeaderStoreItemInfo info, string? value) { Debug.Assert(info != null); @@ -1125,7 +1113,7 @@ private bool TryGetHeaderDescriptor(string name, out HeaderDescriptor descriptor return false; } - private static void CheckInvalidNewLine(string value) + private static void CheckInvalidNewLine(string? value) { if (value == null) { @@ -1148,7 +1136,7 @@ private static bool ContainsInvalidNewLine(string value, string name) return false; } - private static string[] GetValuesAsStrings(HeaderDescriptor descriptor, HeaderStoreItemInfo info, object exclude = null) + private static string[] GetValuesAsStrings(HeaderDescriptor descriptor, HeaderStoreItemInfo info, object? exclude = null) { int length = GetValueCount(info); string[] values; @@ -1158,12 +1146,12 @@ private static string[] GetValuesAsStrings(HeaderDescriptor descriptor, HeaderSt values = new string[length]; int currentIndex = 0; - ReadStoreValues(values, info.RawValue, null, null, ref currentIndex); - ReadStoreValues(values, info.ParsedValue, descriptor.Parser, exclude, ref currentIndex); + ReadStoreValues(values, info.RawValue, null, null, ref currentIndex); + ReadStoreValues(values, info.ParsedValue, descriptor.Parser, exclude, ref currentIndex); // Set parser parameter to 'null' for invalid values: The invalid values is always a string so we // don't need the parser to "serialize" the value to a string. - ReadStoreValues(values, info.InvalidValue, null, null, ref currentIndex); + ReadStoreValues(values, info.InvalidValue, null, null, ref currentIndex); // The values array may not be full because some values were excluded if (currentIndex < length) @@ -1193,9 +1181,9 @@ internal static int GetValuesAsStrings(HeaderDescriptor descriptor, HeaderStoreI } int currentIndex = 0; - ReadStoreValues(values, info.RawValue, null, null, ref currentIndex); - ReadStoreValues(values, info.ParsedValue, descriptor.Parser, null, ref currentIndex); - ReadStoreValues(values, info.InvalidValue, null, null, ref currentIndex); + ReadStoreValues(values, info.RawValue, null, null, ref currentIndex); + ReadStoreValues(values, info.ParsedValue, descriptor.Parser, null, ref currentIndex); + ReadStoreValues(values, info.InvalidValue, null, null, ref currentIndex); Debug.Assert(currentIndex == length); } @@ -1211,20 +1199,20 @@ private static int GetValueCount(HeaderStoreItemInfo info) valueCount += Count(info.ParsedValue); return valueCount; - static int Count(object valueStore) => + static int Count(object? valueStore) => valueStore is null ? 0 : valueStore is List list ? list.Count : 1; } - private static void ReadStoreValues(string[] values, object storeValue, HttpHeaderParser parser, + private static void ReadStoreValues(string?[] values, object? storeValue, HttpHeaderParser? parser, T exclude, ref int currentIndex) { Debug.Assert(values != null); if (storeValue != null) { - List storeValues = storeValue as List; + List? storeValues = storeValue as List; if (storeValues == null) { @@ -1236,10 +1224,11 @@ private static void ReadStoreValues(string[] values, object storeValue, HttpH } else { - foreach (object item in storeValues) + foreach (object? item in storeValues) { if (ShouldAdd(item, parser, exclude)) { + Debug.Assert(item != null); values[currentIndex] = parser == null ? item.ToString() : parser.ToString(item); currentIndex++; } @@ -1248,7 +1237,7 @@ private static void ReadStoreValues(string[] values, object storeValue, HttpH } } - private static bool ShouldAdd(object storeValue, HttpHeaderParser parser, T exclude) + private static bool ShouldAdd(object? storeValue, HttpHeaderParser? parser, T exclude) { bool add = true; if (parser != null && exclude != null) @@ -1265,7 +1254,7 @@ private static bool ShouldAdd(object storeValue, HttpHeaderParser parser, T e return add; } - private bool AreEqual(object value, object storeValue, IEqualityComparer comparer) + private bool AreEqual(object value, object? storeValue, IEqualityComparer? comparer) { Debug.Assert(value != null); @@ -1284,9 +1273,9 @@ internal class HeaderStoreItemInfo { internal HeaderStoreItemInfo() { } - internal object RawValue { get; set; } - internal object InvalidValue { get; set; } - internal object ParsedValue { get; set; } + internal object? RawValue { get; set; } + internal object? InvalidValue { get; set; } + internal object? ParsedValue { get; set; } internal bool CanAddValue(HttpHeaderParser parser) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpRequestHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpRequestHeaders.cs index df0ec9d7fe7650..f62345ab9469c4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpRequestHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpRequestHeaders.cs @@ -19,9 +19,9 @@ public sealed class HttpRequestHeaders : HttpHeaders private const int UserAgentSlot = 7; private const int NumCollectionsSlots = 8; - private object[] _specialCollectionsSlots; - private HttpGeneralHeaders _generalHeaders; - private HttpHeaderValueCollection _expect; + private object[]? _specialCollectionsSlots; + private HttpGeneralHeaders? _generalHeaders; + private HttpHeaderValueCollection? _expect; private bool _expectContinueSet; #region Request Headers @@ -32,7 +32,7 @@ private T GetSpecializedCollection(int slot, Func crea // Rather than having a field for each of these, store them untyped in an array that's lazily // allocated. Then we only pay for the 64 bytes for those fields when any is actually accessed. _specialCollectionsSlots ??= new object[NumCollectionsSlots]; - return (T)(_specialCollectionsSlots[slot] ??= creationFunc(this)); + return (T)(_specialCollectionsSlots[slot] ??= creationFunc(this)!); } public HttpHeaderValueCollection Accept => @@ -47,9 +47,9 @@ private T GetSpecializedCollection(int slot, Func crea public HttpHeaderValueCollection AcceptLanguage => GetSpecializedCollection(AcceptLanguageSlot, thisRef => new HttpHeaderValueCollection(KnownHeaders.AcceptLanguage.Descriptor, thisRef)); - public AuthenticationHeaderValue Authorization + public AuthenticationHeaderValue? Authorization { - get { return (AuthenticationHeaderValue)GetParsedValues(KnownHeaders.Authorization.Descriptor); } + get { return (AuthenticationHeaderValue?)GetParsedValues(KnownHeaders.Authorization.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.Authorization.Descriptor, value); } } @@ -92,9 +92,9 @@ public bool? ExpectContinue } } - public string From + public string? From { - get { return (string)GetParsedValues(KnownHeaders.From.Descriptor); } + get { return (string?)GetParsedValues(KnownHeaders.From.Descriptor); } set { // Null and empty string are equivalent. In this case it means, remove the From header value (if any). @@ -111,9 +111,9 @@ public string From } } - public string Host + public string? Host { - get { return (string)GetParsedValues(KnownHeaders.Host.Descriptor); } + get { return (string?)GetParsedValues(KnownHeaders.Host.Descriptor); } set { // Null and empty string are equivalent. In this case it means, remove the Host header value (if any). @@ -122,8 +122,7 @@ public string Host value = null; } - string host = null; - if ((value != null) && (HttpRuleParser.GetHostLength(value, 0, false, out host) != value.Length)) + if ((value != null) && (HttpRuleParser.GetHostLength(value, 0, false, out string? _) != value.Length)) { throw new FormatException(SR.net_http_headers_invalid_host_header); } @@ -143,9 +142,9 @@ public DateTimeOffset? IfModifiedSince public HttpHeaderValueCollection IfNoneMatch => GetSpecializedCollection(IfNoneMatchSlot, thisRef => new HttpHeaderValueCollection(KnownHeaders.IfNoneMatch.Descriptor, thisRef)); - public RangeConditionHeaderValue IfRange + public RangeConditionHeaderValue? IfRange { - get { return (RangeConditionHeaderValue)GetParsedValues(KnownHeaders.IfRange.Descriptor); } + get { return (RangeConditionHeaderValue?)GetParsedValues(KnownHeaders.IfRange.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.IfRange.Descriptor, value); } } @@ -159,7 +158,7 @@ public int? MaxForwards { get { - object storedValue = GetParsedValues(KnownHeaders.MaxForwards.Descriptor); + object? storedValue = GetParsedValues(KnownHeaders.MaxForwards.Descriptor); if (storedValue != null) { return (int)storedValue; @@ -170,21 +169,21 @@ public int? MaxForwards } - public AuthenticationHeaderValue ProxyAuthorization + public AuthenticationHeaderValue? ProxyAuthorization { - get { return (AuthenticationHeaderValue)GetParsedValues(KnownHeaders.ProxyAuthorization.Descriptor); } + get { return (AuthenticationHeaderValue?)GetParsedValues(KnownHeaders.ProxyAuthorization.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.ProxyAuthorization.Descriptor, value); } } - public RangeHeaderValue Range + public RangeHeaderValue? Range { - get { return (RangeHeaderValue)GetParsedValues(KnownHeaders.Range.Descriptor); } + get { return (RangeHeaderValue?)GetParsedValues(KnownHeaders.Range.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.Range.Descriptor, value); } } - public Uri Referrer + public Uri? Referrer { - get { return (Uri)GetParsedValues(KnownHeaders.Referer.Descriptor); } + get { return (Uri?)GetParsedValues(KnownHeaders.Referer.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.Referer.Descriptor, value); } } @@ -201,7 +200,7 @@ public Uri Referrer #region General Headers - public CacheControlHeaderValue CacheControl + public CacheControlHeaderValue? CacheControl { get { return GeneralHeaders.CacheControl; } set { GeneralHeaders.CacheControl = value; } @@ -270,7 +269,7 @@ internal HttpRequestHeaders() internal override void AddHeaders(HttpHeaders sourceHeaders) { base.AddHeaders(sourceHeaders); - HttpRequestHeaders sourceRequestHeaders = sourceHeaders as HttpRequestHeaders; + HttpRequestHeaders? sourceRequestHeaders = sourceHeaders as HttpRequestHeaders; Debug.Assert(sourceRequestHeaders != null); // Copy special values but do not overwrite. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpResponseHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpResponseHeaders.cs index c08b7456f3606a..8da6741d187480 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpResponseHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpResponseHeaders.cs @@ -16,8 +16,8 @@ public sealed class HttpResponseHeaders : HttpHeaders private const int WwwAuthenticateSlot = 4; private const int NumCollectionsSlots = 5; - private object[] _specialCollectionsSlots; - private HttpGeneralHeaders _generalHeaders; + private object[]? _specialCollectionsSlots; + private HttpGeneralHeaders? _generalHeaders; private bool _containsTrailingHeaders; #region Response Headers @@ -31,7 +31,7 @@ private T GetSpecializedCollection(int slot, Func cre object result = collections[slot]; if (result == null) { - collections[slot] = result = creationFunc(this); + collections[slot] = result = creationFunc(this)!; } return (T)result; } @@ -45,24 +45,24 @@ public TimeSpan? Age set { SetOrRemoveParsedValue(KnownHeaders.Age.Descriptor, value); } } - public EntityTagHeaderValue ETag + public EntityTagHeaderValue? ETag { - get { return (EntityTagHeaderValue)GetParsedValues(KnownHeaders.ETag.Descriptor); } + get { return (EntityTagHeaderValue?)GetParsedValues(KnownHeaders.ETag.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.ETag.Descriptor, value); } } - public Uri Location + public Uri? Location { - get { return (Uri)GetParsedValues(KnownHeaders.Location.Descriptor); } + get { return (Uri?)GetParsedValues(KnownHeaders.Location.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.Location.Descriptor, value); } } public HttpHeaderValueCollection ProxyAuthenticate => GetSpecializedCollection(ProxyAuthenticateSlot, thisRef => new HttpHeaderValueCollection(KnownHeaders.ProxyAuthenticate.Descriptor, thisRef)); - public RetryConditionHeaderValue RetryAfter + public RetryConditionHeaderValue? RetryAfter { - get { return (RetryConditionHeaderValue)GetParsedValues(KnownHeaders.RetryAfter.Descriptor); } + get { return (RetryConditionHeaderValue?)GetParsedValues(KnownHeaders.RetryAfter.Descriptor); } set { SetOrRemoveParsedValue(KnownHeaders.RetryAfter.Descriptor, value); } } @@ -79,7 +79,7 @@ public RetryConditionHeaderValue RetryAfter #region General Headers - public CacheControlHeaderValue CacheControl + public CacheControlHeaderValue? CacheControl { get { return GeneralHeaders.CacheControl; } set { GeneralHeaders.CacheControl = value; } @@ -150,7 +150,7 @@ internal HttpResponseHeaders(bool containsTrailingHeaders = false) internal override void AddHeaders(HttpHeaders sourceHeaders) { base.AddHeaders(sourceHeaders); - HttpResponseHeaders sourceResponseHeaders = sourceHeaders as HttpResponseHeaders; + HttpResponseHeaders? sourceResponseHeaders = sourceHeaders as HttpResponseHeaders; Debug.Assert(sourceResponseHeaders != null); // Copy special values, but do not overwrite @@ -165,7 +165,7 @@ internal override bool IsAllowedHeaderName(HeaderDescriptor descriptor) if (!_containsTrailingHeaders) return true; - KnownHeader knownHeader = KnownHeaders.TryGetKnownHeader(descriptor.Name); + KnownHeader? knownHeader = KnownHeaders.TryGetKnownHeader(descriptor.Name); if (knownHeader == null) return true; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/Int32NumberHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/Int32NumberHeaderParser.cs index d7d812fd693dfe..e02d56c2a79536 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/Int32NumberHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/Int32NumberHeaderParser.cs @@ -29,8 +29,8 @@ public override string ToString(object value) return ((int)value).ToString(NumberFormatInfo.InvariantInfo); } - protected override int GetParsedValueLength(string value, int startIndex, object storeValue, - out object parsedValue) + protected override int GetParsedValueLength(string value, int startIndex, object? storeValue, + out object? parsedValue) { parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/Int64NumberHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/Int64NumberHeaderParser.cs index 539781c56bc684..8f582d05340e5f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/Int64NumberHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/Int64NumberHeaderParser.cs @@ -29,8 +29,8 @@ public override string ToString(object value) return ((long)value).ToString(NumberFormatInfo.InvariantInfo); } - protected override int GetParsedValueLength(string value, int startIndex, object storeValue, - out object parsedValue) + protected override int GetParsedValueLength(string value, int startIndex, object? storeValue, + out object? parsedValue) { parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs index d24739ee04f436..ce0705bbf5f19f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs @@ -17,7 +17,7 @@ public KnownHeader(string name, int? http2StaticTableIndex = null, int? http3Sta Debug.Assert(name[0] == ':' || HttpRuleParser.GetTokenLength(name, 0) == name.Length); } - public KnownHeader(string name, HttpHeaderType headerType, HttpHeaderParser parser, string[] knownValues = null, int? http2StaticTableIndex = null, int? http3StaticTableIndex = null) + public KnownHeader(string name, HttpHeaderType headerType, HttpHeaderParser? parser, string[]? knownValues = null, int? http2StaticTableIndex = null, int? http3StaticTableIndex = null) { Debug.Assert(!string.IsNullOrEmpty(name)); Debug.Assert(name[0] == ':' || HttpRuleParser.GetTokenLength(name, 0) == name.Length); @@ -45,13 +45,13 @@ public KnownHeader(string name, HttpHeaderType headerType, HttpHeaderParser pars } public string Name { get; } - public HttpHeaderParser Parser { get; } + public HttpHeaderParser? Parser { get; } public HttpHeaderType HeaderType { get; } /// /// If a raw string is a known value, this instance will be returned rather than allocating a new string. /// - public string[] KnownValues { get; } + public string[]? KnownValues { get; } public byte[] AsciiBytesWithColonSpace { get; } public HeaderDescriptor Descriptor => new HeaderDescriptor(this); public byte[] Http2EncodedName { get; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs index c65483d2971bf9..d07b87977ebbda 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs @@ -141,7 +141,7 @@ public BytePtrAccessor(byte* p, int length) // Matching is case-insenstive. // NOTE: Because of this, we do not preserve the case of the original header, // whether from the wire or from the user explicitly setting a known header using a header name string. - private static KnownHeader GetCandidate(T key) + private static KnownHeader? GetCandidate(T key) where T : struct, IHeaderNameAccessor // Enforce struct for performance { int length = key.Length; @@ -373,9 +373,9 @@ private static KnownHeader GetCandidate(T key) return null; } - internal static KnownHeader TryGetKnownHeader(string name) + internal static KnownHeader? TryGetKnownHeader(string name) { - KnownHeader candidate = GetCandidate(new StringAccessor(name)); + KnownHeader? candidate = GetCandidate(new StringAccessor(name)); if (candidate != null && StringComparer.OrdinalIgnoreCase.Equals(name, candidate.Name)) { return candidate; @@ -384,11 +384,11 @@ internal static KnownHeader TryGetKnownHeader(string name) return null; } - internal static unsafe KnownHeader TryGetKnownHeader(ReadOnlySpan name) + internal static unsafe KnownHeader? TryGetKnownHeader(ReadOnlySpan name) { fixed (byte* p = &MemoryMarshal.GetReference(name)) { - KnownHeader candidate = GetCandidate(new BytePtrAccessor(p, name.Length)); + KnownHeader? candidate = GetCandidate(new BytePtrAccessor(p, name.Length)); if (candidate != null && ByteArrayHelpers.EqualsOrdinalAsciiIgnoreCase(candidate.Name, name)) { return candidate; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderParser.cs index f70cc01358f53f..a353bed109ccab 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderParser.cs @@ -27,11 +27,10 @@ private MediaTypeHeaderParser(bool supportsMultipleValues, Func _parameters; - private string _mediaType; + private ObjectCollection? _parameters; + private string? _mediaType; - public string CharSet + public string? CharSet { get { - NameValueHeaderValue charSetParameter = NameValueHeaderValue.Find(_parameters, charSet); + NameValueHeaderValue? charSetParameter = NameValueHeaderValue.Find(_parameters, charSet); if (charSetParameter != null) { return charSetParameter.Value; @@ -31,13 +32,13 @@ public string CharSet { // We don't prevent a user from setting whitespace-only charsets. Like we can't prevent a user from // setting a non-existing charset. - NameValueHeaderValue charSetParameter = NameValueHeaderValue.Find(_parameters, charSet); + NameValueHeaderValue? charSetParameter = NameValueHeaderValue.Find(_parameters, charSet); if (string.IsNullOrEmpty(value)) { // Remove charset parameter if (charSetParameter != null) { - _parameters.Remove(charSetParameter); + _parameters!.Remove(charSetParameter); } } else @@ -66,7 +67,8 @@ public ICollection Parameters } } - public string MediaType + [DisallowNull] + public string? MediaType { get { return _mediaType; } set @@ -110,9 +112,9 @@ public override string ToString() return StringBuilderCache.GetStringAndRelease(sb); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - MediaTypeHeaderValue other = obj as MediaTypeHeaderValue; + MediaTypeHeaderValue? other = obj as MediaTypeHeaderValue; if (other == null) { @@ -126,31 +128,30 @@ public override bool Equals(object obj) public override int GetHashCode() { // The media-type string is case-insensitive. - return StringComparer.OrdinalIgnoreCase.GetHashCode(_mediaType) ^ NameValueHeaderValue.GetHashCode(_parameters); + return StringComparer.OrdinalIgnoreCase.GetHashCode(_mediaType!) ^ NameValueHeaderValue.GetHashCode(_parameters); } - public static MediaTypeHeaderValue Parse(string input) + public static MediaTypeHeaderValue Parse(string? input) { int index = 0; return (MediaTypeHeaderValue)MediaTypeHeaderParser.SingleValueParser.ParseValue(input, null, ref index); } - public static bool TryParse(string input, out MediaTypeHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out MediaTypeHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (MediaTypeHeaderParser.SingleValueParser.TryParseValue(input, null, ref index, out output)) + if (MediaTypeHeaderParser.SingleValueParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (MediaTypeHeaderValue)output; + parsedValue = (MediaTypeHeaderValue)output!; return true; } return false; } - internal static int GetMediaTypeLength(string input, int startIndex, - Func mediaTypeCreator, out MediaTypeHeaderValue parsedValue) + internal static int GetMediaTypeLength(string? input, int startIndex, + Func mediaTypeCreator, out MediaTypeHeaderValue? parsedValue) { Debug.Assert(mediaTypeCreator != null); Debug.Assert(startIndex >= 0); @@ -163,8 +164,7 @@ internal static int GetMediaTypeLength(string input, int startIndex, } // Caller must remove leading whitespace. If not, we'll return 0. - string mediaType = null; - int mediaTypeLength = MediaTypeHeaderValue.GetMediaTypeExpressionLength(input, startIndex, out mediaType); + int mediaTypeLength = MediaTypeHeaderValue.GetMediaTypeExpressionLength(input, startIndex, out string? mediaType); if (mediaTypeLength == 0) { @@ -173,7 +173,7 @@ internal static int GetMediaTypeLength(string input, int startIndex, int current = startIndex + mediaTypeLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); - MediaTypeHeaderValue mediaTypeHeader = null; + MediaTypeHeaderValue mediaTypeHeader; // If we're not done and we have a parameter delimiter, then we have a list of parameters. if ((current < input.Length) && (input[current] == ';')) @@ -201,7 +201,7 @@ internal static int GetMediaTypeLength(string input, int startIndex, return current - startIndex; } - private static int GetMediaTypeExpressionLength(string input, int startIndex, out string mediaType) + private static int GetMediaTypeExpressionLength(string input, int startIndex, out string? mediaType) { Debug.Assert((input != null) && (input.Length > 0) && (startIndex < input.Length)); @@ -259,9 +259,8 @@ private static void CheckMediaTypeFormat(string mediaType, string parameterName) // When adding values using strongly typed objects, no leading/trailing LWS (whitespace) are allowed. // Also no LWS between type and subtype are allowed. - string tempMediaType; - int mediaTypeLength = GetMediaTypeExpressionLength(mediaType, 0, out tempMediaType); - if ((mediaTypeLength == 0) || (tempMediaType.Length != mediaType.Length)) + int mediaTypeLength = GetMediaTypeExpressionLength(mediaType, 0, out string? tempMediaType); + if ((mediaTypeLength == 0) || (tempMediaType!.Length != mediaType.Length)) { throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_headers_invalid_value, mediaType)); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeWithQualityHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeWithQualityHeaderValue.cs index ddeeda2c0ba33b..c5d6aeb590bd91 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeWithQualityHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeWithQualityHeaderValue.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { @@ -42,22 +43,21 @@ object ICloneable.Clone() return new MediaTypeWithQualityHeaderValue(this); } - public static new MediaTypeWithQualityHeaderValue Parse(string input) + public static new MediaTypeWithQualityHeaderValue Parse(string? input) { int index = 0; return (MediaTypeWithQualityHeaderValue)MediaTypeHeaderParser.SingleValueWithQualityParser.ParseValue( input, null, ref index); } - public static bool TryParse(string input, out MediaTypeWithQualityHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out MediaTypeWithQualityHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (MediaTypeHeaderParser.SingleValueWithQualityParser.TryParseValue(input, null, ref index, out output)) + if (MediaTypeHeaderParser.SingleValueWithQualityParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (MediaTypeWithQualityHeaderValue)output; + parsedValue = (MediaTypeWithQualityHeaderValue)output!; return true; } return false; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueHeaderValue.cs index ed83707836dd10..098576e977ed1a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueHeaderValue.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; @@ -16,15 +17,15 @@ public class NameValueHeaderValue : ICloneable { private static readonly Func s_defaultNameValueCreator = CreateNameValue; - private string _name; - private string _value; + private string _name = null!; // Name always set after default constructor used + private string? _value; public string Name { get { return _name; } } - public string Value + public string? Value { get { return _value; } set @@ -43,7 +44,7 @@ public NameValueHeaderValue(string name) { } - public NameValueHeaderValue(string name, string value) + public NameValueHeaderValue(string name, string? value) { CheckNameValueFormat(name, value); @@ -80,9 +81,9 @@ public override int GetHashCode() return nameHashCode; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - NameValueHeaderValue other = obj as NameValueHeaderValue; + NameValueHeaderValue? other = obj as NameValueHeaderValue; if (other == null) { @@ -114,22 +115,21 @@ public override bool Equals(object obj) } } - public static NameValueHeaderValue Parse(string input) + public static NameValueHeaderValue Parse(string? input) { int index = 0; return (NameValueHeaderValue)GenericHeaderParser.SingleValueNameValueParser.ParseValue( input, null, ref index); } - public static bool TryParse(string input, out NameValueHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out NameValueHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.SingleValueNameValueParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.SingleValueNameValueParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (NameValueHeaderValue)output; + parsedValue = (NameValueHeaderValue)output!; return true; } return false; @@ -165,7 +165,7 @@ private void AddToStringBuilder(StringBuilder sb) } } - internal static void ToString(ObjectCollection values, char separator, bool leadingSeparator, + internal static void ToString(ObjectCollection? values, char separator, bool leadingSeparator, StringBuilder destination) { Debug.Assert(destination != null); @@ -186,7 +186,7 @@ internal static void ToString(ObjectCollection values, cha } } - internal static int GetHashCode(ObjectCollection values) + internal static int GetHashCode(ObjectCollection? values) { if ((values == null) || (values.Count == 0)) { @@ -201,13 +201,13 @@ internal static int GetHashCode(ObjectCollection values) return result; } - internal static int GetNameValueLength(string input, int startIndex, out NameValueHeaderValue parsedValue) + internal static int GetNameValueLength(string input, int startIndex, out NameValueHeaderValue? parsedValue) { return GetNameValueLength(input, startIndex, s_defaultNameValueCreator, out parsedValue); } internal static int GetNameValueLength(string input, int startIndex, - Func nameValueCreator, out NameValueHeaderValue parsedValue) + Func nameValueCreator, out NameValueHeaderValue? parsedValue) { Debug.Assert(input != null); Debug.Assert(startIndex >= 0); @@ -265,7 +265,7 @@ internal static int GetNameValueLength(string input, int startIndex, // Returns the length of a name/value list, separated by 'delimiter'. E.g. "a=b, c=d, e=f" adds 3 // name/value pairs to 'nameValueCollection' if 'delimiter' equals ','. - internal static int GetNameValueListLength(string input, int startIndex, char delimiter, + internal static int GetNameValueListLength(string? input, int startIndex, char delimiter, ObjectCollection nameValueCollection) { Debug.Assert(nameValueCollection != null); @@ -279,7 +279,7 @@ internal static int GetNameValueListLength(string input, int startIndex, char de int current = startIndex + HttpRuleParser.GetWhitespaceLength(input, startIndex); while (true) { - NameValueHeaderValue parameter = null; + NameValueHeaderValue? parameter; int nameValueLength = NameValueHeaderValue.GetNameValueLength(input, current, s_defaultNameValueCreator, out parameter); @@ -288,7 +288,7 @@ internal static int GetNameValueListLength(string input, int startIndex, char de return 0; } - nameValueCollection.Add(parameter); + nameValueCollection.Add(parameter!); current = current + nameValueLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); @@ -304,7 +304,7 @@ internal static int GetNameValueListLength(string input, int startIndex, char de } } - internal static NameValueHeaderValue Find(ObjectCollection values, string name) + internal static NameValueHeaderValue? Find(ObjectCollection? values, string name) { Debug.Assert((name != null) && (name.Length > 0)); @@ -346,13 +346,13 @@ internal static int GetValueLength(string input, int startIndex) return valueLength; } - private static void CheckNameValueFormat(string name, string value) + private static void CheckNameValueFormat(string name, string? value) { HeaderUtilities.CheckValidToken(name, nameof(name)); CheckValueFormat(value); } - private static void CheckValueFormat(string value) + private static void CheckValueFormat(string? value) { // Either value is null/empty or a valid token/quoted string if (!(string.IsNullOrEmpty(value) || (GetValueLength(value, 0) == value.Length))) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueWithParametersHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueWithParametersHeaderValue.cs index f2a54c1550d3d9..e7f58ea0932bdb 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueWithParametersHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueWithParametersHeaderValue.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; @@ -15,7 +16,7 @@ public class NameValueWithParametersHeaderValue : NameValueHeaderValue, ICloneab { private static readonly Func s_nameValueCreator = CreateNameValue; - private ObjectCollection _parameters; + private ObjectCollection? _parameters; public ICollection Parameters { @@ -34,7 +35,7 @@ public NameValueWithParametersHeaderValue(string name) { } - public NameValueWithParametersHeaderValue(string name, string value) + public NameValueWithParametersHeaderValue(string name, string? value) : base(name, value) { } @@ -55,13 +56,13 @@ protected NameValueWithParametersHeaderValue(NameValueWithParametersHeaderValue } } - public override bool Equals(object obj) + public override bool Equals(object? obj) { bool result = base.Equals(obj); if (result) { - NameValueWithParametersHeaderValue other = obj as NameValueWithParametersHeaderValue; + NameValueWithParametersHeaderValue? other = obj as NameValueWithParametersHeaderValue; if (other == null) { @@ -87,29 +88,28 @@ public override string ToString() return StringBuilderCache.GetStringAndRelease(sb); } - public static new NameValueWithParametersHeaderValue Parse(string input) + public static new NameValueWithParametersHeaderValue Parse(string? input) { int index = 0; return (NameValueWithParametersHeaderValue)GenericHeaderParser.SingleValueNameValueWithParametersParser .ParseValue(input, null, ref index); } - public static bool TryParse(string input, out NameValueWithParametersHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out NameValueWithParametersHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; if (GenericHeaderParser.SingleValueNameValueWithParametersParser.TryParseValue(input, - null, ref index, out output)) + null, ref index, out object? output)) { - parsedValue = (NameValueWithParametersHeaderValue)output; + parsedValue = (NameValueWithParametersHeaderValue)output!; return true; } return false; } - internal static int GetNameValueWithParametersLength(string input, int startIndex, out object parsedValue) + internal static int GetNameValueWithParametersLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(input != null); Debug.Assert(startIndex >= 0); @@ -121,9 +121,8 @@ internal static int GetNameValueWithParametersLength(string input, int startInde return 0; } - NameValueHeaderValue nameValue = null; int nameValueLength = NameValueHeaderValue.GetNameValueLength(input, startIndex, - s_nameValueCreator, out nameValue); + s_nameValueCreator, out NameValueHeaderValue? nameValue); if (nameValueLength == 0) { @@ -132,7 +131,7 @@ internal static int GetNameValueWithParametersLength(string input, int startInde int current = startIndex + nameValueLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); - NameValueWithParametersHeaderValue nameValueWithParameters = + NameValueWithParametersHeaderValue? nameValueWithParameters = nameValue as NameValueWithParametersHeaderValue; Debug.Assert(nameValueWithParameters != null); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductHeaderValue.cs index 677600dbdadde1..ac3a6b5004172a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductHeaderValue.cs @@ -3,13 +3,14 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { public class ProductHeaderValue : ICloneable { - private string _name; - private string _version; + private string _name = null!; + private string? _version; public string Name { @@ -17,7 +18,7 @@ public string Name } // We can't use the System.Version type, since a version can be e.g. "x11". - public string Version + public string? Version { get { return _version; } } @@ -27,7 +28,7 @@ public ProductHeaderValue(string name) { } - public ProductHeaderValue(string name, string version) + public ProductHeaderValue(string name, string? version) { HeaderUtilities.CheckValidToken(name, nameof(name)); @@ -61,9 +62,9 @@ public override string ToString() return _name + "/" + _version; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - ProductHeaderValue other = obj as ProductHeaderValue; + ProductHeaderValue? other = obj as ProductHeaderValue; if (other == null) { @@ -86,27 +87,26 @@ public override int GetHashCode() return result; } - public static ProductHeaderValue Parse(string input) + public static ProductHeaderValue Parse(string? input) { int index = 0; return (ProductHeaderValue)GenericHeaderParser.SingleValueProductParser.ParseValue(input, null, ref index); } - public static bool TryParse(string input, out ProductHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out ProductHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.SingleValueProductParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.SingleValueProductParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (ProductHeaderValue)output; + parsedValue = (ProductHeaderValue)output!; return true; } return false; } - internal static int GetProductLength(string input, int startIndex, out ProductHeaderValue parsedValue) + internal static int GetProductLength(string input, int startIndex, out ProductHeaderValue? parsedValue) { Debug.Assert(startIndex >= 0); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderParser.cs index 97744c20ebbc09..b3e4b6dbf98bf4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderParser.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { @@ -21,7 +22,7 @@ private ProductInfoHeaderParser(bool supportsMultipleValues) { } - public override bool TryParseValue(string value, object storeValue, ref int index, out object parsedValue) + public override bool TryParseValue(string? value, object? storeValue, ref int index, [NotNullWhen(true)] out object? parsedValue) { parsedValue = null; @@ -38,8 +39,7 @@ public override bool TryParseValue(string value, object storeValue, ref int inde return false; // whitespace-only values are not valid } - ProductInfoHeaderValue result = null; - int length = ProductInfoHeaderValue.GetProductInfoLength(value, current, out result); + int length = ProductInfoHeaderValue.GetProductInfoLength(value, current, out ProductInfoHeaderValue? result); if (length == 0) { @@ -65,7 +65,7 @@ public override bool TryParseValue(string value, object storeValue, ref int inde // Separators for "User-Agent" and "Server" headers are whitespace. This is different from most other headers // where comma/semicolon is used as separator. index = current; - parsedValue = result; + parsedValue = result!; return true; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderValue.cs index 1a8f3c6e6e83e0..85d02c1607fb48 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderValue.cs @@ -3,25 +3,26 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { public class ProductInfoHeaderValue : ICloneable { - private ProductHeaderValue _product; - private string _comment; + private ProductHeaderValue? _product; + private string? _comment; - public ProductHeaderValue Product + public ProductHeaderValue? Product { get { return _product; } } - public string Comment + public string? Comment { get { return _comment; } } - public ProductInfoHeaderValue(string productName, string productVersion) + public ProductInfoHeaderValue(string productName, string? productVersion) : this(new ProductHeaderValue(productName, productVersion)) { } @@ -58,14 +59,15 @@ public override string ToString() { if (_product == null) { + Debug.Assert(_comment != null); return _comment; } return _product.ToString(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - ProductInfoHeaderValue other = obj as ProductInfoHeaderValue; + ProductInfoHeaderValue? other = obj as ProductInfoHeaderValue; if (other == null) { @@ -85,6 +87,7 @@ public override int GetHashCode() { if (_product == null) { + Debug.Assert(_comment != null); return _comment.GetHashCode(); } return _product.GetHashCode(); @@ -104,13 +107,12 @@ public static ProductInfoHeaderValue Parse(string input) return (ProductInfoHeaderValue)result; } - public static bool TryParse(string input, out ProductInfoHeaderValue parsedValue) + public static bool TryParse(string input, [NotNullWhen(true)] out ProductInfoHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (ProductInfoHeaderParser.SingleValueParser.TryParseValue(input, null, ref index, out output)) + if (ProductInfoHeaderParser.SingleValueParser.TryParseValue(input, null, ref index, out object? output)) { if (index < input.Length) { @@ -124,7 +126,7 @@ public static bool TryParse(string input, out ProductInfoHeaderValue parsedValue return false; } - internal static int GetProductInfoLength(string input, int startIndex, out ProductInfoHeaderValue parsedValue) + internal static int GetProductInfoLength(string? input, int startIndex, out ProductInfoHeaderValue? parsedValue) { Debug.Assert(startIndex >= 0); @@ -138,8 +140,8 @@ internal static int GetProductInfoLength(string input, int startIndex, out Produ int current = startIndex; // Caller must remove leading whitespace. - string comment = null; - ProductHeaderValue product = null; + string? comment = null; + ProductHeaderValue? product = null; if (input[current] == '(') { int commentLength = 0; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeConditionHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeConditionHeaderValue.cs index 51399c7c1845b7..039cab146ee5e9 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeConditionHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeConditionHeaderValue.cs @@ -3,20 +3,21 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { public class RangeConditionHeaderValue : ICloneable { private DateTimeOffset? _date; - private EntityTagHeaderValue _entityTag; + private EntityTagHeaderValue? _entityTag; public DateTimeOffset? Date { get { return _date; } } - public EntityTagHeaderValue EntityTag + public EntityTagHeaderValue? EntityTag { get { return _entityTag; } } @@ -57,14 +58,15 @@ public override string ToString() { if (_entityTag == null) { + Debug.Assert(_date != null); return HttpDateParser.DateToString(_date.Value); } return _entityTag.ToString(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - RangeConditionHeaderValue other = obj as RangeConditionHeaderValue; + RangeConditionHeaderValue? other = obj as RangeConditionHeaderValue; if (other == null) { @@ -73,6 +75,7 @@ public override bool Equals(object obj) if (_entityTag == null) { + Debug.Assert(_date != null); return (other._date != null) && (_date.Value == other._date.Value); } @@ -83,34 +86,34 @@ public override int GetHashCode() { if (_entityTag == null) { + Debug.Assert(_date != null); return _date.Value.GetHashCode(); } return _entityTag.GetHashCode(); } - public static RangeConditionHeaderValue Parse(string input) + public static RangeConditionHeaderValue Parse(string? input) { int index = 0; return (RangeConditionHeaderValue)GenericHeaderParser.RangeConditionParser.ParseValue( input, null, ref index); } - public static bool TryParse(string input, out RangeConditionHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out RangeConditionHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.RangeConditionParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.RangeConditionParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (RangeConditionHeaderValue)output; + parsedValue = (RangeConditionHeaderValue)output!; return true; } return false; } - internal static int GetRangeConditionLength(string input, int startIndex, out object parsedValue) + internal static int GetRangeConditionLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); @@ -126,7 +129,7 @@ internal static int GetRangeConditionLength(string input, int startIndex, out ob // Caller must remove leading whitespace. DateTimeOffset date = DateTimeOffset.MinValue; - EntityTagHeaderValue entityTag = null; + EntityTagHeaderValue? entityTag = null; // Entity tags are quoted strings optionally preceded by "W/". By looking at the first two character we // can determine whether the string is en entity tag or a date. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeHeaderValue.cs index 554f65c8f85290..b9528755a1f926 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeHeaderValue.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; @@ -12,7 +13,7 @@ namespace System.Net.Http.Headers public class RangeHeaderValue : ICloneable { private string _unit; - private ObjectCollection _ranges; + private ObjectCollection? _ranges; public string Unit { @@ -91,9 +92,9 @@ public override string ToString() return StringBuilderCache.GetStringAndRelease(sb); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - RangeHeaderValue other = obj as RangeHeaderValue; + RangeHeaderValue? other = obj as RangeHeaderValue; if (other == null) { @@ -119,27 +120,26 @@ public override int GetHashCode() return result; } - public static RangeHeaderValue Parse(string input) + public static RangeHeaderValue Parse(string? input) { int index = 0; return (RangeHeaderValue)GenericHeaderParser.RangeParser.ParseValue(input, null, ref index); } - public static bool TryParse(string input, out RangeHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out RangeHeaderValue? parsedValue) { int index = 0; - object output; - parsedValue = null; + parsedValue = null; - if (GenericHeaderParser.RangeParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.RangeParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (RangeHeaderValue)output; + parsedValue = (RangeHeaderValue)output!; return true; } return false; } - internal static int GetRangeLength(string input, int startIndex, out object parsedValue) + internal static int GetRangeLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeItemHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeItemHeaderValue.cs index 4576470c6e77bf..b848eddb3be3bc 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeItemHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeItemHeaderValue.cs @@ -58,6 +58,7 @@ public override string ToString() { if (!_from.HasValue) { + Debug.Assert(_to != null); return "-" + _to.Value.ToString(NumberFormatInfo.InvariantInfo); } else if (!_to.HasValue) @@ -68,9 +69,9 @@ public override string ToString() _to.Value.ToString(NumberFormatInfo.InvariantInfo); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - RangeItemHeaderValue other = obj as RangeItemHeaderValue; + RangeItemHeaderValue? other = obj as RangeItemHeaderValue; if (other == null) { @@ -94,7 +95,7 @@ public override int GetHashCode() // Returns the length of a range list. E.g. "1-2, 3-4, 5-6" adds 3 ranges to 'rangeCollection'. Note that empty // list segments are allowed, e.g. ",1-2, , 3-4,,". - internal static int GetRangeItemListLength(string input, int startIndex, + internal static int GetRangeItemListLength(string? input, int startIndex, ICollection rangeCollection) { Debug.Assert(rangeCollection != null); @@ -115,7 +116,7 @@ internal static int GetRangeItemListLength(string input, int startIndex, return 0; } - RangeItemHeaderValue range = null; + RangeItemHeaderValue? range; while (true) { int rangeLength = GetRangeItemLength(input, current, out range); @@ -125,7 +126,7 @@ internal static int GetRangeItemListLength(string input, int startIndex, return 0; } - rangeCollection.Add(range); + rangeCollection.Add(range!); current = current + rangeLength; current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, current, true, out separatorFound); @@ -144,7 +145,7 @@ internal static int GetRangeItemListLength(string input, int startIndex, } } - internal static int GetRangeItemLength(string input, int startIndex, out RangeItemHeaderValue parsedValue) + internal static int GetRangeItemLength(string? input, int startIndex, out RangeItemHeaderValue? parsedValue) { Debug.Assert(startIndex >= 0); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RetryConditionHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RetryConditionHeaderValue.cs index 81822d93a0db7e..02b085067be9ea 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RetryConditionHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RetryConditionHeaderValue.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Globalization; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { @@ -56,12 +57,13 @@ public override string ToString() { return ((int)_delta.Value.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); } + Debug.Assert(_date != null); return HttpDateParser.DateToString(_date.Value); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - RetryConditionHeaderValue other = obj as RetryConditionHeaderValue; + RetryConditionHeaderValue? other = obj as RetryConditionHeaderValue; if (other == null) { @@ -73,6 +75,7 @@ public override bool Equals(object obj) return (other._delta != null) && (_delta.Value == other._delta.Value); } + Debug.Assert(_date != null); return (other._date != null) && (_date.Value == other._date.Value); } @@ -80,34 +83,34 @@ public override int GetHashCode() { if (_delta == null) { + Debug.Assert(_date != null); return _date.Value.GetHashCode(); } return _delta.Value.GetHashCode(); } - public static RetryConditionHeaderValue Parse(string input) + public static RetryConditionHeaderValue Parse(string? input) { int index = 0; return (RetryConditionHeaderValue)GenericHeaderParser.RetryConditionParser.ParseValue( input, null, ref index); } - public static bool TryParse(string input, out RetryConditionHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out RetryConditionHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.RetryConditionParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.RetryConditionParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (RetryConditionHeaderValue)output; + parsedValue = (RetryConditionHeaderValue)output!; return true; } return false; } - internal static int GetRetryConditionLength(string input, int startIndex, out object parsedValue) + internal static int GetRetryConditionLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/StringWithQualityHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/StringWithQualityHeaderValue.cs index 98e0fcd2531d88..60c0e668865465 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/StringWithQualityHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/StringWithQualityHeaderValue.cs @@ -3,13 +3,14 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace System.Net.Http.Headers { public class StringWithQualityHeaderValue : ICloneable { - private string _value; + private string _value = null!; private double? _quality; public string Value @@ -64,9 +65,9 @@ public override string ToString() return _value; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - StringWithQualityHeaderValue other = obj as StringWithQualityHeaderValue; + StringWithQualityHeaderValue? other = obj as StringWithQualityHeaderValue; if (other == null) { @@ -103,29 +104,28 @@ public override int GetHashCode() return result; } - public static StringWithQualityHeaderValue Parse(string input) + public static StringWithQualityHeaderValue Parse(string? input) { int index = 0; return (StringWithQualityHeaderValue)GenericHeaderParser.SingleValueStringWithQualityParser.ParseValue( input, null, ref index); } - public static bool TryParse(string input, out StringWithQualityHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out StringWithQualityHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; if (GenericHeaderParser.SingleValueStringWithQualityParser.TryParseValue( - input, null, ref index, out output)) + input, null, ref index, out object? output)) { - parsedValue = (StringWithQualityHeaderValue)output; + parsedValue = (StringWithQualityHeaderValue)output!; return true; } return false; } - internal static int GetStringWithQualityLength(string input, int startIndex, out object parsedValue) + internal static int GetStringWithQualityLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TimeSpanHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TimeSpanHeaderParser.cs index 99cd0d192b9ed2..f8db68c5422adc 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TimeSpanHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TimeSpanHeaderParser.cs @@ -23,8 +23,8 @@ public override string ToString(object value) return ((int)((TimeSpan)value).TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); } - protected override int GetParsedValueLength(string value, int startIndex, object storeValue, - out object parsedValue) + protected override int GetParsedValueLength(string value, int startIndex, object? storeValue, + out object? parsedValue) { parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderParser.cs index 8a904bf256ac6a..9bd31fa8171e63 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderParser.cs @@ -28,12 +28,11 @@ private TransferCodingHeaderParser(bool supportsMultipleValues, _transferCodingCreator = transferCodingCreator; } - protected override int GetParsedValueLength(string value, int startIndex, object storeValue, - out object parsedValue) + protected override int GetParsedValueLength(string value, int startIndex, object? storeValue, + out object? parsedValue) { - TransferCodingHeaderValue temp = null; int resultLength = TransferCodingHeaderValue.GetTransferCodingLength(value, startIndex, - _transferCodingCreator, out temp); + _transferCodingCreator, out TransferCodingHeaderValue? temp); parsedValue = temp; return resultLength; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderValue.cs index 177623e8d3e51e..22daaea0d11335 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderValue.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; @@ -12,8 +13,8 @@ namespace System.Net.Http.Headers public class TransferCodingHeaderValue : ICloneable { // Use ObjectCollection since we may have multiple parameters with the same name. - private ObjectCollection _parameters; - private string _value; + private ObjectCollection? _parameters; + private string _value = null!; // empty constructor only used internally and value set with non null public string Value { @@ -57,29 +58,28 @@ public TransferCodingHeaderValue(string value) _value = value; } - public static TransferCodingHeaderValue Parse(string input) + public static TransferCodingHeaderValue Parse(string? input) { int index = 0; return (TransferCodingHeaderValue)TransferCodingHeaderParser.SingleValueParser.ParseValue( input, null, ref index); } - public static bool TryParse(string input, out TransferCodingHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out TransferCodingHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (TransferCodingHeaderParser.SingleValueParser.TryParseValue(input, null, ref index, out output)) + if (TransferCodingHeaderParser.SingleValueParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (TransferCodingHeaderValue)output; + parsedValue = (TransferCodingHeaderValue)output!; return true; } return false; } internal static int GetTransferCodingLength(string input, int startIndex, - Func transferCodingCreator, out TransferCodingHeaderValue parsedValue) + Func transferCodingCreator, out TransferCodingHeaderValue? parsedValue) { Debug.Assert(transferCodingCreator != null); Debug.Assert(startIndex >= 0); @@ -102,7 +102,7 @@ internal static int GetTransferCodingLength(string input, int startIndex, string value = input.Substring(startIndex, valueLength); int current = startIndex + valueLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); - TransferCodingHeaderValue transferCodingHeader = null; + TransferCodingHeaderValue transferCodingHeader; // If we're not done and we have a parameter delimiter, then we have a list of parameters. if ((current < input.Length) && (input[current] == ';')) @@ -138,9 +138,9 @@ public override string ToString() return StringBuilderCache.GetStringAndRelease(sb); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - TransferCodingHeaderValue other = obj as TransferCodingHeaderValue; + TransferCodingHeaderValue? other = obj as TransferCodingHeaderValue; if (other == null) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingWithQualityHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingWithQualityHeaderValue.cs index 5eef034a30037e..6b4781043eab08 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingWithQualityHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingWithQualityHeaderValue.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { @@ -41,23 +42,22 @@ object ICloneable.Clone() return new TransferCodingWithQualityHeaderValue(this); } - public static new TransferCodingWithQualityHeaderValue Parse(string input) + public static new TransferCodingWithQualityHeaderValue Parse(string? input) { int index = 0; return (TransferCodingWithQualityHeaderValue)TransferCodingHeaderParser.SingleValueWithQualityParser .ParseValue(input, null, ref index); } - public static bool TryParse(string input, out TransferCodingWithQualityHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out TransferCodingWithQualityHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; if (TransferCodingHeaderParser.SingleValueWithQualityParser.TryParseValue( - input, null, ref index, out output)) + input, null, ref index, out object? output)) { - parsedValue = (TransferCodingWithQualityHeaderValue)output; + parsedValue = (TransferCodingWithQualityHeaderValue)output!; return true; } return false; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/UriHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/UriHeaderParser.cs index 3e0a6f5748c9ae..4d75e843a9a048 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/UriHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/UriHeaderParser.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http.Headers { @@ -22,7 +23,7 @@ private UriHeaderParser(UriKind uriKind) _uriKind = uriKind; } - public override bool TryParseValue(string value, object storeValue, ref int index, out object parsedValue) + public override bool TryParseValue(string? value, object? storeValue, ref int index, [NotNullWhen(true)] out object? parsedValue) { parsedValue = null; @@ -38,8 +39,7 @@ public override bool TryParseValue(string value, object storeValue, ref int inde uriString = value.Substring(index); } - Uri uri; - if (!Uri.TryCreate(uriString, _uriKind, out uri)) + if (!Uri.TryCreate(uriString, _uriKind, out Uri? uri)) { // Some servers send the host names in Utf-8. uriString = DecodeUtf8FromString(uriString); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs index 2e8ecd74c1c7e7..7aaef31fdf5114 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; @@ -10,12 +11,12 @@ namespace System.Net.Http.Headers { public class ViaHeaderValue : ICloneable { - private string _protocolName; - private string _protocolVersion; - private string _receivedBy; - private string _comment; + private string? _protocolName; + private string _protocolVersion = null!; + private string _receivedBy = null!; + private string? _comment; - public string ProtocolName + public string? ProtocolName { get { return _protocolName; } } @@ -30,7 +31,7 @@ public string ReceivedBy get { return _receivedBy; } } - public string Comment + public string? Comment { get { return _comment; } } @@ -40,12 +41,12 @@ public ViaHeaderValue(string protocolVersion, string receivedBy) { } - public ViaHeaderValue(string protocolVersion, string receivedBy, string protocolName) + public ViaHeaderValue(string protocolVersion, string receivedBy, string? protocolName) : this(protocolVersion, receivedBy, protocolName, null) { } - public ViaHeaderValue(string protocolVersion, string receivedBy, string protocolName, string comment) + public ViaHeaderValue(string protocolVersion, string receivedBy, string? protocolName, string? comment) { HeaderUtilities.CheckValidToken(protocolVersion, nameof(protocolVersion)); CheckReceivedBy(receivedBy); @@ -103,9 +104,9 @@ public override string ToString() return StringBuilderCache.GetStringAndRelease(sb); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - ViaHeaderValue other = obj as ViaHeaderValue; + ViaHeaderValue? other = obj as ViaHeaderValue; if (other == null) { @@ -138,27 +139,26 @@ public override int GetHashCode() return result; } - public static ViaHeaderValue Parse(string input) + public static ViaHeaderValue Parse(string? input) { int index = 0; return (ViaHeaderValue)GenericHeaderParser.SingleValueViaParser.ParseValue(input, null, ref index); } - public static bool TryParse(string input, out ViaHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out ViaHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.SingleValueViaParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.SingleValueViaParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (ViaHeaderValue)output; + parsedValue = (ViaHeaderValue)output!; return true; } return false; } - internal static int GetViaLength(string input, int startIndex, out object parsedValue) + internal static int GetViaLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); @@ -170,9 +170,7 @@ internal static int GetViaLength(string input, int startIndex, out object parsed } // Read and in '[/] []' - string protocolName = null; - string protocolVersion = null; - int current = GetProtocolEndIndex(input, startIndex, out protocolName, out protocolVersion); + int current = GetProtocolEndIndex(input, startIndex, out string? protocolName, out string? protocolVersion); // If we reached the end of the string after reading protocolName/Version we return (we expect at least // to follow). If reading protocolName/Version read 0 bytes, we return. @@ -183,8 +181,7 @@ internal static int GetViaLength(string input, int startIndex, out object parsed Debug.Assert(protocolVersion != null); // Read in '[/] []' - string receivedBy = null; - int receivedByLength = HttpRuleParser.GetHostLength(input, current, true, out receivedBy); + int receivedByLength = HttpRuleParser.GetHostLength(input, current, true, out string? receivedBy); if (receivedByLength == 0) { @@ -194,7 +191,7 @@ internal static int GetViaLength(string input, int startIndex, out object parsed current = current + receivedByLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); - string comment = null; + string? comment = null; if ((current < input.Length) && (input[current] == '(')) { // We have a in '[/] []' @@ -213,15 +210,15 @@ internal static int GetViaLength(string input, int startIndex, out object parsed ViaHeaderValue result = new ViaHeaderValue(); result._protocolVersion = protocolVersion; result._protocolName = protocolName; - result._receivedBy = receivedBy; + result._receivedBy = receivedBy!; result._comment = comment; parsedValue = result; return current - startIndex; } - private static int GetProtocolEndIndex(string input, int startIndex, out string protocolName, - out string protocolVersion) + private static int GetProtocolEndIndex(string input, int startIndex, out string? protocolName, + out string? protocolVersion) { // We have a string of the form '[/] []'. The first // token may either be the protocol name or protocol version. We'll only find out after reading the token @@ -294,9 +291,8 @@ private static void CheckReceivedBy(string receivedBy) } // 'receivedBy' can either be a host or a token. Since a token is a valid host, we only verify if the value - // is a valid host. - string host = null; - if (HttpRuleParser.GetHostLength(receivedBy, 0, true, out host) != receivedBy.Length) + // is a valid host.; + if (HttpRuleParser.GetHostLength(receivedBy, 0, true, out string? host) != receivedBy.Length) { throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_headers_invalid_value, receivedBy)); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs index bf18913fddd291..9572c06eb7b2a3 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Text; @@ -12,8 +13,8 @@ namespace System.Net.Http.Headers public class WarningHeaderValue : ICloneable { private int _code; - private string _agent; - private string _text; + private string _agent = null!; + private string _text = null!; private DateTimeOffset? _date; public int Code @@ -95,9 +96,9 @@ public override string ToString() return StringBuilderCache.GetStringAndRelease(sb); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - WarningHeaderValue other = obj as WarningHeaderValue; + WarningHeaderValue? other = obj as WarningHeaderValue; if (other == null) { @@ -136,27 +137,26 @@ public override int GetHashCode() return result; } - public static WarningHeaderValue Parse(string input) + public static WarningHeaderValue Parse(string? input) { int index = 0; return (WarningHeaderValue)GenericHeaderParser.SingleValueWarningParser.ParseValue(input, null, ref index); } - public static bool TryParse(string input, out WarningHeaderValue parsedValue) + public static bool TryParse(string? input, [NotNullWhen(true)] out WarningHeaderValue? parsedValue) { int index = 0; - object output; parsedValue = null; - if (GenericHeaderParser.SingleValueWarningParser.TryParseValue(input, null, ref index, out output)) + if (GenericHeaderParser.SingleValueWarningParser.TryParseValue(input, null, ref index, out object? output)) { - parsedValue = (WarningHeaderValue)output; + parsedValue = (WarningHeaderValue)output!; return true; } return false; } - internal static int GetWarningLength(string input, int startIndex, out object parsedValue) + internal static int GetWarningLength(string? input, int startIndex, out object? parsedValue) { Debug.Assert(startIndex >= 0); @@ -177,8 +177,7 @@ internal static int GetWarningLength(string input, int startIndex, out object pa } // Read in ' [""]' - string agent; - if (!TryReadAgent(input, current, ref current, out agent)) + if (!TryReadAgent(input, current, ref current, out string? agent)) { return 0; } @@ -210,11 +209,9 @@ internal static int GetWarningLength(string input, int startIndex, out object pa return current - startIndex; } - private static bool TryReadAgent(string input, int startIndex, ref int current, out string agent) + private static bool TryReadAgent(string input, int startIndex, ref int current, [NotNullWhen(true)] out string? agent) { - agent = null; - - int agentLength = HttpRuleParser.GetHostLength(input, startIndex, true, out agent); + int agentLength = HttpRuleParser.GetHostLength(input, startIndex, true, out agent!); if (agentLength == 0) { @@ -337,8 +334,7 @@ private static void CheckAgent(string agent) // 'receivedBy' can either be a host or a token. Since a token is a valid host, we only verify if the value // is a valid host. - string host = null; - if (HttpRuleParser.GetHostLength(agent, 0, true, out host) != agent.Length) + if (HttpRuleParser.GetHostLength(agent, 0, true, out string? host) != agent.Length) { throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_headers_invalid_value, agent)); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs index ba716dae88c534..91d955b3fc96bf 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs @@ -15,7 +15,7 @@ public class HttpClient : HttpMessageInvoker { #region Fields - private static IWebProxy s_defaultProxy; + private static IWebProxy? s_defaultProxy; private static readonly TimeSpan s_defaultTimeout = TimeSpan.FromSeconds(100); private static readonly TimeSpan s_maxTimeout = TimeSpan.FromMilliseconds(int.MaxValue); private static readonly TimeSpan s_infiniteTimeout = Threading.Timeout.InfiniteTimeSpan; @@ -25,10 +25,10 @@ public class HttpClient : HttpMessageInvoker private volatile bool _disposed; private CancellationTokenSource _pendingRequestsCts; - private HttpRequestHeaders _defaultRequestHeaders; + private HttpRequestHeaders? _defaultRequestHeaders; private Version _defaultRequestVersion = HttpUtilities.DefaultRequestVersion; - private Uri _baseAddress; + private Uri? _baseAddress; private TimeSpan _timeout; private int _maxResponseContentBufferSize; @@ -67,7 +67,7 @@ public Version DefaultRequestVersion } } - public Uri BaseAddress + public Uri? BaseAddress { get { return _baseAddress; } set @@ -145,16 +145,16 @@ public HttpClient(HttpMessageHandler handler, bool disposeHandler) #region Simple Get Overloads - public Task GetStringAsync(string requestUri) => + public Task GetStringAsync(string? requestUri) => GetStringAsync(CreateUri(requestUri)); - public Task GetStringAsync(Uri requestUri) => + public Task GetStringAsync(Uri? requestUri) => GetStringAsync(requestUri, CancellationToken.None); - public Task GetStringAsync(string requestUri, CancellationToken cancellationToken) => + public Task GetStringAsync(string? requestUri, CancellationToken cancellationToken) => GetStringAsync(CreateUri(requestUri), cancellationToken); - public Task GetStringAsync(Uri requestUri, CancellationToken cancellationToken) => + public Task GetStringAsync(Uri? requestUri, CancellationToken cancellationToken) => GetStringAsyncCore(GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken), cancellationToken); private async Task GetStringAsyncCore(Task getTask, CancellationToken cancellationToken) @@ -166,7 +166,7 @@ private async Task GetStringAsyncCore(Task getTask, responseMessage.EnsureSuccessStatusCode(); // Get the response content. - HttpContent c = responseMessage.Content; + HttpContent? c = responseMessage.Content; if (c != null) { #if NET46 @@ -202,16 +202,16 @@ private async Task GetStringAsyncCore(Task getTask, } } - public Task GetByteArrayAsync(string requestUri) => + public Task GetByteArrayAsync(string? requestUri) => GetByteArrayAsync(CreateUri(requestUri)); - public Task GetByteArrayAsync(Uri requestUri) => + public Task GetByteArrayAsync(Uri? requestUri) => GetByteArrayAsync(requestUri, CancellationToken.None); - public Task GetByteArrayAsync(string requestUri, CancellationToken cancellationToken) => + public Task GetByteArrayAsync(string? requestUri, CancellationToken cancellationToken) => GetByteArrayAsync(CreateUri(requestUri), cancellationToken); - public Task GetByteArrayAsync(Uri requestUri, CancellationToken cancellationToken) => + public Task GetByteArrayAsync(Uri? requestUri, CancellationToken cancellationToken) => GetByteArrayAsyncCore(GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken), cancellationToken); private async Task GetByteArrayAsyncCore(Task getTask, CancellationToken cancellationToken) @@ -223,7 +223,7 @@ private async Task GetByteArrayAsyncCore(Task getTa responseMessage.EnsureSuccessStatusCode(); // Get the response content. - HttpContent c = responseMessage.Content; + HttpContent? c = responseMessage.Content; if (c != null) { #if NET46 @@ -290,23 +290,23 @@ private async Task GetByteArrayAsyncCore(Task getTa } } - public Task GetStreamAsync(string requestUri) => + public Task GetStreamAsync(string? requestUri) => GetStreamAsync(CreateUri(requestUri)); - public Task GetStreamAsync(string requestUri, CancellationToken cancellationToken) => + public Task GetStreamAsync(string? requestUri, CancellationToken cancellationToken) => GetStreamAsync(CreateUri(requestUri), cancellationToken); - public Task GetStreamAsync(Uri requestUri) => + public Task GetStreamAsync(Uri? requestUri) => GetStreamAsync(requestUri, CancellationToken.None); - public Task GetStreamAsync(Uri requestUri, CancellationToken cancellationToken) => + public Task GetStreamAsync(Uri? requestUri, CancellationToken cancellationToken) => FinishGetStreamAsync(GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken), cancellationToken); private async Task FinishGetStreamAsync(Task getTask, CancellationToken cancellationToken) { HttpResponseMessage response = await getTask.ConfigureAwait(false); response.EnsureSuccessStatusCode(); - HttpContent c = response.Content; + HttpContent? c = response.Content; return c != null ? (c.TryReadAsStream() ?? await c.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false)) : Stream.Null; @@ -316,65 +316,65 @@ private async Task FinishGetStreamAsync(Task getTas #region REST Send Overloads - public Task GetAsync(string requestUri) + public Task GetAsync(string? requestUri) { return GetAsync(CreateUri(requestUri)); } - public Task GetAsync(Uri requestUri) + public Task GetAsync(Uri? requestUri) { return GetAsync(requestUri, defaultCompletionOption); } - public Task GetAsync(string requestUri, HttpCompletionOption completionOption) + public Task GetAsync(string? requestUri, HttpCompletionOption completionOption) { return GetAsync(CreateUri(requestUri), completionOption); } - public Task GetAsync(Uri requestUri, HttpCompletionOption completionOption) + public Task GetAsync(Uri? requestUri, HttpCompletionOption completionOption) { return GetAsync(requestUri, completionOption, CancellationToken.None); } - public Task GetAsync(string requestUri, CancellationToken cancellationToken) + public Task GetAsync(string? requestUri, CancellationToken cancellationToken) { return GetAsync(CreateUri(requestUri), cancellationToken); } - public Task GetAsync(Uri requestUri, CancellationToken cancellationToken) + public Task GetAsync(Uri? requestUri, CancellationToken cancellationToken) { return GetAsync(requestUri, defaultCompletionOption, cancellationToken); } - public Task GetAsync(string requestUri, HttpCompletionOption completionOption, + public Task GetAsync(string? requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) { return GetAsync(CreateUri(requestUri), completionOption, cancellationToken); } - public Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, + public Task GetAsync(Uri? requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) { return SendAsync(CreateRequestMessage(HttpMethod.Get, requestUri), completionOption, cancellationToken); } - public Task PostAsync(string requestUri, HttpContent content) + public Task PostAsync(string? requestUri, HttpContent content) { return PostAsync(CreateUri(requestUri), content); } - public Task PostAsync(Uri requestUri, HttpContent content) + public Task PostAsync(Uri? requestUri, HttpContent content) { return PostAsync(requestUri, content, CancellationToken.None); } - public Task PostAsync(string requestUri, HttpContent content, + public Task PostAsync(string? requestUri, HttpContent content, CancellationToken cancellationToken) { return PostAsync(CreateUri(requestUri), content, cancellationToken); } - public Task PostAsync(Uri requestUri, HttpContent content, + public Task PostAsync(Uri? requestUri, HttpContent content, CancellationToken cancellationToken) { HttpRequestMessage request = CreateRequestMessage(HttpMethod.Post, requestUri); @@ -382,23 +382,23 @@ public Task PostAsync(Uri requestUri, HttpContent content, return SendAsync(request, cancellationToken); } - public Task PutAsync(string requestUri, HttpContent content) + public Task PutAsync(string? requestUri, HttpContent content) { return PutAsync(CreateUri(requestUri), content); } - public Task PutAsync(Uri requestUri, HttpContent content) + public Task PutAsync(Uri? requestUri, HttpContent content) { return PutAsync(requestUri, content, CancellationToken.None); } - public Task PutAsync(string requestUri, HttpContent content, + public Task PutAsync(string? requestUri, HttpContent content, CancellationToken cancellationToken) { return PutAsync(CreateUri(requestUri), content, cancellationToken); } - public Task PutAsync(Uri requestUri, HttpContent content, + public Task PutAsync(Uri? requestUri, HttpContent content, CancellationToken cancellationToken) { HttpRequestMessage request = CreateRequestMessage(HttpMethod.Put, requestUri); @@ -406,23 +406,23 @@ public Task PutAsync(Uri requestUri, HttpContent content, return SendAsync(request, cancellationToken); } - public Task PatchAsync(string requestUri, HttpContent content) + public Task PatchAsync(string? requestUri, HttpContent content) { return PatchAsync(CreateUri(requestUri), content); } - public Task PatchAsync(Uri requestUri, HttpContent content) + public Task PatchAsync(Uri? requestUri, HttpContent content) { return PatchAsync(requestUri, content, CancellationToken.None); } - public Task PatchAsync(string requestUri, HttpContent content, + public Task PatchAsync(string? requestUri, HttpContent content, CancellationToken cancellationToken) { return PatchAsync(CreateUri(requestUri), content, cancellationToken); } - public Task PatchAsync(Uri requestUri, HttpContent content, + public Task PatchAsync(Uri? requestUri, HttpContent content, CancellationToken cancellationToken) { HttpRequestMessage request = CreateRequestMessage(HttpMethod.Patch, requestUri); @@ -430,22 +430,22 @@ public Task PatchAsync(Uri requestUri, HttpContent content, return SendAsync(request, cancellationToken); } - public Task DeleteAsync(string requestUri) + public Task DeleteAsync(string? requestUri) { return DeleteAsync(CreateUri(requestUri)); } - public Task DeleteAsync(Uri requestUri) + public Task DeleteAsync(Uri? requestUri) { return DeleteAsync(requestUri, CancellationToken.None); } - public Task DeleteAsync(string requestUri, CancellationToken cancellationToken) + public Task DeleteAsync(string? requestUri, CancellationToken cancellationToken) { return DeleteAsync(CreateUri(requestUri), cancellationToken); } - public Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken) + public Task DeleteAsync(Uri? requestUri, CancellationToken cancellationToken) { return SendAsync(CreateRequestMessage(HttpMethod.Delete, requestUri), cancellationToken); } @@ -535,7 +535,7 @@ public Task SendAsync(HttpRequestMessage request, HttpCompl private async Task FinishSendAsyncBuffered( Task sendTask, HttpRequestMessage request, CancellationTokenSource cts, bool disposeCts, CancellationToken callerToken, long timeoutTime) { - HttpResponseMessage response = null; + HttpResponseMessage? response = null; try { // Wait for the send request to complete, getting back the response. @@ -740,7 +740,7 @@ private static void CheckRequestMessage(HttpRequestMessage request) private void PrepareRequestMessage(HttpRequestMessage request) { - Uri requestUri = null; + Uri? requestUri = null; if ((request.RequestUri == null) && (_baseAddress == null)) { throw new InvalidOperationException(SR.net_http_client_invalid_requesturi); @@ -778,7 +778,7 @@ private void PrepareRequestMessage(HttpRequestMessage request) } } - private static void CheckBaseAddress(Uri baseAddress, string parameterName) + private static void CheckBaseAddress(Uri? baseAddress, string parameterName) { if (baseAddress == null) { @@ -796,10 +796,10 @@ private static void CheckBaseAddress(Uri baseAddress, string parameterName) } } - private Uri CreateUri(string uri) => + private Uri? CreateUri(string? uri) => string.IsNullOrEmpty(uri) ? null : new Uri(uri, UriKind.RelativeOrAbsolute); - private HttpRequestMessage CreateRequestMessage(HttpMethod method, Uri uri) => + private HttpRequestMessage CreateRequestMessage(HttpMethod method, Uri? uri) => new HttpRequestMessage(method, uri) { Version = _defaultRequestVersion }; #endregion Private Helpers } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs index 280b506bc113db..1851c5aa3da6aa 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs @@ -71,13 +71,13 @@ public bool UseProxy set => _socketsHttpHandler.UseProxy = value; } - public IWebProxy Proxy + public IWebProxy? Proxy { get => _socketsHttpHandler.Proxy; set => _socketsHttpHandler.Proxy = value; } - public ICredentials DefaultProxyCredentials + public ICredentials? DefaultProxyCredentials { get => _socketsHttpHandler.DefaultProxyCredentials; set => _socketsHttpHandler.DefaultProxyCredentials = value; @@ -111,7 +111,7 @@ public bool UseDefaultCredentials } } - public ICredentials Credentials + public ICredentials? Credentials { get => _socketsHttpHandler.Credentials; set => _socketsHttpHandler.Credentials = value; @@ -151,13 +151,13 @@ public ClientCertificateOption ClientCertificateOptions case ClientCertificateOption.Manual: ThrowForModifiedManagedSslOptionsIfStarted(); _clientCertificateOptions = value; - _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate(ClientCertificates); + _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate(ClientCertificates)!; break; case ClientCertificateOption.Automatic: ThrowForModifiedManagedSslOptionsIfStarted(); _clientCertificateOptions = value; - _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate(); + _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate()!; break; default: @@ -180,7 +180,7 @@ public X509CertificateCollection ClientCertificates } } - public Func ServerCertificateCustomValidationCallback + public Func? ServerCertificateCustomValidationCallback { get => (_socketsHttpHandler.SslOptions.RemoteCertificateValidationCallback?.Target as ConnectHelper.CertificateCallbackMapper)?.FromHttpClientHandler; set @@ -212,7 +212,7 @@ public SslProtocols SslProtocols } } - public IDictionary Properties => _socketsHttpHandler.Properties; + public IDictionary Properties => _socketsHttpHandler.Properties; protected internal override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs index aeb543e92689f8..2ba227249dc3ce 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Http.Headers; using System.Text; @@ -14,9 +15,9 @@ namespace System.Net.Http { public abstract class HttpContent : IDisposable { - private HttpContentHeaders _headers; - private MemoryStream _bufferedContent; - private object _contentReadStream; // Stream or Task + private HttpContentHeaders? _headers; + private MemoryStream? _bufferedContent; + private object? _contentReadStream; // Stream or Task private bool _disposed; private bool _canCalculateLength; @@ -169,7 +170,7 @@ private string ReadBufferedContentAsString() { Debug.Assert(IsBuffered); - if (_bufferedContent.Length == 0) + if (_bufferedContent!.Length == 0) { return string.Empty; } @@ -190,10 +191,10 @@ internal static string ReadBufferAsString(ArraySegment buffer, HttpContent // Content-Encoding is 'gzip' the user should set HttpClientHandler.AutomaticDecompression to get a // decoded response stream. - Encoding encoding = null; + Encoding? encoding = null; int bomLength = -1; - string charset = headers.ContentType?.CharSet; + string? charset = headers.ContentType?.CharSet; // If we do have encoding information in the 'Content-Type' header, use that information to convert // the content to a string. @@ -238,7 +239,7 @@ internal static string ReadBufferAsString(ArraySegment buffer, HttpContent } // Drop the BOM when decoding the data. - return encoding.GetString(buffer.Array, buffer.Offset + bomLength, buffer.Count - bomLength); + return encoding.GetString(buffer.Array!, buffer.Offset + bomLength, buffer.Count - bomLength); } public Task ReadAsByteArrayAsync() => @@ -252,6 +253,7 @@ public Task ReadAsByteArrayAsync(CancellationToken cancellationToken) internal byte[] ReadBufferedContentAsByteArray() { + Debug.Assert(_bufferedContent != null); // The returned array is exposed out of the library, so use ToArray rather // than TryGetBuffer in order to make a copy. return _bufferedContent.ToArray(); @@ -271,7 +273,7 @@ public Task ReadAsStreamAsync(CancellationToken cancellationToken) if (_contentReadStream == null) // don't yet have a Stream { Task t = TryGetBuffer(out ArraySegment buffer) ? - Task.FromResult(new MemoryStream(buffer.Array, buffer.Offset, buffer.Count, writable: false)) : + Task.FromResult(new MemoryStream(buffer.Array!, buffer.Offset, buffer.Count, writable: false)) : CreateContentReadStreamAsync(cancellationToken); _contentReadStream = t; return t; @@ -289,7 +291,7 @@ public Task ReadAsStreamAsync(CancellationToken cancellationToken) } } - internal Stream TryReadAsStream() + internal Stream? TryReadAsStream() { CheckDisposed(); @@ -299,8 +301,8 @@ internal Stream TryReadAsStream() if (_contentReadStream == null) // don't yet have a Stream { - Stream s = TryGetBuffer(out ArraySegment buffer) ? - new MemoryStream(buffer.Array, buffer.Offset, buffer.Count, writable: false) : + Stream? s = TryGetBuffer(out ArraySegment buffer) ? + new MemoryStream(buffer.Array!, buffer.Offset, buffer.Count, writable: false) : TryCreateContentReadStream(); _contentReadStream = s; return s; @@ -317,9 +319,9 @@ internal Stream TryReadAsStream() } } - protected abstract Task SerializeToStreamAsync(Stream stream, TransportContext context); + protected abstract Task SerializeToStreamAsync(Stream stream, TransportContext? context); - protected virtual Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) => + protected virtual Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => SerializeToStreamAsync(stream, context); // TODO https://github.com/dotnet/runtime/issues/31316: Expose something to enable this publicly. For very specific @@ -336,10 +338,10 @@ public Task CopyToAsync(Stream stream) => public Task CopyToAsync(Stream stream, CancellationToken cancellationToken) => CopyToAsync(stream, null, cancellationToken); - public Task CopyToAsync(Stream stream, TransportContext context) => + public Task CopyToAsync(Stream stream, TransportContext? context) => CopyToAsync(stream, context, CancellationToken.None); - public Task CopyToAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) + public Task CopyToAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) { CheckDisposed(); if (stream == null) @@ -411,12 +413,11 @@ internal Task LoadIntoBufferAsync(long maxBufferSize, CancellationToken cancella return Task.CompletedTask; } - Exception error = null; - MemoryStream tempBuffer = CreateMemoryStream(maxBufferSize, out error); + MemoryStream? tempBuffer = CreateMemoryStream(maxBufferSize, out Exception? error); if (tempBuffer == null) { // We don't throw in LoadIntoBufferAsync(): return a faulted task. - return Task.FromException(error); + return Task.FromException(error!); } try @@ -463,7 +464,7 @@ protected virtual Task CreateContentReadStreamAsync() // By default just buffer the content to a memory stream. Derived classes can override this behavior // if there is a better way to retrieve the content as stream (e.g. byte array/string use a more efficient // way, like wrapping a read-only MemoryStream around the bytes/string) - return WaitAndReturnAsync(LoadIntoBufferAsync(), this, s => (Stream)s._bufferedContent); + return WaitAndReturnAsync(LoadIntoBufferAsync(), this, s => (Stream)s._bufferedContent!); } protected virtual Task CreateContentReadStreamAsync(CancellationToken cancellationToken) @@ -476,7 +477,7 @@ protected virtual Task CreateContentReadStreamAsync(CancellationToken ca // HttpContent-derived implementations that override CreateContentReadStreamAsync in a way that always // or frequently returns synchronously-completed tasks, we can avoid the task allocation by enabling // callers to try to get the Stream first synchronously. - internal virtual Stream TryCreateContentReadStream() => null; + internal virtual Stream? TryCreateContentReadStream() => null; // Derived types return true if they're able to compute the length. It's OK if derived types return false to // indicate that they're not able to compute the length. The transport channel needs to decide what to do in @@ -489,7 +490,7 @@ protected virtual Task CreateContentReadStreamAsync(CancellationToken ca if (IsBuffered) { - return _bufferedContent.Length; + return _bufferedContent!.Length; } // If we already tried to calculate the length, but the derived class returned 'false', then don't try @@ -509,7 +510,7 @@ protected virtual Task CreateContentReadStreamAsync(CancellationToken ca return null; } - private MemoryStream CreateMemoryStream(long maxBufferSize, out Exception error) + private MemoryStream? CreateMemoryStream(long maxBufferSize, out Exception? error) { error = null; @@ -545,7 +546,7 @@ protected virtual void Dispose(bool disposing) if (_contentReadStream != null) { - Stream s = _contentReadStream as Stream ?? + Stream? s = _contentReadStream as Stream ?? (_contentReadStream is Task t && t.Status == TaskStatus.RanToCompletion ? t.Result : null); s?.Dispose(); _contentReadStream = null; @@ -553,7 +554,7 @@ protected virtual void Dispose(bool disposing) if (IsBuffered) { - _bufferedContent.Dispose(); + _bufferedContent!.Dispose(); } } } @@ -612,7 +613,7 @@ internal static Exception WrapStreamCopyException(Exception e) private static int GetPreambleLength(ArraySegment buffer, Encoding encoding) { - byte[] data = buffer.Array; + byte[]? data = buffer.Array; int offset = buffer.Offset; int dataLength = buffer.Count; @@ -648,9 +649,9 @@ private static int GetPreambleLength(ArraySegment buffer, Encoding encodin } } - private static bool TryDetectEncoding(ArraySegment buffer, out Encoding encoding, out int preambleLength) + private static bool TryDetectEncoding(ArraySegment buffer, [NotNullWhen(true)] out Encoding? encoding, out int preambleLength) { - byte[] data = buffer.Array; + byte[]? data = buffer.Array; int offset = buffer.Offset; int dataLength = buffer.Count; @@ -699,7 +700,7 @@ private static bool TryDetectEncoding(ArraySegment buffer, out Encoding en private static bool BufferHasPrefix(ArraySegment buffer, byte[] prefix) { - byte[] byteArray = buffer.Array; + byte[]? byteArray = buffer.Array; if (prefix == null || byteArray == null || prefix.Length > buffer.Count || prefix.Length == 0) return false; @@ -739,7 +740,7 @@ public LimitMemoryStream(int maxSize, int capacity) public byte[] GetSizedBuffer() { ArraySegment buffer; - return TryGetBuffer(out buffer) && buffer.Offset == 0 && buffer.Count == buffer.Array.Length ? + return TryGetBuffer(out buffer) && buffer.Offset == 0 && buffer.Count == buffer.Array!.Length ? buffer.Array : ToArray(); } @@ -768,7 +769,7 @@ public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationTo return base.WriteAsync(buffer, cancellationToken); } - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { CheckSize(count); return base.BeginWrite(buffer, offset, count, callback, state); @@ -791,7 +792,7 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio Position = length; long bytesToWrite = length - pos; - return destination.WriteAsync(buffer.Array, (int)(buffer.Offset + pos), (int)bytesToWrite, cancellationToken); + return destination.WriteAsync(buffer.Array!, (int)(buffer.Offset + pos), (int)bytesToWrite, cancellationToken); } return base.CopyToAsync(destination, bufferSize, cancellationToken); @@ -837,7 +838,7 @@ protected override void Dispose(bool disposing) Debug.Assert(_buffer != null); ArrayPool.Shared.Return(_buffer); - _buffer = null; + _buffer = null!; base.Dispose(disposing); } @@ -869,7 +870,7 @@ private void Grow(int value) // Extract the current buffer to be replaced. byte[] currentBuffer = _buffer; - _buffer = null; + _buffer = null!; // Determine the capacity to request for the new buffer. It should be // at least twice as long as the current one, if not more if the requested @@ -919,7 +920,7 @@ public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationTo return default; } - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) => + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) => TaskToApm.Begin(WriteAsync(buffer, offset, count, CancellationToken.None), asyncCallback, asyncState); public override void EndWrite(IAsyncResult asyncResult) => diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpMethod.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpMethod.cs index 75460af78e3abf..fef238f73b272b 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpMethod.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpMethod.cs @@ -11,7 +11,7 @@ namespace System.Net.Http public class HttpMethod : IEquatable { private readonly string _method; - private readonly byte[] _http3EncodedBytes; + private readonly byte[]? _http3EncodedBytes; private int _hashcode; private static readonly HttpMethod s_getMethod = new HttpMethod("GET", http3StaticTableIndex: H3StaticTable.MethodGet); @@ -90,7 +90,7 @@ public string Method get { return _method; } } - internal byte[] Http3EncodedBytes + internal byte[]? Http3EncodedBytes { get { return _http3EncodedBytes; } } @@ -119,9 +119,9 @@ private HttpMethod(string method, int? http3StaticTableIndex) #region IEquatable Members - public bool Equals(HttpMethod other) + public bool Equals(HttpMethod? other) { - if ((object)other == null) + if ((object?)other == null) { return false; } @@ -138,7 +138,7 @@ public bool Equals(HttpMethod other) #endregion - public override bool Equals(object obj) + public override bool Equals(object? obj) { return Equals(obj as HttpMethod); } @@ -158,14 +158,14 @@ public override string ToString() return _method; } - public static bool operator ==(HttpMethod left, HttpMethod right) + public static bool operator ==(HttpMethod? left, HttpMethod? right) { - return (object)left == null || (object)right == null ? + return (object?)left == null || (object?)right == null ? ReferenceEquals(left, right) : left.Equals(right); } - public static bool operator !=(HttpMethod left, HttpMethod right) + public static bool operator !=(HttpMethod? left, HttpMethod? right) { return !(left == right); } @@ -177,7 +177,7 @@ public override string ToString() internal static HttpMethod Normalize(HttpMethod method) { Debug.Assert(method != null); - return s_knownMethods.TryGetValue(method, out HttpMethod normalized) ? + return s_knownMethods.TryGetValue(method, out HttpMethod? normalized) ? normalized : method; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestException.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestException.cs index da0bdf64033e21..cba9fe233f54ba 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestException.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestException.cs @@ -15,11 +15,11 @@ public HttpRequestException() : this(null, null) { } - public HttpRequestException(string message) + public HttpRequestException(string? message) : this(message, null) { } - public HttpRequestException(string message, Exception inner) + public HttpRequestException(string? message, Exception? inner) : base(message, inner) { if (inner != null) @@ -34,7 +34,7 @@ public HttpRequestException(string message, Exception inner) /// A message that describes the current exception. /// The inner exception. /// The HTTP status code. - public HttpRequestException(string message, Exception inner, HttpStatusCode? statusCode) + public HttpRequestException(string? message, Exception? inner, HttpStatusCode? statusCode) : this(message, inner) { StatusCode = statusCode; @@ -50,7 +50,7 @@ public HttpRequestException(string message, Exception inner, HttpStatusCode? sta // This constructor is used internally to indicate that a request was not successfully sent due to an IOException, // and the exception occurred early enough so that the request may be retried on another connection. - internal HttpRequestException(string message, Exception inner, RequestRetryType allowRetry) + internal HttpRequestException(string? message, Exception? inner, RequestRetryType allowRetry) : this(message, inner) { AllowRetry = allowRetry; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs index ed2293a36f29fc..a76798fbe0c598 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs @@ -19,13 +19,13 @@ public class HttpRequestMessage : IDisposable // The message shouldn't be sent again if this field is equal to MessageAlreadySent. private int _sendStatus = MessageNotYetSent; - private HttpMethod _method; - private Uri _requestUri; - private HttpRequestHeaders _headers; - private Version _version; - private HttpContent _content; + private HttpMethod _method = null!; + private Uri? _requestUri; + private HttpRequestHeaders? _headers; + private Version _version = null!; + private HttpContent? _content; private bool _disposed; - private IDictionary _properties; + private IDictionary? _properties; public Version Version { @@ -42,7 +42,7 @@ public Version Version } } - public HttpContent Content + public HttpContent? Content { get { return _content; } set @@ -81,7 +81,7 @@ public HttpMethod Method } } - public Uri RequestUri + public Uri? RequestUri { get { return _requestUri; } set @@ -112,31 +112,31 @@ public HttpRequestHeaders Headers internal bool HasHeaders => _headers != null; - public IDictionary Properties + public IDictionary Properties { get { if (_properties == null) { - _properties = new Dictionary(); + _properties = new Dictionary(); } return _properties; } } public HttpRequestMessage() - : this(HttpMethod.Get, (Uri)null) + : this(HttpMethod.Get, (Uri?)null) { } - public HttpRequestMessage(HttpMethod method, Uri requestUri) + public HttpRequestMessage(HttpMethod method, Uri? requestUri) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this, method, requestUri); InitializeValues(method, requestUri); if (NetEventSource.IsEnabled) NetEventSource.Exit(this); } - public HttpRequestMessage(HttpMethod method, string requestUri) + public HttpRequestMessage(HttpMethod method, string? requestUri) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this, method, requestUri); @@ -177,7 +177,7 @@ public override string ToString() return sb.ToString(); } - private void InitializeValues(HttpMethod method, Uri requestUri) + private void InitializeValues(HttpMethod method, Uri? requestUri) { if (method == null) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs index d52f14a2a98af5..dbe85b55dea63e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs @@ -12,12 +12,12 @@ public class HttpResponseMessage : IDisposable private const HttpStatusCode defaultStatusCode = HttpStatusCode.OK; private HttpStatusCode _statusCode; - private HttpResponseHeaders _headers; - private HttpResponseHeaders _trailingHeaders; - private string _reasonPhrase; - private HttpRequestMessage _requestMessage; + private HttpResponseHeaders? _headers; + private HttpResponseHeaders? _trailingHeaders; + private string? _reasonPhrase; + private HttpRequestMessage? _requestMessage; private Version _version; - private HttpContent _content; + private HttpContent? _content; private bool _disposed; public Version Version @@ -39,7 +39,7 @@ public Version Version internal void SetVersionWithoutValidation(Version value) => _version = value; - public HttpContent Content + public HttpContent? Content { get { return _content; } set @@ -79,7 +79,7 @@ public HttpStatusCode StatusCode internal void SetStatusCodeWithoutValidation(HttpStatusCode value) => _statusCode = value; - public string ReasonPhrase + public string? ReasonPhrase { get { @@ -129,7 +129,7 @@ public HttpResponseHeaders TrailingHeaders } } - public HttpRequestMessage RequestMessage + public HttpRequestMessage? RequestMessage { get { return _requestMessage; } set diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRuleParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRuleParser.cs index b45d2db06c653b..c8e223ab7955b0 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRuleParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRuleParser.cs @@ -246,7 +246,7 @@ internal static int GetNumberLength(string input, int startIndex, bool allowDeci return current - startIndex; } - internal static int GetHostLength(string input, int startIndex, bool allowToken, out string host) + internal static int GetHostLength(string input, int startIndex, bool allowToken, out string? host) { Debug.Assert(input != null); Debug.Assert(startIndex >= 0); @@ -425,8 +425,7 @@ private static HttpParseResult GetExpressionLength(string input, int startIndex, private static bool IsValidHostName(string host) { // Also add user info (u@) to make sure 'host' doesn't include user info. - Uri hostUri; - return Uri.TryCreate("http://u@" + host + "/", UriKind.Absolute, out hostUri); + return Uri.TryCreate("http://u@" + host + "/", UriKind.Absolute, out Uri? hostUri); } } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpUtilities.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpUtilities.cs index bf8a98b898041d..400ed5d17b3d44 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpUtilities.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpUtilities.cs @@ -41,7 +41,7 @@ internal static bool IsSecureWebSocketScheme(string scheme) => // Since we're not doing any CPU and/or I/O intensive operations, continue on the same thread. // This results in better performance since the continuation task doesn't get scheduled by the // scheduler and there are no context switches required. - internal static Task ContinueWithStandard(this Task task, object state, Action, object> continuation) + internal static Task ContinueWithStandard(this Task task, object state, Action, object?> continuation) { return task.ContinueWith(continuation, state, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/MessageProcessingHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/MessageProcessingHandler.cs index 55db3c6ce4b448..78f9cc06603d75 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/MessageProcessingHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/MessageProcessingHandler.cs @@ -51,13 +51,13 @@ protected internal sealed override Task SendAsync(HttpReque // processing method. ProcessResponse() is only called if the task wasn't canceled before. sendAsyncTask.ContinueWithStandard(tcs, (task, state) => { - var sendState = (SendState)state; + var sendState = (SendState)state!; MessageProcessingHandler self = sendState._handler; CancellationToken token = sendState._token; if (task.IsFaulted) { - sendState.TrySetException(task.Exception.GetBaseException()); + sendState.TrySetException(task.Exception!.GetBaseException()); return; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/MultipartContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/MultipartContent.cs index 0e259343e5ed0c..20aacaab72cf94 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/MultipartContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/MultipartContent.cs @@ -166,16 +166,16 @@ Collections.IEnumerator Collections.IEnumerable.GetEnumerator() // write "--" + boundary + "--" // Can't be canceled directly by the user. If the overall request is canceled // then the stream will be closed an exception thrown. - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => SerializeToStreamAsyncCore(stream, context, default); - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => // Only skip the original protected virtual SerializeToStreamAsync if this // isn't a derived type that may have overridden the behavior. GetType() == typeof(MultipartContent) ? SerializeToStreamAsyncCore(stream, context, cancellationToken) : base.SerializeToStreamAsync(stream, context, cancellationToken); - private protected async Task SerializeToStreamAsyncCore(Stream stream, TransportContext context, CancellationToken cancellationToken) + private protected async Task SerializeToStreamAsyncCore(Stream stream, TransportContext? context, CancellationToken cancellationToken) { Debug.Assert(stream != null); try @@ -375,7 +375,7 @@ private sealed class ContentReadStream : Stream private readonly long _length; private int _next; - private Stream _current; + private Stream? _current; private long _position; internal ContentReadStream(Stream[] streams) @@ -481,7 +481,7 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) => ReadAsyncPrivate(buffer, cancellationToken); - public override IAsyncResult BeginRead(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) => + public override IAsyncResult BeginRead(byte[] array, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) => TaskToApm.Begin(ReadAsync(array, offset, count, CancellationToken.None), asyncCallback, asyncState); public override int EndRead(IAsyncResult asyncResult) => diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/MultipartFormDataContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/MultipartFormDataContent.cs index dd88505e96c155..8b579c78217155 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/MultipartFormDataContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/MultipartFormDataContent.cs @@ -71,7 +71,7 @@ public void Add(HttpContent content, string name, string fileName) AddInternal(content, name, fileName); } - private void AddInternal(HttpContent content, string name, string fileName) + private void AddInternal(HttpContent content, string name, string? fileName) { if (content.Headers.ContentDisposition == null) { @@ -85,7 +85,7 @@ private void AddInternal(HttpContent content, string name, string fileName) base.Add(content); } - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => // Only skip the original protected virtual SerializeToStreamAsync if this // isn't a derived type that may have overridden the behavior. GetType() == typeof(MultipartFormDataContent) ? SerializeToStreamAsyncCore(stream, context, cancellationToken) : diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/NetEventSource.Http.cs b/src/libraries/System.Net.Http/src/System/Net/Http/NetEventSource.Http.cs index 28dc086406fb03..0d9745d85484ab 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/NetEventSource.Http.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/NetEventSource.Http.cs @@ -21,14 +21,14 @@ internal sealed partial class NetEventSource : EventSource private const int HandlerErrorId = AuthenticationErrorId + 1; [NonEvent] - public static void UriBaseAddress(object obj, Uri baseAddress) + public static void UriBaseAddress(object obj, Uri? baseAddress) { Debug.Assert(IsEnabled); Log.UriBaseAddress(baseAddress?.ToString(), IdOf(obj), GetHashCode(obj)); } [Event(UriBaseAddressId, Keywords = Keywords.Debug, Level = EventLevel.Informational)] - private unsafe void UriBaseAddress(string uriBaseAddress, string objName, int objHash) => + private unsafe void UriBaseAddress(string? uriBaseAddress, string objName, int objHash) => WriteEvent(UriBaseAddressId, uriBaseAddress, objName, objHash); [NonEvent] @@ -50,7 +50,7 @@ public static void ClientSendCompleted(HttpClient httpClient, HttpResponseMessag } [Event(ClientSendCompletedId, Keywords = Keywords.Debug, Level = EventLevel.Verbose)] - private void ClientSendCompleted(string responseString, int httpRequestMessageHash, int httpResponseMessageHash, int httpClientHash) => + private void ClientSendCompleted(string? responseString, int httpRequestMessageHash, int httpResponseMessageHash, int httpClientHash) => WriteEvent(ClientSendCompletedId, responseString, httpRequestMessageHash, httpResponseMessageHash, httpClientHash); [Event(HeadersInvalidValueId, Keywords = Keywords.Debug, Level = EventLevel.Error)] @@ -58,11 +58,11 @@ public void HeadersInvalidValue(string name, string rawValue) => WriteEvent(HeadersInvalidValueId, name, rawValue); [Event(HandlerMessageId, Keywords = Keywords.Debug, Level = EventLevel.Verbose)] - public void HandlerMessage(int poolId, int workerId, int requestId, string memberName, string message) => + public void HandlerMessage(int poolId, int workerId, int requestId, string? memberName, string? message) => WriteEvent(HandlerMessageId, poolId, workerId, requestId, memberName, message); [Event(HandlerErrorId, Keywords = Keywords.Debug, Level = EventLevel.Error)] - public void HandlerMessageError(int poolId, int workerId, int requestId, string memberName, string message) => + public void HandlerMessageError(int poolId, int workerId, int requestId, string? memberName, string message) => WriteEvent(HandlerErrorId, poolId, workerId, requestId, memberName, message); [NonEvent] @@ -73,22 +73,22 @@ public static void AuthenticationInfo(Uri uri, string message) } [Event(AuthenticationInfoId, Keywords = Keywords.Debug, Level = EventLevel.Verbose)] - public void AuthenticationInfo(string uri, string message) => + public void AuthenticationInfo(string? uri, string message) => WriteEvent(AuthenticationInfoId, uri, message); [NonEvent] - public static void AuthenticationError(Uri uri, string message) + public static void AuthenticationError(Uri? uri, string message) { Debug.Assert(IsEnabled); Log.AuthenticationError(uri?.ToString(), message); } [Event(AuthenticationErrorId, Keywords = Keywords.Debug, Level = EventLevel.Error)] - public void AuthenticationError(string uri, string message) => + public void AuthenticationError(string? uri, string message) => WriteEvent(AuthenticationErrorId, uri, message); [NonEvent] - private unsafe void WriteEvent(int eventId, int arg1, int arg2, int arg3, string arg4, string arg5) + private unsafe void WriteEvent(int eventId, int arg1, int arg2, int arg3, string? arg4, string? arg5) { if (IsEnabled()) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs index e73e0d007f0565..b2140a91a3553f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs @@ -20,14 +20,14 @@ public ReadOnlyMemoryContent(ReadOnlyMemory content) { // If we have an array, allow HttpClient to take optimized paths by just // giving it the array content to use as its already buffered data. - SetBuffer(array.Array, array.Offset, array.Count); + SetBuffer(array.Array!, array.Offset, array.Count); } } - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => stream.WriteAsync(_content).AsTask(); - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => stream.WriteAsync(_content, cancellationToken).AsTask(); protected internal override bool TryComputeLength(out long length) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs index 773537dad34538..7f6787741375e3 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs @@ -40,17 +40,17 @@ internal partial class AuthenticationHelper // 48='0', 65='A', 97='a' private static readonly int[] s_alphaNumChooser = new int[] { 48, 65, 97 }; - public static async Task GetDigestTokenForCredential(NetworkCredential credential, HttpRequestMessage request, DigestResponse digestResponse) + public static async Task GetDigestTokenForCredential(NetworkCredential credential, HttpRequestMessage request, DigestResponse digestResponse) { StringBuilder sb = StringBuilderCache.Acquire(); // It is mandatory for servers to implement sha-256 per RFC 7616 // Keep MD5 for backward compatibility. - string algorithm; + string? algorithm; bool isAlgorithmSpecified = digestResponse.Parameters.TryGetValue(Algorithm, out algorithm); if (isAlgorithmSpecified) { - if (!algorithm.Equals(Sha256, StringComparison.OrdinalIgnoreCase) && + if (!algorithm!.Equals(Sha256, StringComparison.OrdinalIgnoreCase) && !algorithm.Equals(Md5, StringComparison.OrdinalIgnoreCase) && !algorithm.Equals(Sha256Sess, StringComparison.OrdinalIgnoreCase) && !algorithm.Equals(MD5Sess, StringComparison.OrdinalIgnoreCase)) @@ -65,7 +65,7 @@ public static async Task GetDigestTokenForCredential(NetworkCredential c } // Check if nonce is there in challenge - string nonce; + string? nonce; if (!digestResponse.Parameters.TryGetValue(Nonce, out nonce)) { if (NetEventSource.IsEnabled) NetEventSource.Error(digestResponse, "Nonce missing"); @@ -73,10 +73,10 @@ public static async Task GetDigestTokenForCredential(NetworkCredential c } // opaque token may or may not exist - string opaque; + string? opaque; digestResponse.Parameters.TryGetValue(Opaque, out opaque); - string realm; + string? realm; if (!digestResponse.Parameters.TryGetValue(Realm, out realm)) { if (NetEventSource.IsEnabled) NetEventSource.Error(digestResponse, "Realm missing"); @@ -84,7 +84,7 @@ public static async Task GetDigestTokenForCredential(NetworkCredential c } // Add username - string userhash; + string? userhash; if (digestResponse.Parameters.TryGetValue(UserHash, out userhash) && userhash == "true") { sb.AppendKeyValue(Username, ComputeHash(credential.UserName + ":" + realm, algorithm)); @@ -110,6 +110,7 @@ public static async Task GetDigestTokenForCredential(NetworkCredential c // Add nonce sb.AppendKeyValue(Nonce, nonce); + Debug.Assert(request.RequestUri != null); // Add uri sb.AppendKeyValue(Uri, request.RequestUri.PathAndQuery); @@ -204,8 +205,7 @@ public static async Task GetDigestTokenForCredential(NetworkCredential c public static bool IsServerNonceStale(DigestResponse digestResponse) { - string stale = null; - return digestResponse.Parameters.TryGetValue(Stale, out stale) && stale == "true"; + return digestResponse.Parameters.TryGetValue(Stale, out string? stale) && stale == "true"; } private static string GetRandomAlphaNumericString() @@ -256,7 +256,7 @@ internal class DigestResponse internal readonly Dictionary Parameters = new Dictionary(StringComparer.OrdinalIgnoreCase); internal const string NonceCount = "00000001"; - internal DigestResponse(string challenge) + internal DigestResponse(string? challenge) { if (!string.IsNullOrEmpty(challenge)) Parse(challenge); @@ -274,7 +274,7 @@ private static bool MustValueBeQuoted(string key) key.Equals(Opaque, StringComparison.OrdinalIgnoreCase) || key.Equals(Qop, StringComparison.OrdinalIgnoreCase); } - private string GetNextKey(string data, int currentIndex, out int parsedIndex) + private string? GetNextKey(string data, int currentIndex, out int parsedIndex) { // Skip leading space or tab. while (currentIndex < data.Length && CharIsSpaceOrTab(data[currentIndex])) @@ -329,7 +329,7 @@ private string GetNextKey(string data, int currentIndex, out int parsedIndex) return data.Substring(start, length); } - private string GetNextValue(string data, int currentIndex, bool expectQuotes, out int parsedIndex) + private string? GetNextValue(string data, int currentIndex, bool expectQuotes, out int parsedIndex) { Debug.Assert(currentIndex < data.Length && !CharIsSpaceOrTab(data[currentIndex])); @@ -406,13 +406,13 @@ private unsafe void Parse(string challenge) while (parsedIndex < challenge.Length) { // Get the key. - string key = GetNextKey(challenge, parsedIndex, out parsedIndex); + string? key = GetNextKey(challenge, parsedIndex, out parsedIndex); // Ensure key is not empty and parsedIndex is still in range. if (string.IsNullOrEmpty(key) || parsedIndex >= challenge.Length) break; // Get the value. - string value = GetNextValue(challenge, parsedIndex, MustValueBeQuoted(key), out parsedIndex); + string? value = GetNextValue(challenge, parsedIndex, MustValueBeQuoted(key), out parsedIndex); // Ensure value is valid. if (string.IsNullOrEmpty(value) && (value == null || !key.Equals(Opaque, StringComparison.OrdinalIgnoreCase))) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs index b1d6e8b30884d1..68f2c4a5d7ddb4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs @@ -23,7 +23,7 @@ private static Task InnerSendAsync(HttpRequestMessage reque private static bool ProxySupportsConnectionAuth(HttpResponseMessage response) { - if (!response.Headers.TryGetValues(KnownHeaders.ProxySupport.Descriptor, out IEnumerable values)) + if (!response.Headers.TryGetValues(KnownHeaders.ProxySupport.Descriptor, out IEnumerable? values)) { return false; } @@ -64,14 +64,16 @@ private static async Task SendWithNtAuthAsync(HttpRequestMe if (response.Headers.ConnectionClose.GetValueOrDefault()) { // Server is closing the connection and asking us to authenticate on a new connection. +#pragma warning disable CS8600 // expression returns null connection on error, was not able to use '!' for the expression (connection, response) = await connectionPool.CreateHttp11ConnectionAsync(request, cancellationToken).ConfigureAwait(false); +#pragma warning restore CS8600 if (response != null) { return response; } connectionPool.IncrementConnectionCount(); - connection.Acquire(); + connection!.Acquire(); isNewConnection = true; needDrain = false; } @@ -119,14 +121,14 @@ private static async Task SendWithNtAuthAsync(HttpRequestMe NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, SPN: {spn}"); } - ChannelBinding channelBinding = connection.TransportContext?.GetChannelBinding(ChannelBindingKind.Endpoint); + ChannelBinding? channelBinding = connection.TransportContext?.GetChannelBinding(ChannelBindingKind.Endpoint); NTAuthentication authContext = new NTAuthentication(isServer: false, challenge.SchemeName, challenge.Credential, spn, ContextFlagsPal.Connection, channelBinding); - string challengeData = challenge.ChallengeData; + string? challengeData = challenge.ChallengeData; try { while (true) { - string challengeResponse = authContext.GetOutgoingBlob(challengeData); + string? challengeResponse = authContext.GetOutgoingBlob(challengeData); if (challengeResponse == null) { // Response indicated denial even after login, so stop processing and return current response. @@ -135,7 +137,7 @@ private static async Task SendWithNtAuthAsync(HttpRequestMe if (needDrain) { - await connection.DrainResponseAsync(response, cancellationToken).ConfigureAwait(false); + await connection.DrainResponseAsync(response!, cancellationToken).ConfigureAwait(false); } SetRequestAuthenticationHeaderValue(request, new AuthenticationHeaderValue(challenge.SchemeName, challengeResponse), isProxyAuth); @@ -158,13 +160,13 @@ private static async Task SendWithNtAuthAsync(HttpRequestMe { if (isNewConnection) { - connection.Release(); + connection!.Release(); } } } } - return response; + return response!; } public static Task SendWithNtProxyAuthAsync(HttpRequestMessage request, Uri proxyUri, ICredentials proxyCredentials, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken) @@ -174,6 +176,7 @@ public static Task SendWithNtProxyAuthAsync(HttpRequestMess public static Task SendWithNtConnectionAuthAsync(HttpRequestMessage request, ICredentials credentials, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken) { + Debug.Assert(request.RequestUri != null); return SendWithNtAuthAsync(request, request.RequestUri, credentials, isProxyAuth: false, connection, connectionPool, cancellationToken); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs index b6855e39ba2b43..4f99031134ba82 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Net.Http.Headers; using System.Text; using System.Threading; @@ -30,9 +31,9 @@ private readonly struct AuthenticationChallenge public AuthenticationType AuthenticationType { get; } public string SchemeName { get; } public NetworkCredential Credential { get; } - public string ChallengeData { get; } + public string? ChallengeData { get; } - public AuthenticationChallenge(AuthenticationType authenticationType, string schemeName, NetworkCredential credential, string challenge) + public AuthenticationChallenge(AuthenticationType authenticationType, string schemeName, NetworkCredential credential, string? challenge) { AuthenticationType = authenticationType; SchemeName = schemeName; @@ -41,7 +42,7 @@ public AuthenticationChallenge(AuthenticationType authenticationType, string sch } } - private static bool TryGetChallengeDataForScheme(string scheme, HttpHeaderValueCollection authenticationHeaderValues, out string challengeData) + private static bool TryGetChallengeDataForScheme(string scheme, HttpHeaderValueCollection authenticationHeaderValues, out string? challengeData) { foreach (AuthenticationHeaderValue ahv in authenticationHeaderValues) { @@ -82,12 +83,12 @@ private static bool TryGetValidAuthenticationChallengeForScheme(string scheme, A { challenge = default; - if (!TryGetChallengeDataForScheme(scheme, authenticationHeaderValues, out string challengeData)) + if (!TryGetChallengeDataForScheme(scheme, authenticationHeaderValues, out string? challengeData)) { return false; } - NetworkCredential credential = credentials.GetCredential(uri, scheme); + NetworkCredential? credential = credentials.GetCredential(uri, scheme); if (credential == null) { // We have no credential for this auth type, so we can't respond to the challenge. @@ -128,7 +129,7 @@ private static bool TryGetAuthenticationChallenge(HttpResponseMessage response, TryGetValidAuthenticationChallengeForScheme(BasicScheme, AuthenticationType.Basic, authUri, credentials, authenticationHeaderValues, out challenge); } - private static bool TryGetRepeatedChallenge(HttpResponseMessage response, string scheme, bool isProxyAuth, out string challengeData) + private static bool TryGetRepeatedChallenge(HttpResponseMessage response, string scheme, bool isProxyAuth, out string? challengeData) { challengeData = null; @@ -186,7 +187,7 @@ private static void SetBasicAuthToken(HttpRequestMessage request, NetworkCredent private static async ValueTask TrySetDigestAuthToken(HttpRequestMessage request, NetworkCredential credential, DigestResponse digestResponse, bool isProxyAuth) { - string parameter = await GetDigestTokenForCredential(credential, request, digestResponse).ConfigureAwait(false); + string? parameter = await GetDigestTokenForCredential(credential, request, digestResponse).ConfigureAwait(false); // Any errors in obtaining parameter return false and we don't proceed with auth if (string.IsNullOrEmpty(parameter)) @@ -219,7 +220,7 @@ private static async Task SendWithAuthAsync(HttpRequestMess if (preAuthenticate) { Debug.Assert(pool.PreAuthCredentials != null); - NetworkCredential credential; + NetworkCredential? credential; lock (pool.PreAuthCredentials) { // Just look for basic credentials. If in the future we support preauth @@ -251,7 +252,7 @@ private static async Task SendWithAuthAsync(HttpRequestMess response = await InnerSendAsync(request, isProxyAuth, doRequestAuth, pool, cancellationToken).ConfigureAwait(false); // Retry in case of nonce timeout in server. - if (TryGetRepeatedChallenge(response, challenge.SchemeName, isProxyAuth, out string challengeData)) + if (TryGetRepeatedChallenge(response, challenge.SchemeName, isProxyAuth, out string? challengeData)) { digestResponse = new DigestResponse(challengeData); if (IsServerNonceStale(digestResponse) && @@ -291,7 +292,7 @@ await TrySetDigestAuthToken(request, challenge.Credential, digestResponse, isPro break; default: - lock (pool.PreAuthCredentials) + lock (pool.PreAuthCredentials!) { try { @@ -332,6 +333,7 @@ public static Task SendWithProxyAuthAsync(HttpRequestMessag public static Task SendWithRequestAuthAsync(HttpRequestMessage request, ICredentials credentials, bool preAuthenticate, HttpConnectionPool pool, CancellationToken cancellationToken) { + Debug.Assert(request.RequestUri != null); return SendWithAuthAsync(request, request.RequestUri, credentials, preAuthenticate, isProxyAuth: false, doRequestAuth: true, pool, cancellationToken); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CancellationHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CancellationHelper.cs index ad5a79a4b9ac9c..d2c9572acab3af 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CancellationHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CancellationHelper.cs @@ -24,13 +24,13 @@ internal static bool ShouldWrapInOperationCanceledException(Exception exception, /// The inner exception to wrap. May be null. /// The that triggered the cancellation. /// The cancellation exception. - internal static Exception CreateOperationCanceledException(Exception innerException, CancellationToken cancellationToken) => + internal static Exception CreateOperationCanceledException(Exception? innerException, CancellationToken cancellationToken) => new TaskCanceledException(s_cancellationMessage, innerException, cancellationToken); // TCE for compatibility with other handlers that use TaskCompletionSource.TrySetCanceled() /// Throws a cancellation exception. /// The inner exception to wrap. May be null. /// The that triggered the cancellation. - private static void ThrowOperationCanceledException(Exception innerException, CancellationToken cancellationToken) => + private static void ThrowOperationCanceledException(Exception? innerException, CancellationToken cancellationToken) => throw CreateOperationCanceledException(innerException, cancellationToken); /// Throws a cancellation exception if cancellation has been requested via . diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs index 32cba801895c7d..72c5858a9a7af8 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs @@ -202,7 +202,7 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio private async Task CopyToAsyncCore(Stream destination, CancellationToken cancellationToken) { - CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); + CancellationTokenRegistration ctr = _connection!.RegisterCancellation(cancellationToken); try { while (true) @@ -257,7 +257,7 @@ private int ReadChunksFromConnectionBuffer(Span buffer, CancellationTokenR private ReadOnlyMemory ReadChunkFromConnectionBuffer(int maxBytesToRead, CancellationTokenRegistration cancellationRegistration) { - Debug.Assert(maxBytesToRead > 0); + Debug.Assert(maxBytesToRead > 0 && _connection != null); try { @@ -393,7 +393,7 @@ private ReadOnlyMemory ReadChunkFromConnectionBuffer(int maxBytesToRead, C catch (Exception) { // Ensure we don't try to read from the connection again (in particular, for draining) - _connection.Dispose(); + _connection!.Dispose(); _connection = null; throw; } @@ -432,7 +432,7 @@ public override async ValueTask DrainAsync(int maxDrainBytes) { Debug.Assert(_connection != null); - CancellationTokenSource cts = null; + CancellationTokenSource? cts = null; CancellationTokenRegistration ctr = default; try { @@ -467,7 +467,7 @@ public override async ValueTask DrainAsync(int maxDrainBytes) if (drainTime != Timeout.InfiniteTimeSpan) { cts = new CancellationTokenSource((int)drainTime.TotalMilliseconds); - ctr = cts.Token.Register(s => ((HttpConnection)s).Dispose(), _connection); + ctr = cts.Token.Register(s => ((HttpConnection)s!).Dispose(), _connection); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs index a364b2e4c28ecb..7f88b005bfdfd6 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs @@ -23,14 +23,14 @@ internal static class ConnectHelper /// internal sealed class CertificateCallbackMapper { - public readonly Func FromHttpClientHandler; + public readonly Func FromHttpClientHandler; public readonly RemoteCertificateValidationCallback ForSocketsHttpHandler; - public CertificateCallbackMapper(Func fromHttpClientHandler) + public CertificateCallbackMapper(Func fromHttpClientHandler) { FromHttpClientHandler = fromHttpClientHandler; - ForSocketsHttpHandler = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => - FromHttpClientHandler(sender as HttpRequestMessage, certificate as X509Certificate2, chain, sslPolicyErrors); + ForSocketsHttpHandler = (object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) => + FromHttpClientHandler((HttpRequestMessage)sender, certificate as X509Certificate2, chain, sslPolicyErrors); } } @@ -51,7 +51,7 @@ public static async ValueTask ConnectAsync(string host, int port, Cancel if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea)) { // Connect completing asynchronously. Enable it to be canceled and wait for it. - using (cancellationToken.UnsafeRegister(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea)) + using (cancellationToken.UnsafeRegister(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s!), saea)) { await saea.Builder.Task.ConfigureAwait(false); } @@ -129,13 +129,13 @@ public static ValueTask EstablishSslConnectionAsync(SslClientAuthenti { // If there's a cert validation callback, and if it came from HttpClientHandler, // wrap the original delegate in order to change the sender to be the request message (expected by HttpClientHandler's delegate). - RemoteCertificateValidationCallback callback = sslOptions.RemoteCertificateValidationCallback; + RemoteCertificateValidationCallback? callback = sslOptions.RemoteCertificateValidationCallback; if (callback != null && callback.Target is CertificateCallbackMapper mapper) { sslOptions = sslOptions.ShallowClone(); // Clone as we're about to mutate it and don't want to affect the cached copy - Func localFromHttpClientHandler = mapper.FromHttpClientHandler; + Func localFromHttpClientHandler = mapper.FromHttpClientHandler; HttpRequestMessage localRequest = request; - sslOptions.RemoteCertificateValidationCallback = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => + sslOptions.RemoteCertificateValidationCallback = (object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) => localFromHttpClientHandler(localRequest, certificate as X509Certificate2, chain, sslPolicyErrors); } @@ -178,10 +178,10 @@ private static async ValueTask EstablishSslConnectionAsyncCore(Stream return sslStream; } - public static async ValueTask ConnectQuicAsync(string host, int port, SslClientAuthenticationOptions clientAuthenticationOptions, CancellationToken cancellationToken) + public static async ValueTask ConnectQuicAsync(string host, int port, SslClientAuthenticationOptions? clientAuthenticationOptions, CancellationToken cancellationToken) { IPAddress[] addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false); - Exception lastException = null; + Exception? lastException = null; foreach (IPAddress address in addresses) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionCloseReadStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionCloseReadStream.cs index 262ab203e6188b..99f9c235b5add0 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionCloseReadStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionCloseReadStream.cs @@ -18,7 +18,7 @@ public ConnectionCloseReadStream(HttpConnection connection) : base(connection) public override int Read(Span buffer) { - HttpConnection connection = _connection; + HttpConnection? connection = _connection; if (connection == null || buffer.Length == 0) { // Response body fully consumed or the caller didn't ask for any data @@ -40,7 +40,7 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation { CancellationHelper.ThrowIfCancellationRequested(cancellationToken); - HttpConnection connection = _connection; + HttpConnection? connection = _connection; if (connection == null || buffer.Length == 0) { // Response body fully consumed or the caller didn't ask for any data @@ -97,7 +97,7 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio return Task.FromCanceled(cancellationToken); } - HttpConnection connection = _connection; + HttpConnection? connection = _connection; if (connection == null) { // null if response body fully consumed diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthReadStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthReadStream.cs index 7aba584ba448d0..cae7197bf0b057 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthReadStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthReadStream.cs @@ -144,6 +144,7 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio private async Task CompleteCopyToAsync(Task copyTask, CancellationToken cancellationToken) { + Debug.Assert(_connection != null); CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { @@ -164,7 +165,7 @@ private async Task CompleteCopyToAsync(Task copyTask, CancellationToken cancella private void Finish() { _contentBytesRemaining = 0; - _connection.CompleteResponse(); + _connection!.CompleteResponse(); _connection = null; } @@ -173,6 +174,7 @@ private ReadOnlyMemory ReadFromConnectionBuffer(int maxBytesToRead) { Debug.Assert(maxBytesToRead > 0); Debug.Assert(_contentBytesRemaining > 0); + Debug.Assert(_connection != null); ReadOnlyMemory connectionBuffer = _connection.RemainingBuffer; if (connectionBuffer.Length == 0) @@ -208,13 +210,13 @@ public override async ValueTask DrainAsync(int maxDrainBytes) return false; } - CancellationTokenSource cts = null; + CancellationTokenSource? cts = null; CancellationTokenRegistration ctr = default; TimeSpan drainTime = _connection._pool.Settings._maxResponseDrainTime; if (drainTime != Timeout.InfiniteTimeSpan) { cts = new CancellationTokenSource((int)drainTime.TotalMilliseconds); - ctr = cts.Token.Register(s => ((HttpConnection)s).Dispose(), _connection); + ctr = cts.Token.Register(s => ((HttpConnection)s!).Dispose(), _connection); } try { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CookieHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CookieHelper.cs index 024359e2471862..64cff3053acaf2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CookieHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CookieHelper.cs @@ -12,12 +12,12 @@ internal static class CookieHelper { public static void ProcessReceivedCookies(HttpResponseMessage response, CookieContainer cookieContainer) { - IEnumerable values; - if (response.Headers.TryGetValues(KnownHeaders.SetCookie.Descriptor, out values)) + if (response.Headers.TryGetValues(KnownHeaders.SetCookie.Descriptor, out IEnumerable? values)) { // The header values are always a string[] var valuesArray = (string[])values; Debug.Assert(valuesArray.Length > 0, "No values for header??"); + Debug.Assert(response.RequestMessage != null && response.RequestMessage.RequestUri != null); Uri requestUri = response.RequestMessage.RequestUri; for (int i = 0; i < valuesArray.Length; i++) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CreditManager.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CreditManager.cs index 2812241ac9c54a..f49d61bc4c0b3b 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CreditManager.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CreditManager.cs @@ -16,7 +16,7 @@ internal sealed class CreditManager private bool _disposed; /// Circular singly-linked list of active waiters. /// If null, the list is empty. If non-null, this is the tail. If the list has one item, its Next is itself. - private CreditWaiter _waitersTail; + private CreditWaiter? _waitersTail; public CreditManager(IHttpTrace owner, string name, int initialCredit) { @@ -102,7 +102,8 @@ public void AdjustCredit(int amount) while (_current > 0 && _waitersTail != null) { // Get the waiter from the head of the queue. - CreditWaiter waiter = _waitersTail.Next; + CreditWaiter? waiter = _waitersTail.Next; + Debug.Assert(waiter != null); int granted = Math.Min(waiter.Amount, _current); // Remove the waiter from the list. @@ -139,12 +140,12 @@ public void Dispose() _disposed = true; - CreditWaiter waiter = _waitersTail; + CreditWaiter? waiter = _waitersTail; if (waiter != null) { do { - CreditWaiter next = waiter.Next; + CreditWaiter? next = waiter!.Next; waiter.Next = null; waiter.Dispose(); waiter = next; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CreditWaiter.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CreditWaiter.cs index 9520eaf6897e5d..9e042935730198 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CreditWaiter.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CreditWaiter.cs @@ -14,7 +14,7 @@ namespace System.Net.Http internal class CreditWaiter : IValueTaskSource { public int Amount; - public CreditWaiter Next; + public CreditWaiter? Next; protected ManualResetValueTaskSourceCore _source; public CreditWaiter() => _source.RunContinuationsAsynchronously = true; @@ -49,7 +49,7 @@ int IValueTaskSource.GetResult(short token) => _source.GetResult(token); ValueTaskSourceStatus IValueTaskSource.GetStatus(short token) => _source.GetStatus(token); - void IValueTaskSource.OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => + void IValueTaskSource.OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => _source.OnCompleted(continuation, state, token, flags); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs index 1a4e8a669c0128..5eb74ef169ff44 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs @@ -56,10 +56,11 @@ protected internal override async Task SendAsync(HttpReques HttpResponseMessage response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false); + Debug.Assert(response.Content != null); ICollection contentEncodings = response.Content.Headers.ContentEncoding; if (contentEncodings.Count > 0) { - string last = null; + string? last = null; foreach (string encoding in contentEncodings) { last = encoding; @@ -108,7 +109,7 @@ public DecompressedContent(HttpContent originalContent) Headers.AddHeaders(originalContent.Headers); Headers.ContentLength = null; Headers.ContentEncoding.Clear(); - string prevEncoding = null; + string? prevEncoding = null; foreach (string encoding in originalContent.Headers.ContentEncoding) { if (prevEncoding != null) @@ -121,10 +122,10 @@ public DecompressedContent(HttpContent originalContent) protected abstract Stream GetDecompressedStream(Stream originalStream); - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => SerializeToStreamAsync(stream, context, CancellationToken.None); - protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) + protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) { using (Stream decompressedStream = TryCreateContentReadStream() ?? await CreateContentReadStreamAsync(cancellationToken).ConfigureAwait(false)) { @@ -145,9 +146,9 @@ protected override async Task CreateContentReadStreamAsync(CancellationT return GetDecompressedStream(originalStream); } - internal override Stream TryCreateContentReadStream() + internal override Stream? TryCreateContentReadStream() { - Stream originalStream = _originalContent.TryReadAsStream(); + Stream? originalStream = _originalContent.TryReadAsStream(); return originalStream is null ? null : GetDecompressedStream(originalStream); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs index 1e9f2091abffd5..b2fbfd39691026 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs @@ -61,13 +61,13 @@ internal sealed partial class Http2Connection : HttpConnectionBase, IDisposable private int _lastStreamId = -1; // This will be set when a connection IO error occurs - private Exception _abortException; + private Exception? _abortException; // If an in-progress write is canceled we need to be able to immediately // report a cancellation to the user, but also block the connection until // the write completes. We avoid actually canceling the write, as we would // then have to close the whole connection. - private Task _inProgressWrite = null; + private Task? _inProgressWrite = null; private const int MaxStreamId = int.MaxValue; @@ -338,7 +338,7 @@ private async Task ProcessIncomingFramesAsync() // Callers must check for this and send a RST_STREAM or ignore as appropriate. // If the streamId is invalid or the stream is idle, calling this function // will result in a connection level error. - private Http2Stream GetStream(int streamId) + private Http2Stream? GetStream(int streamId) { if (streamId <= 0 || streamId >= _nextStream) { @@ -347,7 +347,7 @@ private Http2Stream GetStream(int streamId) lock (SyncObject) { - if (!_httpStreams.TryGetValue(streamId, out Http2Stream http2Stream)) + if (!_httpStreams.TryGetValue(streamId, out Http2Stream? http2Stream)) { return null; } @@ -364,7 +364,7 @@ private async ValueTask ProcessHeadersFrame(FrameHeader frameHeader) bool endStream = frameHeader.EndStreamFlag; int streamId = frameHeader.StreamId; - Http2Stream http2Stream = GetStream(streamId); + Http2Stream? http2Stream = GetStream(streamId); // Note, http2Stream will be null if this is a closed stream. // We will still process the headers, to ensure the header decoding state is up-to-date, @@ -475,7 +475,7 @@ private void ProcessDataFrame(FrameHeader frameHeader) { Debug.Assert(frameHeader.Type == FrameType.Data); - Http2Stream http2Stream = GetStream(frameHeader.StreamId); + Http2Stream? http2Stream = GetStream(frameHeader.StreamId); // Note, http2Stream will be null if this is a closed stream. // Just ignore the frame in this case. @@ -683,7 +683,7 @@ private void ProcessWindowUpdateFrame(FrameHeader frameHeader) } else { - Http2Stream http2Stream = GetStream(frameHeader.StreamId); + Http2Stream? http2Stream = GetStream(frameHeader.StreamId); if (http2Stream == null) { // Ignore invalid stream ID, as per RFC @@ -708,7 +708,7 @@ private void ProcessRstStreamFrame(FrameHeader frameHeader) throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); } - Http2Stream http2Stream = GetStream(frameHeader.StreamId); + Http2Stream? http2Stream = GetStream(frameHeader.StreamId); if (http2Stream == null) { // Ignore invalid stream ID, as per RFC @@ -979,7 +979,7 @@ private void WriteLiteralHeader(string name, ReadOnlySpan values) _headerBuffer.Commit(bytesWritten); } - private void WriteLiteralHeaderValues(ReadOnlySpan values, string separator) + private void WriteLiteralHeaderValues(ReadOnlySpan values, string? separator) { if (NetEventSource.IsEnabled) Trace($"{nameof(values)}={string.Join(separator, values.ToArray())}"); @@ -1033,7 +1033,7 @@ private void WriteHeaderCollection(HttpHeaders headers) Debug.Assert(headerValuesCount > 0, "No values for header??"); ReadOnlySpan headerValues = _headerValues.AsSpan(0, headerValuesCount); - KnownHeader knownHeader = header.Key.KnownHeader; + KnownHeader? knownHeader = header.Key.KnownHeader; if (knownHeader != null) { // The Host header is not sent for HTTP2 because we send the ":authority" pseudo-header instead @@ -1058,10 +1058,10 @@ private void WriteHeaderCollection(HttpHeaders headers) // For all other known headers, send them via their pre-encoded name and the associated value. WriteBytes(knownHeader.Http2EncodedName); - string separator = null; + string? separator = null; if (headerValues.Length > 1) { - HttpHeaderParser parser = header.Key.Parser; + HttpHeaderParser? parser = header.Key.Parser; if (parser != null && parser.SupportsMultipleValues) { separator = parser.Separator; @@ -1121,6 +1121,7 @@ private void WriteHeaders(HttpRequestMessage request) WriteBytes(_pool._http2EncodedAuthorityHostHeader); } + Debug.Assert(request.RequestUri != null); string pathAndQuery = request.RequestUri.PathAndQuery; if (pathAndQuery == "/") { @@ -1139,7 +1140,7 @@ private void WriteHeaders(HttpRequestMessage request) // Determine cookies to send. if (_pool.Settings._useCookies) { - string cookiesFromContainer = _pool.Settings._cookieContainer.GetCookieHeader(request.RequestUri); + string cookiesFromContainer = _pool.Settings._cookieContainer!.GetCookieHeader(request.RequestUri); if (cookiesFromContainer != string.Empty) { WriteBytes(KnownHeaders.Cookie.Http2EncodedName); @@ -1832,7 +1833,7 @@ private void RemoveStream(Http2Stream http2Stream) lock (SyncObject) { - if (!_httpStreams.Remove(http2Stream.StreamId, out Http2Stream removed)) + if (!_httpStreams.Remove(http2Stream.StreamId, out Http2Stream? removed)) { Debug.Fail($"Stream {http2Stream.StreamId} not found in dictionary during RemoveStream???"); return; @@ -1857,10 +1858,10 @@ private void RemoveStream(Http2Stream http2Stream) public sealed override string ToString() => $"{nameof(Http2Connection)}({_pool})"; // Description for diagnostic purposes - public override void Trace(string message, [CallerMemberName] string memberName = null) => + public override void Trace(string message, [CallerMemberName] string? memberName = null) => Trace(0, message, memberName); - internal void Trace(int streamId, string message, [CallerMemberName] string memberName = null) => + internal void Trace(int streamId, string message, [CallerMemberName] string? memberName = null) => NetEventSource.Log.HandlerMessage( _pool?.GetHashCode() ?? 0, // pool ID GetHashCode(), // connection ID diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs index ac9279d22140f7..4ca37b2b702c30 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs @@ -32,13 +32,13 @@ private sealed class Http2Stream : IValueTaskSource, IHttpTrace, IHttpHeadersHan private readonly Http2Connection _connection; private readonly int _streamId; private readonly HttpRequestMessage _request; - private HttpResponseMessage _response; + private HttpResponseMessage? _response; /// Stores any trailers received after returning the response content to the caller. - private List> _trailers; + private List>? _trailers; private ArrayBuffer _responseBuffer; // mutable struct, do not make this readonly private int _pendingWindowUpdate; - private CancelableCreditWaiter _creditWaiter; + private CancelableCreditWaiter? _creditWaiter; private int _availableCredit; private StreamCompletionState _requestCompletionState; @@ -47,7 +47,7 @@ private sealed class Http2Stream : IValueTaskSource, IHttpTrace, IHttpHeadersHan // If this is not null, then we have received a reset from the server // (i.e. RST_STREAM or general IO error processing the connection) - private Exception _resetException; + private Exception? _resetException; private bool _canRetry; // if _resetException != null, this indicates the stream was refused and so the request is retryable // This flag indicates that, per section 8.1 of the RFC, the server completed the response and then sent a RST_STREAM with error = NO_ERROR. @@ -77,12 +77,12 @@ private sealed class Http2Stream : IValueTaskSource, IHttpTrace, IHttpHeadersHan /// private bool _hasWaiter; - private readonly CancellationTokenSource _requestBodyCancellationSource; + private readonly CancellationTokenSource? _requestBodyCancellationSource; // This is a linked token combining the above source and the user-supplied token to SendRequestBodyAsync private CancellationToken _requestBodyCancellationToken; - private readonly TaskCompletionSource _expect100ContinueWaiter; + private readonly TaskCompletionSource? _expect100ContinueWaiter; private int _headerBudgetRemaining; @@ -145,6 +145,7 @@ public HttpResponseMessage GetAndClearResponse() // Since the Http2Stream is rooted by the Http2Connection dictionary, doing so would prevent // the response stream from being collected and finalized if it were to be dropped without // being disposed first. + Debug.Assert(_response != null); HttpResponseMessage r = _response; _response = null; return r; @@ -284,10 +285,10 @@ public async ValueTask WaitFor100ContinueAsync(CancellationToken cancellat // as we could end up starting the body copy operation on the main event loop thread, which could // then starve the processing of other requests. So, we make the TCS RunContinuationsAsynchronously. bool sendRequestContent; - TaskCompletionSource waiter = _expect100ContinueWaiter; + TaskCompletionSource waiter = _expect100ContinueWaiter!; using (var expect100Timer = new Timer(s => { - var thisRef = (Http2Stream)s; + var thisRef = (Http2Stream)s!; if (NetEventSource.IsEnabled) thisRef.Trace($"100-Continue timer expired."); thisRef._expect100ContinueWaiter?.TrySetResult(true); }, this, _connection._pool.Settings._expect100ContinueTimeout, Timeout.InfiniteTimeSpan)) @@ -328,7 +329,7 @@ private void Complete() lock (SyncObject) { - CreditWaiter w = _creditWaiter; + CreditWaiter? w = _creditWaiter; if (w != null) { w.Dispose(); @@ -341,7 +342,7 @@ private void Cancel() { if (NetEventSource.IsEnabled) Trace(""); - CancellationTokenSource requestBodyCancellationSource = null; + CancellationTokenSource? requestBodyCancellationSource = null; bool signalWaiter = false; bool sendReset = false; @@ -542,7 +543,7 @@ public void OnHeader(ReadOnlySpan name, ReadOnlySpan value) } else if ((descriptor.HeaderType & HttpHeaderType.Content) == HttpHeaderType.Content) { - Debug.Assert(_response != null); + Debug.Assert(_response != null && _response.Content != null); _response.Content.Headers.TryAddWithoutValidation(descriptor, headerValue); } else @@ -713,7 +714,7 @@ public void OnReset(Exception resetException, Http2ProtocolErrorCode? resetStrea if (NetEventSource.IsEnabled) Trace($"{nameof(resetException)}={resetException}, {nameof(resetStreamErrorCode)}={resetStreamErrorCode}"); bool cancel = false; - CancellationTokenSource requestBodyCancellationSource = null; + CancellationTokenSource? requestBodyCancellationSource = null; Debug.Assert(!Monitor.IsEntered(SyncObject)); lock (SyncObject) @@ -848,6 +849,7 @@ public async Task ReadResponseHeadersAsync(CancellationToken cancellationToken) throw; } + Debug.Assert(_response != null && _response.Content != null); // Start to process the response body. var responseContent = (HttpConnectionResponseContent)_response.Content; if (emptyResponse) @@ -865,7 +867,7 @@ public async Task ReadResponseHeadersAsync(CancellationToken cancellationToken) // Process Set-Cookie headers. if (_connection._pool.Settings._useCookies) { - CookieHelper.ProcessReceivedCookies(_response, _connection._pool.Settings._cookieContainer); + CookieHelper.ProcessReceivedCookies(_response, _connection._pool.Settings._cookieContainer!); } } @@ -1073,7 +1075,7 @@ private async ValueTask SendDataAsync(ReadOnlyMemory buffer, CancellationT // Deal with [ActiveIssue("https://github.com/dotnet/runtime/issues/17492")] // Custom HttpContent classes do not get passed the cancellationToken. // So, inject the expected CancellationToken here, to ensure we can cancel the request body send if needed. - CancellationTokenSource customCancellationSource = null; + CancellationTokenSource? customCancellationSource = null; if (!cancellationToken.CanBeCanceled) { cancellationToken = _requestBodyCancellationToken; @@ -1082,7 +1084,7 @@ private async ValueTask SendDataAsync(ReadOnlyMemory buffer, CancellationT { // User passed a custom CancellationToken. // We can't tell if it includes our Token or not, so assume it doesn't. - customCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _requestBodyCancellationSource.Token); + customCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _requestBodyCancellationSource!.Token); cancellationToken = customCancellationSource.Token; } @@ -1115,6 +1117,7 @@ private async ValueTask SendDataAsync(ReadOnlyMemory buffer, CancellationT if (sendSize == -1) { + Debug.Assert(_creditWaiter != null); sendSize = await _creditWaiter.AsValueTask().ConfigureAwait(false); _creditWaiter.CleanUp(); } @@ -1157,7 +1160,7 @@ private void CloseResponseBody() // for this object's state transitions at a time, we allow the object to be awaited directly. All functionality // associated with the implementation is just delegated to the ManualResetValueTaskSourceCore. ValueTaskSourceStatus IValueTaskSource.GetStatus(short token) => _waitSource.GetStatus(token); - void IValueTaskSource.OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _waitSource.OnCompleted(continuation, state, token, flags); + void IValueTaskSource.OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => _waitSource.OnCompleted(continuation, state, token, flags); void IValueTaskSource.GetResult(short token) => _waitSource.GetResult(token); private void WaitForData() @@ -1194,7 +1197,7 @@ async ValueTask GetCancelableWaiterTask(CancellationToken cancellationToken) { using (cancellationToken.UnsafeRegister(s => { - var thisRef = (Http2Stream)s; + var thisRef = (Http2Stream)s!; bool signalWaiter; Debug.Assert(!Monitor.IsEntered(thisRef.SyncObject)); @@ -1218,7 +1221,7 @@ async ValueTask GetCancelableWaiterTask(CancellationToken cancellationToken) } } - public void Trace(string message, [CallerMemberName] string memberName = null) => + public void Trace(string message, [CallerMemberName] string? memberName = null) => _connection.Trace(_streamId, message, memberName); private enum ResponseProtocolState : byte @@ -1241,7 +1244,7 @@ private enum StreamCompletionState : byte private sealed class Http2ReadStream : HttpBaseStream { - private Http2Stream _http2Stream; + private Http2Stream? _http2Stream; private readonly HttpResponseMessage _responseMessage; public Http2ReadStream(Http2Stream http2Stream) @@ -1267,7 +1270,7 @@ public Http2ReadStream(Http2Stream http2Stream) protected override void Dispose(bool disposing) { - Http2Stream http2Stream = Interlocked.Exchange(ref _http2Stream, null); + Http2Stream? http2Stream = Interlocked.Exchange(ref _http2Stream, null); if (http2Stream == null) { return; @@ -1296,7 +1299,7 @@ public override int Read(Span destination) public override ValueTask ReadAsync(Memory destination, CancellationToken cancellationToken) { - Http2Stream http2Stream = _http2Stream; + Http2Stream? http2Stream = _http2Stream; if (http2Stream == null) { @@ -1321,7 +1324,7 @@ public override void CopyTo(Stream destination, int bufferSize) public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) { StreamHelpers.ValidateCopyToArgs(this, destination, bufferSize); - Http2Stream http2Stream = _http2Stream; + Http2Stream? http2Stream = _http2Stream; return http2Stream is null ? Task.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new ObjectDisposedException(nameof(Http2ReadStream)))) : cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : @@ -1335,7 +1338,7 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio private sealed class Http2WriteStream : HttpBaseStream { - private Http2Stream _http2Stream; + private Http2Stream? _http2Stream; public Http2WriteStream(Http2Stream http2Stream) { @@ -1345,7 +1348,7 @@ public Http2WriteStream(Http2Stream http2Stream) protected override void Dispose(bool disposing) { - Http2Stream http2Stream = Interlocked.Exchange(ref _http2Stream, null); + Http2Stream? http2Stream = Interlocked.Exchange(ref _http2Stream, null); if (http2Stream == null) { return; @@ -1363,7 +1366,7 @@ protected override void Dispose(bool disposing) public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken) { - Http2Stream http2Stream = _http2Stream; + Http2Stream? http2Stream = _http2Stream; if (http2Stream == null) { @@ -1380,7 +1383,7 @@ public override Task FlushAsync(CancellationToken cancellationToken) return Task.FromCanceled(cancellationToken); } - Http2Stream http2Stream = _http2Stream; + Http2Stream? http2Stream = _http2Stream; if (http2Stream == null) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index 9ed1fc9ff46ae0..50cd701c4cf0bc 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -27,11 +27,11 @@ internal sealed class Http3Connection : HttpConnectionBase, IDisposable private const int MaximumUnknownFramePayloadLength = 4096; private readonly HttpConnectionPool _pool; - private readonly HttpAuthority _origin; + private readonly HttpAuthority? _origin; private readonly HttpAuthority _authority; private readonly byte[] _altUsedEncodedHeader; - private QuicConnection _connection; - private Task _connectionClosedTask; + private QuicConnection? _connection; + private Task? _connectionClosedTask; // Keep a collection of requests around so we can process GOAWAY. private readonly Dictionary _activeRequests = new Dictionary(); @@ -40,7 +40,7 @@ internal sealed class Http3Connection : HttpConnectionBase, IDisposable private long _lastProcessedStreamId = -1; // Our control stream. - private QuicStream _clientControl; + private QuicStream? _clientControl; // Current SETTINGS from the server. private int _maximumHeadersLength = int.MaxValue; // TODO: this is not yet observed by Http3Stream when buffering headers. @@ -56,13 +56,13 @@ internal sealed class Http3Connection : HttpConnectionBase, IDisposable private readonly Queue> _waitingRequests = new Queue>(); // A connection-level error will abort any future operations. - private Exception _abortException; + private Exception? _abortException; public HttpAuthority Authority => _authority; public HttpConnectionPool Pool => _pool; public int MaximumRequestHeadersLength => _maximumHeadersLength; public byte[] AltUsedEncodedHeaderBytes => _altUsedEncodedHeader; - public Exception AbortException => Volatile.Read(ref _abortException); + public Exception? AbortException => Volatile.Read(ref _abortException); private object SyncObj => _activeRequests; /// @@ -77,7 +77,7 @@ private bool ShuttingDown } } - public Http3Connection(HttpConnectionPool pool, HttpAuthority origin, HttpAuthority authority, QuicConnection connection) + public Http3Connection(HttpConnectionPool pool, HttpAuthority? origin, HttpAuthority authority, QuicConnection connection) { _pool = pool; _origin = origin; @@ -148,7 +148,7 @@ private void CheckForShutdown() { if (closeTask.IsFaulted && NetEventSource.IsEnabled) { - Trace($"{nameof(QuicConnection)} failed to close: {closeTask.Exception.InnerException}"); + Trace($"{nameof(QuicConnection)} failed to close: {closeTask.Exception!.InnerException}"); } try @@ -167,7 +167,7 @@ public override async Task SendAsync(HttpRequestMessage req { // Wait for an available stream (based on QUIC MAX_STREAMS) if there isn't one available yet. - TaskCompletionSourceWithCancellation waitForAvailableStreamTcs = null; + TaskCompletionSourceWithCancellation? waitForAvailableStreamTcs = null; lock (SyncObj) { @@ -191,8 +191,8 @@ public override async Task SendAsync(HttpRequestMessage req // Allocate an active request - QuicStream quicStream = null; - Http3RequestStream requestStream = null; + QuicStream? quicStream = null; + Http3RequestStream? requestStream = null; try { @@ -213,7 +213,7 @@ public override async Task SendAsync(HttpRequestMessage req // 0-byte write to force QUIC to allocate a stream ID. await quicStream.WriteAsync(Array.Empty(), cancellationToken).ConfigureAwait(false); - requestStream.StreamId = quicStream.StreamId; + requestStream!.StreamId = quicStream.StreamId; bool goAway; lock (SyncObj) @@ -278,7 +278,7 @@ private void CancelWaiters() { Debug.Assert(Monitor.IsEntered(SyncObj)); - while (_waitingRequests.TryDequeue(out TaskCompletionSourceWithCancellation tcs)) + while (_waitingRequests.TryDequeue(out TaskCompletionSourceWithCancellation? tcs)) { tcs.TrySetException(new HttpRequestException(SR.net_http_request_aborted, null, RequestRetryType.RetryOnSameOrNextProxy)); } @@ -297,7 +297,7 @@ private void OnMaximumStreamCountIncrease(long newMaximumStreamCount) _requestStreamsRemaining += (newMaximumStreamCount - _maximumRequestStreams); _maximumRequestStreams = newMaximumStreamCount; - while (_requestStreamsRemaining != 0 && _waitingRequests.TryDequeue(out TaskCompletionSourceWithCancellation tcs)) + while (_requestStreamsRemaining != 0 && _waitingRequests.TryDequeue(out TaskCompletionSourceWithCancellation? tcs)) { if (tcs.TrySetResult(true)) { @@ -316,7 +316,7 @@ private void OnMaximumStreamCountIncrease(long newMaximumStreamCount) internal Exception Abort(Exception abortException) { // Only observe the first exception we get. - Exception firstException = Interlocked.CompareExchange(ref _abortException, abortException, null); + Exception? firstException = Interlocked.CompareExchange(ref _abortException, abortException, null); if (firstException != null) { @@ -412,10 +412,10 @@ public void RemoveStream(QuicStream stream) } } - public override void Trace(string message, [CallerMemberName] string memberName = null) => + public override void Trace(string message, [CallerMemberName] string? memberName = null) => Trace(0, message, memberName); - internal void Trace(long streamId, string message, [CallerMemberName] string memberName = null) => + internal void Trace(long streamId, string message, [CallerMemberName] string? memberName = null) => NetEventSource.Log.HandlerMessage( _pool?.GetHashCode() ?? 0, // pool ID GetHashCode(), // connection ID @@ -427,7 +427,7 @@ private async Task SendSettingsAsync() { try { - _clientControl = _connection.OpenUnidirectionalStream(); + _clientControl = _connection!.OpenUnidirectionalStream(); await _clientControl.WriteAsync(_pool.Settings.Http3SettingsFrame, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) @@ -471,7 +471,7 @@ private async Task AcceptStreamsAsync() } // No cancellation token is needed here; we expect the operation to cancel itself when _connection is disposed. - streamTask = _connection.AcceptStreamAsync(CancellationToken.None); + streamTask = _connection!.AcceptStreamAsync(CancellationToken.None); } QuicStream stream = await streamTask.ConfigureAwait(false); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs index c15594b6d5e5d6..d1be81f3079018 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs @@ -14,6 +14,7 @@ using System.Net.Http.QPack; using System.Runtime.ExceptionServices; using System.Buffers; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http { @@ -26,14 +27,14 @@ internal sealed class Http3RequestStream : IHttpHeadersHandler, IAsyncDisposable private ArrayBuffer _sendBuffer; private readonly ReadOnlyMemory[] _gatheredSendBuffer = new ReadOnlyMemory[2]; private ArrayBuffer _recvBuffer; - private TaskCompletionSource _expect100ContinueCompletionSource; // True indicates we should send content (e.g. received 100 Continue). + private TaskCompletionSource? _expect100ContinueCompletionSource; // True indicates we should send content (e.g. received 100 Continue). private bool _disposed; - private CancellationTokenSource _goawayCancellationSource; + private CancellationTokenSource? _goawayCancellationSource; private CancellationToken _goawayCancellationToken; // Allocated when we receive a :status header. - private HttpResponseMessage _response; + private HttpResponseMessage? _response; // Header decoding. private QPackDecoder _headerDecoder; @@ -44,7 +45,7 @@ internal sealed class Http3RequestStream : IHttpHeadersHandler, IAsyncDisposable private string[] _headerValues = Array.Empty(); /// Any trailing headers. - private List<(HeaderDescriptor name, string value)> _trailingHeaders; + private List<(HeaderDescriptor name, string value)>? _trailingHeaders; // When reading response content, keep track of the number of bytes left in the current data frame. private long _responseDataPayloadRemaining = 0; @@ -97,8 +98,8 @@ public async ValueTask DisposeAsync() private void DisposeSyncHelper() { _connection.RemoveStream(_stream); - _connection = null; - _stream = null; + _connection = null!; + _stream = null!; _sendBuffer.Dispose(); _recvBuffer.Dispose(); @@ -110,7 +111,7 @@ private void DisposeSyncHelper() public void GoAway() { // Dispose() might be called concurrently with GoAway(), we need to make sure to not Dispose/Cancel the CTS concurrently. - using CancellationTokenSource cts = Interlocked.Exchange(ref _goawayCancellationSource, null); + using CancellationTokenSource? cts = Interlocked.Exchange(ref _goawayCancellationSource, null); cts?.Cancel(); } @@ -199,6 +200,7 @@ public async Task SendAsync(CancellationToken cancellationT // Use an atomic exchange to avoid a race to Cancel()/Dispose(). Interlocked.Exchange(ref _goawayCancellationSource, null)?.Dispose(); + Debug.Assert(_response != null && _response.Content != null); // Set our content stream. var responseContent = (HttpConnectionResponseContent)_response.Content; @@ -221,7 +223,7 @@ public async Task SendAsync(CancellationToken cancellationT // Process any Set-Cookie headers. if (_connection.Pool.Settings._useCookies) { - CookieHelper.ProcessReceivedCookies(_response, _connection.Pool.Settings._cookieContainer); + CookieHelper.ProcessReceivedCookies(_response, _connection.Pool.Settings._cookieContainer!); } // To avoid a circular reference (stream->response->content->stream), null out the stream's response. @@ -242,7 +244,7 @@ public async Task SendAsync(CancellationToken cancellationT { // Our stream was reset. - Exception abortException = _connection.AbortException; + Exception? abortException = _connection.AbortException; throw new HttpRequestException(SR.net_http_client_execution_error, abortException ?? ex); } catch (QuicConnectionAbortedException ex) @@ -295,6 +297,7 @@ public async Task SendAsync(CancellationToken cancellationT /// private async Task ReadResponseAsync(CancellationToken cancellationToken) { + Debug.Assert(_response != null); do { _headerState = HeaderState.StatusHeader; @@ -323,7 +326,7 @@ private async Task SendContentAsync(HttpContent content, CancellationToken cance // until we get a response back or until our timeout elapses. if (_expect100ContinueCompletionSource != null) { - Timer timer = null; + Timer? timer = null; try { @@ -331,7 +334,7 @@ private async Task SendContentAsync(HttpContent content, CancellationToken cance { timer = new Timer(o => { - ((Http3RequestStream)o)._expect100ContinueCompletionSource.TrySetResult(true); + ((Http3RequestStream)o!)._expect100ContinueCompletionSource!.TrySetResult(true); }, this, _connection.Pool.Settings._expect100ContinueTimeout, Timeout.InfiniteTimeSpan); } @@ -444,7 +447,7 @@ private async ValueTask DrainContentLength0Frames(CancellationToken cancellation goto case null; case null: // Done receiving: copy over trailing headers. - CopyTrailersToResponseMessage(_response); + CopyTrailersToResponseMessage(_response!); return; case Http3FrameType.Data: // The sum of data frames must equal content length. Because this method is only @@ -521,6 +524,7 @@ private void BufferHeaders(HttpRequestMessage request) // The only way to reach H3 is to upgrade via an Alt-Svc header, so we can encode Alt-Used for every connection. BufferBytes(_connection.AltUsedEncodedHeaderBytes); + Debug.Assert(request.RequestUri != null); string pathAndQuery = request.RequestUri.PathAndQuery; if (pathAndQuery == "/") { @@ -544,7 +548,7 @@ private void BufferHeaders(HttpRequestMessage request) if (_connection.Pool.Settings._useCookies) { - string cookiesFromContainer = _connection.Pool.Settings._cookieContainer.GetCookieHeader(request.RequestUri); + string cookiesFromContainer = _connection.Pool.Settings._cookieContainer!.GetCookieHeader(request.RequestUri); if (cookiesFromContainer != string.Empty) { BufferLiteralHeaderWithStaticNameReference(H3StaticTable.Cookie, cookiesFromContainer); @@ -595,7 +599,7 @@ private void BufferHeaderCollection(HttpHeaders headers) Debug.Assert(headerValuesCount > 0, "No values for header??"); ReadOnlySpan headerValues = _headerValues.AsSpan(0, headerValuesCount); - KnownHeader knownHeader = header.Key.KnownHeader; + KnownHeader? knownHeader = header.Key.KnownHeader; if (knownHeader != null) { // The Host header is not sent for HTTP/3 because we send the ":authority" pseudo-header instead @@ -620,10 +624,10 @@ private void BufferHeaderCollection(HttpHeaders headers) // For all other known headers, send them via their pre-encoded name and the associated value. BufferBytes(knownHeader.Http3EncodedName); - string separator = null; + string? separator = null; if (headerValues.Length > 1) { - HttpHeaderParser parser = header.Key.Parser; + HttpHeaderParser? parser = header.Key.Parser; if (parser != null && parser.SupportsMultipleValues) { separator = parser.Separator; @@ -685,7 +689,7 @@ private void BufferLiteralHeaderWithoutNameReference(string name, string value) _sendBuffer.Commit(bytesWritten); } - private void BufferLiteralHeaderValues(ReadOnlySpan values, string separator) + private void BufferLiteralHeaderValues(ReadOnlySpan values, string? separator) { int bytesWritten; while (!QPackEncoder.EncodeValueString(values, separator, _sendBuffer.AvailableSpan, out bytesWritten)) @@ -819,7 +823,7 @@ void IHttpHeadersHandler.OnHeader(ReadOnlySpan name, ReadOnlySpan va void IHttpHeadersHandler.OnStaticIndexedHeader(int index) { - GetStaticQPackHeader(index, out HeaderDescriptor descriptor, out string knownValue); + GetStaticQPackHeader(index, out HeaderDescriptor descriptor, out string? knownValue); OnHeader(index, descriptor, knownValue, literalValue: default); } @@ -829,7 +833,7 @@ void IHttpHeadersHandler.OnStaticIndexedHeader(int index, ReadOnlySpan val OnHeader(index, descriptor, staticValue: null, literalValue: value); } - private void GetStaticQPackHeader(int index, out HeaderDescriptor descriptor, out string knownValue) + private void GetStaticQPackHeader(int index, out HeaderDescriptor descriptor, out string? knownValue) { if (!HeaderDescriptor.TryGetStaticQPackHeader(index, out descriptor, out knownValue)) { @@ -843,7 +847,7 @@ private void GetStaticQPackHeader(int index, out HeaderDescriptor descriptor, ou /// The static indexed value, if any. /// The literal ASCII value, if any. /// One of or will be set. - private void OnHeader(int? staticIndex, HeaderDescriptor descriptor, string staticValue, ReadOnlySpan literalValue) + private void OnHeader(int? staticIndex, HeaderDescriptor descriptor, string? staticValue, ReadOnlySpan literalValue) { if (descriptor.Name[0] == ':') { @@ -924,13 +928,13 @@ private void OnHeader(int? staticIndex, HeaderDescriptor descriptor, string stat if (NetEventSource.IsEnabled) Trace($"Received headers without :status."); throw new Http3ConnectionException(Http3ErrorCode.ProtocolError); case HeaderState.ResponseHeaders when descriptor.HeaderType.HasFlag(HttpHeaderType.Content): - _response.Content.Headers.TryAddWithoutValidation(descriptor, headerValue); + _response!.Content!.Headers.TryAddWithoutValidation(descriptor, headerValue); break; case HeaderState.ResponseHeaders: - _response.Headers.TryAddWithoutValidation(descriptor.HeaderType.HasFlag(HttpHeaderType.Request) ? descriptor.AsCustomHeader() : descriptor, headerValue); + _response!.Headers.TryAddWithoutValidation(descriptor.HeaderType.HasFlag(HttpHeaderType.Request) ? descriptor.AsCustomHeader() : descriptor, headerValue); break; case HeaderState.TrailingHeaders: - _trailingHeaders.Add((descriptor.HeaderType.HasFlag(HttpHeaderType.Request) ? descriptor.AsCustomHeader() : descriptor, headerValue)); + _trailingHeaders!.Add((descriptor.HeaderType.HasFlag(HttpHeaderType.Request) ? descriptor.AsCustomHeader() : descriptor, headerValue)); break; default: Debug.Fail($"Unexpected {nameof(Http3RequestStream)}.{nameof(_headerState)} '{_headerState}'."); @@ -1150,14 +1154,14 @@ private async ValueTask ReadNextDataFrameAsync(HttpResponseMessage respons } } - public void Trace(string message, [CallerMemberName] string memberName = null) => + public void Trace(string message, [CallerMemberName] string? memberName = null) => _connection.Trace(StreamId, message, memberName); // TODO: it may be possible for Http3RequestStream to implement Stream directly and avoid this allocation. private sealed class Http3ReadStream : HttpBaseStream { private Http3RequestStream _stream; - private HttpResponseMessage _response; + private HttpResponseMessage? _response; public override bool CanRead => true; @@ -1187,10 +1191,10 @@ protected override void Dispose(bool disposing) // We shouldn't be using a managed instance here, but don't have much choice -- we // need to remove the stream from the connection's GOAWAY collection. _stream._connection.RemoveStream(_stream._stream); - _stream._connection = null; + _stream._connection = null!; } - _stream = null; + _stream = null!; _response = null; } @@ -1202,7 +1206,7 @@ public override async ValueTask DisposeAsync() if (_stream != null) { await _stream.DisposeAsync().ConfigureAwait(false); - _stream = null; + _stream = null!; _response = null; } @@ -1216,6 +1220,7 @@ public override int Read(Span buffer) throw new ObjectDisposedException(nameof(Http3RequestStream)); } + Debug.Assert(_response != null); return _stream.ReadResponseContent(_response, buffer); } @@ -1226,6 +1231,7 @@ public override ValueTask ReadAsync(Memory buffer, CancellationToken return new ValueTask(Task.FromException(new ObjectDisposedException(nameof(Http3RequestStream)))); } + Debug.Assert(_response != null); return _stream.ReadResponseContentAsync(_response, buffer, cancellationToken); } @@ -1238,7 +1244,7 @@ public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationTo // TODO: it may be possible for Http3RequestStream to implement Stream directly and avoid this allocation. private sealed class Http3WriteStream : HttpBaseStream { - private Http3RequestStream _stream; + private Http3RequestStream? _stream; public override bool CanRead => false; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpAuthority.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpAuthority.cs index 428f942c41c8ba..f664b8708b194f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpAuthority.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpAuthority.cs @@ -30,12 +30,13 @@ public HttpAuthority(string host, int port) Port = port; } - public bool Equals(HttpAuthority other) + public bool Equals(HttpAuthority? other) { + Debug.Assert(other != null); return string.Equals(IdnHost, other.IdnHost) && Port == other.Port; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is HttpAuthority other && Equals(other); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpBaseStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpBaseStream.cs index db0398d120ffa2..f26a76648d2ab4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpBaseStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpBaseStream.cs @@ -13,13 +13,13 @@ internal abstract class HttpBaseStream : Stream { public sealed override bool CanSeek => false; - public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => + public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => TaskToApm.Begin(ReadAsync(buffer, offset, count, default), callback, state); public sealed override int EndRead(IAsyncResult asyncResult) => TaskToApm.End(asyncResult); - public sealed override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => + public sealed override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => TaskToApm.Begin(WriteAsync(buffer, offset, count, default), callback, state); public sealed override void EndWrite(IAsyncResult asyncResult) => diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs index df4fcc264c8de3..699e5ce8c44a14 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -44,12 +44,12 @@ internal partial class HttpConnection : HttpConnectionBase, IDisposable private static readonly ulong s_http11Bytes = BitConverter.ToUInt64(Encoding.ASCII.GetBytes("HTTP/1.1")); private readonly HttpConnectionPool _pool; - private readonly Socket _socket; // used for polling; _stream should be used for all reading/writing. _stream owns disposal. + private readonly Socket? _socket; // used for polling; _stream should be used for all reading/writing. _stream owns disposal. private readonly Stream _stream; - private readonly TransportContext _transportContext; + private readonly TransportContext? _transportContext; private readonly WeakReference _weakThisRef; - private HttpRequestMessage _currentRequest; + private HttpRequestMessage? _currentRequest; private readonly byte[] _writeBuffer; private int _writeOffset; private int _allowedReadLineBytes; @@ -69,9 +69,9 @@ internal partial class HttpConnection : HttpConnectionBase, IDisposable public HttpConnection( HttpConnectionPool pool, - Socket socket, + Socket? socket, Stream stream, - TransportContext transportContext) + TransportContext? transportContext) { Debug.Assert(pool != null); Debug.Assert(stream != null); @@ -178,7 +178,7 @@ public bool EnsureReadAheadAndPollRead() return null; } - public TransportContext TransportContext => _transportContext; + public TransportContext? TransportContext => _transportContext; public HttpConnectionKind Kind => _pool.Kind; @@ -192,7 +192,7 @@ private void ConsumeFromRemainingBuffer(int bytesToConsume) _readOffset += bytesToConsume; } - private async ValueTask WriteHeadersAsync(HttpHeaders headers, string cookiesFromContainer) + private async ValueTask WriteHeadersAsync(HttpHeaders headers, string? cookiesFromContainer) { if (headers.HeaderStore != null) { @@ -225,11 +225,11 @@ private async ValueTask WriteHeadersAsync(HttpHeaders headers, string cookiesFro // Some headers such as User-Agent and Server use space as a separator (see: ProductInfoHeaderParser) if (headerValuesCount > 1) { - HttpHeaderParser parser = header.Key.Parser; + HttpHeaderParser? parser = header.Key.Parser; string separator = HttpHeaderParser.DefaultSeparator; if (parser != null && parser.SupportsMultipleValues) { - separator = parser.Separator; + separator = parser.Separator!; } for (int i = 1; i < headerValuesCount; i++) @@ -318,8 +318,8 @@ private Task WriteHexInt32Async(int value) public async Task SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) { - TaskCompletionSource allowExpect100ToContinue = null; - Task sendRequestContentTask = null; + TaskCompletionSource? allowExpect100ToContinue = null; + Task? sendRequestContentTask = null; Debug.Assert(_currentRequest == null, $"Expected null {nameof(_currentRequest)}."); Debug.Assert(RemainingBuffer.Length == 0, "Unexpected data in read buffer"); @@ -334,6 +334,7 @@ public async Task SendAsyncCore(HttpRequestMessage request, CancellationTokenRegistration cancellationRegistration = RegisterCancellation(cancellationToken); try { + Debug.Assert(request.RequestUri != null); // Write request line await WriteStringAsync(normalizedMethod.Method).ConfigureAwait(false); await WriteByteAsync((byte)' ').ConfigureAwait(false); @@ -385,10 +386,10 @@ public async Task SendAsyncCore(HttpRequestMessage request, await WriteBytesAsync(isHttp10 ? s_spaceHttp10NewlineAsciiBytes : s_spaceHttp11NewlineAsciiBytes).ConfigureAwait(false); // Determine cookies to send - string cookiesFromContainer = null; + string? cookiesFromContainer = null; if (_pool.Settings._useCookies) { - cookiesFromContainer = _pool.Settings._cookieContainer.GetCookieHeader(request.RequestUri); + cookiesFromContainer = _pool.Settings._cookieContainer!.GetCookieHeader(request.RequestUri); if (cookiesFromContainer == "") { cookiesFromContainer = null; @@ -455,7 +456,7 @@ public async Task SendAsyncCore(HttpRequestMessage request, // Then kick off the request. The TCS' result indicates whether content should be sent or not. allowExpect100ToContinue = new TaskCompletionSource(); var expect100Timer = new Timer( - s => ((TaskCompletionSource)s).TrySetResult(true), + s => ((TaskCompletionSource)s!).TrySetResult(true), allowExpect100ToContinue, _pool.Settings._expect100ContinueTimeout, Timeout.InfiniteTimeSpan); sendRequestContentTask = SendRequestContentWithExpect100ContinueAsync( request, allowExpect100ToContinue.Task, CreateRequestContentStream(request), expect100Timer, cancellationToken); @@ -648,7 +649,7 @@ public async Task SendAsyncCore(HttpRequestMessage request, // Process Set-Cookie headers. if (_pool.Settings._useCookies) { - CookieHelper.ProcessReceivedCookies(response, _pool.Settings._cookieContainer); + CookieHelper.ProcessReceivedCookies(response, _pool.Settings._cookieContainer!); } return response; @@ -739,8 +740,8 @@ private CancellationTokenRegistration RegisterCancellation(CancellationToken can // artificially keeping this connection alive. return cancellationToken.Register(s => { - var weakThisRef = (WeakReference)s; - if (weakThisRef.TryGetTarget(out HttpConnection strongThisRef)) + var weakThisRef = (WeakReference)s!; + if (weakThisRef.TryGetTarget(out HttpConnection? strongThisRef)) { if (NetEventSource.IsEnabled) strongThisRef.Trace("Cancellation requested. Disposing of the connection."); strongThisRef.Dispose(); @@ -756,7 +757,7 @@ private async ValueTask SendRequestContentAsync(HttpRequestMessage request, Http _canRetry = false; // Copy all of the data to the server. - await request.Content.CopyToAsync(stream, _transportContext, cancellationToken).ConfigureAwait(false); + await request.Content!.CopyToAsync(stream, _transportContext, cancellationToken).ConfigureAwait(false); // Finish the content; with a chunked upload, this includes writing the terminating chunk. await stream.FinishAsync().ConfigureAwait(false); @@ -845,7 +846,7 @@ private static void ParseStatusLine(Span line, HttpResponseMessage respons else if (line[MinStatusLineLength] == ' ') { Span reasonBytes = line.Slice(MinStatusLineLength + 1); - string knownReasonPhrase = HttpStatusDescription.Get(response.StatusCode); + string? knownReasonPhrase = HttpStatusDescription.Get(response.StatusCode); if (knownReasonPhrase != null && EqualsOrdinal(knownReasonPhrase, reasonBytes)) { response.SetReasonPhraseWithoutValidation(knownReasonPhrase); @@ -941,7 +942,7 @@ private static void ParseHeaderNameValue(HttpConnection connection, ReadOnlySpan } else if ((descriptor.HeaderType & HttpHeaderType.Content) == HttpHeaderType.Content) { - response.Content.Headers.TryAddWithoutValidation(descriptor, headerValue); + response.Content!.Headers.TryAddWithoutValidation(descriptor, headerValue); } else { @@ -1637,7 +1638,7 @@ private async Task CopyToContentLengthAsync(Stream destination, ulong length, in // use a temporary buffer from the ArrayPool so that the connection doesn't hog large // buffers from the pool for extended durations, especially if it's going to sit in the // connection pool for a prolonged period. - byte[] origReadBuffer = null; + byte[]? origReadBuffer = null; try { while (true) @@ -1754,8 +1755,9 @@ public async ValueTask DrainResponseAsync(HttpResponseMessage response, Cancella throw new HttpRequestException(SR.net_http_authconnectionfailure); } + Debug.Assert(response.Content != null); Stream stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - HttpContentReadStream responseStream = stream as HttpContentReadStream; + HttpContentReadStream? responseStream = stream as HttpContentReadStream; Debug.Assert(responseStream != null || stream is EmptyReadStream); @@ -1823,7 +1825,7 @@ private static bool EqualsOrdinal(string left, Span right) public sealed override string ToString() => $"{nameof(HttpConnection)}({_pool})"; // Description for diagnostic purposes - public sealed override void Trace(string message, [CallerMemberName] string memberName = null) => + public sealed override void Trace(string message, [CallerMemberName] string? memberName = null) => NetEventSource.Log.HandlerMessage( _pool?.GetHashCode() ?? 0, // pool ID GetHashCode(), // connection ID @@ -1834,7 +1836,7 @@ public sealed override void Trace(string message, [CallerMemberName] string memb internal sealed class HttpConnectionWithFinalizer : HttpConnection { - public HttpConnectionWithFinalizer(HttpConnectionPool pool, Socket socket, Stream stream, TransportContext transportContext) : base(pool, socket, stream, transportContext) { } + public HttpConnectionWithFinalizer(HttpConnectionPool pool, Socket? socket, Stream stream, TransportContext? transportContext) : base(pool, socket, stream, transportContext) { } // This class is separated from HttpConnection so we only pay the price of having a finalizer // when it's actually needed, e.g. when MaxConnectionsPerServer is enabled. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs index 17c9455faf241e..258be9180454f5 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs @@ -13,7 +13,7 @@ namespace System.Net.Http internal abstract class HttpConnectionBase : IHttpTrace { public abstract Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); - public abstract void Trace(string message, [CallerMemberName] string memberName = null); + public abstract void Trace(string message, [CallerMemberName] string? memberName = null); protected void TraceConnection(Stream stream) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs index d8f25b7b926091..61f59a365025b2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs @@ -30,16 +30,16 @@ internal sealed class HttpConnectionPool : IDisposable private readonly HttpConnectionPoolManager _poolManager; private readonly HttpConnectionKind _kind; - private readonly Uri _proxyUri; + private readonly Uri? _proxyUri; /// The origin authority used to construct the . - private readonly HttpAuthority _originAuthority; + private readonly HttpAuthority? _originAuthority; /// Initially set to null, this can be set to enable HTTP/3 based on Alt-Svc. - private volatile HttpAuthority _http3Authority; + private volatile HttpAuthority? _http3Authority; /// A timer to expire and return the pool to . Initialized on first use. - private Timer _authorityExpireTimer; + private Timer? _authorityExpireTimer; /// If true, the will persist across a network change. If false, it will be reset to . private bool _persistAuthority; @@ -48,8 +48,8 @@ internal sealed class HttpConnectionPool : IDisposable /// When an Alt-Svc authority fails due to 421 Misdirected Request, it is placed in the blacklist to be ignored /// for milliseconds. Initialized on first use. /// - private volatile HashSet _altSvcBlacklist; - private CancellationTokenSource _altSvcBlacklistTimerCancellation; + private volatile HashSet? _altSvcBlacklist; + private CancellationTokenSource? _altSvcBlacklistTimerCancellation; private volatile bool _altSvcEnabled = true; /// @@ -67,25 +67,25 @@ internal sealed class HttpConnectionPool : IDisposable private readonly int _maxConnections; private bool _http2Enabled; - private Http2Connection _http2Connection; - private SemaphoreSlim _http2ConnectionCreateLock; - private byte[] _http2AltSvcOriginUri; - internal readonly byte[] _http2EncodedAuthorityHostHeader; + private Http2Connection? _http2Connection; + private SemaphoreSlim? _http2ConnectionCreateLock; + private byte[]? _http2AltSvcOriginUri; + internal readonly byte[]? _http2EncodedAuthorityHostHeader; private readonly bool _http3Enabled; - private Http3Connection _http3Connection; - private SemaphoreSlim _http3ConnectionCreateLock; - internal readonly byte[] _http3EncodedAuthorityHostHeader; + private Http3Connection? _http3Connection; + private SemaphoreSlim? _http3ConnectionCreateLock; + internal readonly byte[]? _http3EncodedAuthorityHostHeader; /// For non-proxy connection pools, this is the host name in bytes; for proxies, null. - private readonly byte[] _hostHeaderValueBytes; + private readonly byte[]? _hostHeaderValueBytes; /// Options specialized and cached for this pool and its key. - private readonly SslClientAuthenticationOptions _sslOptionsHttp11; - private readonly SslClientAuthenticationOptions _sslOptionsHttp2; - private readonly SslClientAuthenticationOptions _sslOptionsHttp3; + private readonly SslClientAuthenticationOptions? _sslOptionsHttp11; + private readonly SslClientAuthenticationOptions? _sslOptionsHttp2; + private readonly SslClientAuthenticationOptions? _sslOptionsHttp3; /// Queue of waiters waiting for a connection. Created on demand. - private Queue> _waiters; + private Queue>? _waiters; /// The number of connections associated with the pool. Some of these may be in , others may be in use. private int _associatedConnectionCount; @@ -99,7 +99,7 @@ internal sealed class HttpConnectionPool : IDisposable /// Initializes the pool. /// The maximum number of connections allowed to be associated with the pool at any given time. - public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionKind kind, string host, int port, string sslHostName, Uri proxyUri, int maxConnections) + public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionKind kind, string? host, int port, string? sslHostName, Uri? proxyUri, int maxConnections) { _poolManager = poolManager; _kind = kind; @@ -186,7 +186,7 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK _altSvcEnabled = false; } - string hostHeader = null; + string? hostHeader = null; if (_originAuthority != null) { // Precalculate ASCII bytes for Host header @@ -281,15 +281,15 @@ private static SslClientAuthenticationOptions ConstructSslOptions(HttpConnection return sslOptions; } - public HttpAuthority OriginAuthority => _originAuthority; + public HttpAuthority? OriginAuthority => _originAuthority; public HttpConnectionSettings Settings => _poolManager.Settings; public bool IsSecure => _sslOptionsHttp11 != null; public HttpConnectionKind Kind => _kind; public bool AnyProxyKind => (_proxyUri != null); - public Uri ProxyUri => _proxyUri; - public ICredentials ProxyCredentials => _poolManager.ProxyCredentials; - public byte[] HostHeaderValueBytes => _hostHeaderValueBytes; - public CredentialCache PreAuthCredentials { get; } + public Uri? ProxyUri => _proxyUri; + public ICredentials? ProxyCredentials => _poolManager.ProxyCredentials; + public byte[]? HostHeaderValueBytes => _hostHeaderValueBytes; + public CredentialCache? PreAuthCredentials { get; } /// /// An ASCII origin string per RFC 6454 Section 6.2, in format <scheme>://<host>[:<port>] @@ -305,6 +305,7 @@ public byte[] Http2AltSvcOriginUri { var sb = new StringBuilder(); + Debug.Assert(_originAuthority != null); sb .Append(_kind == HttpConnectionKind.Https ? "https://" : "http://") .Append(_originAuthority.IdnHost); @@ -326,12 +327,12 @@ public byte[] Http2AltSvcOriginUri /// Object used to synchronize access to state in the pool. private object SyncObj => _idleConnections; - private ValueTask<(HttpConnectionBase connection, bool isNewConnection, HttpResponseMessage failureResponse)> + private ValueTask<(HttpConnectionBase? connection, bool isNewConnection, HttpResponseMessage? failureResponse)> GetConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) { if (_http3Enabled && request.Version.Major >= 3) { - HttpAuthority authority = _http3Authority; + HttpAuthority? authority = _http3Authority; if (authority != null) { return GetHttp3ConnectionAsync(request, authority, cancellationToken); @@ -346,11 +347,11 @@ public byte[] Http2AltSvcOriginUri return GetHttpConnectionAsync(request, cancellationToken); } - private ValueTask GetOrReserveHttp11ConnectionAsync(CancellationToken cancellationToken) + private ValueTask GetOrReserveHttp11ConnectionAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { - return new ValueTask(Task.FromCanceled(cancellationToken)); + return new ValueTask(Task.FromCanceled(cancellationToken)); } TimeSpan pooledConnectionLifetime = _poolManager.Settings._pooledConnectionLifetime; @@ -360,7 +361,7 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation // Try to find a usable cached connection. // If we can't find one, we will either wait for one to become available (if at the connection limit) // or just increment the connection count and return null so the caller can create a new connection. - TaskCompletionSourceWithCancellation waiter; + TaskCompletionSourceWithCancellation waiter; while (true) { CachedConnection cachedConnection; @@ -381,7 +382,7 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation // We are under the connection limit, so just increment the count and return null // to indicate to the caller that they should create a new connection. IncrementConnectionCountNoLock(); - return new ValueTask((HttpConnection)null); + return new ValueTask((HttpConnection?)null); } else { @@ -410,7 +411,7 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation { // We found a valid connection. Return it. if (NetEventSource.IsEnabled) conn.Trace("Found usable connection in pool."); - return new ValueTask(conn); + return new ValueTask(conn); } // We got a connection, but it was already closed by the server or the @@ -425,10 +426,10 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation return waiter.WaitWithCancellationAsync(cancellationToken); } - private async ValueTask<(HttpConnectionBase connection, bool isNewConnection, HttpResponseMessage failureResponse)> + private async ValueTask<(HttpConnectionBase? connection, bool isNewConnection, HttpResponseMessage? failureResponse)> GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - HttpConnection connection = await GetOrReserveHttp11ConnectionAsync(cancellationToken).ConfigureAwait(false); + HttpConnection? connection = await GetOrReserveHttp11ConnectionAsync(cancellationToken).ConfigureAwait(false); if (connection != null) { return (connection, false, null); @@ -438,7 +439,7 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation try { - HttpResponseMessage failureResponse; + HttpResponseMessage? failureResponse; (connection, failureResponse) = await CreateHttp11ConnectionAsync(request, cancellationToken).ConfigureAwait(false); if (connection == null) { @@ -454,13 +455,13 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation } } - private async ValueTask<(HttpConnectionBase connection, bool isNewConnection, HttpResponseMessage failureResponse)> + private async ValueTask<(HttpConnectionBase? connection, bool isNewConnection, HttpResponseMessage? failureResponse)> GetHttp2ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) { Debug.Assert(_kind == HttpConnectionKind.Https || _kind == HttpConnectionKind.SslProxyTunnel || _kind == HttpConnectionKind.Http); // See if we have an HTTP2 connection - Http2Connection http2Connection = _http2Connection; + Http2Connection? http2Connection = _http2Connection; if (http2Connection != null) { @@ -493,9 +494,9 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation } // Try to establish an HTTP2 connection - Socket socket = null; - SslStream sslStream = null; - TransportContext transportContext = null; + Socket? socket = null; + SslStream? sslStream = null; + TransportContext? transportContext = null; // Serialize creation attempt await _http2ConnectionCreateLock.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -521,8 +522,8 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation Trace("Attempting new HTTP2 connection."); } - Stream stream; - HttpResponseMessage failureResponse; + Stream? stream; + HttpResponseMessage? failureResponse; (socket, stream, transportContext, failureResponse) = await ConnectAsync(request, true, cancellationToken).ConfigureAwait(false); if (failureResponse != null) @@ -532,7 +533,7 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation if (_kind == HttpConnectionKind.Http) { - http2Connection = new Http2Connection(this, stream); + http2Connection = new Http2Connection(this, stream!); await http2Connection.SetupAsync().ConfigureAwait(false); Debug.Assert(_http2Connection == null); @@ -546,7 +547,7 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation return (_http2Connection, true, null); } - sslStream = (SslStream)stream; + sslStream = (SslStream)stream!; if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2) { // The server accepted our request for HTTP2. @@ -625,13 +626,13 @@ private ValueTask GetOrReserveHttp11ConnectionAsync(Cancellation return await GetHttpConnectionAsync(request, cancellationToken).ConfigureAwait(false); } - private async ValueTask<(HttpConnectionBase connection, bool isNewConnection, HttpResponseMessage failureResponse)> + private async ValueTask<(HttpConnectionBase? connection, bool isNewConnection, HttpResponseMessage? failureResponse)> GetHttp3ConnectionAsync(HttpRequestMessage request, HttpAuthority authority, CancellationToken cancellationToken) { Debug.Assert(_kind == HttpConnectionKind.Https); Debug.Assert(_http3Enabled == true); - Http3Connection http3Connection = Volatile.Read(ref _http3Connection); + Http3Connection? http3Connection = Volatile.Read(ref _http3Connection); if (http3Connection != null) { @@ -716,7 +717,7 @@ public async Task SendWithRetryAsync(HttpRequestMessage req { // Loop on connection failures and retry if possible. - (HttpConnectionBase connection, bool isNewConnection, HttpResponseMessage failureResponse) = await GetConnectionAsync(request, cancellationToken).ConfigureAwait(false); + (HttpConnectionBase? connection, bool isNewConnection, HttpResponseMessage? failureResponse) = await GetConnectionAsync(request, cancellationToken).ConfigureAwait(false); if (failureResponse != null) { // Proxy tunnel failure; return proxy response @@ -735,7 +736,7 @@ public async Task SendWithRetryAsync(HttpRequestMessage req } else { - response = await connection.SendAsync(request, cancellationToken).ConfigureAwait(false); + response = await connection!.SendAsync(request, cancellationToken).ConfigureAwait(false); } } catch (HttpRequestException e) when (e.AllowRetry == RequestRetryType.RetryOnLowerHttpVersion) @@ -763,7 +764,7 @@ public async Task SendWithRetryAsync(HttpRequestMessage req } // Check for the Alt-Svc header, to upgrade to HTTP/3. - if (_altSvcEnabled && response.Headers.TryGetValues(KnownHeaders.AltSvc.Descriptor, out IEnumerable altSvcHeaderValues)) + if (_altSvcEnabled && response.Headers.TryGetValues(KnownHeaders.AltSvc.Descriptor, out IEnumerable? altSvcHeaderValues)) { HandleAltSvc(altSvcHeaderValues, response.Headers.Age); } @@ -788,7 +789,7 @@ public async Task SendWithRetryAsync(HttpRequestMessage req /// TODO: common case will likely be a single value. Optimize for that. internal void HandleAltSvc(IEnumerable altSvcHeaderValues, TimeSpan? responseAge) { - HttpAuthority nextAuthority = null; + HttpAuthority? nextAuthority = null; TimeSpan nextAuthorityMaxAge = default; bool nextAuthorityPersist = false; @@ -796,21 +797,22 @@ internal void HandleAltSvc(IEnumerable altSvcHeaderValues, TimeSpan? res { int parseIdx = 0; - while (AltSvcHeaderParser.Parser.TryParseValue(altSvcHeaderValue, null, ref parseIdx, out object parsedValue)) + while (AltSvcHeaderParser.Parser.TryParseValue(altSvcHeaderValue, null, ref parseIdx, out object? parsedValue)) { - var value = (AltSvcHeaderValue)parsedValue; + var value = (AltSvcHeaderValue?)parsedValue; // 'clear' should be the only value present. if (value == AltSvcHeaderValue.Clear) { ExpireAltSvcAuthority(); + Debug.Assert(_authorityExpireTimer != null); _authorityExpireTimer.Change(Timeout.Infinite, Timeout.Infinite); break; } - if (nextAuthority == null && value.AlpnProtocolName == "h3") + if (nextAuthority == null && value != null && value.AlpnProtocolName == "h3") { - var authority = new HttpAuthority(value.Host, value.Port); + var authority = new HttpAuthority(value.Host!, value.Port); if (_altSvcBlacklist != null) { @@ -868,8 +870,8 @@ internal void HandleAltSvc(IEnumerable altSvcHeaderValues, TimeSpan? res _authorityExpireTimer = new Timer(o => { - var wr = (WeakReference)o; - if (wr.TryGetTarget(out HttpConnectionPool @this)) + var wr = (WeakReference)o!; + if (wr.TryGetTarget(out HttpConnectionPool? @this)) { @this.ExpireAltSvcAuthority(); } @@ -923,7 +925,7 @@ internal void BlacklistAuthority(HttpAuthority badAuthority) Debug.Assert(badAuthority != null); Debug.Assert(badAuthority != _originAuthority); - HashSet altSvcBlacklist = _altSvcBlacklist; + HashSet? altSvcBlacklist = _altSvcBlacklist; if (altSvcBlacklist == null) { @@ -957,13 +959,15 @@ internal void BlacklistAuthority(HttpAuthority badAuthority) if (_http3Authority == badAuthority) { ExpireAltSvcAuthority(); + Debug.Assert(_authorityExpireTimer != null); _authorityExpireTimer.Change(Timeout.Infinite, Timeout.Infinite); } } + Debug.Assert(_altSvcBlacklistTimerCancellation != null); if (added) { - _ = Task.Delay(AltSvcBlacklistTimeoutInMilliseconds) + _ = Task.Delay(AltSvcBlacklistTimeoutInMilliseconds) .ContinueWith(t => { lock (altSvcBlacklist) @@ -990,6 +994,7 @@ public void OnNetworkChanged() if (_http3Authority != null && _persistAuthority == false) { ExpireAltSvcAuthority(); + Debug.Assert(_authorityExpireTimer != null); _authorityExpireTimer.Change(Timeout.Infinite, Timeout.Infinite); } } @@ -1017,7 +1022,7 @@ public Task SendWithNtProxyAuthAsync(HttpConnection connect { if (AnyProxyKind && ProxyCredentials != null) { - return AuthenticationHelper.SendWithNtProxyAuthAsync(request, ProxyUri, ProxyCredentials, connection, this, cancellationToken); + return AuthenticationHelper.SendWithNtProxyAuthAsync(request, ProxyUri!, ProxyCredentials, connection, this, cancellationToken); } return connection.SendAsync(request, cancellationToken); @@ -1029,7 +1034,7 @@ public Task SendWithProxyAuthAsync(HttpRequestMessage reque if ((_kind == HttpConnectionKind.Proxy || _kind == HttpConnectionKind.ProxyConnect) && _poolManager.ProxyCredentials != null) { - return AuthenticationHelper.SendWithProxyAuthAsync(request, _proxyUri, _poolManager.ProxyCredentials, doRequestAuth, this, cancellationToken); + return AuthenticationHelper.SendWithProxyAuthAsync(request, _proxyUri!, _poolManager.ProxyCredentials, doRequestAuth, this, cancellationToken); } return SendWithRetryAsync(request, doRequestAuth, cancellationToken); @@ -1045,11 +1050,11 @@ public Task SendAsync(HttpRequestMessage request, bool doRe return SendWithProxyAuthAsync(request, doRequestAuth, cancellationToken); } - private async ValueTask<(Socket, Stream, TransportContext, HttpResponseMessage)> ConnectAsync(HttpRequestMessage request, bool allowHttp2, CancellationToken cancellationToken) + private async ValueTask<(Socket?, Stream?, TransportContext?, HttpResponseMessage?)> ConnectAsync(HttpRequestMessage request, bool allowHttp2, CancellationToken cancellationToken) { // If a non-infinite connect timeout has been set, create and use a new CancellationToken that'll be canceled // when either the original token is canceled or a connect timeout occurs. - CancellationTokenSource cancellationWithConnectTimeout = null; + CancellationTokenSource? cancellationWithConnectTimeout = null; if (Settings._connectTimeout != Timeout.InfiniteTimeSpan) { cancellationWithConnectTimeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); @@ -1059,22 +1064,23 @@ public Task SendAsync(HttpRequestMessage request, bool doRe try { - Stream stream = null; + Stream? stream = null; switch (_kind) { case HttpConnectionKind.Http: case HttpConnectionKind.Https: case HttpConnectionKind.ProxyConnect: + Debug.Assert(_originAuthority != null); stream = await ConnectHelper.ConnectAsync(_originAuthority.IdnHost, _originAuthority.Port, cancellationToken).ConfigureAwait(false); break; case HttpConnectionKind.Proxy: - stream = await ConnectHelper.ConnectAsync(_proxyUri.IdnHost, _proxyUri.Port, cancellationToken).ConfigureAwait(false); + stream = await ConnectHelper.ConnectAsync(_proxyUri!.IdnHost, _proxyUri.Port, cancellationToken).ConfigureAwait(false); break; case HttpConnectionKind.ProxyTunnel: case HttpConnectionKind.SslProxyTunnel: - HttpResponseMessage response; + HttpResponseMessage? response; (stream, response) = await EstablishProxyTunnel(request.HasHeaders ? request.Headers : null, cancellationToken).ConfigureAwait(false); if (response != null) { @@ -1085,12 +1091,12 @@ public Task SendAsync(HttpRequestMessage request, bool doRe break; } - Socket socket = (stream as NetworkStream)?.Socket; + Socket? socket = (stream as NetworkStream)?.Socket; - TransportContext transportContext = null; + TransportContext? transportContext = null; if (_kind == HttpConnectionKind.Https || _kind == HttpConnectionKind.SslProxyTunnel) { - SslStream sslStream = await ConnectHelper.EstablishSslConnectionAsync(allowHttp2 ? _sslOptionsHttp2 : _sslOptionsHttp11, request, stream, cancellationToken).ConfigureAwait(false); + SslStream sslStream = await ConnectHelper.EstablishSslConnectionAsync(allowHttp2 ? _sslOptionsHttp2! : _sslOptionsHttp11!, request, stream!, cancellationToken).ConfigureAwait(false); stream = sslStream; transportContext = sslStream.TransportContext; } @@ -1103,9 +1109,9 @@ public Task SendAsync(HttpRequestMessage request, bool doRe } } - internal async ValueTask<(HttpConnection, HttpResponseMessage)> CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) + internal async ValueTask<(HttpConnection?, HttpResponseMessage?)> CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - (Socket socket, Stream stream, TransportContext transportContext, HttpResponseMessage failureResponse) = + (Socket? socket, Stream? stream, TransportContext? transportContext, HttpResponseMessage? failureResponse) = await ConnectAsync(request, false, cancellationToken).ConfigureAwait(false); if (failureResponse != null) @@ -1113,10 +1119,10 @@ public Task SendAsync(HttpRequestMessage request, bool doRe return (null, failureResponse); } - return (ConstructHttp11Connection(socket, stream, transportContext), null); + return (ConstructHttp11Connection(socket, stream!, transportContext), null); } - private HttpConnection ConstructHttp11Connection(Socket socket, Stream stream, TransportContext transportContext) + private HttpConnection ConstructHttp11Connection(Socket? socket, Stream stream, TransportContext? transportContext) { return _maxConnections == int.MaxValue ? new HttpConnection(this, socket, stream, transportContext) : @@ -1124,29 +1130,30 @@ private HttpConnection ConstructHttp11Connection(Socket socket, Stream stream, T } // Returns the established stream or an HttpResponseMessage from the proxy indicating failure. - private async ValueTask<(Stream, HttpResponseMessage)> EstablishProxyTunnel(HttpRequestHeaders headers, CancellationToken cancellationToken) + private async ValueTask<(Stream?, HttpResponseMessage?)> EstablishProxyTunnel(HttpRequestHeaders? headers, CancellationToken cancellationToken) { + Debug.Assert(_originAuthority != null); // Send a CONNECT request to the proxy server to establish a tunnel. HttpRequestMessage tunnelRequest = new HttpRequestMessage(HttpMethod.Connect, _proxyUri); tunnelRequest.Headers.Host = $"{_originAuthority.IdnHost}:{_originAuthority.Port}"; // This specifies destination host/port to connect to - if (headers != null && headers.TryGetValues(HttpKnownHeaderNames.UserAgent, out IEnumerable values)) + if (headers != null && headers.TryGetValues(HttpKnownHeaderNames.UserAgent, out IEnumerable? values)) { tunnelRequest.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.UserAgent, values); } - HttpResponseMessage tunnelResponse = await _poolManager.SendProxyConnectAsync(tunnelRequest, _proxyUri, cancellationToken).ConfigureAwait(false); + HttpResponseMessage tunnelResponse = await _poolManager.SendProxyConnectAsync(tunnelRequest, _proxyUri!, cancellationToken).ConfigureAwait(false); if (tunnelResponse.StatusCode != HttpStatusCode.OK) { return (null, tunnelResponse); } - return (await tunnelResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false), null); + return (await tunnelResponse.Content!.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false), null); } /// Enqueues a waiter to the waiters list. - private TaskCompletionSourceWithCancellation EnqueueWaiter() + private TaskCompletionSourceWithCancellation EnqueueWaiter() { Debug.Assert(Monitor.IsEntered(SyncObj)); Debug.Assert(Settings._maxConnectionsPerServer != int.MaxValue); @@ -1154,10 +1161,10 @@ private TaskCompletionSourceWithCancellation EnqueueWaiter() if (_waiters == null) { - _waiters = new Queue>(); + _waiters = new Queue>(); } - var waiter = new TaskCompletionSourceWithCancellation(); + var waiter = new TaskCompletionSourceWithCancellation(); _waiters.Enqueue(waiter); return waiter; } @@ -1171,13 +1178,13 @@ private bool HasWaiter() /// Dequeues a waiter from the waiters list. The list must not be empty. /// The dequeued waiter. - private TaskCompletionSourceWithCancellation DequeueWaiter() + private TaskCompletionSourceWithCancellation DequeueWaiter() { Debug.Assert(Monitor.IsEntered(SyncObj)); Debug.Assert(Settings._maxConnectionsPerServer != int.MaxValue); Debug.Assert(_idleConnections.Count == 0, $"With {_idleConnections.Count} idle connections, we shouldn't have a waiter."); - return _waiters.Dequeue(); + return _waiters!.Dequeue(); } private void IncrementConnectionCountNoLock() @@ -1201,13 +1208,13 @@ internal void IncrementConnectionCount() } } - private bool TransferConnection(HttpConnection connection) + private bool TransferConnection(HttpConnection? connection) { Debug.Assert(Monitor.IsEntered(SyncObj)); while (HasWaiter()) { - TaskCompletionSource waiter = DequeueWaiter(); + TaskCompletionSource waiter = DequeueWaiter(); // Try to complete the task. If it's been cancelled already, this will fail. if (waiter.TrySetResult(connection)) @@ -1386,7 +1393,7 @@ public bool CleanCacheAndDisposeIfUnused() TimeSpan pooledConnectionIdleTimeout = _poolManager.Settings._pooledConnectionIdleTimeout; List list = _idleConnections; - List toDispose = null; + List? toDispose = null; bool tookLock = false; try @@ -1397,7 +1404,7 @@ public bool CleanCacheAndDisposeIfUnused() // Get the current time. This is compared against each connection's last returned // time to determine whether a connection is too old and should be closed. long nowTicks = Environment.TickCount64; - Http2Connection http2Connection = _http2Connection; + Http2Connection? http2Connection = _http2Connection; if (http2Connection != null) { @@ -1500,12 +1507,12 @@ public override string ToString() => (_proxyUri == null ? (_sslOptionsHttp11 == null ? $"http://{_originAuthority}" : - $"https://{_originAuthority}" + (_sslOptionsHttp11.TargetHost != _originAuthority.IdnHost ? $", SSL TargetHost={_sslOptionsHttp11.TargetHost}" : null)) : + $"https://{_originAuthority}" + (_sslOptionsHttp11.TargetHost != _originAuthority!.IdnHost ? $", SSL TargetHost={_sslOptionsHttp11.TargetHost}" : null)) : (_sslOptionsHttp11 == null ? $"Proxy {_proxyUri}" : - $"https://{_originAuthority}/ tunnelled via Proxy {_proxyUri}" + (_sslOptionsHttp11.TargetHost != _originAuthority.IdnHost ? $", SSL TargetHost={_sslOptionsHttp11.TargetHost}" : null))); + $"https://{_originAuthority}/ tunnelled via Proxy {_proxyUri}" + (_sslOptionsHttp11.TargetHost != _originAuthority!.IdnHost ? $", SSL TargetHost={_sslOptionsHttp11.TargetHost}" : null))); - private void Trace(string message, [CallerMemberName] string memberName = null) => + private void Trace(string? message, [CallerMemberName] string? memberName = null) => NetEventSource.Log.HandlerMessage( GetHashCode(), // pool ID 0, // connection ID @@ -1574,7 +1581,7 @@ public bool IsUsable( } public bool Equals(CachedConnection other) => ReferenceEquals(other._connection, _connection); - public override bool Equals(object obj) => obj is CachedConnection && Equals((CachedConnection)obj); + public override bool Equals(object? obj) => obj is CachedConnection && Equals((CachedConnection)obj); public override int GetHashCode() => _connection?.GetHashCode() ?? 0; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs index d7cf0407401f3f..252c3e5795c998 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs @@ -36,15 +36,15 @@ internal sealed class HttpConnectionPoolManager : IDisposable /// The pools, indexed by endpoint. private readonly ConcurrentDictionary _pools; /// Timer used to initiate cleaning of the pools. - private readonly Timer _cleaningTimer; + private readonly Timer? _cleaningTimer; /// The maximum number of connections allowed per pool. indicates unlimited. private readonly int _maxConnectionsPerServer; // Temporary private readonly HttpConnectionSettings _settings; - private readonly IWebProxy _proxy; - private readonly ICredentials _proxyCredentials; + private readonly IWebProxy? _proxy; + private readonly ICredentials? _proxyCredentials; - private NetworkChangeCleanup _networkChangeCleanup; + private NetworkChangeCleanup? _networkChangeCleanup; /// /// Keeps track of whether or not the cleanup timer is running. It helps us avoid the expensive @@ -105,8 +105,8 @@ public HttpConnectionPoolManager(HttpConnectionSettings settings) // implementation until the handler is Disposed (or indefinitely if it's not). _cleaningTimer = new Timer(s => { - var wr = (WeakReference)s; - if (wr.TryGetTarget(out HttpConnectionPoolManager thisRef)) + var wr = (WeakReference)s!; + if (wr.TryGetTarget(out HttpConnectionPoolManager? thisRef)) { thisRef.RemoveStalePools(); } @@ -149,7 +149,7 @@ public void StartMonitoringNetworkChanges() var poolsRef = new WeakReference>(_pools); NetworkAddressChangedEventHandler networkChangedDelegate = delegate { - if (poolsRef.TryGetTarget(out ConcurrentDictionary pools)) + if (poolsRef.TryGetTarget(out ConcurrentDictionary? pools)) { foreach (HttpConnectionPool pool in pools.Values) { @@ -201,7 +201,7 @@ public void Dispose() } public HttpConnectionSettings Settings => _settings; - public ICredentials ProxyCredentials => _proxyCredentials; + public ICredentials? ProxyCredentials => _proxyCredentials; private static string ParseHostNameFromHeader(string hostHeader) { @@ -232,9 +232,10 @@ private static string ParseHostNameFromHeader(string hostHeader) return hostHeader; } - private HttpConnectionKey GetConnectionKey(HttpRequestMessage request, Uri proxyUri, bool isProxyConnect) + private HttpConnectionKey GetConnectionKey(HttpRequestMessage request, Uri? proxyUri, bool isProxyConnect) { - Uri uri = request.RequestUri; + Uri? uri = request.RequestUri; + Debug.Assert(uri != null); if (isProxyConnect) { @@ -242,10 +243,10 @@ private HttpConnectionKey GetConnectionKey(HttpRequestMessage request, Uri proxy return new HttpConnectionKey(HttpConnectionKind.ProxyConnect, uri.IdnHost, uri.Port, null, proxyUri, GetIdentityIfDefaultCredentialsUsed(_settings._defaultCredentialsUsedForProxy)); } - string sslHostName = null; + string? sslHostName = null; if (HttpUtilities.IsSupportedSecureScheme(uri.Scheme)) { - string hostHeader = request.Headers.Host; + string? hostHeader = request.Headers.Host; if (hostHeader != null) { sslHostName = ParseHostNameFromHeader(hostHeader); @@ -293,11 +294,11 @@ private HttpConnectionKey GetConnectionKey(HttpRequestMessage request, Uri proxy } } - public Task SendAsyncCore(HttpRequestMessage request, Uri proxyUri, bool doRequestAuth, bool isProxyConnect, CancellationToken cancellationToken) + public Task SendAsyncCore(HttpRequestMessage request, Uri? proxyUri, bool doRequestAuth, bool isProxyConnect, CancellationToken cancellationToken) { HttpConnectionKey key = GetConnectionKey(request, proxyUri, isProxyConnect); - HttpConnectionPool pool; + HttpConnectionPool? pool; while (!_pools.TryGetValue(key, out pool)) { pool = new HttpConnectionPool(this, key.Kind, key.Host, key.Port, key.SslHostName, key.ProxyUri, _maxConnectionsPerServer); @@ -345,9 +346,10 @@ public Task SendAsync(HttpRequestMessage request, bool doRe } // Do proxy lookup. - Uri proxyUri = null; + Uri? proxyUri = null; try { + Debug.Assert(request.RequestUri != null); if (!_proxy.IsBypassed(request.RequestUri)) { if (_proxy is IMultiWebProxy multiWebProxy) @@ -385,9 +387,9 @@ public Task SendAsync(HttpRequestMessage request, bool doRe /// /// The set of proxies to use. /// The first proxy try. - private async Task SendAsyncMultiProxy(HttpRequestMessage request, bool doRequestAuth, MultiProxy multiProxy, Uri firstProxy, CancellationToken cancellationToken) + private async Task SendAsyncMultiProxy(HttpRequestMessage request, bool doRequestAuth, MultiProxy multiProxy, Uri? firstProxy, CancellationToken cancellationToken) { - HttpRequestException rethrowException = null; + HttpRequestException rethrowException; do { @@ -424,7 +426,7 @@ private void SetCleaningTimer(TimeSpan timeout) { try { - _cleaningTimer.Change(timeout, timeout); + _cleaningTimer!.Change(timeout, timeout); _timerIsRunning = timeout != Timeout.InfiniteTimeSpan; } catch (ObjectDisposedException) @@ -486,13 +488,13 @@ private static string GetIdentityIfDefaultCredentialsUsed(bool defaultCredential internal readonly struct HttpConnectionKey : IEquatable { public readonly HttpConnectionKind Kind; - public readonly string Host; + public readonly string? Host; public readonly int Port; - public readonly string SslHostName; // null if not SSL - public readonly Uri ProxyUri; + public readonly string? SslHostName; // null if not SSL + public readonly Uri? ProxyUri; public readonly string Identity; - public HttpConnectionKey(HttpConnectionKind kind, string host, int port, string sslHostName, Uri proxyUri, string identity) + public HttpConnectionKey(HttpConnectionKind kind, string? host, int port, string? sslHostName, Uri? proxyUri, string identity) { Kind = kind; Host = host; @@ -508,10 +510,9 @@ public override int GetHashCode() => HashCode.Combine(Kind, Host, Port, ProxyUri, Identity) : HashCode.Combine(Kind, Host, Port, SslHostName, ProxyUri, Identity)); - public override bool Equals(object obj) => - obj != null && - obj is HttpConnectionKey && - Equals((HttpConnectionKey)obj); + public override bool Equals(object? obj) => + obj is HttpConnectionKey hck && + Equals(hck); public bool Equals(HttpConnectionKey other) => Kind == other.Kind && diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionResponseContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionResponseContent.cs index 360c06e24f3332..7ed050b6990ab8 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionResponseContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionResponseContent.cs @@ -11,7 +11,7 @@ namespace System.Net.Http { internal sealed class HttpConnectionResponseContent : HttpContent { - private Stream _stream; + private Stream? _stream; private bool _consumedStream; // separate from _stream so that Dispose can drain _stream public void SetStream(Stream stream) @@ -34,10 +34,10 @@ private Stream ConsumeStream() return _stream; } - protected sealed override Task SerializeToStreamAsync(Stream stream, TransportContext context) => + protected sealed override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => SerializeToStreamAsync(stream, context, CancellationToken.None); - protected sealed override async Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) + protected sealed override async Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) { Debug.Assert(stream != null); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs index 3971c9d6db6141..7e847ade77ee43 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs @@ -20,16 +20,16 @@ internal sealed class HttpConnectionSettings internal DecompressionMethods _automaticDecompression = HttpHandlerDefaults.DefaultAutomaticDecompression; internal bool _useCookies = HttpHandlerDefaults.DefaultUseCookies; - internal CookieContainer _cookieContainer; + internal CookieContainer? _cookieContainer; internal bool _useProxy = HttpHandlerDefaults.DefaultUseProxy; - internal IWebProxy _proxy; - internal ICredentials _defaultProxyCredentials; + internal IWebProxy? _proxy; + internal ICredentials? _defaultProxyCredentials; internal bool _defaultCredentialsUsedForProxy; internal bool _defaultCredentialsUsedForServer; internal bool _preAuthenticate = HttpHandlerDefaults.DefaultPreAuthenticate; - internal ICredentials _credentials; + internal ICredentials? _credentials; internal bool _allowAutoRedirect = HttpHandlerDefaults.DefaultAutomaticRedirection; internal int _maxAutomaticRedirections = HttpHandlerDefaults.DefaultMaxAutomaticRedirections; @@ -51,9 +51,9 @@ internal sealed class HttpConnectionSettings // Used for testing until https://github.com/dotnet/runtime/issues/987 internal bool _assumePrenegotiatedHttp3ForTesting; - internal SslClientAuthenticationOptions _sslOptions; + internal SslClientAuthenticationOptions? _sslOptions; - internal IDictionary _properties; + internal IDictionary? _properties; public HttpConnectionSettings() { @@ -120,7 +120,7 @@ private static bool AllowHttp2 } // AppContext switch wasn't used. Check the environment variable. - string envVar = Environment.GetEnvironmentVariable(Http2SupportEnvironmentVariableSettingName); + string? envVar = Environment.GetEnvironmentVariable(Http2SupportEnvironmentVariableSettingName); if (envVar != null && (envVar.Equals("false", StringComparison.OrdinalIgnoreCase) || envVar.Equals("0"))) { // Disallow HTTP/2 protocol. @@ -146,7 +146,7 @@ private static bool AllowUnencryptedHttp2 } // AppContext switch wasn't used. Check the environment variable. - string envVar = Environment.GetEnvironmentVariable(Http2UnencryptedSupportEnvironmentVariableSettingName); + string? envVar = Environment.GetEnvironmentVariable(Http2UnencryptedSupportEnvironmentVariableSettingName); if (envVar != null && (envVar.Equals("true", StringComparison.OrdinalIgnoreCase) || envVar.Equals("1"))) { // Allow HTTP/2.0 protocol for HTTP endpoints. @@ -172,7 +172,7 @@ private static bool AllowDraftHttp3 } // AppContext switch wasn't used. Check the environment variable. - string envVar = Environment.GetEnvironmentVariable(Http3DraftSupportEnvironmentVariableSettingName); + string? envVar = Environment.GetEnvironmentVariable(Http3DraftSupportEnvironmentVariableSettingName); if (envVar != null && (envVar.Equals("true", StringComparison.OrdinalIgnoreCase) || envVar.Equals("1"))) { // Allow HTTP/3 protocol for HTTP endpoints. @@ -184,7 +184,7 @@ private static bool AllowDraftHttp3 } } - private byte[] _http3SettingsFrame; + private byte[]? _http3SettingsFrame; internal byte[] Http3SettingsFrame => _http3SettingsFrame ??= Http3Connection.BuildSettingsFrame(this); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentReadStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentReadStream.cs index 11ac180c4e8c03..af41e3fdcb5ed0 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentReadStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentReadStream.cs @@ -61,8 +61,8 @@ protected override void Dispose(bool disposing) private async Task DrainOnDisposeAsync() { - HttpConnection connection = _connection; // Will be null after drain succeeds - + HttpConnection? connection = _connection; // Will be null after drain succeeds + Debug.Assert(connection != null); try { bool drained = await DrainAsync(connection._pool.Settings._maxResponseDrainSize).ConfigureAwait(false); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentStream.cs index 860fb558bfee91..294389040edcec 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentStream.cs @@ -6,7 +6,7 @@ namespace System.Net.Http { internal abstract class HttpContentStream : HttpBaseStream { - protected HttpConnection _connection; + protected HttpConnection? _connection; public HttpContentStream(HttpConnection connection) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentWriteStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentWriteStream.cs index 3c53400ac27512..9cdd9a6977999d 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentWriteStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentWriteStream.cs @@ -24,10 +24,10 @@ public sealed override void Flush() => public sealed override Task FlushAsync(CancellationToken ignored) { - HttpConnection connection = _connection; + HttpConnection? connection = _connection; return connection != null ? connection.FlushAsync().AsTask() : - default; + default!; } public sealed override int Read(Span buffer) => throw new NotSupportedException(); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.Unix.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.Unix.cs index 91fea8cd81402a..9798c72972d5e7 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.Unix.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.Unix.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Net.Http { internal sealed partial class HttpEnvironmentProxy : IWebProxy @@ -11,24 +13,24 @@ internal sealed partial class HttpEnvironmentProxy : IWebProxy private const string EnvHttpsProxyLC = "https_proxy"; private const string EnvNoProxyLC = "no_proxy"; - public static bool TryCreate(out IWebProxy proxy) + public static bool TryCreate([NotNullWhen(true)] out IWebProxy? proxy) { // Get environment variables. Protocol specific take precedence over // general all_*, lower case variable has precedence over upper case. // Note that curl uses HTTPS_PROXY but not HTTP_PROXY. - Uri httpProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpProxyLC)); + Uri? httpProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpProxyLC)); if (httpProxy == null && Environment.GetEnvironmentVariable(EnvCGI) == null) { httpProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpProxyUC)); } - Uri httpsProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpsProxyLC)) ?? + Uri? httpsProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpsProxyLC)) ?? GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpsProxyUC)); if (httpProxy == null || httpsProxy == null) { - Uri allProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvAllProxyLC)) ?? + Uri? allProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvAllProxyLC)) ?? GetUriFromString(Environment.GetEnvironmentVariable(EnvAllProxyUC)); if (httpProxy == null) @@ -50,7 +52,7 @@ public static bool TryCreate(out IWebProxy proxy) return false; } - string noProxy = Environment.GetEnvironmentVariable(EnvNoProxyLC) ?? + string? noProxy = Environment.GetEnvironmentVariable(EnvNoProxyLC) ?? Environment.GetEnvironmentVariable(EnvNoProxyUC); proxy = new HttpEnvironmentProxy(httpProxy, httpsProxy, noProxy); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.Windows.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.Windows.cs index da78df4d8e8208..0c977a713b25d1 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.Windows.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.Windows.cs @@ -2,26 +2,28 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Net.Http { internal sealed partial class HttpEnvironmentProxy : IWebProxy { - public static bool TryCreate(out IWebProxy proxy) + public static bool TryCreate([NotNullWhen(true)] out IWebProxy? proxy) { // Get environment variables. Protocol specific take precedence over // general all_*. On Windows, environment variables are case insensitive. - Uri httpProxy = null; + Uri? httpProxy = null; if (Environment.GetEnvironmentVariable(EnvCGI) == null) { httpProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpProxyUC)); } - Uri httpsProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpsProxyUC)); + Uri? httpsProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpsProxyUC)); if (httpProxy == null || httpsProxy == null) { - Uri allProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvAllProxyUC)); + Uri? allProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvAllProxyUC)); if (httpProxy == null) { @@ -42,7 +44,7 @@ public static bool TryCreate(out IWebProxy proxy) return false; } - string noProxy = Environment.GetEnvironmentVariable(EnvNoProxyUC); + string? noProxy = Environment.GetEnvironmentVariable(EnvNoProxyUC); proxy = new HttpEnvironmentProxy(httpProxy, httpsProxy, noProxy); return true; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs index 43268fe5732360..f110c70d31d3ee 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs @@ -12,13 +12,13 @@ namespace System.Net.Http internal sealed class HttpEnvironmentProxyCredentials : ICredentials { // Wrapper class for cases when http and https has different authentication. - private readonly NetworkCredential _httpCred; - private readonly NetworkCredential _httpsCred; - private readonly Uri _httpProxy; - private readonly Uri _httpsProxy; + private readonly NetworkCredential? _httpCred; + private readonly NetworkCredential? _httpsCred; + private readonly Uri? _httpProxy; + private readonly Uri? _httpsProxy; - public HttpEnvironmentProxyCredentials(Uri httpProxy, NetworkCredential httpCred, - Uri httpsProxy, NetworkCredential httpsCred) + public HttpEnvironmentProxyCredentials(Uri? httpProxy, NetworkCredential? httpCred, + Uri? httpsProxy, NetworkCredential? httpsCred) { _httpCred = httpCred; _httpsCred = httpsCred; @@ -26,7 +26,7 @@ public HttpEnvironmentProxyCredentials(Uri httpProxy, NetworkCredential httpCred _httpsProxy = httpsProxy; } - public NetworkCredential GetCredential(Uri uri, string authType) + public NetworkCredential? GetCredential(Uri? uri, string authType) { if (uri == null) { @@ -36,10 +36,10 @@ public NetworkCredential GetCredential(Uri uri, string authType) uri.Equals(_httpsProxy) ? _httpsCred : null; } - public static HttpEnvironmentProxyCredentials TryCreate(Uri httpProxy, Uri httpsProxy) + public static HttpEnvironmentProxyCredentials? TryCreate(Uri? httpProxy, Uri? httpsProxy) { - NetworkCredential httpCred = null; - NetworkCredential httpsCred = null; + NetworkCredential? httpCred = null; + NetworkCredential? httpsCred = null; if (httpProxy != null) { @@ -59,7 +59,7 @@ public static HttpEnvironmentProxyCredentials TryCreate(Uri httpProxy, Uri https /// /// Converts string containing user:password to NetworkCredential object /// - private static NetworkCredential GetCredentialsFromString(string value) + private static NetworkCredential? GetCredentialsFromString(string? value) { if (string.IsNullOrWhiteSpace(value)) { @@ -69,7 +69,7 @@ private static NetworkCredential GetCredentialsFromString(string value) value = Uri.UnescapeDataString(value); string password = ""; - string domain = null; + string? domain = null; int idx = value.IndexOf(':'); if (idx != -1) { @@ -96,12 +96,12 @@ internal sealed partial class HttpEnvironmentProxy : IWebProxy private const string EnvNoProxyUC = "NO_PROXY"; private const string EnvCGI = "GATEWAY_INTERFACE"; // Running in a CGI environment. - private readonly Uri _httpProxyUri; // String URI for HTTP requests - private readonly Uri _httpsProxyUri; // String URI for HTTPS requests - private readonly string[] _bypass = null; // list of domains not to proxy - private ICredentials _credentials; + private readonly Uri? _httpProxyUri; // String URI for HTTP requests + private readonly Uri? _httpsProxyUri; // String URI for HTTPS requests + private readonly string[]? _bypass = null; // list of domains not to proxy + private ICredentials? _credentials; - private HttpEnvironmentProxy(Uri httpProxy, Uri httpsProxy, string bypassList) + private HttpEnvironmentProxy(Uri? httpProxy, Uri? httpsProxy, string? bypassList) { _httpProxyUri = httpProxy; _httpsProxyUri = httpsProxy; @@ -133,7 +133,7 @@ private HttpEnvironmentProxy(Uri httpProxy, Uri httpsProxy, string bypassList) /// it to Uri object. The string could contain URI fragment, IP address and port /// tuple or just IP address or name. It will return null if parsing fails. /// - private static Uri GetUriFromString(string value) + private static Uri? GetUriFromString(string? value) { if (string.IsNullOrEmpty(value)) { @@ -144,10 +144,10 @@ private static Uri GetUriFromString(string value) value = value.Substring(7); } - string user = null; - string password = null; + string? user = null; + string? password = null; ushort port = 80; - string host = null; + string host; // Check if there is authentication part with user and possibly password. // Curl accepts raw text and that may break URI parser. @@ -264,7 +264,7 @@ private bool IsMatchInBypassList(Uri input) /// /// Gets the proxy URI. (iWebProxy interface) /// - public Uri GetProxy(Uri uri) + public Uri? GetProxy(Uri uri) { return HttpUtilities.IsSupportedNonSecureScheme(uri.Scheme) ? _httpProxyUri : _httpsProxyUri; } @@ -277,7 +277,7 @@ public bool IsBypassed(Uri uri) return GetProxy(uri) == null ? true : IsMatchInBypassList(uri); } - public ICredentials Credentials + public ICredentials? Credentials { get { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpNoProxy.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpNoProxy.cs index bc33faf2402820..1189cfa78c082c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpNoProxy.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpNoProxy.cs @@ -6,8 +6,8 @@ namespace System.Net.Http { internal sealed class HttpNoProxy : IWebProxy { - public ICredentials Credentials { get; set; } - public Uri GetProxy(Uri destination) => null; + public ICredentials? Credentials { get; set; } + public Uri? GetProxy(Uri destination) => null; public bool IsBypassed(Uri host) => true; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpWindowsProxy.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpWindowsProxy.cs index 3434641e9aba38..277dd2711e906d 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpWindowsProxy.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpWindowsProxy.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO.Compression; using System.Net.NetworkInformation; using System.Runtime.InteropServices; @@ -20,19 +21,19 @@ internal sealed class HttpWindowsProxy : IMultiWebProxy, IDisposable private readonly MultiProxy _insecureProxy; // URI of the http system proxy if set private readonly MultiProxy _secureProxy; // URI of the https system proxy if set private readonly FailedProxyCache _failedProxies = new FailedProxyCache(); - private readonly List _bypass; // list of domains not to proxy + private readonly List? _bypass; // list of domains not to proxy private readonly bool _bypassLocal = false; // we should bypass domain considered local - private readonly List _localIp; - private ICredentials _credentials; + private readonly List? _localIp; + private ICredentials? _credentials; private readonly WinInetProxyHelper _proxyHelper; - private SafeWinHttpHandle _sessionHandle; + private SafeWinHttpHandle? _sessionHandle; private bool _disposed; - public static bool TryCreate(out IWebProxy proxy) + public static bool TryCreate([NotNullWhen(true)] out IWebProxy? proxy) { // This will get basic proxy setting from system using existing // WinInetProxyHelper functions. If no proxy is enabled, it will return null. - SafeWinHttpHandle sessionHandle = null; + SafeWinHttpHandle? sessionHandle = null; proxy = null; WinInetProxyHelper proxyHelper = new WinInetProxyHelper(); @@ -63,7 +64,7 @@ public static bool TryCreate(out IWebProxy proxy) return true; } - private HttpWindowsProxy(WinInetProxyHelper proxyHelper, SafeWinHttpHandle sessionHandle) + private HttpWindowsProxy(WinInetProxyHelper proxyHelper, SafeWinHttpHandle? sessionHandle) { _proxyHelper = proxyHelper; _sessionHandle = sessionHandle; @@ -79,7 +80,7 @@ private HttpWindowsProxy(WinInetProxyHelper proxyHelper, SafeWinHttpHandle sessi { int idx = 0; int start = 0; - string tmp; + string? tmp; // Process bypass list for manual setting. // Initial list size is best guess based on string length assuming each entry is at least 5 characters on average. @@ -177,9 +178,9 @@ public void Dispose() /// /// Gets the proxy URI. (IWebProxy interface) /// - public Uri GetProxy(Uri uri) + public Uri? GetProxy(Uri uri) { - GetMultiProxy(uri).ReadNext(out Uri proxyUri, out _); + GetMultiProxy(uri).ReadNext(out Uri? proxyUri, out _); return proxyUri; } @@ -209,7 +210,7 @@ public MultiProxy GetMultiProxy(Uri uri) { if (proxyInfo.Proxy != IntPtr.Zero) { - string proxyStr = Marshal.PtrToStringUni(proxyInfo.Proxy); + string proxyStr = Marshal.PtrToStringUni(proxyInfo.Proxy)!; return MultiProxy.CreateLazy(_failedProxies, proxyStr, IsSecureUri(uri)); } @@ -242,7 +243,7 @@ public MultiProxy GetMultiProxy(Uri uri) { if (_bypassLocal) { - IPAddress address = null; + IPAddress? address; if (uri.IsLoopback) { @@ -261,7 +262,7 @@ public MultiProxy GetMultiProxy(Uri uri) { // Host is valid IP address. // Check if it belongs to local system. - foreach (IPAddress a in _localIp) + foreach (IPAddress a in _localIp!) { if (a.Equals(address)) { @@ -317,7 +318,7 @@ public bool IsBypassed(Uri uri) return false; } - public ICredentials Credentials + public ICredentials? Credentials { get { @@ -330,6 +331,6 @@ public ICredentials Credentials } // Access function for unit tests. - internal List BypassList => _bypass; + internal List? BypassList => _bypass; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/IHttpTrace.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/IHttpTrace.cs index e98938f5031570..4e86a8215b95d9 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/IHttpTrace.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/IHttpTrace.cs @@ -8,6 +8,6 @@ namespace System.Net.Http { internal interface IHttpTrace { - void Trace(string message, [CallerMemberName] string memberName = null); + void Trace(string message, [CallerMemberName] string? memberName = null); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MacProxy.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MacProxy.cs index 881f9c4f72d6e1..135fe109231385 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MacProxy.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MacProxy.cs @@ -17,7 +17,7 @@ namespace System.Net.Http { internal sealed class MacProxy : IWebProxy { - public ICredentials Credentials { get; set; } + public ICredentials? Credentials { get; set; } private static Uri GetProxyUri(string scheme, CFProxy proxy) { @@ -31,9 +31,9 @@ private static Uri GetProxyUri(string scheme, CFProxy proxy) return uriBuilder.Uri; } - public Uri ExecuteProxyAutoConfiguration(SafeCreateHandle cfurl, CFProxy proxy) + public Uri? ExecuteProxyAutoConfiguration(SafeCreateHandle cfurl, CFProxy proxy) { - Uri result = null; + Uri? result = null; CFRunLoopRef runLoop = CFRunLoopGetCurrent(); // Callback that will be called after executing the configuration script @@ -68,7 +68,7 @@ public Uri ExecuteProxyAutoConfiguration(SafeCreateHandle cfurl, CFProxy proxy) CFNetworkExecuteProxyAutoConfigurationURL(proxy.AutoConfigurationURL, cfurl, cb, ref clientContext) : CFNetworkExecuteProxyAutoConfigurationScript(proxy.AutoConfigurationJavaScript, cfurl, cb, ref clientContext); - using (var mode = CFStringCreateWithCString(typeof(MacProxy).FullName)) + using (var mode = CFStringCreateWithCString(typeof(MacProxy).FullName!)) { IntPtr modeHandle = mode.DangerousGetHandle(); CFRunLoopAddSource(runLoop, loopSource, modeHandle); @@ -81,7 +81,7 @@ public Uri ExecuteProxyAutoConfiguration(SafeCreateHandle cfurl, CFProxy proxy) return result; } - public Uri GetProxy(Uri targetUri) + public Uri? GetProxy(Uri targetUri) { using (SafeCFDictionaryHandle systemProxySettings = CFNetworkCopySystemProxySettings()) using (SafeCreateHandle cfurl = CFURLCreateWithString(targetUri.AbsoluteUri)) @@ -97,7 +97,7 @@ public Uri GetProxy(Uri targetUri) if (proxy.ProxyType == CFProxy.kCFProxyTypeAutoConfigurationURL || proxy.ProxyType == CFProxy.kCFProxyTypeAutoConfigurationJavaScript) { - Uri result = ExecuteProxyAutoConfiguration(cfurl, proxy); + Uri? result = ExecuteProxyAutoConfiguration(cfurl, proxy); if (result != null) return result; } @@ -117,7 +117,7 @@ public bool IsBypassed(Uri targetUri) if (targetUri == null) throw new ArgumentNullException(nameof(targetUri)); - Uri proxyUri = GetProxy(targetUri); + Uri? proxyUri = GetProxy(targetUri); return Equals(proxyUri, targetUri) || proxyUri == null; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MultiProxy.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MultiProxy.cs index 985e943ffe110b..7c2131c881e9a8 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MultiProxy.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MultiProxy.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http { @@ -12,16 +13,16 @@ namespace System.Net.Http 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 FailedProxyCache? _failedProxyCache; + private readonly Uri[]? _uris; + private readonly string? _proxyConfig; private readonly bool _secure; private int _currentIndex; - private Uri _currentUri; + private Uri? _currentUri; public static MultiProxy Empty => new MultiProxy(null, Array.Empty()); - private MultiProxy(FailedProxyCache failedProxyCache, Uri[] uris) + private MultiProxy(FailedProxyCache? failedProxyCache, Uri[] uris) { _failedProxyCache = failedProxyCache; _uris = uris; @@ -46,14 +47,14 @@ private MultiProxy(FailedProxyCache failedProxyCache, string proxyConfig, bool s /// /// The WinHTTP proxy config to parse. /// If true, return proxies suitable for use with a secure connection. If false, return proxies suitable for an insecure connection. - public static MultiProxy Parse(FailedProxyCache failedProxyCache, string proxyConfig, bool secure) + public static MultiProxy Parse(FailedProxyCache failedProxyCache, string? proxyConfig, bool secure) { Debug.Assert(failedProxyCache != null); Uri[] uris = Array.Empty(); ReadOnlySpan span = proxyConfig; - while (TryParseProxyConfigPart(span, secure, out Uri uri, out int charactersConsumed)) + while (TryParseProxyConfigPart(span, secure, out Uri? uri, out int charactersConsumed)) { int idx = uris.Length; @@ -89,11 +90,12 @@ public static MultiProxy CreateLazy(FailedProxyCache failedProxyCache, string pr /// The next proxy to use for the request. /// If true, indicates there are no further proxies to read from the config. /// If there is a proxy available, true. Otherwise, false. - public bool ReadNext(out Uri uri, out bool isFinalProxy) + public bool ReadNext([NotNullWhen(true)] out Uri? uri, out bool isFinalProxy) { // Enumerating indicates the previous proxy has failed; mark it as such. if (_currentUri != null) { + Debug.Assert(_failedProxyCache != null); _failedProxyCache.SetProxyFailed(_currentUri); } @@ -105,11 +107,12 @@ public bool ReadNext(out Uri uri, out bool isFinalProxy) } // If this is the first ReadNext() and all proxies are marked as failed, return the proxy that is closest to renewal. - Uri oldestFailedProxyUri = null; + Uri? oldestFailedProxyUri = null; long oldestFailedProxyTicks = long.MaxValue; do { + Debug.Assert(_failedProxyCache != null); long renewTicks = _failedProxyCache.GetProxyRenewTicks(uri); // Proxy hasn't failed recently, return for use. @@ -135,6 +138,7 @@ public bool ReadNext(out Uri uri, out bool isFinalProxy) if (oldestFailedProxyUri != null) { + Debug.Assert(uri != null); _failedProxyCache.TryRenewProxy(uri, oldestFailedProxyTicks); return true; } @@ -146,7 +150,7 @@ public bool ReadNext(out Uri uri, out bool isFinalProxy) /// /// Reads the next proxy URI from the MultiProxy, either via parsing a config string or from an array. /// - private bool ReadNextHelper(out Uri uri, out bool isFinalProxy) + private bool ReadNextHelper([NotNullWhen(true)] out Uri? uri, out bool isFinalProxy) { Debug.Assert(_uris != null || _proxyConfig != null, $"{nameof(ReadNext)} must not be called on a default-initialized {nameof(MultiProxy)}."); @@ -164,14 +168,16 @@ private bool ReadNextHelper(out Uri uri, out bool isFinalProxy) return true; } + Debug.Assert(_proxyConfig != null); if (_currentIndex < _proxyConfig.Length) { - bool hasProxy = TryParseProxyConfigPart(_proxyConfig.AsSpan(_currentIndex), _secure, out uri, out int charactersConsumed); + bool hasProxy = TryParseProxyConfigPart(_proxyConfig.AsSpan(_currentIndex), _secure, out uri!, out int charactersConsumed); _currentIndex += charactersConsumed; Debug.Assert(_currentIndex <= _proxyConfig.Length); isFinalProxy = _currentIndex == _proxyConfig.Length; + return hasProxy; } @@ -187,7 +193,7 @@ private bool ReadNextHelper(out Uri uri, out bool isFinalProxy) /// The strings are a semicolon or whitespace separated list, with each entry in the following format: /// ([<scheme>=][<scheme>"://"]<server>[":"<port>]) /// - private static bool TryParseProxyConfigPart(ReadOnlySpan proxyString, bool secure, out Uri uri, out int charactersConsumed) + private static bool TryParseProxyConfigPart(ReadOnlySpan proxyString, bool secure, [NotNullWhen(true)] out Uri? uri, out int charactersConsumed) { const int SECURE_FLAG = 1; const int INSECURE_FLAG = 2; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs index 05ec6f462b40a8..9d1184dd38320c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs @@ -23,7 +23,7 @@ public RawConnectionStream(HttpConnection connection) : base(connection) public override int Read(Span buffer) { - HttpConnection connection = _connection; + HttpConnection? connection = _connection; if (connection == null || buffer.Length == 0) { // Response body fully consumed or the caller didn't ask for any data @@ -45,7 +45,7 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation { CancellationHelper.ThrowIfCancellationRequested(cancellationToken); - HttpConnection connection = _connection; + HttpConnection? connection = _connection; if (connection == null || buffer.Length == 0) { // Response body fully consumed or the caller didn't ask for any data @@ -97,7 +97,7 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio return Task.FromCanceled(cancellationToken); } - HttpConnection connection = _connection; + HttpConnection? connection = _connection; if (connection == null) { // null if response body fully consumed @@ -154,7 +154,7 @@ public override void Write(byte[] buffer, int offset, int count) public override void Write(ReadOnlySpan buffer) { - HttpConnection connection = _connection; + HttpConnection? connection = _connection; if (connection == null) { throw new IOException(SR.ObjectDisposed_StreamClosed); @@ -173,7 +173,7 @@ public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationTo return new ValueTask(Task.FromCanceled(cancellationToken)); } - HttpConnection connection = _connection; + HttpConnection? connection = _connection; if (connection == null) { return new ValueTask(Task.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException(SR.ObjectDisposed_StreamClosed)))); @@ -199,7 +199,7 @@ public override Task FlushAsync(CancellationToken cancellationToken) return Task.FromCanceled(cancellationToken); } - HttpConnection connection = _connection; + HttpConnection? connection = _connection; if (connection == null) { return Task.CompletedTask; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs index 06050c94eccf3c..8917d85ef9e908 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs @@ -33,7 +33,8 @@ protected internal override async Task SendAsync(HttpReques HttpResponseMessage response = await _initialInnerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false); uint redirectCount = 0; - Uri redirectUri; + Uri? redirectUri; + Debug.Assert(request.RequestUri != null); while ((redirectUri = GetUriForRedirect(request.RequestUri, response)) != null) { redirectCount++; @@ -86,7 +87,7 @@ protected internal override async Task SendAsync(HttpReques return response; } - private Uri GetUriForRedirect(Uri requestUri, HttpResponseMessage response) + private Uri? GetUriForRedirect(Uri requestUri, HttpResponseMessage response) { switch (response.StatusCode) { @@ -102,7 +103,7 @@ private Uri GetUriForRedirect(Uri requestUri, HttpResponseMessage response) return null; } - Uri location = response.Headers.Location; + Uri? location = response.Headers.Location; if (location == null) { return null; @@ -131,7 +132,7 @@ private Uri GetUriForRedirect(Uri requestUri, HttpResponseMessage response) { if (NetEventSource.IsEnabled) { - TraceError($"Insecure https to http redirect from '{requestUri}' to '{location}' blocked.", response.RequestMessage.GetHashCode()); + TraceError($"Insecure https to http redirect from '{requestUri}' to '{location}' blocked.", response.RequestMessage!.GetHashCode()); } return null; @@ -165,10 +166,10 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - internal void Trace(string message, int requestId, [CallerMemberName] string memberName = null) => + internal void Trace(string message, int requestId, [CallerMemberName] string? memberName = null) => NetEventSource.Log.HandlerMessage(0, 0, requestId, memberName, ToString() + ": " + message); - internal void TraceError(string message, int requestId, [CallerMemberName] string memberName = null) => + internal void TraceError(string message, int requestId, [CallerMemberName] string? memberName = null) => NetEventSource.Log.HandlerMessageError(0, 0, requestId, memberName, ToString() + ": " + message); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs index 161d8b40fffdb9..3f6ec70d07da93 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs @@ -6,13 +6,14 @@ using System.Net.Security; using System.Threading; using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; namespace System.Net.Http { public sealed class SocketsHttpHandler : HttpMessageHandler { private readonly HttpConnectionSettings _settings = new HttpConnectionSettings(); - private HttpMessageHandler _handler; + private HttpMessageHandler? _handler; private bool _disposed; private void CheckDisposed() @@ -42,6 +43,7 @@ public bool UseCookies } } + [AllowNull] public CookieContainer CookieContainer { get => _settings._cookieContainer ?? (_settings._cookieContainer = new CookieContainer()); @@ -72,7 +74,7 @@ public bool UseProxy } } - public IWebProxy Proxy + public IWebProxy? Proxy { get => _settings._proxy; set @@ -82,7 +84,7 @@ public IWebProxy Proxy } } - public ICredentials DefaultProxyCredentials + public ICredentials? DefaultProxyCredentials { get => _settings._defaultProxyCredentials; set @@ -102,7 +104,7 @@ public bool PreAuthenticate } } - public ICredentials Credentials + public ICredentials? Credentials { get => _settings._credentials; set @@ -198,6 +200,7 @@ public int MaxResponseHeadersLength } } + [AllowNull] public SslClientAuthenticationOptions SslOptions { get => _settings._sslOptions ?? (_settings._sslOptions = new SslClientAuthenticationOptions()); @@ -270,8 +273,8 @@ public TimeSpan Expect100ContinueTimeout } } - public IDictionary Properties => - _settings._properties ?? (_settings._properties = new Dictionary()); + public IDictionary Properties => + _settings._properties ?? (_settings._properties = new Dictionary()); protected override void Dispose(bool disposing) { @@ -336,7 +339,7 @@ protected internal override Task SendAsync( CheckDisposed(); HttpMessageHandler handler = _handler ?? SetupHandlerChain(); - Exception error = ValidateAndNormalizeRequest(request); + Exception? error = ValidateAndNormalizeRequest(request); if (error != null) { return Task.FromException(error); @@ -345,7 +348,7 @@ protected internal override Task SendAsync( return handler.SendAsync(request, cancellationToken); } - private Exception ValidateAndNormalizeRequest(HttpRequestMessage request) + private Exception? ValidateAndNormalizeRequest(HttpRequestMessage request) { if (request.Version.Major == 0) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.OSX.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.OSX.cs index ce164aa189c4a3..dee627e1cf367f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.OSX.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.OSX.cs @@ -9,7 +9,7 @@ internal static partial class SystemProxyInfo // On OSX we get default proxy configuration from either environment variables or the OSX system proxy. public static IWebProxy ConstructSystemProxy() { - return HttpEnvironmentProxy.TryCreate(out IWebProxy proxy) ? proxy : new MacProxy(); + return HttpEnvironmentProxy.TryCreate(out IWebProxy? proxy) ? proxy : new MacProxy(); } } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Unix.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Unix.cs index bb9ec768f0f01c..daa122094e8216 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Unix.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Unix.cs @@ -11,7 +11,7 @@ internal static partial class SystemProxyInfo // the "no proxy" object. public static IWebProxy ConstructSystemProxy() { - return HttpEnvironmentProxy.TryCreate(out IWebProxy proxy) ? proxy : new HttpNoProxy(); + return HttpEnvironmentProxy.TryCreate(out IWebProxy? proxy) ? proxy : new HttpNoProxy(); } } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Windows.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Windows.cs index 68ae86b57008bd..e42cc460d999e6 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Windows.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Windows.cs @@ -9,7 +9,7 @@ internal static partial class SystemProxyInfo // On Windows we get default proxy configuration from either environment variables or the Windows system proxy. public static IWebProxy ConstructSystemProxy() { - if (!HttpEnvironmentProxy.TryCreate(out IWebProxy proxy)) + if (!HttpEnvironmentProxy.TryCreate(out IWebProxy? proxy)) { HttpWindowsProxy.TryCreate(out proxy); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/StreamContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/StreamContent.cs index b0e6852e665079..c4e4e80e1d2472 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/StreamContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/StreamContent.cs @@ -11,7 +11,7 @@ namespace System.Net.Http { public class StreamContent : HttpContent { - private Stream _content; + private Stream _content = null!; // Initialized in helper private int _bufferSize; private bool _contentConsumed; private long _start; @@ -52,10 +52,10 @@ private void InitializeContent(Stream content, int bufferSize) if (NetEventSource.IsEnabled) NetEventSource.Associate(this, content); } - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => SerializeToStreamAsyncCore(stream, default); - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => // Only skip the original protected virtual SerializeToStreamAsync if this // isn't a derived type that may have overridden the behavior. GetType() == typeof(StreamContent) ? SerializeToStreamAsyncCore(stream, cancellationToken) : @@ -102,7 +102,7 @@ protected override Task CreateContentReadStreamAsync() return Task.FromResult(new ReadOnlyStream(_content)); } - internal override Stream TryCreateContentReadStream() => + internal override Stream? TryCreateContentReadStream() => GetType() == typeof(StreamContent) ? new ReadOnlyStream(_content) : // type check ensures we use possible derived type's CreateContentReadStreamAsync override null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/StringContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/StringContent.cs index 139f0a85c14159..d19d8f2e2f126e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/StringContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/StringContent.cs @@ -19,12 +19,12 @@ public StringContent(string content) { } - public StringContent(string content, Encoding encoding) + public StringContent(string content, Encoding? encoding) : this(content, encoding, null) { } - public StringContent(string content, Encoding encoding, string mediaType) + public StringContent(string content, Encoding? encoding, string? mediaType) : base(GetContentByteArray(content, encoding)) { // Initialize the 'Content-Type' header with information provided by parameters. @@ -37,7 +37,7 @@ public StringContent(string content, Encoding encoding, string mediaType) // A StringContent is essentially a ByteArrayContent. We serialize the string into a byte-array in the // constructor using encoding information provided by the caller (if any). When this content is sent, the // Content-Length can be retrieved easily (length of the array). - private static byte[] GetContentByteArray(string content, Encoding encoding) + private static byte[] GetContentByteArray(string content, Encoding? encoding) { // In this case we treat 'null' strings different from string.Empty in order to be consistent with our // other *Content constructors: 'null' throws, empty values are allowed. @@ -54,13 +54,13 @@ private static byte[] GetContentByteArray(string content, Encoding encoding) return encoding.GetBytes(content); } - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => // Only skip the original protected virtual SerializeToStreamAsync if this // isn't a derived type that may have overridden the behavior. GetType() == typeof(StringContent) ? SerializeToStreamAsyncCore(stream, cancellationToken) : base.SerializeToStreamAsync(stream, context, cancellationToken); - internal override Stream TryCreateContentReadStream() => + internal override Stream? TryCreateContentReadStream() => GetType() == typeof(StringContent) ? CreateMemoryStreamForByteArray() : // type check ensures we use possible derived type's CreateContentReadStreamAsync override null; } diff --git a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj index 1de59a3b0249d4..6350fbf6cd779c 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj @@ -4,6 +4,7 @@ true true $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS + annotations diff --git a/src/libraries/System.Net.Requests/ref/System.Net.Requests.cs b/src/libraries/System.Net.Requests/ref/System.Net.Requests.cs index 9b306672f05d71..6ea59d4b46607b 100644 --- a/src/libraries/System.Net.Requests/ref/System.Net.Requests.cs +++ b/src/libraries/System.Net.Requests/ref/System.Net.Requests.cs @@ -10,44 +10,44 @@ namespace System.Net public partial class AuthenticationManager { internal AuthenticationManager() { } - public static System.Net.ICredentialPolicy CredentialPolicy { get { throw null; } set { } } + public static System.Net.ICredentialPolicy? CredentialPolicy { get { throw null; } set { } } public static System.Collections.Specialized.StringDictionary CustomTargetNameDictionary { get { throw null; } } public static System.Collections.IEnumerator RegisteredModules { get { throw null; } } - public static System.Net.Authorization Authenticate(string challenge, System.Net.WebRequest request, System.Net.ICredentials credentials) { throw null; } - public static System.Net.Authorization PreAuthenticate(System.Net.WebRequest request, System.Net.ICredentials credentials) { throw null; } + public static System.Net.Authorization? Authenticate(string challenge, System.Net.WebRequest request, System.Net.ICredentials credentials) { throw null; } + public static System.Net.Authorization? PreAuthenticate(System.Net.WebRequest request, System.Net.ICredentials credentials) { throw null; } public static void Register(System.Net.IAuthenticationModule authenticationModule) { } public static void Unregister(System.Net.IAuthenticationModule authenticationModule) { } public static void Unregister(string authenticationScheme) { } } public partial class Authorization { - public Authorization(string token) { } - public Authorization(string token, bool finished) { } - public Authorization(string token, bool finished, string connectionGroupId) { } + public Authorization(string? token) { } + public Authorization(string? token, bool finished) { } + public Authorization(string? token, bool finished, string? connectionGroupId) { } public bool Complete { get { throw null; } } - public string ConnectionGroupId { get { throw null; } } - public string Message { get { throw null; } } + public string? ConnectionGroupId { get { throw null; } } + public string? Message { get { throw null; } } public bool MutuallyAuthenticated { get { throw null; } set { } } - public string[] ProtectionRealm { get { throw null; } set { } } + public string[]? ProtectionRealm { get { throw null; } set { } } } public partial class FileWebRequest : System.Net.WebRequest, System.Runtime.Serialization.ISerializable { [System.ObsoleteAttribute("Serialization is obsoleted for this type. https://go.microsoft.com/fwlink/?linkid=14202")] protected FileWebRequest(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } - public override string ConnectionGroupName { get { throw null; } set { } } + public override string? ConnectionGroupName { get { throw null; } set { } } public override long ContentLength { get { throw null; } set { } } - public override string ContentType { get { throw null; } set { } } - public override System.Net.ICredentials Credentials { get { throw null; } set { } } + public override string? ContentType { get { throw null; } set { } } + public override System.Net.ICredentials? Credentials { get { throw null; } set { } } public override System.Net.WebHeaderCollection Headers { get { throw null; } } public override string Method { get { throw null; } set { } } public override bool PreAuthenticate { get { throw null; } set { } } - public override System.Net.IWebProxy Proxy { get { throw null; } set { } } + public override System.Net.IWebProxy? Proxy { get { throw null; } set { } } public override System.Uri RequestUri { get { throw null; } } public override int Timeout { get { throw null; } set { } } public override bool UseDefaultCredentials { get { throw null; } set { } } public override void Abort() { } - public override System.IAsyncResult BeginGetRequestStream(System.AsyncCallback callback, object state) { throw null; } - public override System.IAsyncResult BeginGetResponse(System.AsyncCallback callback, object state) { throw null; } + public override System.IAsyncResult BeginGetRequestStream(System.AsyncCallback? callback, object? state) { throw null; } + public override System.IAsyncResult BeginGetResponse(System.AsyncCallback? callback, object? state) { throw null; } public override System.IO.Stream EndGetRequestStream(System.IAsyncResult asyncResult) { throw null; } public override System.Net.WebResponse EndGetResponse(System.IAsyncResult asyncResult) { throw null; } protected override void GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } @@ -115,20 +115,20 @@ public sealed partial class FtpWebRequest : System.Net.WebRequest { internal FtpWebRequest() { } public System.Security.Cryptography.X509Certificates.X509CertificateCollection ClientCertificates { get { throw null; } set { } } - public override string ConnectionGroupName { get { throw null; } set { } } + public override string? ConnectionGroupName { get { throw null; } set { } } public override long ContentLength { get { throw null; } set { } } public long ContentOffset { get { throw null; } set { } } - public override string ContentType { get { throw null; } set { } } - public override System.Net.ICredentials Credentials { get { throw null; } set { } } - public static new System.Net.Cache.RequestCachePolicy DefaultCachePolicy { get { throw null; } set { } } + public override string? ContentType { get { throw null; } set { } } + public override System.Net.ICredentials? Credentials { get { throw null; } set { } } + public static new System.Net.Cache.RequestCachePolicy? DefaultCachePolicy { get { throw null; } set { } } public bool EnableSsl { get { throw null; } set { } } public override System.Net.WebHeaderCollection Headers { get { throw null; } set { } } public bool KeepAlive { get { throw null; } set { } } public override string Method { get { throw null; } set { } } public override bool PreAuthenticate { get { throw null; } set { } } - public override System.Net.IWebProxy Proxy { get { throw null; } set { } } + public override System.Net.IWebProxy? Proxy { get { throw null; } set { } } public int ReadWriteTimeout { get { throw null; } set { } } - public string RenameTo { get { throw null; } set { } } + public string? RenameTo { get { throw null; } set { } } public override System.Uri RequestUri { get { throw null; } } public System.Net.ServicePoint ServicePoint { get { throw null; } } public override int Timeout { get { throw null; } set { } } @@ -136,8 +136,8 @@ internal FtpWebRequest() { } public override bool UseDefaultCredentials { get { throw null; } set { } } public bool UsePassive { get { throw null; } set { } } public override void Abort() { } - public override System.IAsyncResult BeginGetRequestStream(System.AsyncCallback callback, object state) { throw null; } - public override System.IAsyncResult BeginGetResponse(System.AsyncCallback callback, object state) { throw null; } + public override System.IAsyncResult BeginGetRequestStream(System.AsyncCallback? callback, object? state) { throw null; } + public override System.IAsyncResult BeginGetResponse(System.AsyncCallback? callback, object? state) { throw null; } public override System.IO.Stream EndGetRequestStream(System.IAsyncResult asyncResult) { throw null; } public override System.Net.WebResponse EndGetResponse(System.IAsyncResult asyncResult) { throw null; } public override System.IO.Stream GetRequestStream() { throw null; } @@ -146,17 +146,16 @@ public override void Abort() { } public partial class FtpWebResponse : System.Net.WebResponse, System.IDisposable { internal FtpWebResponse() { } - public string BannerMessage { get { throw null; } } + public string? BannerMessage { get { throw null; } } public override long ContentLength { get { throw null; } } - public override string ContentType { get { throw null; } } - public string ExitMessage { get { throw null; } } + public string? ExitMessage { get { throw null; } } public override System.Net.WebHeaderCollection Headers { get { throw null; } } public System.DateTime LastModified { get { throw null; } } public override System.Uri ResponseUri { get { throw null; } } public System.Net.FtpStatusCode StatusCode { get { throw null; } } - public string StatusDescription { get { throw null; } } + public string? StatusDescription { get { throw null; } } public override bool SupportsHeaders { get { throw null; } } - public string WelcomeMessage { get { throw null; } } + public string? WelcomeMessage { get { throw null; } } public override void Close() { } public override System.IO.Stream GetResponseStream() { throw null; } } @@ -164,6 +163,7 @@ public override void Close() { } public partial class GlobalProxySelection { public GlobalProxySelection() { } + [System.Diagnostics.CodeAnalysis.AllowNull] public static System.Net.IWebProxy Select { get { throw null; } set { } } public static System.Net.IWebProxy GetEmptyWebProxy() { throw null; } } @@ -172,26 +172,26 @@ public partial class HttpWebRequest : System.Net.WebRequest, System.Runtime.Seri { [System.ObsoleteAttribute("Serialization is obsoleted for this type. https://go.microsoft.com/fwlink/?linkid=14202")] protected HttpWebRequest(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } - public string Accept { get { throw null; } set { } } + public string? Accept { get { throw null; } set { } } public System.Uri Address { get { throw null; } } public virtual bool AllowAutoRedirect { get { throw null; } set { } } public virtual bool AllowReadStreamBuffering { get { throw null; } set { } } public virtual bool AllowWriteStreamBuffering { get { throw null; } set { } } public System.Net.DecompressionMethods AutomaticDecompression { get { throw null; } set { } } public System.Security.Cryptography.X509Certificates.X509CertificateCollection ClientCertificates { get { throw null; } set { } } - public string Connection { get { throw null; } set { } } - public override string ConnectionGroupName { get { throw null; } set { } } + public string? Connection { get { throw null; } set { } } + public override string? ConnectionGroupName { get { throw null; } set { } } public override long ContentLength { get { throw null; } set { } } - public override string ContentType { get { throw null; } set { } } - public System.Net.HttpContinueDelegate ContinueDelegate { get { throw null; } set { } } + public override string? ContentType { get { throw null; } set { } } + public System.Net.HttpContinueDelegate? ContinueDelegate { get { throw null; } set { } } public int ContinueTimeout { get { throw null; } set { } } - public virtual System.Net.CookieContainer CookieContainer { get { throw null; } set { } } - public override System.Net.ICredentials Credentials { get { throw null; } set { } } + public virtual System.Net.CookieContainer? CookieContainer { get { throw null; } set { } } + public override System.Net.ICredentials? Credentials { get { throw null; } set { } } public System.DateTime Date { get { throw null; } set { } } - public static new System.Net.Cache.RequestCachePolicy DefaultCachePolicy { get { throw null; } set { } } + public static new System.Net.Cache.RequestCachePolicy? DefaultCachePolicy { get { throw null; } set { } } public static int DefaultMaximumErrorResponseLength { get { throw null; } set { } } public static int DefaultMaximumResponseHeadersLength { get { throw null; } set { } } - public string Expect { get { throw null; } set { } } + public string? Expect { get { throw null; } set { } } public virtual bool HaveResponse { get { throw null; } } public override System.Net.WebHeaderCollection Headers { get { throw null; } set { } } public string Host { get { throw null; } set { } } @@ -199,24 +199,24 @@ protected HttpWebRequest(System.Runtime.Serialization.SerializationInfo serializ public bool KeepAlive { get { throw null; } set { } } public int MaximumAutomaticRedirections { get { throw null; } set { } } public int MaximumResponseHeadersLength { get { throw null; } set { } } - public string MediaType { get { throw null; } set { } } + public string? MediaType { get { throw null; } set { } } public override string Method { get { throw null; } set { } } public bool Pipelined { get { throw null; } set { } } public override bool PreAuthenticate { get { throw null; } set { } } public System.Version ProtocolVersion { get { throw null; } set { } } - public override System.Net.IWebProxy Proxy { get { throw null; } set { } } + public override System.Net.IWebProxy? Proxy { get { throw null; } set { } } public int ReadWriteTimeout { get { throw null; } set { } } - public string Referer { get { throw null; } set { } } + public string? Referer { get { throw null; } set { } } public override System.Uri RequestUri { get { throw null; } } public bool SendChunked { get { throw null; } set { } } - public System.Net.Security.RemoteCertificateValidationCallback ServerCertificateValidationCallback { get { throw null; } set { } } + public System.Net.Security.RemoteCertificateValidationCallback? ServerCertificateValidationCallback { get { throw null; } set { } } public System.Net.ServicePoint ServicePoint { get { throw null; } } public virtual bool SupportsCookieContainer { get { throw null; } } public override int Timeout { get { throw null; } set { } } - public string TransferEncoding { get { throw null; } set { } } + public string? TransferEncoding { get { throw null; } set { } } public bool UnsafeAuthenticatedConnectionSharing { get { throw null; } set { } } public override bool UseDefaultCredentials { get { throw null; } set { } } - public string UserAgent { get { throw null; } set { } } + public string? UserAgent { get { throw null; } set { } } public override void Abort() { } public void AddRange(int range) { } public void AddRange(int from, int to) { } @@ -226,27 +226,29 @@ public void AddRange(string rangeSpecifier, int range) { } public void AddRange(string rangeSpecifier, int from, int to) { } public void AddRange(string rangeSpecifier, long range) { } public void AddRange(string rangeSpecifier, long from, long to) { } - public override System.IAsyncResult BeginGetRequestStream(System.AsyncCallback callback, object state) { throw null; } - public override System.IAsyncResult BeginGetResponse(System.AsyncCallback callback, object state) { throw null; } + public override System.IAsyncResult BeginGetRequestStream(System.AsyncCallback? callback, object? state) { throw null; } + public override System.IAsyncResult BeginGetResponse(System.AsyncCallback? callback, object? state) { throw null; } public override System.IO.Stream EndGetRequestStream(System.IAsyncResult asyncResult) { throw null; } - public System.IO.Stream EndGetRequestStream(System.IAsyncResult asyncResult, out System.Net.TransportContext context) { throw null; } + public System.IO.Stream EndGetRequestStream(System.IAsyncResult asyncResult, out System.Net.TransportContext? context) { throw null; } public override System.Net.WebResponse EndGetResponse(System.IAsyncResult asyncResult) { throw null; } #pragma warning disable 0809 // Obsolete member overrides non-obsolete member [System.ObsoleteAttribute("Serialization is obsoleted for this type. https://go.microsoft.com/fwlink/?linkid=14202")] protected override void GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } #pragma warning restore 0809 public override System.IO.Stream GetRequestStream() { throw null; } - public System.IO.Stream GetRequestStream(out System.Net.TransportContext context) { throw null; } + public System.IO.Stream GetRequestStream(out System.Net.TransportContext? context) { throw null; } public override System.Net.WebResponse GetResponse() { throw null; } [System.ObsoleteAttribute("Serialization is obsoleted for this type. https://go.microsoft.com/fwlink/?linkid=14202")] void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } } public partial class HttpWebResponse : System.Net.WebResponse, System.Runtime.Serialization.ISerializable { + [System.Obsolete("This API supports the .NET infrastructure and is not intended to be used directly from your code.", true)] + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public HttpWebResponse() { } [System.ObsoleteAttribute("Serialization is obsoleted for this type. https://go.microsoft.com/fwlink/?linkid=14202")] protected HttpWebResponse(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } - public string CharacterSet { get { throw null; } } + public string? CharacterSet { get { throw null; } } public string ContentEncoding { get { throw null; } } public override long ContentLength { get { throw null; } } public override string ContentType { get { throw null; } } @@ -276,8 +278,8 @@ public partial interface IAuthenticationModule { string AuthenticationType { get; } bool CanPreAuthenticate { get; } - System.Net.Authorization Authenticate(string challenge, System.Net.WebRequest request, System.Net.ICredentials credentials); - System.Net.Authorization PreAuthenticate(System.Net.WebRequest request, System.Net.ICredentials credentials); + System.Net.Authorization? Authenticate(string challenge, System.Net.WebRequest request, System.Net.ICredentials credentials); + System.Net.Authorization? PreAuthenticate(System.Net.WebRequest request, System.Net.ICredentials credentials); } public partial interface ICredentialPolicy { @@ -291,7 +293,7 @@ public partial class ProtocolViolationException : System.InvalidOperationExcepti { public ProtocolViolationException() { } protected ProtocolViolationException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } - public ProtocolViolationException(string message) { } + public ProtocolViolationException(string? message) { } public override void GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } } @@ -299,11 +301,11 @@ public partial class WebException : System.InvalidOperationException, System.Run { public WebException() { } protected WebException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } - public WebException(string message) { } - public WebException(string message, System.Exception innerException) { } - public WebException(string message, System.Exception innerException, System.Net.WebExceptionStatus status, System.Net.WebResponse response) { } - public WebException(string message, System.Net.WebExceptionStatus status) { } - public System.Net.WebResponse Response { get { throw null; } } + public WebException(string? message) { } + public WebException(string? message, System.Exception? innerException) { } + public WebException(string? message, System.Exception? innerException, System.Net.WebExceptionStatus status, System.Net.WebResponse? response) { } + public WebException(string? message, System.Net.WebExceptionStatus status) { } + public System.Net.WebResponse? Response { get { throw null; } } public System.Net.WebExceptionStatus Status { get { throw null; } } public override void GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } @@ -337,24 +339,24 @@ public abstract partial class WebRequest : System.MarshalByRefObject, System.Run protected WebRequest() { } protected WebRequest(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } public System.Net.Security.AuthenticationLevel AuthenticationLevel { get { throw null; } set { } } - public virtual System.Net.Cache.RequestCachePolicy CachePolicy { get { throw null; } set { } } - public virtual string ConnectionGroupName { get { throw null; } set { } } + public virtual System.Net.Cache.RequestCachePolicy? CachePolicy { get { throw null; } set { } } + public virtual string? ConnectionGroupName { get { throw null; } set { } } public virtual long ContentLength { get { throw null; } set { } } - public virtual string ContentType { get { throw null; } set { } } - public virtual System.Net.ICredentials Credentials { get { throw null; } set { } } - public static System.Net.Cache.RequestCachePolicy DefaultCachePolicy { get { throw null; } set { } } - public static System.Net.IWebProxy DefaultWebProxy { get { throw null; } set { } } + public virtual string? ContentType { get { throw null; } set { } } + public virtual System.Net.ICredentials? Credentials { get { throw null; } set { } } + public static System.Net.Cache.RequestCachePolicy? DefaultCachePolicy { get { throw null; } set { } } + public static System.Net.IWebProxy? DefaultWebProxy { get { throw null; } set { } } public virtual System.Net.WebHeaderCollection Headers { get { throw null; } set { } } public System.Security.Principal.TokenImpersonationLevel ImpersonationLevel { get { throw null; } set { } } public virtual string Method { get { throw null; } set { } } public virtual bool PreAuthenticate { get { throw null; } set { } } - public virtual System.Net.IWebProxy Proxy { get { throw null; } set { } } + public virtual System.Net.IWebProxy? Proxy { get { throw null; } set { } } public virtual System.Uri RequestUri { get { throw null; } } public virtual int Timeout { get { throw null; } set { } } public virtual bool UseDefaultCredentials { get { throw null; } set { } } public virtual void Abort() { } - public virtual System.IAsyncResult BeginGetRequestStream(System.AsyncCallback callback, object state) { throw null; } - public virtual System.IAsyncResult BeginGetResponse(System.AsyncCallback callback, object state) { throw null; } + public virtual System.IAsyncResult BeginGetRequestStream(System.AsyncCallback? callback, object? state) { throw null; } + public virtual System.IAsyncResult BeginGetResponse(System.AsyncCallback? callback, object? state) { throw null; } public static System.Net.WebRequest Create(string requestUriString) { throw null; } public static System.Net.WebRequest Create(System.Uri requestUri) { throw null; } public static System.Net.WebRequest CreateDefault(System.Uri requestUri) { throw null; } diff --git a/src/libraries/System.Net.Requests/ref/System.Net.Requests.csproj b/src/libraries/System.Net.Requests/ref/System.Net.Requests.csproj index 8ac18e90f8f6f5..a3513661f18e10 100644 --- a/src/libraries/System.Net.Requests/ref/System.Net.Requests.csproj +++ b/src/libraries/System.Net.Requests/ref/System.Net.Requests.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent) + enable diff --git a/src/libraries/System.Net.Requests/src/System.Net.Requests.csproj b/src/libraries/System.Net.Requests/src/System.Net.Requests.csproj index fe4a6b1d1399e2..63f1a993667655 100644 --- a/src/libraries/System.Net.Requests/src/System.Net.Requests.csproj +++ b/src/libraries/System.Net.Requests/src/System.Net.Requests.csproj @@ -4,6 +4,7 @@ System.Net.Requests true $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix + enable diff --git a/src/libraries/System.Net.Requests/src/System/Net/AuthenticationManager.cs b/src/libraries/System.Net.Requests/src/System/Net/AuthenticationManager.cs index e23459e47c6123..9ba085703b0519 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/AuthenticationManager.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/AuthenticationManager.cs @@ -11,23 +11,19 @@ public class AuthenticationManager { private AuthenticationManager() { } - public static ICredentialPolicy CredentialPolicy { get; set; } + public static ICredentialPolicy? CredentialPolicy { get; set; } public static StringDictionary CustomTargetNameDictionary { get; } = new StringDictionary(); - public static Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials) - { + public static Authorization? Authenticate(string challenge, WebRequest request, ICredentials credentials) => throw new PlatformNotSupportedException(); - } - public static Authorization PreAuthenticate(WebRequest request, ICredentials credentials) - { + public static Authorization? PreAuthenticate(WebRequest request, ICredentials credentials) => throw new PlatformNotSupportedException(); - } public static void Register(IAuthenticationModule authenticationModule) { - if (authenticationModule == null) + if (authenticationModule is null) { throw new ArgumentNullException(nameof(authenticationModule)); } @@ -35,10 +31,18 @@ public static void Register(IAuthenticationModule authenticationModule) public static void Unregister(IAuthenticationModule authenticationModule) { + if (authenticationModule is null) + { + throw new ArgumentNullException(nameof(authenticationModule)); + } } public static void Unregister(string authenticationScheme) { + if (authenticationScheme is null) + { + throw new ArgumentNullException(nameof(authenticationScheme)); + } } public static IEnumerator RegisteredModules => Array.Empty().GetEnumerator(); diff --git a/src/libraries/System.Net.Requests/src/System/Net/Authorization.cs b/src/libraries/System.Net.Requests/src/System/Net/Authorization.cs index 90e62cf90f187c..e02541e03aa01a 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/Authorization.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/Authorization.cs @@ -6,19 +6,19 @@ namespace System.Net { public class Authorization { - private string[] _protectionRealm; + private string[]? _protectionRealm; private bool _mutualAuth; - public Authorization(string token) : + public Authorization(string? token) : this(token, true) { } - public Authorization(string token, bool finished) : + public Authorization(string? token, bool finished) : this(token, finished, null) { } - public Authorization(string token, bool finished, string connectionGroupId) : + public Authorization(string? token, bool finished, string? connectionGroupId) : this(token, finished, connectionGroupId, false) { } - internal Authorization(string token, bool finished, string connectionGroupId, bool mutualAuth) + internal Authorization(string? token, bool finished, string? connectionGroupId, bool mutualAuth) { Message = string.IsNullOrEmpty(token) ? null : token; ConnectionGroupId = string.IsNullOrEmpty(connectionGroupId) ? null : connectionGroupId; @@ -26,13 +26,13 @@ internal Authorization(string token, bool finished, string connectionGroupId, bo _mutualAuth = mutualAuth; } - public string Message { get; } + public string? Message { get; } - public string ConnectionGroupId { get; } + public string? ConnectionGroupId { get; } public bool Complete { get; internal set; } - public string[] ProtectionRealm + public string[]? ProtectionRealm { get { return _protectionRealm; } set { _protectionRealm = value != null && value.Length != 0 ? value : null; } diff --git a/src/libraries/System.Net.Requests/src/System/Net/CommandStream.cs b/src/libraries/System.Net.Requests/src/System/Net/CommandStream.cs index dfcc72705ece7a..e013d8d21831a4 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/CommandStream.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/CommandStream.cs @@ -26,16 +26,16 @@ internal class CommandStream : NetworkStreamWrapper // Active variables used for the command state machine // - protected WebRequest _request; + protected WebRequest? _request; protected bool _isAsync; private bool _aborted; - protected PipelineEntry[] _commands; + protected PipelineEntry[]? _commands; protected int _index; private bool _doRead; private bool _doSend; - private ResponseDescription _currentResponseDescription; - protected string _abortReason; + private ResponseDescription? _currentResponseDescription; + protected string? _abortReason; internal CommandStream(TcpClient client) : base(client) @@ -82,9 +82,9 @@ protected override void Dispose(bool disposing) // request that does not own the web request. } - protected void InvokeRequestCallback(object obj) + protected void InvokeRequestCallback(object? obj) { - WebRequest webRequest = _request; + WebRequest? webRequest = _request; if (webRequest != null) { FtpWebRequest ftpWebRequest = (FtpWebRequest)webRequest; @@ -108,10 +108,10 @@ protected void MarkAsRecoverableFailure() } } - internal Stream SubmitRequest(WebRequest request, bool isAsync, bool readInitalResponseOnConnect) + internal Stream? SubmitRequest(WebRequest request, bool isAsync, bool readInitalResponseOnConnect) { ClearState(); - PipelineEntry[] commands = BuildCommandsList(request); + PipelineEntry[]? commands = BuildCommandsList(request); InitCommandPipeline(request, commands, isAsync); if (readInitalResponseOnConnect) { @@ -126,12 +126,12 @@ protected virtual void ClearState() InitCommandPipeline(null, null, false); } - protected virtual PipelineEntry[] BuildCommandsList(WebRequest request) + protected virtual PipelineEntry[]? BuildCommandsList(WebRequest request) { return null; } - protected Exception GenerateException(string message, WebExceptionStatus status, Exception innerException) + protected Exception GenerateException(string message, WebExceptionStatus status, Exception? innerException) { return new WebException( message, @@ -140,13 +140,13 @@ protected Exception GenerateException(string message, WebExceptionStatus status, null /* no response */ ); } - protected Exception GenerateException(FtpStatusCode code, string statusDescription, Exception innerException) + protected Exception GenerateException(FtpStatusCode code, string? statusDescription, Exception? innerException) { return new WebException(SR.Format(SR.net_ftp_servererror, NetRes.GetWebStatusCodeString(code, statusDescription)), innerException, WebExceptionStatus.ProtocolError, null); } - protected void InitCommandPipeline(WebRequest request, PipelineEntry[] commands, bool isAsync) + protected void InitCommandPipeline(WebRequest? request, PipelineEntry[]? commands, bool isAsync) { _commands = commands; _index = 0; @@ -180,7 +180,7 @@ internal void CheckContinuePipeline() /// each command such STOR, PORT, etc, is sent to the server, then the response is parsed into a string, /// with the response, the delegate is called, which returns an instruction (either continue, stop, or read additional /// responses from server). - protected Stream ContinueCommandPipeline() + protected Stream? ContinueCommandPipeline() { // In async case, The BeginWrite can actually result in a // series of synchronous completions that eventually close @@ -188,7 +188,7 @@ protected Stream ContinueCommandPipeline() // we need to access, since they may not be valid after // BeginWrite returns bool isAsync = _isAsync; - while (_index < _commands.Length) + while (_index < _commands!.Length) { if (_doSend) { @@ -236,7 +236,7 @@ protected Stream ContinueCommandPipeline() } } - Stream stream = null; + Stream? stream = null; bool isReturn = PostSendCommandProcessing(ref stream); if (isReturn) { @@ -252,7 +252,7 @@ protected Stream ContinueCommandPipeline() return null; } - private bool PostSendCommandProcessing(ref Stream stream) + private bool PostSendCommandProcessing(ref Stream? stream) { if (_doRead) { @@ -263,11 +263,11 @@ private bool PostSendCommandProcessing(ref Stream stream) // next call returns bool isAsync = _isAsync; int index = _index; - PipelineEntry[] commands = _commands; + PipelineEntry[] commands = _commands!; try { - ResponseDescription response = ReceiveCommandResponse(); + ResponseDescription? response = ReceiveCommandResponse(); if (isAsync) { return true; @@ -279,7 +279,7 @@ private bool PostSendCommandProcessing(ref Stream stream) // If we get an exception on the QUIT command (which is // always the last command), ignore the final exception // and continue with the pipeline regardlss of sync/async - if (index < 0 || index >= commands.Length || + if (index < 0 || index >= commands!.Length || commands[index].Command != "QUIT\r\n") throw; } @@ -287,9 +287,9 @@ private bool PostSendCommandProcessing(ref Stream stream) return PostReadCommandProcessing(ref stream); } - private bool PostReadCommandProcessing(ref Stream stream) + private bool PostReadCommandProcessing(ref Stream? stream) { - if (_index >= _commands.Length) + if (_index >= _commands!.Length) return false; // Set up front to prevent a race condition on result == PipelineInstruction.Pause @@ -297,7 +297,7 @@ private bool PostReadCommandProcessing(ref Stream stream) _doRead = false; PipelineInstruction result; - PipelineEntry entry; + PipelineEntry? entry; if (_index == -1) entry = null; else @@ -306,7 +306,7 @@ private bool PostReadCommandProcessing(ref Stream stream) // Final QUIT command may get exceptions since the connection // may be already closed by the server. So there is no response // to process, just advance the pipeline to continue. - if (_currentResponseDescription == null && entry.Command == "QUIT\r\n") + if (_currentResponseDescription == null && entry!.Command == "QUIT\r\n") result = PipelineInstruction.Advance; else result = PipelineCallback(entry, _currentResponseDescription, false, ref stream); @@ -393,7 +393,7 @@ internal bool HasFlag(PipelineEntryFlags flags) internal PipelineEntryFlags Flags; } - protected virtual PipelineInstruction PipelineCallback(PipelineEntry entry, ResponseDescription response, bool timeout, ref Stream stream) + protected virtual PipelineInstruction PipelineCallback(PipelineEntry? entry, ResponseDescription? response, bool timeout, ref Stream? stream) { return PipelineInstruction.Abort; } @@ -404,7 +404,7 @@ protected virtual PipelineInstruction PipelineCallback(PipelineEntry entry, Resp private static void ReadCallback(IAsyncResult asyncResult) { - ReceiveState state = (ReceiveState)asyncResult.AsyncState; + ReceiveState state = (ReceiveState)asyncResult.AsyncState!; try { Stream stream = (Stream)state.Connection; @@ -435,7 +435,7 @@ private static void ReadCallback(IAsyncResult asyncResult) private static void WriteCallback(IAsyncResult asyncResult) { - CommandStream connection = (CommandStream)asyncResult.AsyncState; + CommandStream connection = (CommandStream)asyncResult.AsyncState!; try { try @@ -451,7 +451,7 @@ private static void WriteCallback(IAsyncResult asyncResult) { throw; } - Stream stream = null; + Stream? stream = null; if (connection.PostSendCommandProcessing(ref stream)) return; connection.ContinueCommandPipeline(); @@ -496,7 +496,7 @@ protected virtual bool CheckValid(ResponseDescription response, ref int validThr /// Uses the Encoding encoding to transform the bytes received into a string to be /// returned in the GeneralResponseDescription's StatusDescription field. /// - private ResponseDescription ReceiveCommandResponse() + private ResponseDescription? ReceiveCommandResponse() { // These are the things that will be needed to maintain state. ReceiveState state = new ReceiveState(this); @@ -668,7 +668,7 @@ private void ReceiveCommandResponseCallback(ReceiveState state, int bytesRead) { _currentResponseDescription = state.Resp; } - Stream stream = null; + Stream? stream = null; if (PostReadCommandProcessing(ref stream)) return; ContinueCommandPipeline(); @@ -685,10 +685,10 @@ internal class ResponseDescription internal bool Multiline = false; internal int Status = NoStatus; - internal string StatusDescription; + internal string? StatusDescription; internal StringBuilder StatusBuffer = new StringBuilder(); - internal string StatusCodeString; + internal string? StatusCodeString; internal bool PositiveIntermediate { get { return (Status >= 100 && Status <= 199); } } internal bool PositiveCompletion { get { return (Status >= 200 && Status <= 299); } } diff --git a/src/libraries/System.Net.Requests/src/System/Net/FileWebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/FileWebRequest.cs index c314cde69d2f61..a7b4af8c071dfc 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/FileWebRequest.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/FileWebRequest.cs @@ -14,9 +14,9 @@ public class FileWebRequest : WebRequest, ISerializable private readonly WebHeaderCollection _headers = new WebHeaderCollection(); private string _method = WebRequestMethods.File.DownloadFile; private FileAccess _fileAccess = FileAccess.Read; - private ManualResetEventSlim _blockReaderUntilRequestStreamDisposed; - private WebResponse _response; - private WebFileStream _stream; + private ManualResetEventSlim? _blockReaderUntilRequestStreamDisposed; + private WebResponse? _response; + private WebFileStream? _stream; private readonly Uri _uri; private long _contentLength; private int _timeout = DefaultTimeoutMilliseconds; @@ -52,7 +52,7 @@ protected override void GetObjectData(SerializationInfo serializationInfo, Strea internal bool Aborted => _aborted != 0; - public override string ConnectionGroupName { get; set; } + public override string? ConnectionGroupName { get; set; } public override long ContentLength { @@ -67,13 +67,13 @@ public override long ContentLength } } - public override string ContentType + public override string? ContentType { get { return _headers["Content-Type"]; } set { _headers["Content-Type"] = value; } } - public override ICredentials Credentials { get; set; } + public override ICredentials? Credentials { get; set; } public override WebHeaderCollection Headers => _headers; @@ -92,7 +92,7 @@ public override string Method public override bool PreAuthenticate { get; set; } - public override IWebProxy Proxy { get; set; } + public override IWebProxy? Proxy { get; set; } public override int Timeout { @@ -155,10 +155,10 @@ private Stream CreateWriteStream() catch (Exception e) { throw new WebException(e.Message, e); } } - public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state) + public override IAsyncResult BeginGetRequestStream(AsyncCallback? callback, object? state) { CheckAndMarkAsyncGetRequestStreamPending(); - Task t = Task.Factory.StartNew(s => ((FileWebRequest)s).CreateWriteStream(), + Task t = Task.Factory.StartNew(s => ((FileWebRequest)s!).CreateWriteStream(), this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); return TaskToApm.Begin(t, callback, state); } @@ -168,7 +168,7 @@ public override Task GetRequestStreamAsync() CheckAndMarkAsyncGetRequestStreamPending(); return Task.Factory.StartNew(s => { - FileWebRequest thisRef = (FileWebRequest)s; + FileWebRequest thisRef = (FileWebRequest)s!; Stream writeStream = thisRef.CreateWriteStream(); thisRef._writePending = false; return writeStream; @@ -216,10 +216,10 @@ private WebResponse CreateResponse() } } - public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) + public override IAsyncResult BeginGetResponse(AsyncCallback? callback, object? state) { CheckAndMarkAsyncGetResponsePending(); - Task t = Task.Factory.StartNew(s => ((FileWebRequest)s).CreateResponse(), + Task t = Task.Factory.StartNew(s => ((FileWebRequest)s!).CreateResponse(), this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); return TaskToApm.Begin(t, callback, state); } @@ -229,7 +229,7 @@ public override Task GetResponseAsync() CheckAndMarkAsyncGetResponsePending(); return Task.Factory.StartNew(s => { - var thisRef = (FileWebRequest)s; + var thisRef = (FileWebRequest)s!; WebResponse response = thisRef.CreateResponse(); _readPending = false; return response; @@ -366,7 +366,7 @@ public override void Write(byte[] buffer, int offset, int size) } } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback? callback, object? state) { CheckAborted(); try @@ -393,7 +393,7 @@ public override int EndRead(IAsyncResult ar) } } - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback? callback, object? state) { CheckAborted(); try diff --git a/src/libraries/System.Net.Requests/src/System/Net/FileWebResponse.cs b/src/libraries/System.Net.Requests/src/System/Net/FileWebResponse.cs index 0e7f0cef213105..24f331d9426e29 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/FileWebResponse.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/FileWebResponse.cs @@ -114,11 +114,11 @@ public override void Close() { _closed = true; - Stream chkStream = _stream; + Stream? chkStream = _stream; if (chkStream != null) { chkStream.Close(); - _stream = null; + _stream = null!; } } } diff --git a/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs b/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs index d2fdb5f2918032..f36b48483d54a6 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections; -using System.Diagnostics; using System.Globalization; using System.IO; using System.Net.Sockets; @@ -27,36 +26,36 @@ internal enum FtpLoginState : byte /// internal class FtpControlStream : CommandStream { - private Socket _dataSocket; - private IPEndPoint _passiveEndPoint; - private TlsStream _tlsStream; - - private StringBuilder _bannerMessage; - private StringBuilder _welcomeMessage; - private StringBuilder _exitMessage; - private WeakReference _credentials; + private Socket? _dataSocket; + private IPEndPoint? _passiveEndPoint; + private TlsStream? _tlsStream; + + private StringBuilder? _bannerMessage; + private StringBuilder? _welcomeMessage; + private StringBuilder? _exitMessage; + private WeakReference? _credentials; private string _currentTypeSetting = string.Empty; private long _contentLength = -1; private DateTime _lastModified; private bool _dataHandshakeStarted = false; - private string _loginDirectory = null; - private string _establishedServerDirectory = null; - private string _requestedServerDirectory = null; - private Uri _responseUri; + private string? _loginDirectory; + private string? _establishedServerDirectory; + private string? _requestedServerDirectory; + private Uri? _responseUri; private FtpLoginState _loginState = FtpLoginState.NotLoggedIn; internal FtpStatusCode StatusCode; - internal string StatusLine; + internal string? StatusLine; - internal NetworkCredential Credentials + internal NetworkCredential? Credentials { get { if (_credentials != null && _credentials.IsAlive) { - return (NetworkCredential)_credentials.Target; + return (NetworkCredential?)_credentials.Target; } else { @@ -87,7 +86,7 @@ internal FtpControlStream(TcpClient client) /// internal void AbortConnect() { - Socket socket = _dataSocket; + Socket? socket = _dataSocket; if (socket != null) { try @@ -105,12 +104,12 @@ internal void AbortConnect() /// private static void AcceptCallback(IAsyncResult asyncResult) { - FtpControlStream connection = (FtpControlStream)asyncResult.AsyncState; - Socket listenSocket = connection._dataSocket; + FtpControlStream connection = (FtpControlStream)asyncResult.AsyncState!; + Socket listenSocket = connection._dataSocket!; try { connection._dataSocket = listenSocket.EndAccept(asyncResult); - if (!connection.ServerAddress.Equals(((IPEndPoint)connection._dataSocket.RemoteEndPoint).Address)) + if (!connection.ServerAddress.Equals(((IPEndPoint)connection._dataSocket.RemoteEndPoint!).Address)) { connection._dataSocket.Close(); throw new WebException(SR.net_ftp_active_address_different, WebExceptionStatus.ProtocolError); @@ -133,10 +132,10 @@ private static void AcceptCallback(IAsyncResult asyncResult) /// private static void ConnectCallback(IAsyncResult asyncResult) { - FtpControlStream connection = (FtpControlStream)asyncResult.AsyncState; + FtpControlStream connection = (FtpControlStream)asyncResult.AsyncState!; try { - connection._dataSocket.EndConnect(asyncResult); + connection._dataSocket!.EndConnect(asyncResult); connection.ContinueCommandPipeline(); } catch (Exception e) @@ -148,10 +147,10 @@ private static void ConnectCallback(IAsyncResult asyncResult) private static void SSLHandshakeCallback(IAsyncResult asyncResult) { - FtpControlStream connection = (FtpControlStream)asyncResult.AsyncState; + FtpControlStream connection = (FtpControlStream)asyncResult.AsyncState!; try { - connection._tlsStream.EndAuthenticateAsClient(asyncResult); + connection._tlsStream!.EndAuthenticateAsClient(asyncResult); connection.ContinueCommandPipeline(); } catch (Exception e) @@ -163,7 +162,7 @@ private static void SSLHandshakeCallback(IAsyncResult asyncResult) // Creates a FtpDataStream object, constructs a TLS stream if needed. // In case SSL and ASYNC we delay sigaling the user stream until the handshake is done. - private PipelineInstruction QueueOrCreateFtpDataStream(ref Stream stream) + private PipelineInstruction QueueOrCreateFtpDataStream(ref Stream? stream) { if (_dataSocket == null) throw new InternalException(); @@ -173,7 +172,7 @@ private PipelineInstruction QueueOrCreateFtpDataStream(ref Stream stream) // if (_tlsStream != null) { - stream = new FtpDataStream(_tlsStream, (FtpWebRequest)_request, IsFtpDataStreamWriteable()); + stream = new FtpDataStream(_tlsStream, (FtpWebRequest)_request!, IsFtpDataStreamWriteable()); _tlsStream = null; return PipelineInstruction.GiveStream; } @@ -182,7 +181,7 @@ private PipelineInstruction QueueOrCreateFtpDataStream(ref Stream stream) if (UsingSecureStream) { - FtpWebRequest request = (FtpWebRequest)_request; + FtpWebRequest request = (FtpWebRequest)_request!; TlsStream tlsStream = new TlsStream(networkStream, _dataSocket, request.RequestUri.Host, request.ClientCertificates); networkStream = tlsStream; @@ -200,7 +199,7 @@ private PipelineInstruction QueueOrCreateFtpDataStream(ref Stream stream) } } - stream = new FtpDataStream(networkStream, (FtpWebRequest)_request, IsFtpDataStreamWriteable()); + stream = new FtpDataStream(networkStream, (FtpWebRequest)_request!, IsFtpDataStreamWriteable()); return PipelineInstruction.GiveStream; } @@ -222,7 +221,7 @@ protected override void ClearState() // This is called by underlying base class code, each time a new response is received from the wire or a protocol stage is resumed. // This function controls the setting up of a data socket/connection, and of saving off the server responses. - protected override PipelineInstruction PipelineCallback(PipelineEntry entry, ResponseDescription response, bool timeout, ref Stream stream) + protected override PipelineInstruction PipelineCallback(PipelineEntry? entry, ResponseDescription? response, bool timeout, ref Stream? stream) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Command:{entry?.Command} Description:{response?.StatusDescription}"); @@ -267,7 +266,7 @@ protected override PipelineInstruction PipelineCallback(PipelineEntry entry, Res // // Check for the result of our attempt to use UTF8 // - if (entry.Command == "OPTS utf8 on\r\n") + if (entry!.Command == "OPTS utf8 on\r\n") { if (response.PositiveCompletion) { @@ -342,13 +341,13 @@ protected override PipelineInstruction PipelineCallback(PipelineEntry entry, Res } // Parse out the Content length, if we can - TryUpdateContentLength(response.StatusDescription); + TryUpdateContentLength(response.StatusDescription!); // Parse out the file name, when it is returned and use it for our ResponseUri - FtpWebRequest request = (FtpWebRequest)_request; + FtpWebRequest request = (FtpWebRequest)_request!; if (request.MethodInfo.ShouldParseForResponseUri) { - TryUpdateResponseUri(response.StatusDescription, request); + TryUpdateResponseUri(response.StatusDescription!, request); } return QueueOrCreateFtpDataStream(ref stream); @@ -362,12 +361,12 @@ protected override PipelineInstruction PipelineCallback(PipelineEntry entry, Res // Update welcome message if (status == FtpStatusCode.LoggedInProceed) { - _welcomeMessage.Append(StatusLine); + _welcomeMessage!.Append(StatusLine); } // OR set the user response ExitMessage else if (status == FtpStatusCode.ClosingControl) { - _exitMessage.Append(response.StatusDescription); + _exitMessage!.Append(response.StatusDescription); // And close the control stream socket on "QUIT" CloseSocket(); } @@ -379,7 +378,7 @@ protected override PipelineInstruction PipelineCallback(PipelineEntry entry, Res // So just let the pipeline continue. if (!(NetworkStream is TlsStream)) { - FtpWebRequest request = (FtpWebRequest)_request; + FtpWebRequest request = (FtpWebRequest)_request!; TlsStream tlsStream = new TlsStream(NetworkStream, Socket, request.RequestUri.Host, request.ClientCertificates); if (_isAsync) @@ -413,11 +412,11 @@ protected override PipelineInstruction PipelineCallback(PipelineEntry entry, Res { if (entry.Command.StartsWith("SIZE ", StringComparison.Ordinal)) { - _contentLength = GetContentLengthFrom213Response(response.StatusDescription); + _contentLength = GetContentLengthFrom213Response(response.StatusDescription!); } else if (entry.Command.StartsWith("MDTM ", StringComparison.Ordinal)) { - _lastModified = GetLastModifiedFrom213Response(response.StatusDescription); + _lastModified = GetLastModifiedFrom213Response(response.StatusDescription!); } } // OR parse out our login directory @@ -425,7 +424,7 @@ protected override PipelineInstruction PipelineCallback(PipelineEntry entry, Res { if (entry.Command == "PWD\r\n" && !entry.HasFlag(PipelineEntryFlags.UserCommand)) { - _loginDirectory = GetLoginDirectory(response.StatusDescription); + _loginDirectory = GetLoginDirectory(response.StatusDescription!); } } // Asserting we have some positive response @@ -479,7 +478,7 @@ protected override PipelineEntry[] BuildCommandsList(WebRequest req) if (_loginState != FtpLoginState.LoggedIn) { - Credentials = request.Credentials.GetCredential(request.RequestUri, "basic"); + Credentials = request.Credentials!.GetCredential(request.RequestUri, "basic"); _welcomeMessage = new StringBuilder(); _exitMessage = new StringBuilder(); @@ -630,7 +629,7 @@ protected override PipelineEntry[] BuildCommandsList(WebRequest req) return (PipelineEntry[])commandList.ToArray(typeof(PipelineEntry)); } - private PipelineInstruction QueueOrCreateDataConection(PipelineEntry entry, ResponseDescription response, bool timeout, ref Stream stream, out bool isSocketReady) + private PipelineInstruction QueueOrCreateDataConection(PipelineEntry entry, ResponseDescription response, bool timeout, ref Stream? stream, out bool isSocketReady) { isSocketReady = false; if (_dataHandshakeStarted) @@ -654,11 +653,11 @@ private PipelineInstruction QueueOrCreateDataConection(PipelineEntry entry, Resp } if (entry.Command == "PASV\r\n") { - port = GetPortV4(response.StatusDescription); + port = GetPortV4(response.StatusDescription!); } else { - port = GetPortV6(response.StatusDescription); + port = GetPortV6(response.StatusDescription!); } isPassive = true; @@ -673,14 +672,14 @@ private PipelineInstruction QueueOrCreateDataConection(PipelineEntry entry, Resp try { - _dataSocket = CreateFtpDataSocket((FtpWebRequest)_request, Socket); + _dataSocket = CreateFtpDataSocket((FtpWebRequest)_request!, Socket); } catch (ObjectDisposedException) { throw ExceptionHelper.RequestAbortedException; } - IPEndPoint localEndPoint = new IPEndPoint(((IPEndPoint)Socket.LocalEndPoint).Address, 0); + IPEndPoint localEndPoint = new IPEndPoint(((IPEndPoint)Socket.LocalEndPoint!).Address, 0); _dataSocket.Bind(localEndPoint); _passiveEndPoint = new IPEndPoint(ServerAddress, port); @@ -695,12 +694,12 @@ private PipelineInstruction QueueOrCreateDataConection(PipelineEntry entry, Resp if (NetEventSource.IsEnabled) NetEventSource.Info(this, "starting Connect()"); if (_isAsync) { - _dataSocket.BeginConnect(passiveEndPoint, s_connectCallbackDelegate, this); + _dataSocket!.BeginConnect(passiveEndPoint, s_connectCallbackDelegate, this); result = PipelineInstruction.Pause; } else { - _dataSocket.Connect(passiveEndPoint); + _dataSocket!.Connect(passiveEndPoint); result = PipelineInstruction.Advance; // for passive mode we end up going to the next command } } @@ -710,16 +709,16 @@ private PipelineInstruction QueueOrCreateDataConection(PipelineEntry entry, Resp if (_isAsync) { - _dataSocket.BeginAccept(s_acceptCallbackDelegate, this); + _dataSocket!.BeginAccept(s_acceptCallbackDelegate, this); result = PipelineInstruction.Pause; } else { - Socket listenSocket = _dataSocket; + Socket listenSocket = _dataSocket!; try { - _dataSocket = _dataSocket.Accept(); - if (!ServerAddress.Equals(((IPEndPoint)_dataSocket.RemoteEndPoint).Address)) + _dataSocket = _dataSocket!.Accept(); + if (!ServerAddress.Equals(((IPEndPoint)_dataSocket.RemoteEndPoint!).Address)) { _dataSocket.Close(); throw new WebException(SR.net_ftp_active_address_different, WebExceptionStatus.ProtocolError); @@ -839,14 +838,14 @@ internal Uri ResponseUri { get { - return _responseUri; + return _responseUri!; } } /// /// Returns the server message sent before user credentials are sent /// - internal string BannerMessage + internal string? BannerMessage { get { @@ -857,7 +856,7 @@ internal string BannerMessage /// /// Returns the server message sent after user credentials are sent /// - internal string WelcomeMessage + internal string? WelcomeMessage { get { @@ -868,7 +867,7 @@ internal string WelcomeMessage /// /// Returns the exit sent message on shutdown /// - internal string ExitMessage + internal string? ExitMessage { get { @@ -966,7 +965,7 @@ private void TryUpdateResponseUri(string str, FtpWebRequest request) baseUri = uriBuilder.Uri; } - Uri newUri; + Uri? newUri; if (!Uri.TryCreate(baseUri, escapedFilename, out newUri)) { throw new FormatException(SR.Format(SR.net_ftp_invalid_response_filename, filename)); @@ -1076,7 +1075,7 @@ private int GetPortV6(string responseString) private void CreateFtpListenerSocket(FtpWebRequest request) { // Gets an IPEndPoint for the local host for the data socket to bind to. - IPEndPoint epListener = new IPEndPoint(((IPEndPoint)Socket.LocalEndPoint).Address, 0); + IPEndPoint epListener = new IPEndPoint(((IPEndPoint)Socket.LocalEndPoint!).Address, 0); try { _dataSocket = CreateFtpDataSocket(request, Socket); @@ -1099,7 +1098,7 @@ private string GetPortCommandLine(FtpWebRequest request) try { // retrieves the IP address of the local endpoint - IPEndPoint localEP = (IPEndPoint)_dataSocket.LocalEndPoint; + IPEndPoint localEP = (IPEndPoint)_dataSocket!.LocalEndPoint!; if (ServerAddress.AddressFamily == AddressFamily.InterNetwork || ServerAddress.IsIPv4MappedToIPv6) { return FormatAddress(localEP.Address, localEP.Port); @@ -1122,7 +1121,7 @@ private string GetPortCommandLine(FtpWebRequest request) /// /// Formats a simple FTP command + parameter in correct pre-wire format /// - private string FormatFtpCommand(string command, string parameter) + private string FormatFtpCommand(string command, string? parameter) { StringBuilder stringBuilder = new StringBuilder(command.Length + ((parameter != null) ? parameter.Length : 0) + 3 /*size of ' ' \r\n*/); stringBuilder.Append(command); @@ -1228,7 +1227,7 @@ protected override bool CheckValid(ResponseDescription response, ref int validTh /// private TriState IsFtpDataStreamWriteable() { - FtpWebRequest request = _request as FtpWebRequest; + FtpWebRequest? request = _request as FtpWebRequest; if (request != null) { if (request.MethodInfo.IsUpload) diff --git a/src/libraries/System.Net.Requests/src/System/Net/FtpDataStream.cs b/src/libraries/System.Net.Requests/src/System/Net/FtpDataStream.cs index 40c048620e9792..b40457020acd3b 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/FtpDataStream.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/FtpDataStream.cs @@ -88,10 +88,10 @@ void ICloseEx.CloseEx(CloseExState closeState) catch (Exception exception) { bool doThrow = true; - WebException webException = exception as WebException; + WebException? webException = exception as WebException; if (webException != null) { - FtpWebResponse response = webException.Response as FtpWebResponse; + FtpWebResponse? response = webException.Response as FtpWebResponse; if (response != null) { if (!_isFullyRead @@ -210,7 +210,7 @@ public override void Write(byte[] buffer, int offset, int size) private void AsyncReadCallback(IAsyncResult ar) { - LazyAsyncResult userResult = (LazyAsyncResult)ar.AsyncState; + LazyAsyncResult userResult = (LazyAsyncResult)ar.AsyncState!; try { try @@ -233,7 +233,7 @@ private void AsyncReadCallback(IAsyncResult ar) catch { } } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback? callback, object? state) { CheckError(); LazyAsyncResult userResult = new LazyAsyncResult(this, state, callback); @@ -253,7 +253,7 @@ public override int EndRead(IAsyncResult ar) { try { - object result = ((LazyAsyncResult)ar).InternalWaitForCompletion(); + object result = ((LazyAsyncResult)ar).InternalWaitForCompletion()!; if (result is Exception e) { @@ -268,7 +268,7 @@ public override int EndRead(IAsyncResult ar) } } - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback? callback, object? state) { CheckError(); try diff --git a/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs index 65aebf79a995ab..de94b5c088de6f 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; -using System.Globalization; using System.IO; using System.Net.Cache; using System.Net.Sockets; @@ -12,7 +10,7 @@ using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading; -using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; namespace System.Net { @@ -54,12 +52,12 @@ internal class FtpMethodInfo internal string Method; internal FtpOperation Operation; internal FtpMethodFlags Flags; - internal string HttpCommand; + internal string? HttpCommand; internal FtpMethodInfo(string method, FtpOperation operation, FtpMethodFlags flags, - string httpCommand) + string? httpCommand) { Method = method; Operation = operation; @@ -187,7 +185,7 @@ public sealed class FtpWebRequest : WebRequest private ICredentials _authInfo; private readonly Uri _uri; private FtpMethodInfo _methodInfo; - private string _renameTo = null; + private string? _renameTo; private bool _getRequestStreamStarted; private bool _getResponseStarted; private DateTime _startTime; @@ -195,33 +193,33 @@ public sealed class FtpWebRequest : WebRequest private int _remainingTimeout; private long _contentLength = 0; private long _contentOffset = 0; - private X509CertificateCollection _clientCertificates; + private X509CertificateCollection? _clientCertificates; private bool _passive = true; private bool _binary = true; - private string _connectionGroupName; - private ServicePoint _servicePoint; + private string? _connectionGroupName; + private ServicePoint? _servicePoint; private bool _async; private bool _aborted; private bool _timedOut; - private Exception _exception; + private Exception? _exception; - private TimerThread.Queue _timerQueue = s_DefaultTimerQueue; + private TimerThread.Queue? _timerQueue = s_DefaultTimerQueue; private readonly TimerThread.Callback _timerCallback; private bool _enableSsl; - private FtpControlStream _connection; - private Stream _stream; + private FtpControlStream? _connection; + private Stream? _stream; private RequestStage _requestStage; private bool _onceFailed; - private WebHeaderCollection _ftpRequestHeaders; - private FtpWebResponse _ftpWebResponse; + private WebHeaderCollection? _ftpRequestHeaders; + private FtpWebResponse? _ftpWebResponse; private int _readWriteTimeout = 5 * 60 * 1000; // 5 minutes. - private ContextAwareResult _writeAsyncResult; - private LazyAsyncResult _readAsyncResult; - private LazyAsyncResult _requestCompleteAsyncResult; + private ContextAwareResult? _writeAsyncResult; + private LazyAsyncResult? _readAsyncResult; + private LazyAsyncResult? _requestCompleteAsyncResult; private static readonly NetworkCredential s_defaultFtpNetworkCredential = new NetworkCredential("anonymous", "anonymous@", string.Empty); private const int s_DefaultTimeout = 100000; // 100 seconds @@ -236,7 +234,7 @@ internal FtpMethodInfo MethodInfo } } - public static new RequestCachePolicy DefaultCachePolicy + public static new RequestCachePolicy? DefaultCachePolicy { get { @@ -287,7 +285,8 @@ public override string Method /// Not allowed to be changed once request is started. /// /// - public string RenameTo + [DisallowNull] + public string? RenameTo { get { @@ -312,7 +311,8 @@ public string RenameTo /// /// Used for clear text authentication with FTP server /// - public override ICredentials Credentials + [DisallowNull] + public override ICredentials? Credentials { get { @@ -446,7 +446,7 @@ public override long ContentLength } } - public override IWebProxy Proxy + public override IWebProxy? Proxy { get { @@ -463,7 +463,7 @@ public override IWebProxy Proxy } } - public override string ConnectionGroupName + public override string? ConnectionGroupName { get { @@ -479,17 +479,7 @@ public override string ConnectionGroupName } } - public ServicePoint ServicePoint - { - get - { - if (_servicePoint == null) - { - _servicePoint = ServicePointManager.FindServicePoint(_uri); - } - return _servicePoint; - } - } + public ServicePoint ServicePoint => _servicePoint ??= ServicePointManager.FindServicePoint(_uri); internal bool Aborted { @@ -509,7 +499,7 @@ internal FtpWebRequest(Uri uri) _timerCallback = new TimerThread.Callback(TimerCallback); _syncObject = new object(); - NetworkCredential networkCredential = null; + NetworkCredential? networkCredential = null; _uri = uri; _methodInfo = FtpMethodInfo.GetMethodInfo(WebRequestMethods.Ftp.DownloadFile); if (_uri.UserInfo != null && _uri.UserInfo.Length != 0) @@ -622,13 +612,13 @@ public override WebResponse GetResponse() { if (NetEventSource.IsEnabled) NetEventSource.Exit(this, _ftpWebResponse); } - return _ftpWebResponse; + return _ftpWebResponse!; } /// /// Used to query for the Response of an FTP request [async version] /// - public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) + public override IAsyncResult BeginGetResponse(AsyncCallback? callback, object? state) { if (NetEventSource.IsEnabled) { @@ -636,7 +626,7 @@ public override IAsyncResult BeginGetResponse(AsyncCallback callback, object sta NetEventSource.Info(this, $"Method: {_methodInfo.Method}"); } - ContextAwareResult asyncResult; + ContextAwareResult? asyncResult; try { @@ -721,7 +711,7 @@ public override WebResponse EndGetResponse(IAsyncResult asyncResult) { throw new ArgumentNullException(nameof(asyncResult)); } - LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult; + LazyAsyncResult? castedAsyncResult = asyncResult as LazyAsyncResult; if (castedAsyncResult == null) { throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult)); @@ -745,7 +735,7 @@ public override WebResponse EndGetResponse(IAsyncResult asyncResult) if (NetEventSource.IsEnabled) NetEventSource.Exit(this); } - return _ftpWebResponse; + return _ftpWebResponse!; } /// @@ -790,7 +780,7 @@ public override Stream GetRequestStream() FinishRequestStage(RequestStage.WriteReady); CheckError(); - if (_stream.CanTimeout) + if (_stream!.CanTimeout) { _stream.WriteTimeout = ReadWriteTimeout; _stream.ReadTimeout = ReadWriteTimeout; @@ -811,7 +801,7 @@ public override Stream GetRequestStream() /// /// Used to query for the Request stream of an FTP Request [async version] /// - public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state) + public override IAsyncResult BeginGetRequestStream(AsyncCallback? callback, object? state) { if (NetEventSource.IsEnabled) { @@ -819,7 +809,7 @@ public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, objec NetEventSource.Info(this, $"Method: {_methodInfo.Method}"); } - ContextAwareResult asyncResult = null; + ContextAwareResult? asyncResult = null; try { if (_getRequestStreamStarted) @@ -859,7 +849,7 @@ public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, objec public override Stream EndGetRequestStream(IAsyncResult asyncResult) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this); - Stream requestStream = null; + Stream? requestStream = null; try { if (asyncResult == null) @@ -867,7 +857,7 @@ public override Stream EndGetRequestStream(IAsyncResult asyncResult) throw new ArgumentNullException(nameof(asyncResult)); } - LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult; + LazyAsyncResult? castedAsyncResult = asyncResult as LazyAsyncResult; if (castedAsyncResult == null) { @@ -885,7 +875,7 @@ public override Stream EndGetRequestStream(IAsyncResult asyncResult) requestStream = _stream; castedAsyncResult.EndCalled = true; - if (requestStream.CanTimeout) + if (requestStream!.CanTimeout) { requestStream.WriteTimeout = ReadWriteTimeout; requestStream.ReadTimeout = ReadWriteTimeout; @@ -916,11 +906,11 @@ private void SubmitRequest(bool isAsync) // // FYI: Will do 2 attempts max as per AttemptedRecovery // - Stream stream; + Stream? stream; while (true) { - FtpControlStream connection = _connection; + FtpControlStream? connection = _connection; if (connection == null) { @@ -981,20 +971,16 @@ private void SubmitRequest(bool isAsync) catch (WebException webException) { // If this was a timeout, throw a timeout exception - IOException ioEx = webException.InnerException as IOException; - if (ioEx != null) + if (webException.InnerException is IOException ioEx && + ioEx.InnerException is SocketException sEx && + sEx.SocketErrorCode == SocketError.TimedOut) { - SocketException sEx = ioEx.InnerException as SocketException; - if (sEx != null) - { - if (sEx.SocketErrorCode == SocketError.TimedOut) - { - SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new WebException(SR.net_timeout, WebExceptionStatus.Timeout))); - } - } + SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new WebException(SR.net_timeout, WebExceptionStatus.Timeout))); + } + else + { + SetException(webException); } - - SetException(webException); } catch (Exception exception) { @@ -1004,8 +990,7 @@ private void SubmitRequest(bool isAsync) private Exception TranslateConnectException(Exception e) { - SocketException se = e as SocketException; - if (se != null) + if (e is SocketException se) { if (se.SocketErrorCode == SocketError.HostNotFound) { @@ -1061,22 +1046,22 @@ private FtpControlStream CreateConnection() return new FtpControlStream(client); } - private Stream TimedSubmitRequestHelper(bool isAsync) + private Stream? TimedSubmitRequestHelper(bool isAsync) { if (isAsync) { // non-null in the case of re-submit (recovery) if (_requestCompleteAsyncResult == null) _requestCompleteAsyncResult = new LazyAsyncResult(null, null, null); - return _connection.SubmitRequest(this, true, true); + return _connection!.SubmitRequest(this, true, true)!; } - Stream stream = null; + Stream? stream = null; bool timedOut = false; TimerThread.Timer timer = TimerQueue.CreateTimer(_timerCallback, null); try { - stream = _connection.SubmitRequest(this, false, true); + stream = _connection!.SubmitRequest(this, false, true); } catch (Exception exception) { @@ -1115,11 +1100,11 @@ private Stream TimedSubmitRequestHelper(bool isAsync) /// /// Because this is called from the timer thread, neither it nor any methods it calls can call user code. /// - private void TimerCallback(TimerThread.Timer timer, int timeNoticed, object context) + private void TimerCallback(TimerThread.Timer timer, int timeNoticed, object? context) { if (NetEventSource.IsEnabled) NetEventSource.Info(this); - FtpControlStream connection = _connection; + FtpControlStream? connection = _connection; if (connection != null) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, "aborting connection"); @@ -1185,7 +1170,7 @@ private void SetException(Exception exception) throw exception; } - FtpControlStream connection = _connection; + FtpControlStream? connection = _connection; if (_exception == null) { if (exception is WebException) @@ -1223,7 +1208,7 @@ private void CheckError() } } - internal void RequestCallback(object obj) + internal void RequestCallback(object? obj) { if (_async) AsyncRequestCallback(obj); @@ -1234,7 +1219,7 @@ internal void RequestCallback(object obj) // // Only executed for Sync requests when the pipline is completed // - private void SyncRequestCallback(object obj) + private void SyncRequestCallback(object? obj) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this, obj); @@ -1242,7 +1227,7 @@ private void SyncRequestCallback(object obj) try { bool completedRequest = obj == null; - Exception exception = obj as Exception; + Exception? exception = obj as Exception; if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"exp:{exception} completedRequest:{completedRequest}"); @@ -1256,7 +1241,7 @@ private void SyncRequestCallback(object obj) } else { - FtpControlStream connection = _connection; + FtpControlStream? connection = _connection; if (connection != null) { @@ -1264,7 +1249,7 @@ private void SyncRequestCallback(object obj) // This to update response status and exit message if any. // Note that status 221 "Service closing control connection" is always suppressed. - _ftpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage); + _ftpWebResponse!.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage); } stageMode = RequestStage.ReleaseConnection; @@ -1285,17 +1270,16 @@ private void SyncRequestCallback(object obj) // // Only executed for Async requests // - private void AsyncRequestCallback(object obj) + private void AsyncRequestCallback(object? obj) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this, obj); RequestStage stageMode = RequestStage.CheckForError; try { - FtpControlStream connection; - connection = obj as FtpControlStream; - FtpDataStream stream = obj as FtpDataStream; - Exception exception = obj as Exception; + FtpControlStream? connection = obj as FtpControlStream; + FtpDataStream? stream = obj as FtpDataStream; + Exception? exception = obj as Exception; bool completedRequest = (obj == null); @@ -1335,7 +1319,7 @@ private void AsyncRequestCallback(object obj) try { - stream = (FtpDataStream)TimedSubmitRequestHelper(true); + stream = (FtpDataStream?)TimedSubmitRequestHelper(true); } catch (Exception e) { @@ -1371,7 +1355,7 @@ private void AsyncRequestCallback(object obj) // This to update response status and exit message if any. // Note that the status 221 "Service closing control connection" is always suppressed. - _ftpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage); + _ftpWebResponse!.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage); } stageMode = RequestStage.ReleaseConnection; @@ -1414,9 +1398,9 @@ private RequestStage FinishRequestStage(RequestStage stage) stage = RequestStage.ReleaseConnection; RequestStage prev; - LazyAsyncResult writeResult; - LazyAsyncResult readResult; - FtpControlStream connection; + LazyAsyncResult? writeResult; + LazyAsyncResult? readResult; + FtpControlStream? connection; lock (_syncObject) { @@ -1447,7 +1431,7 @@ private RequestStage FinishRequestStage(RequestStage stage) !_aborted && prev != RequestStage.ReadReady && _methodInfo.IsDownload && - !_ftpWebResponse.IsFromCache) + !_ftpWebResponse!.IsFromCache) { return prev; } @@ -1523,8 +1507,8 @@ public override void Abort() try { - Stream stream; - FtpControlStream connection; + Stream? stream; + FtpControlStream? connection; lock (_syncObject) { if (_requestStage >= RequestStage.ReleaseConnection) @@ -1575,7 +1559,7 @@ public bool KeepAlive } } - public override RequestCachePolicy CachePolicy + public override RequestCachePolicy? CachePolicy { get { @@ -1679,7 +1663,7 @@ public override WebHeaderCollection Headers } // NOT SUPPORTED method - public override string ContentType + public override string? ContentType { get { @@ -1738,7 +1722,7 @@ private bool InUse /// /// Creates an FTP WebResponse based off the responseStream and our active Connection /// - private void EnsureFtpWebResponse(Exception exception) + private void EnsureFtpWebResponse(Exception? exception) { if (_ftpWebResponse == null || (_ftpWebResponse.GetResponseStream() is FtpWebResponse.EmptyStream && _stream != null)) { @@ -1746,7 +1730,7 @@ private void EnsureFtpWebResponse(Exception exception) { if (_ftpWebResponse == null || (_ftpWebResponse.GetResponseStream() is FtpWebResponse.EmptyStream && _stream != null)) { - Stream responseStream = _stream; + Stream? responseStream = _stream; if (_methodInfo.IsUpload) { @@ -1759,7 +1743,7 @@ private void EnsureFtpWebResponse(Exception exception) _stream.WriteTimeout = ReadWriteTimeout; } - FtpControlStream connection = _connection; + FtpControlStream? connection = _connection; long contentLength = connection != null ? connection.ContentLength : -1; if (responseStream == null) @@ -1804,13 +1788,13 @@ internal void DataStreamClosed(CloseExState closeState) } else { - _requestCompleteAsyncResult.InternalWaitForCompletion(); + _requestCompleteAsyncResult!.InternalWaitForCompletion(); CheckError(); } } else { - FtpControlStream connection = _connection; + FtpControlStream? connection = _connection; if (connection != null) connection.Abort(ExceptionHelper.RequestAbortedException); } diff --git a/src/libraries/System.Net.Requests/src/System/Net/FtpWebResponse.cs b/src/libraries/System.Net.Requests/src/System/Net/FtpWebResponse.cs index 2706cf226a48d7..de1c522c63340c 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/FtpWebResponse.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/FtpWebResponse.cs @@ -11,18 +11,18 @@ namespace System.Net /// public class FtpWebResponse : WebResponse, IDisposable { - internal Stream _responseStream; + internal Stream? _responseStream; private readonly long _contentLength; private readonly Uri _responseUri; private FtpStatusCode _statusCode; - private string _statusLine; - private WebHeaderCollection _ftpRequestHeaders; + private string? _statusLine; + private WebHeaderCollection? _ftpRequestHeaders; private readonly DateTime _lastModified; - private readonly string _bannerMessage; - private readonly string _welcomeMessage; - private string _exitMessage; + private readonly string? _bannerMessage; + private readonly string? _welcomeMessage; + private string? _exitMessage; - internal FtpWebResponse(Stream responseStream, long contentLength, Uri responseUri, FtpStatusCode statusCode, string statusLine, DateTime lastModified, string bannerMessage, string welcomeMessage, string exitMessage) + internal FtpWebResponse(Stream? responseStream, long contentLength, Uri responseUri, FtpStatusCode statusCode, string? statusLine, DateTime lastModified, string? bannerMessage, string? welcomeMessage, string? exitMessage) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this, contentLength, statusLine); @@ -41,7 +41,7 @@ internal FtpWebResponse(Stream responseStream, long contentLength, Uri responseU _exitMessage = exitMessage; } - internal void UpdateStatus(FtpStatusCode statusCode, string statusLine, string exitMessage) + internal void UpdateStatus(FtpStatusCode statusCode, string? statusLine, string? exitMessage) { _statusCode = statusCode; _statusLine = statusLine; @@ -50,7 +50,7 @@ internal void UpdateStatus(FtpStatusCode statusCode, string statusLine, string e public override Stream GetResponseStream() { - Stream responseStream = null; + Stream? responseStream = null; if (_responseStream != null) { @@ -70,7 +70,7 @@ internal EmptyStream() : base(Array.Empty(), false) } } - internal void SetResponseStream(Stream stream) + internal void SetResponseStream(Stream? stream) { if (stream == null || stream == Stream.Null || stream is EmptyStream) return; @@ -149,7 +149,7 @@ public FtpStatusCode StatusCode /// /// Last status line retrieved /// - public string StatusDescription + public string? StatusDescription { get { @@ -171,7 +171,7 @@ public DateTime LastModified /// /// Returns the server message sent before user credentials are sent /// - public string BannerMessage + public string? BannerMessage { get { @@ -182,7 +182,7 @@ public string BannerMessage /// /// Returns the server message sent after user credentials are sent /// - public string WelcomeMessage + public string? WelcomeMessage { get { @@ -193,7 +193,7 @@ public string WelcomeMessage /// /// Returns the exit sent message on shutdown /// - public string ExitMessage + public string? ExitMessage { get { diff --git a/src/libraries/System.Net.Requests/src/System/Net/GlobalProxySelection.cs b/src/libraries/System.Net.Requests/src/System/Net/GlobalProxySelection.cs index 01178131bdad3b..e6ac71fee02427 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/GlobalProxySelection.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/GlobalProxySelection.cs @@ -2,63 +2,37 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Net { [Obsolete("This class has been deprecated. Please use WebRequest.DefaultWebProxy instead to access and set the global default proxy. Use 'null' instead of GetEmptyWebProxy. https://go.microsoft.com/fwlink/?linkid=14202")] public class GlobalProxySelection { // This defers to WebRequest.DefaultWebProxy, but returns EmptyWebProxy instead of null. + [AllowNull] public static IWebProxy Select { - get - { - IWebProxy proxy = WebRequest.DefaultWebProxy; - if (proxy == null) - { - proxy = GetEmptyWebProxy(); - } - return proxy; - } - - set - { - WebRequest.DefaultWebProxy = value; - } + get => WebRequest.DefaultWebProxy ?? GetEmptyWebProxy(); + set => WebRequest.DefaultWebProxy = value; } - public static IWebProxy GetEmptyWebProxy() - { - return new EmptyWebProxy(); - } + public static IWebProxy GetEmptyWebProxy() => new EmptyWebProxy(); private sealed class EmptyWebProxy : IWebProxy { - private ICredentials _credentials; + private ICredentials? _credentials; - public EmptyWebProxy() - { - } + public EmptyWebProxy() { } - public Uri GetProxy(Uri uri) - { - return uri; - } + public Uri GetProxy(Uri uri) => uri; - public bool IsBypassed(Uri uri) - { - return true; // no proxy, always bypasses - } + public bool IsBypassed(Uri uri) => true; // no proxy, always bypasses - public ICredentials Credentials + public ICredentials? Credentials { - get - { - return _credentials; - } - set - { - _credentials = value; // doesn't do anything, but doesn't break contract either - } + get => _credentials; + set => _credentials = value; // doesn't do anything, but doesn't break contract either } } } diff --git a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs index 6bfd49f554fb78..cf9b579d5d0617 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Net.Cache; @@ -11,7 +12,6 @@ using System.Runtime.Serialization; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -26,7 +26,7 @@ public class HttpWebRequest : WebRequest, ISerializable private WebHeaderCollection _webHeaderCollection = new WebHeaderCollection(); - private readonly Uri _requestUri; + private readonly Uri _requestUri = null!; private string _originVerb = HttpMethod.Get.Method; // We allow getting and setting this (to preserve app-compat). But we don't do anything with it @@ -34,11 +34,11 @@ public class HttpWebRequest : WebRequest, ISerializable private int _continueTimeout = DefaultContinueTimeout; private bool _allowReadStreamBuffering = false; - private CookieContainer _cookieContainer = null; - private ICredentials _credentials = null; - private IWebProxy _proxy = WebRequest.DefaultWebProxy; + private CookieContainer? _cookieContainer; + private ICredentials? _credentials; + private IWebProxy? _proxy = WebRequest.DefaultWebProxy; - private Task _sendRequestTask; + private Task? _sendRequestTask; private static int _defaultMaxResponseHeadersLength = HttpHandlerDefaults.DefaultMaxResponseHeadersLength; @@ -49,33 +49,33 @@ public class HttpWebRequest : WebRequest, ISerializable private int _maximumAllowedRedirections = HttpHandlerDefaults.DefaultMaxAutomaticRedirections; private int _maximumResponseHeadersLen = _defaultMaxResponseHeadersLength; - private ServicePoint _servicePoint; + private ServicePoint? _servicePoint; private int _timeout = WebRequest.DefaultTimeoutMilliseconds; private int _readWriteTimeout = DefaultReadWriteTimeout; - private HttpContinueDelegate _continueDelegate; + private HttpContinueDelegate? _continueDelegate; // stores the user provided Host header as Uri. If the user specified a default port explicitly we'll lose // that information when converting the host string to a Uri. _HostHasPort will store that information. private bool _hostHasPort; - private Uri _hostUri; + private Uri? _hostUri; - private RequestStream _requestStream; - private TaskCompletionSource _requestStreamOperation = null; - private TaskCompletionSource _responseOperation = null; - private AsyncCallback _requestStreamCallback = null; - private AsyncCallback _responseCallback = null; + private RequestStream? _requestStream; + private TaskCompletionSource? _requestStreamOperation; + private TaskCompletionSource? _responseOperation; + private AsyncCallback? _requestStreamCallback; + private AsyncCallback? _responseCallback; private int _abortCalled = 0; - private CancellationTokenSource _sendRequestCts; - private X509CertificateCollection _clientCertificates; + private CancellationTokenSource? _sendRequestCts; + private X509CertificateCollection? _clientCertificates; private Booleans _booleans = Booleans.Default; private bool _pipelined = true; private bool _preAuthenticate; private DecompressionMethods _automaticDecompression = HttpHandlerDefaults.DefaultAutomaticDecompression; private static readonly object s_syncRoot = new object(); - private static volatile HttpClient s_cachedHttpClient; - private static HttpClientParameters s_cachedHttpClientParameters; + private static volatile HttpClient? s_cachedHttpClient; + private static HttpClientParameters? s_cachedHttpClientParameters; //these should be safe. [Flags] @@ -106,11 +106,11 @@ private class HttpClientParameters public readonly TimeSpan Timeout; public readonly SecurityProtocolType SslProtocols; public readonly bool CheckCertificateRevocationList; - public readonly ICredentials Credentials; - public readonly IWebProxy Proxy; - public readonly RemoteCertificateValidationCallback ServerCertificateValidationCallback; - public readonly X509CertificateCollection ClientCertificates; - public readonly CookieContainer CookieContainer; + public readonly ICredentials? Credentials; + public readonly IWebProxy? Proxy; + public readonly RemoteCertificateValidationCallback? ServerCertificateValidationCallback; + public readonly X509CertificateCollection? ClientCertificates; + public readonly CookieContainer? CookieContainer; public HttpClientParameters(HttpWebRequest webRequest) { @@ -186,7 +186,7 @@ internal HttpWebRequest(Uri uri) _requestUri = uri; } - private void SetSpecialHeaders(string HeaderName, string value) + private void SetSpecialHeaders(string HeaderName, string? value) { _webHeaderCollection.Remove(HeaderName); if (!string.IsNullOrEmpty(value)) @@ -195,7 +195,7 @@ private void SetSpecialHeaders(string HeaderName, string value) } } - public string Accept + public string? Accept { get { @@ -252,7 +252,7 @@ public int MaximumAutomaticRedirections } } - public override string ContentType + public override string? ContentType { get { @@ -331,7 +331,7 @@ public Uri Address } } - public string UserAgent + public string? UserAgent { get { @@ -363,7 +363,7 @@ public string Host throw new ArgumentNullException(nameof(value)); } - Uri hostUri; + Uri? hostUri; if ((value.Contains('/')) || (!TryGetHostUri(value, out hostUri))) { throw new ArgumentException(SR.net_invalid_host, nameof(value)); @@ -405,7 +405,7 @@ public bool Pipelined /// Gets or sets the value of the Referer header. /// /// - public string Referer + public string? Referer { get { @@ -420,7 +420,7 @@ public string Referer /// /// Sets the media type header /// - public string MediaType + public string? MediaType { get; set; @@ -431,7 +431,7 @@ public string MediaType /// Gets or sets the value of the Transfer-Encoding header. Setting null clears it out. /// /// - public string TransferEncoding + public string? TransferEncoding { get { @@ -565,7 +565,7 @@ public virtual bool AllowAutoRedirect } } - public override string ConnectionGroupName { get; set; } + public override string? ConnectionGroupName { get; set; } public override bool PreAuthenticate { @@ -579,7 +579,7 @@ public override bool PreAuthenticate } } - public string Connection + public string? Connection { get { @@ -636,7 +636,7 @@ The property that controls the Expect header Returns: The value of the Expect on get. */ - public string Expect + public string? Expect { get { @@ -708,7 +708,7 @@ public static int DefaultMaximumErrorResponseLength get; set; } - public static new RequestCachePolicy DefaultCachePolicy { get; set; } = new RequestCachePolicy(RequestCacheLevel.BypassCache); + public static new RequestCachePolicy? DefaultCachePolicy { get; set; } = new RequestCachePolicy(RequestCacheLevel.BypassCache); public DateTime IfModifiedSince { @@ -762,7 +762,7 @@ public bool SendChunked } } - public HttpContinueDelegate ContinueDelegate + public HttpContinueDelegate? ContinueDelegate { // Nop since the underlying API do not expose 100 continue. get @@ -775,19 +775,9 @@ public HttpContinueDelegate ContinueDelegate } } - public ServicePoint ServicePoint - { - get - { - if (_servicePoint == null) - { - _servicePoint = ServicePointManager.FindServicePoint(Address, Proxy); - } - return _servicePoint; - } - } + public ServicePoint ServicePoint => _servicePoint ??= ServicePointManager.FindServicePoint(Address, Proxy); - public RemoteCertificateValidationCallback ServerCertificateValidationCallback { get; set; } + public RemoteCertificateValidationCallback? ServerCertificateValidationCallback { get; set; } // // ClientCertificates - sets our certs for our reqest, @@ -797,20 +787,8 @@ public ServicePoint ServicePoint // public X509CertificateCollection ClientCertificates { - get - { - if (_clientCertificates == null) - _clientCertificates = new X509CertificateCollection(); - return _clientCertificates; - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _clientCertificates = value; - } + get => _clientCertificates ??= new X509CertificateCollection(); + set => _clientCertificates = value ?? throw new ArgumentNullException(nameof(value)); } // HTTP Version @@ -865,7 +843,7 @@ public int ReadWriteTimeout } } - public virtual CookieContainer CookieContainer + public virtual CookieContainer? CookieContainer { get { @@ -877,7 +855,7 @@ public virtual CookieContainer CookieContainer } } - public override ICredentials Credentials + public override ICredentials? Credentials { get { @@ -983,7 +961,7 @@ public override bool UseDefaultCredentials } } - public override IWebProxy Proxy + public override IWebProxy? Proxy { get { @@ -1099,19 +1077,19 @@ private Task InternalGetRequestStream() return Task.FromResult((Stream)_requestStream); } - public Stream EndGetRequestStream(IAsyncResult asyncResult, out TransportContext context) + public Stream EndGetRequestStream(IAsyncResult asyncResult, out TransportContext? context) { context = null; return EndGetRequestStream(asyncResult); } - public Stream GetRequestStream(out TransportContext context) + public Stream GetRequestStream(out TransportContext? context) { context = null; return GetRequestStream(); } - public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state) + public override IAsyncResult BeginGetRequestStream(AsyncCallback? callback, object? state) { CheckAbort(); @@ -1163,14 +1141,14 @@ private async Task SendRequest() var request = new HttpRequestMessage(new HttpMethod(_originVerb), _requestUri); bool disposeRequired = false; - HttpClient client = null; + HttpClient? client = null; try { client = GetCachedOrCreateHttpClient(out disposeRequired); if (_requestStream != null) { ArraySegment bytes = _requestStream.GetBuffer(); - request.Content = new ByteArrayContent(bytes.Array, bytes.Offset, bytes.Count); + request.Content = new ByteArrayContent(bytes.Array!, bytes.Offset, bytes.Count); } if (_hostUri != null) @@ -1180,12 +1158,12 @@ private async Task SendRequest() // Copy the HttpWebRequest request headers from the WebHeaderCollection into HttpRequestMessage.Headers and // HttpRequestMessage.Content.Headers. - foreach (string headerName in _webHeaderCollection) + foreach (string? headerName in _webHeaderCollection) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/3214 { // The System.Net.Http APIs require HttpRequestMessage headers to be properly divided between the request headers // collection and the request content headers collection for all well-known header names. And custom headers // are only allowed in the request headers collection and not in the request content headers collection. - if (IsWellKnownContentHeader(headerName)) + if (IsWellKnownContentHeader(headerName!)) { if (request.Content == null) { @@ -1193,11 +1171,11 @@ private async Task SendRequest() request.Content = new ByteArrayContent(Array.Empty()); } - request.Content.Headers.TryAddWithoutValidation(headerName, _webHeaderCollection[headerName]); + request.Content.Headers.TryAddWithoutValidation(headerName!, _webHeaderCollection[headerName!]); } else { - request.Headers.TryAddWithoutValidation(headerName, _webHeaderCollection[headerName]); + request.Headers.TryAddWithoutValidation(headerName!, _webHeaderCollection[headerName!]); } } @@ -1217,7 +1195,7 @@ private async Task SendRequest() _sendRequestTask = client.SendAsync( request, _allowReadStreamBuffering ? HttpCompletionOption.ResponseContentRead : HttpCompletionOption.ResponseHeadersRead, - _sendRequestCts.Token); + _sendRequestCts!.Token); HttpResponseMessage responseMessage = await _sendRequestTask.ConfigureAwait(false); HttpWebResponse response = new HttpWebResponse(responseMessage, _requestUri, _cookieContainer); @@ -1242,7 +1220,7 @@ private async Task SendRequest() } } - public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) + public override IAsyncResult BeginGetResponse(AsyncCallback? callback, object? state) { CheckAbort(); @@ -1387,9 +1365,9 @@ public void AddRange(string rangeSpecifier, long range) } } - private bool AddRange(string rangeSpecifier, string from, string to) + private bool AddRange(string rangeSpecifier, string from, string? to) { - string curRange = _webHeaderCollection[HttpKnownHeaderNames.Range]; + string? curRange = _webHeaderCollection[HttpKnownHeaderNames.Range]; if ((curRange == null) || (curRange.Length == 0)) { @@ -1460,7 +1438,7 @@ private DateTime GetDateHeaderHelper(string headerName) using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) { #endif - string headerValue = _webHeaderCollection[headerName]; + string? headerValue = _webHeaderCollection[headerName]; if (headerValue == null) { @@ -1494,7 +1472,7 @@ private void SetDateHeaderHelper(string headerName, DateTime dateTime) #endif } - private bool TryGetHostUri(string hostName, out Uri hostUri) + private bool TryGetHostUri(string hostName, [NotNullWhen(true)] out Uri? hostUri) { string s = Address.Scheme + "://" + hostName + Address.PathAndQuery; return Uri.TryCreate(s, UriKind.Absolute, out hostUri); @@ -1519,7 +1497,7 @@ private HttpClient GetCachedOrCreateHttpClient(out bool disposeRequired) } } - if (s_cachedHttpClientParameters.Matches(parameters)) + if (s_cachedHttpClientParameters!.Matches(parameters)) { return s_cachedHttpClient; } @@ -1529,9 +1507,9 @@ private HttpClient GetCachedOrCreateHttpClient(out bool disposeRequired) return CreateHttpClient(parameters, this); } - private static HttpClient CreateHttpClient(HttpClientParameters parameters, HttpWebRequest request) + private static HttpClient CreateHttpClient(HttpClientParameters parameters, HttpWebRequest? request) { - HttpClient client = null; + HttpClient? client = null; try { var handler = new HttpClientHandler(); @@ -1591,11 +1569,11 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http // Set relevant properties from ServicePointManager handler.SslProtocols = (SslProtocols)parameters.SslProtocols; handler.CheckCertificateRevocationList = parameters.CheckCertificateRevocationList; - RemoteCertificateValidationCallback rcvc = parameters.ServerCertificateValidationCallback; + RemoteCertificateValidationCallback? rcvc = parameters.ServerCertificateValidationCallback; if (rcvc != null) { RemoteCertificateValidationCallback localRcvc = rcvc; - HttpWebRequest localRequest = request; + HttpWebRequest localRequest = request!; handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => localRcvc(localRequest, cert, chain, errors); } diff --git a/src/libraries/System.Net.Requests/src/System/Net/HttpWebResponse.cs b/src/libraries/System.Net.Requests/src/System/Net/HttpWebResponse.cs index 7307c1812ef42c..e7addde19b7372 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/HttpWebResponse.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/HttpWebResponse.cs @@ -3,11 +3,10 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; -using System.Globalization; using System.IO; using System.Net.Http; -using System.Net.Http.Headers; using System.Runtime.Serialization; using System.Text; @@ -21,14 +20,20 @@ namespace System.Net /// public class HttpWebResponse : WebResponse, ISerializable { - private HttpResponseMessage _httpResponseMessage; + private HttpResponseMessage _httpResponseMessage = null!; private readonly Uri _requestUri; private CookieCollection _cookies; - private WebHeaderCollection _webHeaderCollection = null; - private string _characterSet = null; + private WebHeaderCollection? _webHeaderCollection; + private string? _characterSet; private readonly bool _isVersionHttp11 = true; - public HttpWebResponse() { } + [Obsolete("This API supports the .NET infrastructure and is not intended to be used directly from your code.", true)] + [EditorBrowsable(EditorBrowsableState.Never)] + public HttpWebResponse() + { + _requestUri = null!; + _cookies = null!; + } [ObsoleteAttribute("Serialization is obsoleted for this type. https://go.microsoft.com/fwlink/?linkid=14202")] protected HttpWebResponse(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) @@ -46,7 +51,7 @@ protected override void GetObjectData(SerializationInfo serializationInfo, Strea throw new PlatformNotSupportedException(); } - internal HttpWebResponse(HttpResponseMessage _message, Uri requestUri, CookieContainer cookieContainer) + internal HttpWebResponse(HttpResponseMessage _message, Uri requestUri, CookieContainer? cookieContainer) { _httpResponseMessage = _message; _requestUri = requestUri; @@ -74,7 +79,7 @@ public override long ContentLength get { CheckDisposed(); - long? length = _httpResponseMessage.Content.Headers.ContentLength; + long? length = _httpResponseMessage.Content?.Headers.ContentLength; return length.HasValue ? length.Value : -1; } } @@ -88,8 +93,7 @@ public override string ContentType // We use TryGetValues() instead of the strongly type Headers.ContentType property so that // we return a string regardless of it being fully RFC conformant. This matches current // .NET Framework behavior. - IEnumerable values; - if (_httpResponseMessage.Content.Headers.TryGetValues("Content-Type", out values)) + if (_httpResponseMessage.Content != null && _httpResponseMessage.Content.Headers.TryGetValues("Content-Type", out IEnumerable? values)) { // In most cases, there is only one media type value as per RFC. But for completeness, we // return all values in cases of overly malformed strings. @@ -120,7 +124,12 @@ public string ContentEncoding get { CheckDisposed(); - return GetHeaderValueAsString(_httpResponseMessage.Content.Headers.ContentEncoding); + if (_httpResponseMessage.Content != null) + { + return GetHeaderValueAsString(_httpResponseMessage.Content.Headers.ContentEncoding); + } + + return string.Empty; } } @@ -144,7 +153,7 @@ public DateTime LastModified get { CheckDisposed(); - string lastmodHeaderValue = Headers["Last-Modified"]; + string? lastmodHeaderValue = Headers["Last-Modified"]; if (string.IsNullOrEmpty(lastmodHeaderValue)) { return DateTime.Now; @@ -171,7 +180,8 @@ public string Server get { CheckDisposed(); - return string.IsNullOrEmpty(Headers["Server"]) ? string.Empty : Headers["Server"]; + string? server = Headers["Server"]; + return string.IsNullOrEmpty(server) ? string.Empty : server; } } @@ -222,7 +232,7 @@ public virtual string Method get { CheckDisposed(); - return _httpResponseMessage.RequestMessage.Method.Method; + return _httpResponseMessage.RequestMessage!.Method.Method; } } @@ -234,7 +244,7 @@ public override Uri ResponseUri // The underlying System.Net.Http API will automatically update // the .RequestUri property to be the final URI of the response. - return _httpResponseMessage.RequestMessage.RequestUri; + return _httpResponseMessage.RequestMessage!.RequestUri!; } } @@ -252,19 +262,19 @@ public virtual string StatusDescription get { CheckDisposed(); - return _httpResponseMessage.ReasonPhrase; + return _httpResponseMessage.ReasonPhrase ?? string.Empty; } } /// /// [To be supplied.] /// - public string CharacterSet + public string? CharacterSet { get { CheckDisposed(); - string contentType = Headers["Content-Type"]; + string? contentType = Headers["Content-Type"]; if (_characterSet == null && !string.IsNullOrWhiteSpace(contentType)) { @@ -337,14 +347,19 @@ public override bool SupportsHeaders public override Stream GetResponseStream() { CheckDisposed(); - return _httpResponseMessage.Content.ReadAsStreamAsync().GetAwaiter().GetResult(); + if (_httpResponseMessage.Content != null) + { + return _httpResponseMessage.Content.ReadAsStreamAsync().GetAwaiter().GetResult(); + } + + return Stream.Null; } public string GetResponseHeader(string headerName) { CheckDisposed(); - string headerValue = Headers[headerName]; - return ((headerValue == null) ? string.Empty : headerValue); + string? headerValue = Headers[headerName]; + return (headerValue == null) ? string.Empty : headerValue; } public override void Close() @@ -358,7 +373,7 @@ protected override void Dispose(bool disposing) if (httpResponseMessage != null) { httpResponseMessage.Dispose(); - _httpResponseMessage = null; + _httpResponseMessage = null!; } } diff --git a/src/libraries/System.Net.Requests/src/System/Net/IAuthenticationModule.cs b/src/libraries/System.Net.Requests/src/System/Net/IAuthenticationModule.cs index ea18022f53ee31..273fe03cb7bfc7 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/IAuthenticationModule.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/IAuthenticationModule.cs @@ -6,8 +6,8 @@ namespace System.Net { public interface IAuthenticationModule { - Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials); - Authorization PreAuthenticate(WebRequest request, ICredentials credentials); + Authorization? Authenticate(string challenge, WebRequest request, ICredentials credentials); + Authorization? PreAuthenticate(WebRequest request, ICredentials credentials); bool CanPreAuthenticate { get; } string AuthenticationType { get; } } diff --git a/src/libraries/System.Net.Requests/src/System/Net/IWebRequestCreate.cs b/src/libraries/System.Net.Requests/src/System/Net/IWebRequestCreate.cs index d13f4d782c8735..0f5c44d57dc7fe 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/IWebRequestCreate.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/IWebRequestCreate.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; - namespace System.Net { /// diff --git a/src/libraries/System.Net.Requests/src/System/Net/NetRes.cs b/src/libraries/System.Net.Requests/src/System/Net/NetRes.cs index 5be6fd5d24590e..193eb1bd8ef79d 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/NetRes.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/NetRes.cs @@ -8,10 +8,10 @@ namespace System.Net { internal static class NetRes { - public static string GetWebStatusCodeString(FtpStatusCode statusCode, string statusDescription) + public static string GetWebStatusCodeString(FtpStatusCode statusCode, string? statusDescription) { string webStatusCode = "(" + ((int)statusCode).ToString(NumberFormatInfo.InvariantInfo) + ")"; - string statusMessage = null; + string? statusMessage = null; switch (statusCode) { diff --git a/src/libraries/System.Net.Requests/src/System/Net/NetworkStreamWrapper.cs b/src/libraries/System.Net.Requests/src/System/Net/NetworkStreamWrapper.cs index c33981794e0a04..d881bd7eaaa74a 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/NetworkStreamWrapper.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/NetworkStreamWrapper.cs @@ -32,7 +32,7 @@ internal IPAddress ServerAddress { get { - return ((IPEndPoint)Socket.RemoteEndPoint).Address; + return ((IPEndPoint)Socket.RemoteEndPoint!).Address; } } @@ -175,7 +175,7 @@ public void Close(int timeout) _client.Dispose(); } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback? callback, object? state) { return _networkStream.BeginRead(buffer, offset, size, callback, state); } @@ -190,7 +190,7 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel return _networkStream.ReadAsync(buffer, offset, count, cancellationToken); } - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback? callback, object? state) { return _networkStream.BeginWrite(buffer, offset, size, callback, state); } diff --git a/src/libraries/System.Net.Requests/src/System/Net/ProtocolViolationException.cs b/src/libraries/System.Net.Requests/src/System/Net/ProtocolViolationException.cs index 6773fef2a6737b..34515900a4d0a4 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/ProtocolViolationException.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/ProtocolViolationException.cs @@ -31,7 +31,7 @@ public ProtocolViolationException() : base() /// class with the specified message. /// /// - public ProtocolViolationException(string message) : base(message) + public ProtocolViolationException(string? message) : base(message) { } diff --git a/src/libraries/System.Net.Requests/src/System/Net/RequestStream.cs b/src/libraries/System.Net.Requests/src/System/Net/RequestStream.cs index 278d85e43356d4..4717f3f7ee31d0 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/RequestStream.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/RequestStream.cs @@ -2,11 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -131,7 +128,7 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati return _buffer.WriteAsync(buffer, offset, count, cancellationToken); } - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) { if (buffer == null) { diff --git a/src/libraries/System.Net.Requests/src/System/Net/TaskExtensions.cs b/src/libraries/System.Net.Requests/src/System/Net/TaskExtensions.cs index 3600c4f948488e..b191aec05938ad 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/TaskExtensions.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/TaskExtensions.cs @@ -12,8 +12,8 @@ internal static class TaskExtensions { public static TaskCompletionSource ToApm( this Task task, - AsyncCallback callback, - object state) + AsyncCallback? callback, + object? state) { TaskCompletionSource tcs = new TaskCompletionSource(state); @@ -23,7 +23,7 @@ public static TaskCompletionSource ToApm( if (completedTask.IsFaulted) { - shouldInvokeCallback = tcs.TrySetException(completedTask.Exception.InnerExceptions); + shouldInvokeCallback = tcs.TrySetException(completedTask.Exception!.InnerExceptions); } else if (completedTask.IsCanceled) { diff --git a/src/libraries/System.Net.Requests/src/System/Net/TimerThread.cs b/src/libraries/System.Net.Requests/src/System/Net/TimerThread.cs index 7cfcaa9086bbeb..a64a6ca5775dbf 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/TimerThread.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/TimerThread.cs @@ -34,7 +34,7 @@ internal Queue(int durationMilliseconds) /// /// Creates and returns a handle to a new timer with attached context. /// - internal abstract Timer CreateTimer(Callback callback, object context); + internal abstract Timer CreateTimer(Callback callback, object? context); } /// @@ -77,7 +77,7 @@ internal Timer(int durationMilliseconds) /// /// Prototype for the callback that is called when a timer expires. /// - internal delegate void Callback(Timer timer, int timeNoticed, object context); + internal delegate void Callback(Timer timer, int timeNoticed, object? context); private const int ThreadIdleTimeoutMilliseconds = 30 * 1000; private const int CacheScanPerIterations = 32; @@ -117,15 +117,15 @@ internal static Queue GetOrCreateQueue(int durationMilliseconds) throw new ArgumentOutOfRangeException(nameof(durationMilliseconds)); } - TimerQueue queue; + TimerQueue? queue; object key = durationMilliseconds; // Box once. - WeakReference weakQueue = (WeakReference)s_queuesCache[key]; - if (weakQueue == null || (queue = (TimerQueue)weakQueue.Target) == null) + WeakReference? weakQueue = (WeakReference?)s_queuesCache[key]; + if (weakQueue == null || (queue = (TimerQueue?)weakQueue.Target) == null) { lock (s_newQueues) { - weakQueue = (WeakReference)s_queuesCache[key]; - if (weakQueue == null || (queue = (TimerQueue)weakQueue.Target) == null) + weakQueue = (WeakReference?)s_queuesCache[key]; + if (weakQueue == null || (queue = (TimerQueue?)weakQueue.Target) == null) { queue = new TimerQueue(durationMilliseconds); weakQueue = new WeakReference(queue); @@ -141,7 +141,7 @@ internal static Queue GetOrCreateQueue(int durationMilliseconds) while (e.MoveNext()) { DictionaryEntry pair = e.Entry; - if (((WeakReference)pair.Value).Target == null) + if (((WeakReference)pair.Value!).Target == null) { garbage.Add(pair.Key); } @@ -192,7 +192,7 @@ internal TimerQueue(int durationMilliseconds) : /// /// Creates new timers. This method is thread-safe. /// - internal override Timer CreateTimer(Callback callback, object context) + internal override Timer CreateTimer(Callback callback, object? context) { TimerNode timer = new TimerNode(callback, context, Duration, _timers); @@ -200,7 +200,7 @@ internal override Timer CreateTimer(Callback callback, object context) bool needProd = false; lock (_timers) { - if (!(_timers.Prev.Next == _timers)) + if (!(_timers.Prev!.Next == _timers)) { NetEventSource.Fail(this, $"Tail corruption."); } @@ -240,12 +240,12 @@ internal bool Fire(out int nextExpiration) while (true) { // Check if we got to the end. If so, free the handle. - TimerNode timer = _timers.Next; + TimerNode timer = _timers.Next!; if (timer == _timers) { lock (_timers) { - timer = _timers.Next; + timer = _timers.Next!; if (timer == _timers) { if (_thisHandle != IntPtr.Zero) @@ -279,7 +279,7 @@ internal InfiniteTimerQueue() : base(Timeout.Infinite) { } /// /// Always returns a dummy infinite timer. /// - internal override Timer CreateTimer(Callback callback, object context) => new InfiniteTimer(); + internal override Timer CreateTimer(Callback callback, object? context) => new InfiniteTimer(); } /// @@ -288,11 +288,11 @@ internal InfiniteTimerQueue() : base(Timeout.Infinite) { } private class TimerNode : Timer { private TimerState _timerState; - private Callback _callback; - private object _context; - private readonly object _queueLock; - private TimerNode _next; - private TimerNode _prev; + private Callback? _callback; + private object? _context; + private readonly object _queueLock = null!; + private TimerNode? _next; + private TimerNode? _prev; /// /// Status of the timer. @@ -305,7 +305,7 @@ private enum TimerState Sentinel } - internal TimerNode(Callback callback, object context, int durationMilliseconds, object queueLock) : base(durationMilliseconds) + internal TimerNode(Callback callback, object? context, int durationMilliseconds, object queueLock) : base(durationMilliseconds) { if (callback != null) { @@ -325,13 +325,13 @@ internal TimerNode() : base(0) internal override bool HasExpired => _timerState == TimerState.Fired; - internal TimerNode Next + internal TimerNode? Next { get { return _next; } set { _next = value; } } - internal TimerNode Prev + internal TimerNode? Prev { get { return _prev; } set { _prev = value; } @@ -351,8 +351,8 @@ internal override bool Cancel() // Remove it from the list. This keeps the list from getting too big when there are a lot of rapid creations // and cancellations. This is done before setting it to Cancelled to try to prevent the Fire() loop from // seeing it, or if it does, of having to take a lock to synchronize with the state of the list. - Next.Prev = Prev; - Prev.Next = Next; + Next!.Prev = Prev; + Prev!.Next = Next; // Just cleanup. Doesn't need to be in the lock but is easier to have here. Next = null; @@ -406,8 +406,8 @@ internal bool Fire() _timerState = TimerState.Fired; // Remove it from the list. - Next.Prev = Prev; - Prev.Next = Next; + Next!.Prev = Prev; + Prev!.Next = Next; Next = null; Prev = null; @@ -419,8 +419,8 @@ internal bool Fire() { try { - Callback callback = _callback; - object context = _context; + Callback callback = _callback!; + object? context = _context; _callback = null; _context = null; callback(this, nowMilliseconds, context); @@ -517,7 +517,7 @@ private static void ThreadProc() { lock (s_newQueues) { - for (LinkedListNode node = s_newQueues.First; node != null; node = s_newQueues.First) + for (LinkedListNode? node = s_newQueues.First; node != null; node = s_newQueues.First) { s_newQueues.Remove(node); s_queues.AddLast(node); @@ -528,12 +528,12 @@ private static void ThreadProc() int now = Environment.TickCount; int nextTick = 0; bool haveNextTick = false; - for (LinkedListNode node = s_queues.First; node != null; /* node = node.Next must be done in the body */) + for (LinkedListNode? node = s_queues.First; node != null; /* node = node.Next must be done in the body */) { - TimerQueue queue = (TimerQueue)node.Value.Target; + TimerQueue? queue = (TimerQueue?)node.Value.Target; if (queue == null) { - LinkedListNode next = node.Next; + LinkedListNode? next = node.Next; s_queues.Remove(node); node = next; continue; diff --git a/src/libraries/System.Net.Requests/src/System/Net/WebException.cs b/src/libraries/System.Net.Requests/src/System/Net/WebException.cs index 52189652f44424..88fa5867ab0b36 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/WebException.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/WebException.cs @@ -17,31 +17,31 @@ public partial class WebException : InvalidOperationException, ISerializable private const WebExceptionStatus DefaultStatus = WebExceptionStatus.UnknownError; private readonly WebExceptionStatus _status = DefaultStatus; - private readonly WebResponse _response = null; + private readonly WebResponse? _response; public WebException() { } - public WebException(string message) : + public WebException(string? message) : base(message) { } - public WebException(string message, Exception innerException) : + public WebException(string? message, Exception? innerException) : this(message, innerException, DefaultStatus, null) { } - public WebException(string message, WebExceptionStatus status) : + public WebException(string? message, WebExceptionStatus status) : this(message, null, status, null) { } - public WebException(string message, - Exception innerException, + public WebException(string? message, + Exception? innerException, WebExceptionStatus status, - WebResponse response) : + WebResponse? response) : base(message, innerException) { _status = status; @@ -58,21 +58,9 @@ protected WebException(SerializationInfo serializationInfo, StreamingContext str { } - public WebExceptionStatus Status - { - get - { - return _status; - } - } + public WebExceptionStatus Status => _status; - public WebResponse Response - { - get - { - return _response; - } - } + public WebResponse? Response => _response; void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext) { @@ -109,7 +97,7 @@ internal static Exception CreateCompatibleException(Exception exception) private static WebExceptionStatus GetStatusFromExceptionHelper(HttpRequestException ex) { - SocketException socketEx = ex.InnerException as SocketException; + SocketException? socketEx = ex.InnerException as SocketException; if (socketEx is null) { diff --git a/src/libraries/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs b/src/libraries/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs index 875ac726935d24..2059f41312fc26 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Net.Http; namespace System.Net diff --git a/src/libraries/System.Net.Requests/src/System/Net/WebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/WebRequest.cs index 976b6ef53c9864..3b1d805fb24be2 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/WebRequest.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/WebRequest.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Cache; using System.Net.Http; @@ -28,7 +29,7 @@ public WebRequestPrefixElement(string prefix, IWebRequestCreate creator) } } - private static List s_prefixList; + private static List? s_prefixList; private static object s_internalSyncObject = new object(); internal const int DefaultTimeoutMilliseconds = 100 * 1000; @@ -69,7 +70,7 @@ private static WebRequest Create(Uri requestUri, bool useUriBase) if (NetEventSource.IsEnabled) NetEventSource.Enter(null, requestUri); string LookupUri; - WebRequestPrefixElement Current = null; + WebRequestPrefixElement? Current = null; bool Found = false; if (!useUriBase) @@ -121,12 +122,10 @@ private static WebRequest Create(Uri requestUri, bool useUriBase) } } - WebRequest webRequest = null; - if (Found) { // We found a match, so just call the creator and return what it does. - webRequest = Current.Creator.Create(requestUri); + WebRequest webRequest = Current!.Creator.Create(requestUri); if (NetEventSource.IsEnabled) NetEventSource.Exit(null, webRequest); return webRequest; } @@ -261,8 +260,7 @@ public static bool RegisterPrefix(string prefix, IWebRequestCreate creator) // As AbsoluteUri is used later for Create, account for formating changes // like Unicode escaping, default ports, etc. - Uri tempUri; - if (Uri.TryCreate(prefix, UriKind.Absolute, out tempUri)) + if (Uri.TryCreate(prefix, UriKind.Absolute, out Uri? tempUri)) { string cookedUri = tempUri.AbsoluteUri; @@ -385,15 +383,15 @@ internal static List PrefixList } } - public static RequestCachePolicy DefaultCachePolicy { get; set; } = new RequestCachePolicy(RequestCacheLevel.BypassCache); + public static RequestCachePolicy? DefaultCachePolicy { get; set; } = new RequestCachePolicy(RequestCacheLevel.BypassCache); - public virtual RequestCachePolicy CachePolicy { get; set; } + public virtual RequestCachePolicy? CachePolicy { get; set; } public AuthenticationLevel AuthenticationLevel { get; set; } = AuthenticationLevel.MutualAuthRequested; public TokenImpersonationLevel ImpersonationLevel { get; set; } = TokenImpersonationLevel.Delegation; - public virtual string ConnectionGroupName + public virtual string? ConnectionGroupName { get { @@ -449,7 +447,7 @@ public virtual long ContentLength } } - public virtual string ContentType + public virtual string? ContentType { get { @@ -461,7 +459,8 @@ public virtual string ContentType } } - public virtual ICredentials Credentials + [DisallowNull] + public virtual ICredentials? Credentials { get { @@ -507,7 +506,7 @@ public virtual WebResponse GetResponse() throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); } - public virtual IAsyncResult BeginGetResponse(AsyncCallback callback, object state) + public virtual IAsyncResult BeginGetResponse(AsyncCallback? callback, object? state) { throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); } @@ -517,7 +516,7 @@ public virtual WebResponse EndGetResponse(IAsyncResult asyncResult) throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); } - public virtual IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state) + public virtual IAsyncResult BeginGetRequestStream(AsyncCallback? callback, object? state) { throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); } @@ -537,8 +536,8 @@ public virtual Task GetRequestStreamAsync() // Unwrap() that it's worth it to just rely on Task.Run and accept the closure/delegate. return Task.Run(() => Task.Factory.FromAsync( - (callback, state) => ((WebRequest)state).BeginGetRequestStream(callback, state), - iar => ((WebRequest)iar.AsyncState).EndGetRequestStream(iar), + (callback, state) => ((WebRequest)state!).BeginGetRequestStream(callback, state), + iar => ((WebRequest)iar.AsyncState!).EndGetRequestStream(iar), this)); } @@ -547,8 +546,8 @@ public virtual Task GetResponseAsync() // See comment in GetRequestStreamAsync(). Same logic applies here. return Task.Run(() => Task.Factory.FromAsync( - (callback, state) => ((WebRequest)state).BeginGetResponse(callback, state), - iar => ((WebRequest)iar.AsyncState).EndGetResponse(iar), + (callback, state) => ((WebRequest)state!).BeginGetResponse(callback, state), + iar => ((WebRequest)iar.AsyncState!).EndGetResponse(iar), this)); } @@ -557,17 +556,14 @@ public virtual void Abort() throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); } - private static IWebProxy s_DefaultWebProxy; + private static IWebProxy? s_DefaultWebProxy; private static bool s_DefaultWebProxyInitialized; public static IWebProxy GetSystemWebProxy() => HttpClient.DefaultProxy; - public static IWebProxy DefaultWebProxy + public static IWebProxy? DefaultWebProxy { - get - { - return LazyInitializer.EnsureInitialized(ref s_DefaultWebProxy, ref s_DefaultWebProxyInitialized, ref s_internalSyncObject, () => GetSystemWebProxy()); - } + get => LazyInitializer.EnsureInitialized(ref s_DefaultWebProxy, ref s_DefaultWebProxyInitialized, ref s_internalSyncObject, () => GetSystemWebProxy()); set { lock (s_internalSyncObject) @@ -590,7 +586,7 @@ public virtual bool PreAuthenticate } } - public virtual IWebProxy Proxy + public virtual IWebProxy? Proxy { get { diff --git a/src/libraries/System.Net.Requests/tests/AuthenticationManagerTest.cs b/src/libraries/System.Net.Requests/tests/AuthenticationManagerTest.cs index a54598b3c0cdc9..2aacd2ba0b614f 100644 --- a/src/libraries/System.Net.Requests/tests/AuthenticationManagerTest.cs +++ b/src/libraries/System.Net.Requests/tests/AuthenticationManagerTest.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections; -using System.Diagnostics; using Microsoft.DotNet.RemoteExecutor; using Xunit; @@ -26,6 +25,13 @@ public void Register_Null_Throws() Assert.Throws(() => AuthenticationManager.Register(null)); } + [Fact] + public void Unregister_Null_Throws() + { + Assert.Throws(() => AuthenticationManager.Unregister((IAuthenticationModule)null)); + Assert.Throws(() => AuthenticationManager.Unregister((string)null)); + } + [Fact] public void Register_Unregister_ModuleCountUnchanged() { diff --git a/src/libraries/System.Net.Requests/tests/FileWebRequestTest.cs b/src/libraries/System.Net.Requests/tests/FileWebRequestTest.cs index d55182f83392e7..0d7037306389a7 100644 --- a/src/libraries/System.Net.Requests/tests/FileWebRequestTest.cs +++ b/src/libraries/System.Net.Requests/tests/FileWebRequestTest.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.IO; -using System.Net.Http; -using System.Net.Test.Common; -using System.Text; using System.Threading.Tasks; using Xunit; diff --git a/src/libraries/System.Net.Requests/tests/GlobalProxySelectionTest.cs b/src/libraries/System.Net.Requests/tests/GlobalProxySelectionTest.cs index 4e1340581baac5..01613fb8da660a 100644 --- a/src/libraries/System.Net.Requests/tests/GlobalProxySelectionTest.cs +++ b/src/libraries/System.Net.Requests/tests/GlobalProxySelectionTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; using Microsoft.DotNet.RemoteExecutor; using Xunit; diff --git a/src/libraries/System.Net.Requests/tests/HttpRequestCachePolicyTest.cs b/src/libraries/System.Net.Requests/tests/HttpRequestCachePolicyTest.cs index d8c2553f27adde..a224053fde7416 100644 --- a/src/libraries/System.Net.Requests/tests/HttpRequestCachePolicyTest.cs +++ b/src/libraries/System.Net.Requests/tests/HttpRequestCachePolicyTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Net.Cache; diff --git a/src/libraries/System.Net.Requests/tests/HttpWebRequestTest.cs b/src/libraries/System.Net.Requests/tests/HttpWebRequestTest.cs index b69c855f28f781..69eb963d7f5a48 100644 --- a/src/libraries/System.Net.Requests/tests/HttpWebRequestTest.cs +++ b/src/libraries/System.Net.Requests/tests/HttpWebRequestTest.cs @@ -9,11 +9,9 @@ using System.Linq; using System.Net.Cache; using System.Net.Http; -using System.Net.Security; using System.Net.Sockets; using System.Net.Test.Common; using System.Runtime.Serialization.Formatters.Binary; -using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.Json; diff --git a/src/libraries/System.Net.Requests/tests/HttpWebResponseHeaderTest.cs b/src/libraries/System.Net.Requests/tests/HttpWebResponseHeaderTest.cs index 2d48cf8995f2f0..ae72865d7b2fba 100644 --- a/src/libraries/System.Net.Requests/tests/HttpWebResponseHeaderTest.cs +++ b/src/libraries/System.Net.Requests/tests/HttpWebResponseHeaderTest.cs @@ -9,7 +9,6 @@ using System.Runtime.Serialization.Formatters.Binary; using Xunit; -using Xunit.Abstractions; using System.Runtime.Serialization; namespace System.Net.Tests diff --git a/src/libraries/System.Net.Requests/tests/WebRequestTest.cs b/src/libraries/System.Net.Requests/tests/WebRequestTest.cs index c8fe8692e53fe1..e558dbd9b00fed 100644 --- a/src/libraries/System.Net.Requests/tests/WebRequestTest.cs +++ b/src/libraries/System.Net.Requests/tests/WebRequestTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; using Microsoft.DotNet.RemoteExecutor; using Xunit; diff --git a/src/libraries/System.Net.Security/src/System/Net/HelperAsyncResults.cs b/src/libraries/System.Net.Security/src/System/Net/HelperAsyncResults.cs index 3350245eb73c5c..5501d65c9cd6c2 100644 --- a/src/libraries/System.Net.Security/src/System/Net/HelperAsyncResults.cs +++ b/src/libraries/System.Net.Security/src/System/Net/HelperAsyncResults.cs @@ -62,7 +62,7 @@ public void SetNextRequest(byte[]? buffer, int offset, int count, AsyncProtocolC _callback = callback; } - internal object AsyncObject => UserAsyncResult.AsyncObject; + internal object? AsyncObject => UserAsyncResult.AsyncObject; // // Notify protocol so a next stage could be started. diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/InternalNegotiateStream.cs b/src/libraries/System.Net.Security/src/System/Net/Security/InternalNegotiateStream.cs index 7bc1fe817b8640..4c748bd307c29d 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/InternalNegotiateStream.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/InternalNegotiateStream.cs @@ -387,7 +387,7 @@ private static void WriteCallback(IAsyncResult transportResult) try { - NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject; + NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject!; TaskToApm.End(transportResult); if (asyncRequest.Count == 0) { @@ -414,7 +414,7 @@ private static void ReadCallback(AsyncProtocolRequest asyncRequest) // Async ONLY completion. try { - NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject; + NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject!; BufferAsyncResult bufferResult = (BufferAsyncResult)asyncRequest.UserAsyncResult; // This is an optimization to avoid an additional callback. diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/NegoState.cs b/src/libraries/System.Net.Security/src/System/Net/Security/NegoState.cs index abc42dfe2eb025..b59ffb97692ca1 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/NegoState.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/NegoState.cs @@ -708,7 +708,7 @@ private static void WriteCallback(IAsyncResult transportResult) // Async completion. try { - NegoState authState = (NegoState)lazyResult.AsyncObject; + NegoState authState = (NegoState)lazyResult.AsyncObject!; authState._framer!.EndWriteMessage(transportResult); // Special case for an error notification. @@ -749,7 +749,7 @@ private static void ReadCallback(IAsyncResult transportResult) // Async completion. try { - NegoState authState = (NegoState)lazyResult.AsyncObject; + NegoState authState = (NegoState)lazyResult.AsyncObject!; byte[]? message = authState._framer!.EndReadMessage(transportResult); authState.ProcessReceivedBlob(message, lazyResult); } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.Adapters.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.Adapters.cs index 982837e7fc93d9..4995f3fd09bf0e 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.Adapters.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.Adapters.cs @@ -12,9 +12,8 @@ public partial class SslStream private interface ISslIOAdapter { ValueTask ReadAsync(Memory buffer); - ValueTask ReadLockAsync(Memory buffer); - Task WriteLockAsync(); ValueTask WriteAsync(byte[] buffer, int offset, int count); + Task WaitAsync(TaskCompletionSource waiter); CancellationToken CancellationToken { get; } } @@ -31,12 +30,10 @@ public AsyncSslIOAdapter(SslStream sslStream, CancellationToken cancellationToke public ValueTask ReadAsync(Memory buffer) => _sslStream.InnerStream.ReadAsync(buffer, _cancellationToken); - public ValueTask ReadLockAsync(Memory buffer) => _sslStream.CheckEnqueueReadAsync(buffer); - - public Task WriteLockAsync() => _sslStream.CheckEnqueueWriteAsync(); - public ValueTask WriteAsync(byte[] buffer, int offset, int count) => _sslStream.InnerStream.WriteAsync(new ReadOnlyMemory(buffer, offset, count), _cancellationToken); + public Task WaitAsync(TaskCompletionSource waiter) => waiter.Task; + public CancellationToken CancellationToken => _cancellationToken; } @@ -48,17 +45,15 @@ public AsyncSslIOAdapter(SslStream sslStream, CancellationToken cancellationToke public ValueTask ReadAsync(Memory buffer) => new ValueTask(_sslStream.InnerStream.Read(buffer.Span)); - public ValueTask ReadLockAsync(Memory buffer) => new ValueTask(_sslStream.CheckEnqueueRead(buffer)); - public ValueTask WriteAsync(byte[] buffer, int offset, int count) { _sslStream.InnerStream.Write(buffer, offset, count); return default; } - public Task WriteLockAsync() + public Task WaitAsync(TaskCompletionSource waiter) { - _sslStream.CheckEnqueueWrite(); + waiter.Task.Wait(); return Task.CompletedTask; } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs index fbb6a002613413..a54caecb9d69db 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs @@ -43,24 +43,14 @@ private enum FrameType : byte AppData = 23 } - // - // This block is used to rule the >>re-handshakes<< that are concurrent with read/write I/O requests. - // - private const int LockNone = 0; - private const int LockWrite = 1; - private const int LockHandshake = 2; - private const int LockPendingWrite = 3; - private const int LockRead = 4; - private const int LockPendingRead = 6; + private readonly object _handshakeLock = new object(); + private volatile TaskCompletionSource? _handshakeWaiter; private const int FrameOverhead = 32; private const int ReadBufferSize = 4096 * 4 + FrameOverhead; // We read in 16K chunks + headers. private const int InitialHandshakeBufferSize = 4096 + FrameOverhead; // try to fit at least 4K ServerCertificate private ArrayBuffer _handshakeBuffer; - private int _lockWriteState; - private int _lockReadState; - private void ValidateCreateContext(SslClientAuthenticationOptions sslClientAuthenticationOptions, RemoteCertValidationCallback remoteCallback, LocalCertSelectionCallback? localCallback) { ThrowIfExceptional(); @@ -175,7 +165,18 @@ private void CloseInternal() private SecurityStatusPal EncryptData(ReadOnlyMemory buffer, ref byte[] outBuffer, out int outSize) { ThrowIfExceptionalOrNotAuthenticated(); - return _context!.Encrypt(buffer, ref outBuffer, out outSize); + + lock (_handshakeLock) + { + if (_handshakeWaiter != null) + { + outSize = 0; + // avoid waiting under lock. + return new SecurityStatusPal(SecurityStatusPalErrorCode.TryAgain); + } + + return _context!.Encrypt(buffer, ref outBuffer, out outSize); + } } private SecurityStatusPal DecryptData() @@ -218,14 +219,15 @@ private SecurityStatusPal PrivateDecryptData(byte[]? buffer, ref int offset, ref private async Task ReplyOnReAuthenticationAsync(TIOAdapter adapter, byte[]? buffer) where TIOAdapter : ISslIOAdapter { - lock (SyncLock!) + try { - // Note we are already inside the read, so checking for already going concurrent handshake. - _lockReadState = LockHandshake; + await ForceAuthenticationAsync(adapter, receiveFirst: false, buffer).ConfigureAwait(false); + } + finally + { + _handshakeWaiter!.SetResult(true); + _handshakeWaiter = null; } - - await ForceAuthenticationAsync(adapter, receiveFirst: false, buffer).ConfigureAwait(false); - FinishHandshakeRead(LockNone); } // reAuthenticationData is only used on Windows in case of renegotiation. @@ -427,169 +429,6 @@ private bool CompleteHandshake(ref ProtocolToken? alertToken) return true; } - private void FinishHandshakeRead(int newState) - { - lock (SyncLock!) - { - // Lock is redundant here. Included for clarity. - int lockState = Interlocked.Exchange(ref _lockReadState, newState); - - if (lockState != LockPendingRead) - { - return; - } - - _lockReadState = LockRead; - } - } - - // Returns: - // -1 - proceed - // 0 - queued - // X - some bytes are ready, no need for IO - private int CheckEnqueueRead(Memory buffer) - { - ThrowIfExceptionalOrNotAuthenticated(); - - int lockState = Interlocked.CompareExchange(ref _lockReadState, LockRead, LockNone); - if (lockState != LockHandshake) - { - // Proceed, no concurrent handshake is ongoing so no need for a lock. - return -1; - } - - LazyAsyncResult? lazyResult = null; - lock (SyncLock!) - { - // Check again under lock. - if (_lockReadState != LockHandshake) - { - // The other thread has finished before we grabbed the lock. - _lockReadState = LockRead; - return -1; - } - - _lockReadState = LockPendingRead; - } - // Need to exit from lock before waiting. - lazyResult!.InternalWaitForCompletion(); - ThrowIfExceptionalOrNotAuthenticated(); - return -1; - } - - private ValueTask CheckEnqueueReadAsync(Memory buffer) - { - ThrowIfExceptionalOrNotAuthenticated(); - - int lockState = Interlocked.CompareExchange(ref _lockReadState, LockRead, LockNone); - if (lockState != LockHandshake) - { - // Proceed, no concurrent handshake is ongoing so no need for a lock. - return new ValueTask(-1); - } - - lock (SyncLock!) - { - // Check again under lock. - if (_lockReadState != LockHandshake) - { - // The other thread has finished before we grabbed the lock. - _lockReadState = LockRead; - return new ValueTask(-1); - } - - _lockReadState = LockPendingRead; - TaskCompletionSource taskCompletionSource = new TaskCompletionSource(buffer, TaskCreationOptions.RunContinuationsAsynchronously); - return new ValueTask(taskCompletionSource.Task); - } - } - - private Task CheckEnqueueWriteAsync() - { - ThrowIfExceptionalOrNotAuthenticated(); - - // Clear previous request. - int lockState = Interlocked.CompareExchange(ref _lockWriteState, LockWrite, LockNone); - if (lockState != LockHandshake) - { - return Task.CompletedTask; - } - - lock (SyncLock!) - { - if (_lockWriteState != LockHandshake) - { - ThrowIfExceptionalOrNotAuthenticated(); - return Task.CompletedTask; - } - - _lockWriteState = LockPendingWrite; - TaskCompletionSource completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - return completionSource.Task; - } - } - - private void CheckEnqueueWrite() - { - // Clear previous request. - int lockState = Interlocked.CompareExchange(ref _lockWriteState, LockWrite, LockNone); - if (lockState != LockHandshake) - { - // Proceed with write. - return; - } - - LazyAsyncResult? lazyResult = null; - lock (SyncLock!) - { - if (_lockWriteState != LockHandshake) - { - // Handshake has completed before we grabbed the lock. - ThrowIfExceptionalOrNotAuthenticated(); - return; - } - - _lockWriteState = LockPendingWrite; - } - - // Need to exit from lock before waiting. - lazyResult!.InternalWaitForCompletion(); - ThrowIfExceptionalOrNotAuthenticated(); - return; - } - - private void FinishWrite() - { - int lockState = Interlocked.CompareExchange(ref _lockWriteState, LockNone, LockWrite); - if (lockState != LockHandshake) - { - return; - } - } - - private void FinishHandshake(Exception e) - { - lock (SyncLock!) - { - if (e != null) - { - SetException(e); - } - - // Release read if any. - FinishHandshakeRead(LockNone); - - // If there is a pending write we want to keep it's lock state. - int lockState = Interlocked.CompareExchange(ref _lockWriteState, LockNone, LockHandshake); - if (lockState != LockPendingWrite) - { - return; - } - - _lockWriteState = LockWrite; - } - } - private async ValueTask WriteAsyncChunked(TIOAdapter writeAdapter, ReadOnlyMemory buffer) where TIOAdapter : struct, ISslIOAdapter { @@ -604,22 +443,38 @@ private async ValueTask WriteAsyncChunked(TIOAdapter writeAdapter, R private ValueTask WriteSingleChunk(TIOAdapter writeAdapter, ReadOnlyMemory buffer) where TIOAdapter : struct, ISslIOAdapter { - // Request a write IO slot. - Task ioSlot = writeAdapter.WriteLockAsync(); - if (!ioSlot.IsCompletedSuccessfully) - { - // Operation is async and has been queued, return. - return WaitForWriteIOSlot(writeAdapter, ioSlot, buffer); - } - byte[] rentedBuffer = ArrayPool.Shared.Rent(buffer.Length + FrameOverhead); byte[] outBuffer = rentedBuffer; - SecurityStatusPal status = EncryptData(buffer, ref outBuffer, out int encryptedBytes); + SecurityStatusPal status; + int encryptedBytes; + while (true) + { + status = EncryptData(buffer, ref outBuffer, out encryptedBytes); + + // TryAgain should be rare, when renegotiation happens exactly when we want to write. + if (status.ErrorCode != SecurityStatusPalErrorCode.TryAgain) + { + break; + } + + TaskCompletionSource? waiter = _handshakeWaiter; + if (waiter != null) + { + Task waiterTask = writeAdapter.WaitAsync(waiter); + // We finished synchronously waiting for renegotiation. We can try again immediately. + if (waiterTask.IsCompletedSuccessfully) + { + continue; + } + + // We need to wait asynchronously as well as for the write when EncryptData is finished. + return WaitAndWriteAsync(writeAdapter, buffer, waiterTask, rentedBuffer); + } + } if (status.ErrorCode != SecurityStatusPalErrorCode.OK) { - // Re-handshake status is not supported. ArrayPool.Shared.Return(rentedBuffer); return new ValueTask(Task.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException(SR.net_io_encrypt, SslStreamPal.GetException(status))))); } @@ -628,21 +483,51 @@ private ValueTask WriteSingleChunk(TIOAdapter writeAdapter, ReadOnly if (t.IsCompletedSuccessfully) { ArrayPool.Shared.Return(rentedBuffer); - FinishWrite(); return t; } else { - return CompleteAsync(t, rentedBuffer); + return CompleteWriteAsync(t, rentedBuffer); } - async ValueTask WaitForWriteIOSlot(TIOAdapter wAdapter, Task lockTask, ReadOnlyMemory buff) + async ValueTask WaitAndWriteAsync(TIOAdapter writeAdapter, ReadOnlyMemory buffer, Task waitTask, byte[] rentedBuffer) { - await lockTask.ConfigureAwait(false); - await WriteSingleChunk(wAdapter, buff).ConfigureAwait(false); + byte[]? bufferToReturn = rentedBuffer; + byte[] outBuffer = rentedBuffer; + try + { + // Wait for renegotiation to finish. + await waitTask.ConfigureAwait(false); + + SecurityStatusPal status = EncryptData(buffer, ref outBuffer, out int encryptedBytes); + if (status.ErrorCode == SecurityStatusPalErrorCode.TryAgain) + { + // No need to hold on the buffer any more. + ArrayPool.Shared.Return(bufferToReturn); + bufferToReturn = null; + // Call WriteSingleChunk() recursively to avoid code duplication. + // This should be extremely rare in cases when second renegotiation happens concurrently with Write. + await WriteSingleChunk(writeAdapter, buffer).ConfigureAwait(false); + } + else if (status.ErrorCode == SecurityStatusPalErrorCode.OK) + { + await writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes).ConfigureAwait(false); + } + else + { + throw new IOException(SR.net_io_encrypt, SslStreamPal.GetException(status)); + } + } + finally + { + if (bufferToReturn != null) + { + ArrayPool.Shared.Return(bufferToReturn); + } + } } - async ValueTask CompleteAsync(ValueTask writeTask, byte[] bufferToReturn) + async ValueTask CompleteWriteAsync(ValueTask writeTask, byte[] bufferToReturn) { try { @@ -651,7 +536,6 @@ async ValueTask CompleteAsync(ValueTask writeTask, byte[] bufferToReturn) finally { ArrayPool.Shared.Return(bufferToReturn); - FinishWrite(); } } } @@ -719,12 +603,6 @@ private async ValueTask ReadAsyncInternal(TIOAdapter adapter, M return CopyDecryptedData(buffer); } - int copyBytes = await adapter.ReadLockAsync(buffer).ConfigureAwait(false); - if (copyBytes > 0) - { - return copyBytes; - } - ResetReadBuffer(); // Read the next frame header. @@ -766,7 +644,27 @@ private async ValueTask ReadAsyncInternal(TIOAdapter adapter, M // DecryptData will decrypt in-place and modify these to point to the actual decrypted data, which may be smaller. _decryptedBytesOffset = _internalOffset; _decryptedBytesCount = payloadBytes; - SecurityStatusPal status = DecryptData(); + + SecurityStatusPal status; + lock (_handshakeLock) + { + status = DecryptData(); + if (status.ErrorCode == SecurityStatusPalErrorCode.Renegotiate) + { + // The status indicates that peer wants to renegotiate. (Windows only) + // In practice, there can be some other reasons too - like TLS1.3 session creation + // of alert handling. We need to pass the data to lsass and it is not safe to do parallel + // write any more as that can change TLS state and the EncryptData() can fail in strange ways. + + // To handle this we call DecryptData() under lock and we create TCS waiter. + // EncryptData() checks that under same lock and if it exist it will not call low-level crypto. + // Instead it will wait synchronously or asynchronously and it will try again after the wait. + // The result will be set when ReplyOnReAuthenticationAsync() is finished e.g. lsass business is over + // or if we bail to continue. If either one happen before EncryptData(), _handshakeWaiter will be set to null + // and EncryptData() will work normally e.g. no waiting, just exclusion with DecryptData() + _handshakeWaiter = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + } + } // Treat the bytes we just decrypted as consumed // Note, we won't do another buffer read until the decrypted bytes are processed @@ -790,6 +688,9 @@ private async ValueTask ReadAsyncInternal(TIOAdapter adapter, M { if (!_sslAuthenticationOptions!.AllowRenegotiation) { + _handshakeWaiter!.SetResult(false); + _handshakeWaiter = null; + if (NetEventSource.IsEnabled) NetEventSource.Fail(this, "Renegotiation was requested but it is disallowed"); throw new IOException(SR.net_ssl_io_renego); } @@ -919,8 +820,6 @@ private async ValueTask WriteAsyncInternal(TIOAdapter writeAdapter, } catch (Exception e) { - FinishWrite(); - if (e is IOException || (e is OperationCanceledException && writeAdapter.CancellationToken.IsCancellationRequested)) { throw; diff --git a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj index f1941c277c2f37..89b10587443878 100644 --- a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj +++ b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj @@ -2,7 +2,7 @@ System.Net.Sockets true - $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix + $(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Windows_NT enable diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/BaseOverlappedAsyncResult.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/BaseOverlappedAsyncResult.Windows.cs index 65cab7837e4c3b..004c0598796592 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/BaseOverlappedAsyncResult.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/BaseOverlappedAsyncResult.Windows.cs @@ -36,7 +36,7 @@ internal BaseOverlappedAsyncResult(Socket socket, object? asyncState, AsyncCallb // since the overlapped calls may complete asynchronously. internal void SetUnmanagedStructures(object? objectsToPin) { - Socket s = (Socket)AsyncObject; + Socket s = (Socket)AsyncObject!; // Bind the Win32 Socket Handle to the ThreadPool Debug.Assert(s != null, "m_CurrentSocket is null"); @@ -149,7 +149,7 @@ internal SocketError ProcessOverlappedResult(bool success, int bytesTransferred) if (success) { // Synchronous success. - Socket socket = (Socket)AsyncObject; + Socket socket = (Socket)AsyncObject!; if (socket.SafeHandle.SkipCompletionPortOnSuccess) { // The socket handle is configured to skip completion on success, diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ConnectOverlappedAsyncResult.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ConnectOverlappedAsyncResult.Unix.cs index af40673f5f3591..da31c753c1b9e6 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ConnectOverlappedAsyncResult.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ConnectOverlappedAsyncResult.Unix.cs @@ -24,7 +24,7 @@ public void CompletionCallback(SocketError errorCode) var errorCode = (SocketError)ErrorCode; if (errorCode == SocketError.Success) { - var socket = (Socket)AsyncObject; + var socket = (Socket)AsyncObject!; socket.SetToConnected(); return socket; } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ConnectOverlappedAsyncResult.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ConnectOverlappedAsyncResult.Windows.cs index f8489738536028..2aad89d357393c 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ConnectOverlappedAsyncResult.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ConnectOverlappedAsyncResult.Windows.cs @@ -11,7 +11,7 @@ internal sealed partial class ConnectOverlappedAsyncResult : BaseOverlappedAsync internal override unsafe object? PostCompletion(int numBytes) { SocketError errorCode = (SocketError)ErrorCode; - Socket socket = (Socket)AsyncObject; + Socket socket = (Socket)AsyncObject!; if (errorCode == SocketError.Success) { diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/DisconnectOverlappedAsyncResult.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/DisconnectOverlappedAsyncResult.cs index 0ad746c4b3fce7..85769024cd0096 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/DisconnectOverlappedAsyncResult.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/DisconnectOverlappedAsyncResult.cs @@ -18,7 +18,7 @@ internal DisconnectOverlappedAsyncResult(Socket socket, object? asyncState, Asyn { if (ErrorCode == (int)SocketError.Success) { - Socket socket = (Socket)AsyncObject; + Socket socket = (Socket)AsyncObject!; socket.SetToDisconnected(); socket._remoteEndPoint = null; } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ReceiveMessageOverlappedAsyncResult.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ReceiveMessageOverlappedAsyncResult.Windows.cs index f9da58f2192a42..4311037393eb9a 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ReceiveMessageOverlappedAsyncResult.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/ReceiveMessageOverlappedAsyncResult.Windows.cs @@ -37,7 +37,7 @@ internal unsafe void SetUnmanagedStructures(byte[] buffer, int offset, int size, _wsaBufferArray = new byte[sizeof(WSABuffer)]; bool ipv4, ipv6; - Socket.GetIPProtocolInformation(((Socket)AsyncObject).AddressFamily, socketAddress, out ipv4, out ipv6); + Socket.GetIPProtocolInformation(((Socket)AsyncObject!).AddressFamily, socketAddress, out ipv4, out ipv6); // Prepare control buffer. if (ipv4) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs index 8b4e20756f9bb9..9d5f48b7045e37 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs @@ -105,7 +105,7 @@ public bool TryRegister(SafeSocketHandle socket, out Interop.Error error) // private static readonly IntPtr MaxHandles = IntPtr.Size == 4 ? (IntPtr)int.MaxValue : (IntPtr)long.MaxValue; #endif - private static readonly IntPtr MinHandlesForAdditionalEngine = s_engineCount == 1 ? MaxHandles : (IntPtr)EventBufferCount; + private static readonly IntPtr MinHandlesForAdditionalEngine = s_engineCount == 1 ? MaxHandles : (IntPtr)32; // // Sentinel handle value to identify events from the "shutdown pipe," used to signal an event loop to stop diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs index 8c116cdffd9944..b012817e5cbd2e 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs @@ -1846,7 +1846,7 @@ public static SocketError ReceiveMessageFromAsync(Socket socket, SafeSocketHandl asyncResult.SocketAddress = socketAddress; bool isIPv4, isIPv6; - Socket.GetIPProtocolInformation(((Socket)asyncResult.AsyncObject).AddressFamily, socketAddress, out isIPv4, out isIPv6); + Socket.GetIPProtocolInformation(((Socket)asyncResult.AsyncObject!).AddressFamily, socketAddress, out isIPv4, out isIPv6); int socketAddressSize = socketAddress.InternalSize; int bytesReceived; diff --git a/src/libraries/System.Net.WebClient/ref/System.Net.WebClient.cs b/src/libraries/System.Net.WebClient/ref/System.Net.WebClient.cs index 44fc90a0f7c865..e9aa7f4ce4a9b5 100644 --- a/src/libraries/System.Net.WebClient/ref/System.Net.WebClient.cs +++ b/src/libraries/System.Net.WebClient/ref/System.Net.WebClient.cs @@ -80,47 +80,50 @@ public WebClient() { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.ObsoleteAttribute("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)] public bool AllowWriteStreamBuffering { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.AllowNull] public string BaseAddress { get { throw null; } set { } } - public System.Net.Cache.RequestCachePolicy CachePolicy { get { throw null; } set { } } - public System.Net.ICredentials Credentials { get { throw null; } set { } } + public System.Net.Cache.RequestCachePolicy? CachePolicy { get { throw null; } set { } } + public System.Net.ICredentials? Credentials { get { throw null; } set { } } public System.Text.Encoding Encoding { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.AllowNull] public System.Net.WebHeaderCollection Headers { get { throw null; } set { } } public bool IsBusy { get { throw null; } } - public System.Net.IWebProxy Proxy { get { throw null; } set { } } + public System.Net.IWebProxy? Proxy { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.AllowNull] public System.Collections.Specialized.NameValueCollection QueryString { get { throw null; } set { } } - public System.Net.WebHeaderCollection ResponseHeaders { get { throw null; } } + public System.Net.WebHeaderCollection? ResponseHeaders { get { throw null; } } public bool UseDefaultCredentials { get { throw null; } set { } } - public event System.Net.DownloadDataCompletedEventHandler DownloadDataCompleted { add { } remove { } } - public event System.ComponentModel.AsyncCompletedEventHandler DownloadFileCompleted { add { } remove { } } - public event System.Net.DownloadProgressChangedEventHandler DownloadProgressChanged { add { } remove { } } - public event System.Net.DownloadStringCompletedEventHandler DownloadStringCompleted { add { } remove { } } - public event System.Net.OpenReadCompletedEventHandler OpenReadCompleted { add { } remove { } } - public event System.Net.OpenWriteCompletedEventHandler OpenWriteCompleted { add { } remove { } } - public event System.Net.UploadDataCompletedEventHandler UploadDataCompleted { add { } remove { } } - public event System.Net.UploadFileCompletedEventHandler UploadFileCompleted { add { } remove { } } - public event System.Net.UploadProgressChangedEventHandler UploadProgressChanged { add { } remove { } } - public event System.Net.UploadStringCompletedEventHandler UploadStringCompleted { add { } remove { } } - public event System.Net.UploadValuesCompletedEventHandler UploadValuesCompleted { add { } remove { } } + public event System.Net.DownloadDataCompletedEventHandler? DownloadDataCompleted { add { } remove { } } + public event System.ComponentModel.AsyncCompletedEventHandler? DownloadFileCompleted { add { } remove { } } + public event System.Net.DownloadProgressChangedEventHandler? DownloadProgressChanged { add { } remove { } } + public event System.Net.DownloadStringCompletedEventHandler? DownloadStringCompleted { add { } remove { } } + public event System.Net.OpenReadCompletedEventHandler? OpenReadCompleted { add { } remove { } } + public event System.Net.OpenWriteCompletedEventHandler? OpenWriteCompleted { add { } remove { } } + public event System.Net.UploadDataCompletedEventHandler? UploadDataCompleted { add { } remove { } } + public event System.Net.UploadFileCompletedEventHandler? UploadFileCompleted { add { } remove { } } + public event System.Net.UploadProgressChangedEventHandler? UploadProgressChanged { add { } remove { } } + public event System.Net.UploadStringCompletedEventHandler? UploadStringCompleted { add { } remove { } } + public event System.Net.UploadValuesCompletedEventHandler? UploadValuesCompleted { add { } remove { } } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.ObsoleteAttribute("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)] - public event System.Net.WriteStreamClosedEventHandler WriteStreamClosed { add { } remove { } } + public event System.Net.WriteStreamClosedEventHandler? WriteStreamClosed { add { } remove { } } public void CancelAsync() { } public byte[] DownloadData(string address) { throw null; } public byte[] DownloadData(System.Uri address) { throw null; } public void DownloadDataAsync(System.Uri address) { } - public void DownloadDataAsync(System.Uri address, object userToken) { } + public void DownloadDataAsync(System.Uri address, object? userToken) { } public System.Threading.Tasks.Task DownloadDataTaskAsync(string address) { throw null; } public System.Threading.Tasks.Task DownloadDataTaskAsync(System.Uri address) { throw null; } public void DownloadFile(string address, string fileName) { } public void DownloadFile(System.Uri address, string fileName) { } public void DownloadFileAsync(System.Uri address, string fileName) { } - public void DownloadFileAsync(System.Uri address, string fileName, object userToken) { } + public void DownloadFileAsync(System.Uri address, string fileName, object? userToken) { } public System.Threading.Tasks.Task DownloadFileTaskAsync(string address, string fileName) { throw null; } public System.Threading.Tasks.Task DownloadFileTaskAsync(System.Uri address, string fileName) { throw null; } public string DownloadString(string address) { throw null; } public string DownloadString(System.Uri address) { throw null; } public void DownloadStringAsync(System.Uri address) { } - public void DownloadStringAsync(System.Uri address, object userToken) { } + public void DownloadStringAsync(System.Uri address, object? userToken) { } public System.Threading.Tasks.Task DownloadStringTaskAsync(string address) { throw null; } public System.Threading.Tasks.Task DownloadStringTaskAsync(System.Uri address) { throw null; } protected virtual System.Net.WebRequest GetWebRequest(System.Uri address) { throw null; } @@ -143,64 +146,64 @@ protected virtual void OnWriteStreamClosed(System.Net.WriteStreamClosedEventArgs public System.IO.Stream OpenRead(string address) { throw null; } public System.IO.Stream OpenRead(System.Uri address) { throw null; } public void OpenReadAsync(System.Uri address) { } - public void OpenReadAsync(System.Uri address, object userToken) { } + public void OpenReadAsync(System.Uri address, object? userToken) { } public System.Threading.Tasks.Task OpenReadTaskAsync(string address) { throw null; } public System.Threading.Tasks.Task OpenReadTaskAsync(System.Uri address) { throw null; } public System.IO.Stream OpenWrite(string address) { throw null; } - public System.IO.Stream OpenWrite(string address, string method) { throw null; } + public System.IO.Stream OpenWrite(string address, string? method) { throw null; } public System.IO.Stream OpenWrite(System.Uri address) { throw null; } - public System.IO.Stream OpenWrite(System.Uri address, string method) { throw null; } + public System.IO.Stream OpenWrite(System.Uri address, string? method) { throw null; } public void OpenWriteAsync(System.Uri address) { } - public void OpenWriteAsync(System.Uri address, string method) { } - public void OpenWriteAsync(System.Uri address, string method, object userToken) { } + public void OpenWriteAsync(System.Uri address, string? method) { } + public void OpenWriteAsync(System.Uri address, string? method, object? userToken) { } public System.Threading.Tasks.Task OpenWriteTaskAsync(string address) { throw null; } - public System.Threading.Tasks.Task OpenWriteTaskAsync(string address, string method) { throw null; } + public System.Threading.Tasks.Task OpenWriteTaskAsync(string address, string? method) { throw null; } public System.Threading.Tasks.Task OpenWriteTaskAsync(System.Uri address) { throw null; } - public System.Threading.Tasks.Task OpenWriteTaskAsync(System.Uri address, string method) { throw null; } + public System.Threading.Tasks.Task OpenWriteTaskAsync(System.Uri address, string? method) { throw null; } public byte[] UploadData(string address, byte[] data) { throw null; } - public byte[] UploadData(string address, string method, byte[] data) { throw null; } + public byte[] UploadData(string address, string? method, byte[] data) { throw null; } public byte[] UploadData(System.Uri address, byte[] data) { throw null; } - public byte[] UploadData(System.Uri address, string method, byte[] data) { throw null; } + public byte[] UploadData(System.Uri address, string? method, byte[] data) { throw null; } public void UploadDataAsync(System.Uri address, byte[] data) { } - public void UploadDataAsync(System.Uri address, string method, byte[] data) { } - public void UploadDataAsync(System.Uri address, string method, byte[] data, object userToken) { } + public void UploadDataAsync(System.Uri address, string? method, byte[] data) { } + public void UploadDataAsync(System.Uri address, string? method, byte[] data, object? userToken) { } public System.Threading.Tasks.Task UploadDataTaskAsync(string address, byte[] data) { throw null; } - public System.Threading.Tasks.Task UploadDataTaskAsync(string address, string method, byte[] data) { throw null; } + public System.Threading.Tasks.Task UploadDataTaskAsync(string address, string? method, byte[] data) { throw null; } public System.Threading.Tasks.Task UploadDataTaskAsync(System.Uri address, byte[] data) { throw null; } - public System.Threading.Tasks.Task UploadDataTaskAsync(System.Uri address, string method, byte[] data) { throw null; } + public System.Threading.Tasks.Task UploadDataTaskAsync(System.Uri address, string? method, byte[] data) { throw null; } public byte[] UploadFile(string address, string fileName) { throw null; } - public byte[] UploadFile(string address, string method, string fileName) { throw null; } + public byte[] UploadFile(string address, string? method, string fileName) { throw null; } public byte[] UploadFile(System.Uri address, string fileName) { throw null; } - public byte[] UploadFile(System.Uri address, string method, string fileName) { throw null; } + public byte[] UploadFile(System.Uri address, string? method, string fileName) { throw null; } public void UploadFileAsync(System.Uri address, string fileName) { } - public void UploadFileAsync(System.Uri address, string method, string fileName) { } - public void UploadFileAsync(System.Uri address, string method, string fileName, object userToken) { } + public void UploadFileAsync(System.Uri address, string? method, string fileName) { } + public void UploadFileAsync(System.Uri address, string? method, string fileName, object? userToken) { } public System.Threading.Tasks.Task UploadFileTaskAsync(string address, string fileName) { throw null; } - public System.Threading.Tasks.Task UploadFileTaskAsync(string address, string method, string fileName) { throw null; } + public System.Threading.Tasks.Task UploadFileTaskAsync(string address, string? method, string fileName) { throw null; } public System.Threading.Tasks.Task UploadFileTaskAsync(System.Uri address, string fileName) { throw null; } - public System.Threading.Tasks.Task UploadFileTaskAsync(System.Uri address, string method, string fileName) { throw null; } + public System.Threading.Tasks.Task UploadFileTaskAsync(System.Uri address, string? method, string fileName) { throw null; } public string UploadString(string address, string data) { throw null; } - public string UploadString(string address, string method, string data) { throw null; } + public string UploadString(string address, string? method, string data) { throw null; } public string UploadString(System.Uri address, string data) { throw null; } - public string UploadString(System.Uri address, string method, string data) { throw null; } + public string UploadString(System.Uri address, string? method, string data) { throw null; } public void UploadStringAsync(System.Uri address, string data) { } - public void UploadStringAsync(System.Uri address, string method, string data) { } - public void UploadStringAsync(System.Uri address, string method, string data, object userToken) { } + public void UploadStringAsync(System.Uri address, string? method, string data) { } + public void UploadStringAsync(System.Uri address, string? method, string data, object? userToken) { } public System.Threading.Tasks.Task UploadStringTaskAsync(string address, string data) { throw null; } - public System.Threading.Tasks.Task UploadStringTaskAsync(string address, string method, string data) { throw null; } + public System.Threading.Tasks.Task UploadStringTaskAsync(string address, string? method, string data) { throw null; } public System.Threading.Tasks.Task UploadStringTaskAsync(System.Uri address, string data) { throw null; } - public System.Threading.Tasks.Task UploadStringTaskAsync(System.Uri address, string method, string data) { throw null; } + public System.Threading.Tasks.Task UploadStringTaskAsync(System.Uri address, string? method, string data) { throw null; } public byte[] UploadValues(string address, System.Collections.Specialized.NameValueCollection data) { throw null; } - public byte[] UploadValues(string address, string method, System.Collections.Specialized.NameValueCollection data) { throw null; } + public byte[] UploadValues(string address, string? method, System.Collections.Specialized.NameValueCollection data) { throw null; } public byte[] UploadValues(System.Uri address, System.Collections.Specialized.NameValueCollection data) { throw null; } - public byte[] UploadValues(System.Uri address, string method, System.Collections.Specialized.NameValueCollection data) { throw null; } + public byte[] UploadValues(System.Uri address, string? method, System.Collections.Specialized.NameValueCollection data) { throw null; } public void UploadValuesAsync(System.Uri address, System.Collections.Specialized.NameValueCollection data) { } - public void UploadValuesAsync(System.Uri address, string method, System.Collections.Specialized.NameValueCollection data) { } - public void UploadValuesAsync(System.Uri address, string method, System.Collections.Specialized.NameValueCollection data, object userToken) { } + public void UploadValuesAsync(System.Uri address, string? method, System.Collections.Specialized.NameValueCollection data) { } + public void UploadValuesAsync(System.Uri address, string? method, System.Collections.Specialized.NameValueCollection data, object? userToken) { } public System.Threading.Tasks.Task UploadValuesTaskAsync(string address, System.Collections.Specialized.NameValueCollection data) { throw null; } - public System.Threading.Tasks.Task UploadValuesTaskAsync(string address, string method, System.Collections.Specialized.NameValueCollection data) { throw null; } + public System.Threading.Tasks.Task UploadValuesTaskAsync(string address, string? method, System.Collections.Specialized.NameValueCollection data) { throw null; } public System.Threading.Tasks.Task UploadValuesTaskAsync(System.Uri address, System.Collections.Specialized.NameValueCollection data) { throw null; } - public System.Threading.Tasks.Task UploadValuesTaskAsync(System.Uri address, string method, System.Collections.Specialized.NameValueCollection data) { throw null; } + public System.Threading.Tasks.Task UploadValuesTaskAsync(System.Uri address, string? method, System.Collections.Specialized.NameValueCollection data) { throw null; } } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public partial class WriteStreamClosedEventArgs : System.EventArgs @@ -210,7 +213,7 @@ public partial class WriteStreamClosedEventArgs : System.EventArgs public WriteStreamClosedEventArgs() { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] [System.ObsoleteAttribute("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)] - public System.Exception Error { get { throw null; } } + public System.Exception? Error { get { throw null; } } } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public delegate void WriteStreamClosedEventHandler(object sender, System.Net.WriteStreamClosedEventArgs e); diff --git a/src/libraries/System.Net.WebClient/ref/System.Net.WebClient.csproj b/src/libraries/System.Net.WebClient/ref/System.Net.WebClient.csproj index 5033ea94e9f263..9174f984584489 100644 --- a/src/libraries/System.Net.WebClient/ref/System.Net.WebClient.csproj +++ b/src/libraries/System.Net.WebClient/ref/System.Net.WebClient.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent) + enable diff --git a/src/libraries/System.Net.WebClient/src/System.Net.WebClient.csproj b/src/libraries/System.Net.WebClient/src/System.Net.WebClient.csproj index 8ef6982edcda6b..282b766f7fcb36 100644 --- a/src/libraries/System.Net.WebClient/src/System.Net.WebClient.csproj +++ b/src/libraries/System.Net.WebClient/src/System.Net.WebClient.csproj @@ -2,6 +2,7 @@ true $(NetCoreAppCurrent) + enable diff --git a/src/libraries/System.Net.WebClient/src/System/Net/WebClient.cs b/src/libraries/System.Net.WebClient/src/System/Net/WebClient.cs index 2cc0b3f2cc2276..ea4109ad607de8 100644 --- a/src/libraries/System.Net.WebClient/src/System/Net/WebClient.cs +++ b/src/libraries/System.Net.WebClient/src/System/Net/WebClient.cs @@ -5,6 +5,7 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Net.Cache; @@ -24,34 +25,34 @@ public class WebClient : Component private const string UploadFileContentType = "multipart/form-data"; private const string UploadValuesContentType = "application/x-www-form-urlencoded"; - private Uri _baseAddress; - private ICredentials _credentials; - private WebHeaderCollection _headers; - private NameValueCollection _requestParameters; - private WebResponse _webResponse; - private WebRequest _webRequest; + private Uri? _baseAddress; + private ICredentials? _credentials; + private WebHeaderCollection? _headers; + private NameValueCollection? _requestParameters; + private WebResponse? _webResponse; + private WebRequest? _webRequest; private Encoding _encoding = Encoding.Default; - private string _method; + private string? _method; private long _contentLength = -1; private bool _initWebClientAsync; private bool _canceled; - private ProgressData _progress; - private IWebProxy _proxy; + private ProgressData? _progress; + private IWebProxy? _proxy; private bool _proxySet; private int _callNesting; // > 0 if we're in a Read/Write call - private AsyncOperation _asyncOp; - - private SendOrPostCallback _downloadDataOperationCompleted; - private SendOrPostCallback _openReadOperationCompleted; - private SendOrPostCallback _openWriteOperationCompleted; - private SendOrPostCallback _downloadStringOperationCompleted; - private SendOrPostCallback _downloadFileOperationCompleted; - private SendOrPostCallback _uploadStringOperationCompleted; - private SendOrPostCallback _uploadDataOperationCompleted; - private SendOrPostCallback _uploadFileOperationCompleted; - private SendOrPostCallback _uploadValuesOperationCompleted; - private SendOrPostCallback _reportDownloadProgressChanged; - private SendOrPostCallback _reportUploadProgressChanged; + private AsyncOperation? _asyncOp; + + private SendOrPostCallback? _downloadDataOperationCompleted; + private SendOrPostCallback? _openReadOperationCompleted; + private SendOrPostCallback? _openWriteOperationCompleted; + private SendOrPostCallback? _downloadStringOperationCompleted; + private SendOrPostCallback? _downloadFileOperationCompleted; + private SendOrPostCallback? _uploadStringOperationCompleted; + private SendOrPostCallback? _uploadDataOperationCompleted; + private SendOrPostCallback? _uploadFileOperationCompleted; + private SendOrPostCallback? _uploadValuesOperationCompleted; + private SendOrPostCallback? _reportDownloadProgressChanged; + private SendOrPostCallback? _reportUploadProgressChanged; public WebClient() { @@ -62,17 +63,17 @@ public WebClient() } } - public event DownloadStringCompletedEventHandler DownloadStringCompleted; - public event DownloadDataCompletedEventHandler DownloadDataCompleted; - public event AsyncCompletedEventHandler DownloadFileCompleted; - public event UploadStringCompletedEventHandler UploadStringCompleted; - public event UploadDataCompletedEventHandler UploadDataCompleted; - public event UploadFileCompletedEventHandler UploadFileCompleted; - public event UploadValuesCompletedEventHandler UploadValuesCompleted; - public event OpenReadCompletedEventHandler OpenReadCompleted; - public event OpenWriteCompletedEventHandler OpenWriteCompleted; - public event DownloadProgressChangedEventHandler DownloadProgressChanged; - public event UploadProgressChangedEventHandler UploadProgressChanged; + public event DownloadStringCompletedEventHandler? DownloadStringCompleted; + public event DownloadDataCompletedEventHandler? DownloadDataCompleted; + public event AsyncCompletedEventHandler? DownloadFileCompleted; + public event UploadStringCompletedEventHandler? UploadStringCompleted; + public event UploadDataCompletedEventHandler? UploadDataCompleted; + public event UploadFileCompletedEventHandler? UploadFileCompleted; + public event UploadValuesCompletedEventHandler? UploadValuesCompleted; + public event OpenReadCompletedEventHandler? OpenReadCompleted; + public event OpenWriteCompletedEventHandler? OpenWriteCompleted; + public event DownloadProgressChangedEventHandler? DownloadProgressChanged; + public event UploadProgressChangedEventHandler? UploadProgressChanged; protected virtual void OnDownloadStringCompleted(DownloadStringCompletedEventArgs e) => DownloadStringCompleted?.Invoke(this, e); protected virtual void OnDownloadDataCompleted(DownloadDataCompletedEventArgs e) => DownloadDataCompleted?.Invoke(this, e); @@ -103,26 +104,26 @@ private void StartOperation() _progress?.Reset(); } - private AsyncOperation StartAsyncOperation(object userToken) + private AsyncOperation StartAsyncOperation(object? userToken) { if (!_initWebClientAsync) { // Set up the async delegates - _openReadOperationCompleted = arg => OnOpenReadCompleted((OpenReadCompletedEventArgs)arg); - _openWriteOperationCompleted = arg => OnOpenWriteCompleted((OpenWriteCompletedEventArgs)arg); + _openReadOperationCompleted = arg => OnOpenReadCompleted((OpenReadCompletedEventArgs)arg!); + _openWriteOperationCompleted = arg => OnOpenWriteCompleted((OpenWriteCompletedEventArgs)arg!); - _downloadStringOperationCompleted = arg => OnDownloadStringCompleted((DownloadStringCompletedEventArgs)arg); - _downloadDataOperationCompleted = arg => OnDownloadDataCompleted((DownloadDataCompletedEventArgs)arg); - _downloadFileOperationCompleted = arg => OnDownloadFileCompleted((AsyncCompletedEventArgs)arg); + _downloadStringOperationCompleted = arg => OnDownloadStringCompleted((DownloadStringCompletedEventArgs)arg!); + _downloadDataOperationCompleted = arg => OnDownloadDataCompleted((DownloadDataCompletedEventArgs)arg!); + _downloadFileOperationCompleted = arg => OnDownloadFileCompleted((AsyncCompletedEventArgs)arg!); - _uploadStringOperationCompleted = arg => OnUploadStringCompleted((UploadStringCompletedEventArgs)arg); - _uploadDataOperationCompleted = arg => OnUploadDataCompleted((UploadDataCompletedEventArgs)arg); - _uploadFileOperationCompleted = arg => OnUploadFileCompleted((UploadFileCompletedEventArgs)arg); - _uploadValuesOperationCompleted = arg => OnUploadValuesCompleted((UploadValuesCompletedEventArgs)arg); + _uploadStringOperationCompleted = arg => OnUploadStringCompleted((UploadStringCompletedEventArgs)arg!); + _uploadDataOperationCompleted = arg => OnUploadDataCompleted((UploadDataCompletedEventArgs)arg!); + _uploadFileOperationCompleted = arg => OnUploadFileCompleted((UploadFileCompletedEventArgs)arg!); + _uploadValuesOperationCompleted = arg => OnUploadValuesCompleted((UploadValuesCompletedEventArgs)arg!); - _reportDownloadProgressChanged = arg => OnDownloadProgressChanged((DownloadProgressChangedEventArgs)arg); - _reportUploadProgressChanged = arg => OnUploadProgressChanged((UploadProgressChangedEventArgs)arg); + _reportDownloadProgressChanged = arg => OnDownloadProgressChanged((DownloadProgressChangedEventArgs)arg!); + _reportUploadProgressChanged = arg => OnUploadProgressChanged((UploadProgressChangedEventArgs)arg!); _progress = new ProgressData(); _initWebClientAsync = true; @@ -148,6 +149,7 @@ public Encoding Encoding } } + [AllowNull] public string BaseAddress { get { return _baseAddress != null ? _baseAddress.ToString() : string.Empty; } @@ -171,7 +173,7 @@ public string BaseAddress } } - public ICredentials Credentials + public ICredentials? Credentials { get { return _credentials; } set { _credentials = value; } @@ -183,21 +185,23 @@ public bool UseDefaultCredentials set { _credentials = value ? CredentialCache.DefaultCredentials : null; } } + [AllowNull] public WebHeaderCollection Headers { - get { return _headers ?? (_headers = new WebHeaderCollection()); } + get { return _headers ??= new WebHeaderCollection(); } set { _headers = value; } } + [AllowNull] public NameValueCollection QueryString { - get { return _requestParameters ?? (_requestParameters = new NameValueCollection()); } + get { return _requestParameters ??= new NameValueCollection(); } set { _requestParameters = value; } } - public WebHeaderCollection ResponseHeaders => _webResponse?.Headers; + public WebHeaderCollection? ResponseHeaders => _webResponse?.Headers; - public IWebProxy Proxy + public IWebProxy? Proxy { get { return _proxySet ? _proxy : WebRequest.DefaultWebProxy; } set @@ -207,7 +211,7 @@ public IWebProxy Proxy } } - public RequestCachePolicy CachePolicy { get; set; } + public RequestCachePolicy? CachePolicy { get; set; } public bool IsBusy => _asyncOp != null; @@ -290,18 +294,23 @@ public byte[] DownloadData(Uri address) private byte[] DownloadDataInternal(Uri address, out WebRequest request) { - request = null; + WebRequest? tmpRequest = null; + byte[] result; + try { - request = _webRequest = GetWebRequest(GetUri(address)); - return DownloadBits(request, new ChunkedMemoryStream()); + tmpRequest = _webRequest = GetWebRequest(GetUri(address)); + result = DownloadBits(tmpRequest, new ChunkedMemoryStream())!; } catch (Exception e) when (!(e is OutOfMemoryException)) { - AbortRequest(request); + AbortRequest(tmpRequest); if (e is WebException || e is SecurityException) throw; throw new WebException(SR.net_webclient, e); } + + request = tmpRequest; + return result; } public void DownloadFile(string address, string fileName) => @@ -312,8 +321,8 @@ public void DownloadFile(Uri address, string fileName) ThrowIfNull(address, nameof(address)); ThrowIfNull(fileName, nameof(fileName)); - WebRequest request = null; - FileStream fs = null; + WebRequest? request = null; + FileStream? fs = null; bool succeeded = false; StartOperation(); try @@ -350,7 +359,7 @@ public Stream OpenRead(Uri address) { ThrowIfNull(address, nameof(address)); - WebRequest request = null; + WebRequest? request = null; StartOperation(); try { @@ -376,10 +385,10 @@ public Stream OpenWrite(string address) => public Stream OpenWrite(Uri address) => OpenWrite(address, null); - public Stream OpenWrite(string address, string method) => + public Stream OpenWrite(string address, string? method) => OpenWrite(GetUri(address), method); - public Stream OpenWrite(Uri address, string method) + public Stream OpenWrite(Uri address, string? method) { ThrowIfNull(address, nameof(address)); if (method == null) @@ -387,7 +396,7 @@ public Stream OpenWrite(Uri address, string method) method = MapToDefaultMethod(address); } - WebRequest request = null; + WebRequest? request = null; StartOperation(); try { @@ -416,10 +425,10 @@ public byte[] UploadData(string address, byte[] data) => public byte[] UploadData(Uri address, byte[] data) => UploadData(address, null, data); - public byte[] UploadData(string address, string method, byte[] data) => + public byte[] UploadData(string address, string? method, byte[] data) => UploadData(GetUri(address), method, data); - public byte[] UploadData(Uri address, string method, byte[] data) + public byte[] UploadData(Uri address, string? method, byte[] data) { ThrowIfNull(address, nameof(address)); ThrowIfNull(data, nameof(data)); @@ -442,30 +451,35 @@ public byte[] UploadData(Uri address, string method, byte[] data) private byte[] UploadDataInternal(Uri address, string method, byte[] data, out WebRequest request) { - request = null; + WebRequest? tmpRequest = null; + byte[] result; + try { _method = method; _contentLength = data.Length; - request = _webRequest = GetWebRequest(GetUri(address)); - return UploadBits(request, null, data, 0, null, null); + tmpRequest = _webRequest = GetWebRequest(GetUri(address)); + result = UploadBits(tmpRequest, null, data, 0, null, null); } catch (Exception e) when (!(e is OutOfMemoryException)) { - AbortRequest(request); + AbortRequest(tmpRequest); if (e is WebException || e is SecurityException) throw; throw new WebException(SR.net_webclient, e); } + + request = tmpRequest; + return result; } private void OpenFileInternal( bool needsHeaderAndBoundary, string fileName, - ref FileStream fs, ref byte[] buffer, ref byte[] formHeaderBytes, ref byte[] boundaryBytes) + out FileStream fs, out byte[] buffer, ref byte[]? formHeaderBytes, ref byte[]? boundaryBytes) { fileName = Path.GetFullPath(fileName); WebHeaderCollection headers = Headers; - string contentType = headers[HttpKnownHeaderNames.ContentType]; + string? contentType = headers[HttpKnownHeaderNames.ContentType]; if (contentType == null) { @@ -532,10 +546,10 @@ public byte[] UploadFile(string address, string fileName) => public byte[] UploadFile(Uri address, string fileName) => UploadFile(address, null, fileName); - public byte[] UploadFile(string address, string method, string fileName) => + public byte[] UploadFile(string address, string? method, string fileName) => UploadFile(GetUri(address), method, fileName); - public byte[] UploadFile(Uri address, string method, string fileName) + public byte[] UploadFile(Uri address, string? method, string fileName) { ThrowIfNull(address, nameof(address)); ThrowIfNull(fileName, nameof(fileName)); @@ -544,16 +558,16 @@ public byte[] UploadFile(Uri address, string method, string fileName) method = MapToDefaultMethod(address); } - FileStream fs = null; - WebRequest request = null; + FileStream? fs = null; + WebRequest? request = null; StartOperation(); try { _method = method; - byte[] formHeaderBytes = null, boundaryBytes = null, buffer = null; + byte[]? formHeaderBytes = null, boundaryBytes = null, buffer; Uri uri = GetUri(address); bool needsHeaderAndBoundary = (uri.Scheme != Uri.UriSchemeFile); - OpenFileInternal(needsHeaderAndBoundary, fileName, ref fs, ref buffer, ref formHeaderBytes, ref boundaryBytes); + OpenFileInternal(needsHeaderAndBoundary, fileName, out fs, out buffer, ref formHeaderBytes, ref boundaryBytes); request = _webRequest = GetWebRequest(uri); return UploadBits(request, fs, buffer, 0, formHeaderBytes, boundaryBytes); } @@ -575,7 +589,7 @@ private byte[] GetValuesToUpload(NameValueCollection data) { WebHeaderCollection headers = Headers; - string contentType = headers[HttpKnownHeaderNames.ContentType]; + string? contentType = headers[HttpKnownHeaderNames.ContentType]; if (contentType != null && !string.Equals(contentType, UploadValuesContentType, StringComparison.OrdinalIgnoreCase)) { throw new WebException(SR.net_webclient_ContentType); @@ -585,7 +599,7 @@ private byte[] GetValuesToUpload(NameValueCollection data) string delimiter = string.Empty; var values = new StringBuilder(); - foreach (string name in data.AllKeys) + foreach (string? name in data.AllKeys) { values.Append(delimiter); values.Append(UrlEncode(name)); @@ -605,10 +619,10 @@ public byte[] UploadValues(string address, NameValueCollection data) => public byte[] UploadValues(Uri address, NameValueCollection data) => UploadValues(address, null, data); - public byte[] UploadValues(string address, string method, NameValueCollection data) => + public byte[] UploadValues(string address, string? method, NameValueCollection data) => UploadValues(GetUri(address), method, data); - public byte[] UploadValues(Uri address, string method, NameValueCollection data) + public byte[] UploadValues(Uri address, string? method, NameValueCollection data) { ThrowIfNull(address, nameof(address)); ThrowIfNull(data, nameof(data)); @@ -617,7 +631,7 @@ public byte[] UploadValues(Uri address, string method, NameValueCollection data) method = MapToDefaultMethod(address); } - WebRequest request = null; + WebRequest? request = null; StartOperation(); try { @@ -644,10 +658,10 @@ public string UploadString(string address, string data) => public string UploadString(Uri address, string data) => UploadString(address, null, data); - public string UploadString(string address, string method, string data) => + public string UploadString(string address, string? method, string data) => UploadString(GetUri(address), method, data); - public string UploadString(Uri address, string method, string data) + public string UploadString(Uri address, string? method, string data) { ThrowIfNull(address, nameof(address)); ThrowIfNull(data, nameof(data)); @@ -690,7 +704,7 @@ public string DownloadString(Uri address) } } - private static void AbortRequest(WebRequest request) + private static void AbortRequest(WebRequest? request) { try { request?.Abort(); } catch (Exception exception) when (!(exception is OutOfMemoryException)) { } @@ -709,13 +723,13 @@ private void CopyHeadersTo(WebRequest request) return; } - string accept = _headers[HttpKnownHeaderNames.Accept]; - string connection = _headers[HttpKnownHeaderNames.Connection]; - string contentType = _headers[HttpKnownHeaderNames.ContentType]; - string expect = _headers[HttpKnownHeaderNames.Expect]; - string referrer = _headers[HttpKnownHeaderNames.Referer]; - string userAgent = _headers[HttpKnownHeaderNames.UserAgent]; - string host = _headers[HttpKnownHeaderNames.Host]; + string? accept = _headers[HttpKnownHeaderNames.Accept]; + string? connection = _headers[HttpKnownHeaderNames.Connection]; + string? contentType = _headers[HttpKnownHeaderNames.ContentType]; + string? expect = _headers[HttpKnownHeaderNames.Expect]; + string? referrer = _headers[HttpKnownHeaderNames.Referer]; + string? userAgent = _headers[HttpKnownHeaderNames.UserAgent]; + string? host = _headers[HttpKnownHeaderNames.Host]; _headers.Remove(HttpKnownHeaderNames.Accept); _headers.Remove(HttpKnownHeaderNames.Connection); @@ -767,7 +781,7 @@ private Uri GetUri(string address) { ThrowIfNull(address, nameof(address)); - Uri uri; + Uri? uri; if (_baseAddress != null) { if (!Uri.TryCreate(_baseAddress, address, out uri)) @@ -787,7 +801,7 @@ private Uri GetUri(Uri address) { ThrowIfNull(address, nameof(address)); - Uri uri = address; + Uri? uri = address; if (!address.IsAbsoluteUri && _baseAddress != null && !Uri.TryCreate(_baseAddress, address, out uri)) { @@ -811,7 +825,7 @@ private Uri GetUri(Uri address) return uri; } - private byte[] DownloadBits(WebRequest request, Stream writeStream) + private byte[]? DownloadBits(WebRequest request, Stream writeStream) { try { @@ -854,12 +868,12 @@ private byte[] DownloadBits(WebRequest request, Stream writeStream) private async void DownloadBitsAsync( WebRequest request, Stream writeStream, - AsyncOperation asyncOp, Action completionDelegate) + AsyncOperation asyncOp, Action completionDelegate) { Debug.Assert(_progress != null, "ProgressData should have been initialized"); Debug.Assert(asyncOp != null); - Exception exception = null; + Exception? exception = null; try { WebResponse response = _webResponse = await GetWebResponseTaskAsync(request).ConfigureAwait(false); @@ -929,8 +943,8 @@ private async void DownloadBitsAsync( } private byte[] UploadBits( - WebRequest request, Stream readStream, byte[] buffer, int chunkSize, - byte[] header, byte[] footer) + WebRequest request, Stream? readStream, byte[] buffer, int chunkSize, + byte[]? header, byte[]? footer) { try { @@ -979,7 +993,7 @@ private byte[] UploadBits( } } - return DownloadBits(request, new ChunkedMemoryStream()); + return DownloadBits(request, new ChunkedMemoryStream())!; } catch (Exception e) when (!(e is OutOfMemoryException)) { @@ -990,15 +1004,15 @@ private byte[] UploadBits( } private async void UploadBitsAsync( - WebRequest request, Stream readStream, byte[] buffer, int chunkSize, - byte[] header, byte[] footer, - AsyncOperation asyncOp, Action completionDelegate) + WebRequest request, Stream? readStream, byte[] buffer, int chunkSize, + byte[]? header, byte[]? footer, + AsyncOperation asyncOp, Action completionDelegate) { Debug.Assert(asyncOp != null); Debug.Assert(_progress != null, "ProgressData should have been initialized"); _progress.HasUploadPhase = true; - Exception exception = null; + Exception? exception = null; try { if (request.RequestUri.Scheme == Uri.UriSchemeFile) @@ -1093,12 +1107,12 @@ private static bool ByteArrayHasPrefix(byte[] prefix, byte[] byteArray) private string GetStringUsingEncoding(WebRequest request, byte[] data) { - Encoding enc = null; + Encoding? enc = null; int bomLengthInData = -1; // Figure out encoding by first checking for encoding string in Content-Type HTTP header // This can throw NotImplementedException if the derived class of WebRequest doesn't support it. - string contentType; + string? contentType; try { contentType = request.ContentType; @@ -1183,7 +1197,8 @@ private string MapToDefaultMethod(Uri address) "POST"; } - private static string UrlEncode(string str) + [return: NotNullIfNotNull("str")] + private static string? UrlEncode(string? str) { if (str == null) return null; @@ -1278,7 +1293,7 @@ private void InvokeOperationCompleted(AsyncOperation asyncOp, SendOrPostCallback public void OpenReadAsync(Uri address) => OpenReadAsync(address, null); - public void OpenReadAsync(Uri address, object userToken) + public void OpenReadAsync(Uri address, object? userToken) { ThrowIfNull(address, nameof(address)); @@ -1288,8 +1303,8 @@ public void OpenReadAsync(Uri address, object userToken) WebRequest request = _webRequest = GetWebRequest(GetUri(address)); request.BeginGetResponse(iar => { - Stream stream = null; - Exception exception = null; + Stream? stream = null; + Exception? exception = null; try { WebResponse response = _webResponse = GetWebResponse(request, iar); @@ -1300,12 +1315,12 @@ public void OpenReadAsync(Uri address, object userToken) exception = GetExceptionToPropagate(e); } - InvokeOperationCompleted(asyncOp, _openReadOperationCompleted, new OpenReadCompletedEventArgs(stream, exception, _canceled, asyncOp.UserSuppliedState)); + InvokeOperationCompleted(asyncOp, _openReadOperationCompleted!, new OpenReadCompletedEventArgs(stream, exception, _canceled, asyncOp.UserSuppliedState)); }, null); } catch (Exception e) when (!(e is OutOfMemoryException)) { - InvokeOperationCompleted(asyncOp, _openReadOperationCompleted, + InvokeOperationCompleted(asyncOp, _openReadOperationCompleted!, new OpenReadCompletedEventArgs(null, GetExceptionToPropagate(e), _canceled, asyncOp.UserSuppliedState)); } } @@ -1313,10 +1328,10 @@ public void OpenReadAsync(Uri address, object userToken) public void OpenWriteAsync(Uri address) => OpenWriteAsync(address, null, null); - public void OpenWriteAsync(Uri address, string method) => + public void OpenWriteAsync(Uri address, string? method) => OpenWriteAsync(address, method, null); - public void OpenWriteAsync(Uri address, string method, object userToken) + public void OpenWriteAsync(Uri address, string? method, object? userToken) { ThrowIfNull(address, nameof(address)); if (method == null) @@ -1331,8 +1346,8 @@ public void OpenWriteAsync(Uri address, string method, object userToken) WebRequest request = _webRequest = GetWebRequest(GetUri(address)); request.BeginGetRequestStream(iar => { - WebClientWriteStream stream = null; - Exception exception = null; + WebClientWriteStream? stream = null; + Exception? exception = null; try { @@ -1343,25 +1358,25 @@ public void OpenWriteAsync(Uri address, string method, object userToken) exception = GetExceptionToPropagate(e); } - InvokeOperationCompleted(asyncOp, _openWriteOperationCompleted, new OpenWriteCompletedEventArgs(stream, exception, _canceled, asyncOp.UserSuppliedState)); + InvokeOperationCompleted(asyncOp, _openWriteOperationCompleted!, new OpenWriteCompletedEventArgs(stream, exception, _canceled, asyncOp.UserSuppliedState)); }, null); } catch (Exception e) when (!(e is OutOfMemoryException)) { var eventArgs = new OpenWriteCompletedEventArgs(null, GetExceptionToPropagate(e), _canceled, asyncOp.UserSuppliedState); - InvokeOperationCompleted(asyncOp, _openWriteOperationCompleted, eventArgs); + InvokeOperationCompleted(asyncOp, _openWriteOperationCompleted!, eventArgs); } } - private void DownloadStringAsyncCallback(byte[] returnBytes, Exception exception, object state) + private void DownloadStringAsyncCallback(byte[]? returnBytes, Exception? exception, object state) { AsyncOperation asyncOp = (AsyncOperation)state; - string stringData = null; + string? stringData = null; try { if (returnBytes != null) { - stringData = GetStringUsingEncoding(_webRequest, returnBytes); + stringData = GetStringUsingEncoding(_webRequest!, returnBytes); } } catch (Exception e) when (!(e is OutOfMemoryException)) @@ -1370,14 +1385,14 @@ private void DownloadStringAsyncCallback(byte[] returnBytes, Exception exception } var eventArgs = new DownloadStringCompletedEventArgs(stringData, exception, _canceled, asyncOp.UserSuppliedState); - InvokeOperationCompleted(asyncOp, _downloadStringOperationCompleted, eventArgs); + InvokeOperationCompleted(asyncOp, _downloadStringOperationCompleted!, eventArgs); } public void DownloadStringAsync(Uri address) => DownloadStringAsync(address, null); - public void DownloadStringAsync(Uri address, object userToken) + public void DownloadStringAsync(Uri address, object? userToken) { ThrowIfNull(address, nameof(address)); @@ -1393,17 +1408,17 @@ public void DownloadStringAsync(Uri address, object userToken) } } - private void DownloadDataAsyncCallback(byte[] returnBytes, Exception exception, object state) + private void DownloadDataAsyncCallback(byte[]? returnBytes, Exception? exception, object state) { AsyncOperation asyncOp = (AsyncOperation)state; - DownloadDataCompletedEventArgs eventArgs = new DownloadDataCompletedEventArgs(returnBytes, exception, _canceled, asyncOp.UserSuppliedState); - InvokeOperationCompleted(asyncOp, _downloadDataOperationCompleted, eventArgs); + DownloadDataCompletedEventArgs eventArgs = new DownloadDataCompletedEventArgs(returnBytes, exception, _canceled, asyncOp.UserSuppliedState!); + InvokeOperationCompleted(asyncOp, _downloadDataOperationCompleted!, eventArgs); } public void DownloadDataAsync(Uri address) => DownloadDataAsync(address, null); - public void DownloadDataAsync(Uri address, object userToken) + public void DownloadDataAsync(Uri address, object? userToken) { ThrowIfNull(address, nameof(address)); @@ -1419,22 +1434,22 @@ public void DownloadDataAsync(Uri address, object userToken) } } - private void DownloadFileAsyncCallback(byte[] returnBytes, Exception exception, object state) + private void DownloadFileAsyncCallback(byte[]? returnBytes, Exception? exception, object state) { AsyncOperation asyncOp = (AsyncOperation)state; AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(exception, _canceled, asyncOp.UserSuppliedState); - InvokeOperationCompleted(asyncOp, _downloadFileOperationCompleted, eventArgs); + InvokeOperationCompleted(asyncOp, _downloadFileOperationCompleted!, eventArgs); } public void DownloadFileAsync(Uri address, string fileName) => DownloadFileAsync(address, fileName, null); - public void DownloadFileAsync(Uri address, string fileName, object userToken) + public void DownloadFileAsync(Uri address, string fileName, object? userToken) { ThrowIfNull(address, nameof(address)); ThrowIfNull(fileName, nameof(fileName)); - FileStream fs = null; + FileStream? fs = null; AsyncOperation asyncOp = StartAsyncOperation(userToken); try { @@ -1452,10 +1467,10 @@ public void DownloadFileAsync(Uri address, string fileName, object userToken) public void UploadStringAsync(Uri address, string data) => UploadStringAsync(address, null, data, null); - public void UploadStringAsync(Uri address, string method, string data) => + public void UploadStringAsync(Uri address, string? method, string data) => UploadStringAsync(address, method, data, null); - public void UploadStringAsync(Uri address, string method, string data, object userToken) + public void UploadStringAsync(Uri address, string? method, string data, object? userToken) { ThrowIfNull(address, nameof(address)); ThrowIfNull(data, nameof(data)); @@ -1476,7 +1491,7 @@ public void UploadStringAsync(Uri address, string method, string data, object us request, null, requestData, 0, null, null, asyncOp, (bytesResult, error, uploadAsyncOp) => { - string stringResult = null; + string? stringResult = null; if (error == null && bytesResult != null) { try @@ -1489,24 +1504,24 @@ public void UploadStringAsync(Uri address, string method, string data, object us } } - InvokeOperationCompleted(uploadAsyncOp, _uploadStringOperationCompleted, + InvokeOperationCompleted(uploadAsyncOp, _uploadStringOperationCompleted!, new UploadStringCompletedEventArgs(stringResult, error, _canceled, uploadAsyncOp.UserSuppliedState)); }); } catch (Exception e) when (!(e is OutOfMemoryException)) { var eventArgs = new UploadStringCompletedEventArgs(null, GetExceptionToPropagate(e), _canceled, asyncOp.UserSuppliedState); - InvokeOperationCompleted(asyncOp, _uploadStringOperationCompleted, eventArgs); + InvokeOperationCompleted(asyncOp, _uploadStringOperationCompleted!, eventArgs); } } public void UploadDataAsync(Uri address, byte[] data) => UploadDataAsync(address, null, data, null); - public void UploadDataAsync(Uri address, string method, byte[] data) => + public void UploadDataAsync(Uri address, string? method, byte[] data) => UploadDataAsync(address, method, data, null); - public void UploadDataAsync(Uri address, string method, byte[] data, object userToken) + public void UploadDataAsync(Uri address, string? method, byte[] data, object? userToken) { ThrowIfNull(address, nameof(address)); ThrowIfNull(data, nameof(data)); @@ -1532,22 +1547,22 @@ public void UploadDataAsync(Uri address, string method, byte[] data, object user UploadBitsAsync( request, null, data, chunkSize, null, null, asyncOp, (result, error, uploadAsyncOp) => - InvokeOperationCompleted(asyncOp, _uploadDataOperationCompleted, new UploadDataCompletedEventArgs(result, error, _canceled, uploadAsyncOp.UserSuppliedState))); + InvokeOperationCompleted(asyncOp, _uploadDataOperationCompleted!, new UploadDataCompletedEventArgs(result, error, _canceled, uploadAsyncOp.UserSuppliedState))); } catch (Exception e) when (!(e is OutOfMemoryException)) { var eventArgs = new UploadDataCompletedEventArgs(null, GetExceptionToPropagate(e), _canceled, asyncOp.UserSuppliedState); - InvokeOperationCompleted(asyncOp, _uploadDataOperationCompleted, eventArgs); + InvokeOperationCompleted(asyncOp, _uploadDataOperationCompleted!, eventArgs); } } public void UploadFileAsync(Uri address, string fileName) => UploadFileAsync(address, null, fileName, null); - public void UploadFileAsync(Uri address, string method, string fileName) => + public void UploadFileAsync(Uri address, string? method, string fileName) => UploadFileAsync(address, method, fileName, null); - public void UploadFileAsync(Uri address, string method, string fileName, object userToken) + public void UploadFileAsync(Uri address, string? method, string fileName, object? userToken) { ThrowIfNull(address, nameof(address)); ThrowIfNull(fileName, nameof(fileName)); @@ -1556,37 +1571,37 @@ public void UploadFileAsync(Uri address, string method, string fileName, object method = MapToDefaultMethod(address); } - FileStream fs = null; + FileStream? fs = null; AsyncOperation asyncOp = StartAsyncOperation(userToken); try { _method = method; - byte[] formHeaderBytes = null, boundaryBytes = null, buffer = null; + byte[]? formHeaderBytes = null, boundaryBytes = null, buffer = null; Uri uri = GetUri(address); bool needsHeaderAndBoundary = (uri.Scheme != Uri.UriSchemeFile); - OpenFileInternal(needsHeaderAndBoundary, fileName, ref fs, ref buffer, ref formHeaderBytes, ref boundaryBytes); + OpenFileInternal(needsHeaderAndBoundary, fileName, out fs, out buffer, ref formHeaderBytes, ref boundaryBytes); WebRequest request = _webRequest = GetWebRequest(uri); UploadBitsAsync( request, fs, buffer, 0, formHeaderBytes, boundaryBytes, asyncOp, (result, error, uploadAsyncOp) => - InvokeOperationCompleted(asyncOp, _uploadFileOperationCompleted, new UploadFileCompletedEventArgs(result, error, _canceled, uploadAsyncOp.UserSuppliedState))); + InvokeOperationCompleted(asyncOp, _uploadFileOperationCompleted!, new UploadFileCompletedEventArgs(result, error, _canceled, uploadAsyncOp.UserSuppliedState))); } catch (Exception e) when (!(e is OutOfMemoryException)) { fs?.Close(); var eventArgs = new UploadFileCompletedEventArgs(null, GetExceptionToPropagate(e), _canceled, asyncOp.UserSuppliedState); - InvokeOperationCompleted(asyncOp, _uploadFileOperationCompleted, eventArgs); + InvokeOperationCompleted(asyncOp, _uploadFileOperationCompleted!, eventArgs); } } public void UploadValuesAsync(Uri address, NameValueCollection data) => UploadValuesAsync(address, null, data, null); - public void UploadValuesAsync(Uri address, string method, NameValueCollection data) => + public void UploadValuesAsync(Uri address, string? method, NameValueCollection data) => UploadValuesAsync(address, method, data, null); - public void UploadValuesAsync(Uri address, string method, NameValueCollection data, object userToken) + public void UploadValuesAsync(Uri address, string? method, NameValueCollection data, object? userToken) { ThrowIfNull(address, nameof(address)); ThrowIfNull(data, nameof(data)); @@ -1612,12 +1627,12 @@ public void UploadValuesAsync(Uri address, string method, NameValueCollection da UploadBitsAsync( request, null, buffer, chunkSize, null, null, asyncOp, (result, error, uploadAsyncOp) => - InvokeOperationCompleted(asyncOp, _uploadValuesOperationCompleted, new UploadValuesCompletedEventArgs(result, error, _canceled, uploadAsyncOp.UserSuppliedState))); + InvokeOperationCompleted(asyncOp, _uploadValuesOperationCompleted!, new UploadValuesCompletedEventArgs(result, error, _canceled, uploadAsyncOp.UserSuppliedState))); } catch (Exception e) when (!(e is OutOfMemoryException)) { - var eventArgs = new UploadValuesCompletedEventArgs(null, GetExceptionToPropagate(e), _canceled, asyncOp.UserSuppliedState); - InvokeOperationCompleted(asyncOp, _uploadValuesOperationCompleted, eventArgs); + var eventArgs = new UploadValuesCompletedEventArgs(null, GetExceptionToPropagate(e), _canceled, asyncOp.UserSuppliedState!); + InvokeOperationCompleted(asyncOp, _uploadValuesOperationCompleted!, eventArgs); } } @@ -1626,7 +1641,7 @@ private static Exception GetExceptionToPropagate(Exception e) => public void CancelAsync() { - WebRequest request = _webRequest; + WebRequest? request = _webRequest; _canceled = true; AbortRequest(request); } @@ -1639,7 +1654,7 @@ public Task DownloadStringTaskAsync(Uri address) // Create the task to be returned var tcs = new TaskCompletionSource(address); - DownloadStringCompletedEventHandler handler = null; + DownloadStringCompletedEventHandler? handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.DownloadStringCompleted -= completion); DownloadStringCompleted += handler; @@ -1664,7 +1679,7 @@ public Task OpenReadTaskAsync(Uri address) var tcs = new TaskCompletionSource(address); // Setup the callback event handler - OpenReadCompletedEventHandler handler = null; + OpenReadCompletedEventHandler? handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.OpenReadCompleted -= completion); OpenReadCompleted += handler; @@ -1686,16 +1701,16 @@ public Task OpenWriteTaskAsync(string address) => public Task OpenWriteTaskAsync(Uri address) => OpenWriteTaskAsync(address, null); - public Task OpenWriteTaskAsync(string address, string method) => + public Task OpenWriteTaskAsync(string address, string? method) => OpenWriteTaskAsync(GetUri(address), method); - public Task OpenWriteTaskAsync(Uri address, string method) + public Task OpenWriteTaskAsync(Uri address, string? method) { // Create the task to be returned var tcs = new TaskCompletionSource(address); // Setup the callback event handler - OpenWriteCompletedEventHandler handler = null; + OpenWriteCompletedEventHandler? handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.OpenWriteCompleted -= completion); OpenWriteCompleted += handler; @@ -1717,16 +1732,16 @@ public Task UploadStringTaskAsync(string address, string data) => public Task UploadStringTaskAsync(Uri address, string data) => UploadStringTaskAsync(address, null, data); - public Task UploadStringTaskAsync(string address, string method, string data) => + public Task UploadStringTaskAsync(string address, string? method, string data) => UploadStringTaskAsync(GetUri(address), method, data); - public Task UploadStringTaskAsync(Uri address, string method, string data) + public Task UploadStringTaskAsync(Uri address, string? method, string data) { // Create the task to be returned var tcs = new TaskCompletionSource(address); // Setup the callback event handler - UploadStringCompletedEventHandler handler = null; + UploadStringCompletedEventHandler? handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadStringCompleted -= completion); UploadStringCompleted += handler; @@ -1751,7 +1766,7 @@ public Task DownloadDataTaskAsync(Uri address) var tcs = new TaskCompletionSource(address); // Setup the callback event handler - DownloadDataCompletedEventHandler handler = null; + DownloadDataCompletedEventHandler? handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.DownloadDataCompleted -= completion); DownloadDataCompleted += handler; @@ -1773,10 +1788,10 @@ public Task DownloadFileTaskAsync(string address, string fileName) => public Task DownloadFileTaskAsync(Uri address, string fileName) { // Create the task to be returned - var tcs = new TaskCompletionSource(address); + var tcs = new TaskCompletionSource(address); // Setup the callback event handler - AsyncCompletedEventHandler handler = null; + AsyncCompletedEventHandler? handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => null, handler, (webClient, completion) => webClient.DownloadFileCompleted -= completion); DownloadFileCompleted += handler; @@ -1798,16 +1813,16 @@ public Task UploadDataTaskAsync(string address, byte[] data) => public Task UploadDataTaskAsync(Uri address, byte[] data) => UploadDataTaskAsync(address, null, data); - public Task UploadDataTaskAsync(string address, string method, byte[] data) => + public Task UploadDataTaskAsync(string address, string? method, byte[] data) => UploadDataTaskAsync(GetUri(address), method, data); - public Task UploadDataTaskAsync(Uri address, string method, byte[] data) + public Task UploadDataTaskAsync(Uri address, string? method, byte[] data) { // Create the task to be returned var tcs = new TaskCompletionSource(address); // Setup the callback event handler - UploadDataCompletedEventHandler handler = null; + UploadDataCompletedEventHandler? handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadDataCompleted -= completion); UploadDataCompleted += handler; @@ -1829,16 +1844,16 @@ public Task UploadFileTaskAsync(string address, string fileName) => public Task UploadFileTaskAsync(Uri address, string fileName) => UploadFileTaskAsync(address, null, fileName); - public Task UploadFileTaskAsync(string address, string method, string fileName) => + public Task UploadFileTaskAsync(string address, string? method, string fileName) => UploadFileTaskAsync(GetUri(address), method, fileName); - public Task UploadFileTaskAsync(Uri address, string method, string fileName) + public Task UploadFileTaskAsync(Uri address, string? method, string fileName) { // Create the task to be returned var tcs = new TaskCompletionSource(address); // Setup the callback event handler - UploadFileCompletedEventHandler handler = null; + UploadFileCompletedEventHandler? handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadFileCompleted -= completion); UploadFileCompleted += handler; @@ -1857,19 +1872,19 @@ public Task UploadFileTaskAsync(Uri address, string method, string fileN public Task UploadValuesTaskAsync(string address, NameValueCollection data) => UploadValuesTaskAsync(GetUri(address), null, data); - public Task UploadValuesTaskAsync(string address, string method, NameValueCollection data) => + public Task UploadValuesTaskAsync(string address, string? method, NameValueCollection data) => UploadValuesTaskAsync(GetUri(address), method, data); public Task UploadValuesTaskAsync(Uri address, NameValueCollection data) => UploadValuesTaskAsync(address, null, data); - public Task UploadValuesTaskAsync(Uri address, string method, NameValueCollection data) + public Task UploadValuesTaskAsync(Uri address, string? method, NameValueCollection data) { // Create the task to be returned var tcs = new TaskCompletionSource(address); // Setup the callback event handler - UploadValuesCompletedEventHandler handler = null; + UploadValuesCompletedEventHandler? handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadValuesCompleted -= completion); UploadValuesCompleted += handler; @@ -1912,13 +1927,13 @@ private void PostProgressChanged(AsyncOperation asyncOp, ProgressData progress) progressPercentage = progress.TotalBytesToReceive < 0 && progress.BytesReceived == 0 ? progress.TotalBytesToSend < 0 ? 0 : progress.TotalBytesToSend == 0 ? 50 : (int)((50 * progress.BytesSent) / progress.TotalBytesToSend) : progress.TotalBytesToSend < 0 ? 50 : progress.TotalBytesToReceive == 0 ? 100 : (int)((50 * progress.BytesReceived) / progress.TotalBytesToReceive + 50); - asyncOp.Post(_reportUploadProgressChanged, new UploadProgressChangedEventArgs(progressPercentage, asyncOp.UserSuppliedState, progress.BytesSent, progress.TotalBytesToSend, progress.BytesReceived, progress.TotalBytesToReceive)); + asyncOp.Post(_reportUploadProgressChanged!, new UploadProgressChangedEventArgs(progressPercentage, asyncOp.UserSuppliedState!, progress.BytesSent, progress.TotalBytesToSend, progress.BytesReceived, progress.TotalBytesToReceive)); } } else if (DownloadProgressChanged != null) { progressPercentage = progress.TotalBytesToReceive < 0 ? 0 : progress.TotalBytesToReceive == 0 ? 100 : (int)((100 * progress.BytesReceived) / progress.TotalBytesToReceive); - asyncOp.Post(_reportDownloadProgressChanged, new DownloadProgressChangedEventArgs(progressPercentage, asyncOp.UserSuppliedState, progress.BytesReceived, progress.TotalBytesToReceive)); + asyncOp.Post(_reportDownloadProgressChanged!, new DownloadProgressChangedEventArgs(progressPercentage, asyncOp.UserSuppliedState!, progress.BytesReceived, progress.TotalBytesToReceive)); } } } @@ -2015,9 +2030,9 @@ protected virtual void OnWriteStreamClosed(WriteStreamClosedEventArgs e) { } public class OpenReadCompletedEventArgs : AsyncCompletedEventArgs { - private readonly Stream _result; + private readonly Stream? _result; - internal OpenReadCompletedEventArgs(Stream result, Exception exception, bool cancelled, object userToken) : base(exception, cancelled, userToken) + internal OpenReadCompletedEventArgs(Stream? result, Exception? exception, bool cancelled, object? userToken) : base(exception, cancelled, userToken) { _result = result; } @@ -2027,16 +2042,16 @@ public Stream Result get { RaiseExceptionIfNecessary(); - return _result; + return _result!; } } } public class OpenWriteCompletedEventArgs : AsyncCompletedEventArgs { - private readonly Stream _result; + private readonly Stream? _result; - internal OpenWriteCompletedEventArgs(Stream result, Exception exception, bool cancelled, object userToken) : base(exception, cancelled, userToken) + internal OpenWriteCompletedEventArgs(Stream? result, Exception? exception, bool cancelled, object? userToken) : base(exception, cancelled, userToken) { _result = result; } @@ -2046,16 +2061,16 @@ public Stream Result get { RaiseExceptionIfNecessary(); - return _result; + return _result!; } } } public class DownloadStringCompletedEventArgs : AsyncCompletedEventArgs { - private readonly string _result; + private readonly string? _result; - internal DownloadStringCompletedEventArgs(string result, Exception exception, bool cancelled, object userToken) : base(exception, cancelled, userToken) + internal DownloadStringCompletedEventArgs(string? result, Exception? exception, bool cancelled, object? userToken) : base(exception, cancelled, userToken) { _result = result; } @@ -2065,7 +2080,7 @@ public string Result get { RaiseExceptionIfNecessary(); - return _result; + return _result!; } } @@ -2073,9 +2088,9 @@ public string Result public class DownloadDataCompletedEventArgs : AsyncCompletedEventArgs { - private readonly byte[] _result; + private readonly byte[]? _result; - internal DownloadDataCompletedEventArgs(byte[] result, Exception exception, bool cancelled, object userToken) : base(exception, cancelled, userToken) + internal DownloadDataCompletedEventArgs(byte[]? result, Exception? exception, bool cancelled, object? userToken) : base(exception, cancelled, userToken) { _result = result; } @@ -2085,16 +2100,16 @@ public byte[] Result get { RaiseExceptionIfNecessary(); - return _result; + return _result!; } } } public class UploadStringCompletedEventArgs : AsyncCompletedEventArgs { - private readonly string _result; + private readonly string? _result; - internal UploadStringCompletedEventArgs(string result, Exception exception, bool cancelled, object userToken) : base(exception, cancelled, userToken) + internal UploadStringCompletedEventArgs(string? result, Exception? exception, bool cancelled, object? userToken) : base(exception, cancelled, userToken) { _result = result; } @@ -2104,16 +2119,16 @@ public string Result get { RaiseExceptionIfNecessary(); - return _result; + return _result!; } } } public class UploadDataCompletedEventArgs : AsyncCompletedEventArgs { - private readonly byte[] _result; + private readonly byte[]? _result; - internal UploadDataCompletedEventArgs(byte[] result, Exception exception, bool cancelled, object userToken) : base(exception, cancelled, userToken) + internal UploadDataCompletedEventArgs(byte[]? result, Exception? exception, bool cancelled, object? userToken) : base(exception, cancelled, userToken) { _result = result; } @@ -2123,16 +2138,16 @@ public byte[] Result get { RaiseExceptionIfNecessary(); - return _result; + return _result!; } } } public class UploadFileCompletedEventArgs : AsyncCompletedEventArgs { - private readonly byte[] _result; + private readonly byte[]? _result; - internal UploadFileCompletedEventArgs(byte[] result, Exception exception, bool cancelled, object userToken) : base(exception, cancelled, userToken) + internal UploadFileCompletedEventArgs(byte[]? result, Exception? exception, bool cancelled, object? userToken) : base(exception, cancelled, userToken) { _result = result; } @@ -2142,16 +2157,16 @@ public byte[] Result get { RaiseExceptionIfNecessary(); - return _result; + return _result!; } } } public class UploadValuesCompletedEventArgs : AsyncCompletedEventArgs { - private readonly byte[] _result; + private readonly byte[]? _result; - internal UploadValuesCompletedEventArgs(byte[] result, Exception exception, bool cancelled, object userToken) : base(exception, cancelled, userToken) + internal UploadValuesCompletedEventArgs(byte[]? result, Exception? exception, bool cancelled, object? userToken) : base(exception, cancelled, userToken) { _result = result; } @@ -2161,14 +2176,14 @@ public byte[] Result get { RaiseExceptionIfNecessary(); - return _result; + return _result!; } } } public class DownloadProgressChangedEventArgs : ProgressChangedEventArgs { - internal DownloadProgressChangedEventArgs(int progressPercentage, object userToken, long bytesReceived, long totalBytesToReceive) : + internal DownloadProgressChangedEventArgs(int progressPercentage, object? userToken, long bytesReceived, long totalBytesToReceive) : base(progressPercentage, userToken) { BytesReceived = bytesReceived; @@ -2182,7 +2197,7 @@ internal DownloadProgressChangedEventArgs(int progressPercentage, object userTok public class UploadProgressChangedEventArgs : ProgressChangedEventArgs { - internal UploadProgressChangedEventArgs(int progressPercentage, object userToken, long bytesSent, long totalBytesToSend, long bytesReceived, long totalBytesToReceive) : + internal UploadProgressChangedEventArgs(int progressPercentage, object? userToken, long bytesSent, long totalBytesToSend, long bytesReceived, long totalBytesToReceive) : base(progressPercentage, userToken) { BytesReceived = bytesReceived; @@ -2207,7 +2222,7 @@ public WriteStreamClosedEventArgs() { } [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)] [EditorBrowsable(EditorBrowsableState.Never)] - public Exception Error { get { return null; } } + public Exception? Error { get { return null; } } } #endregion } diff --git a/src/libraries/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.cs b/src/libraries/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.cs index 2a43104d3291d6..3ddc2363b0f063 100644 --- a/src/libraries/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.cs +++ b/src/libraries/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.cs @@ -11,13 +11,13 @@ public sealed partial class ClientWebSocket : System.Net.WebSockets.WebSocket { public ClientWebSocket() { } public override System.Net.WebSockets.WebSocketCloseStatus? CloseStatus { get { throw null; } } - public override string CloseStatusDescription { get { throw null; } } + public override string? CloseStatusDescription { get { throw null; } } public System.Net.WebSockets.ClientWebSocketOptions Options { get { throw null; } } public override System.Net.WebSockets.WebSocketState State { get { throw null; } } - public override string SubProtocol { get { throw null; } } + public override string? SubProtocol { get { throw null; } } public override void Abort() { } - public override System.Threading.Tasks.Task CloseAsync(System.Net.WebSockets.WebSocketCloseStatus closeStatus, string statusDescription, System.Threading.CancellationToken cancellationToken) { throw null; } - public override System.Threading.Tasks.Task CloseOutputAsync(System.Net.WebSockets.WebSocketCloseStatus closeStatus, string statusDescription, System.Threading.CancellationToken cancellationToken) { throw null; } + public override System.Threading.Tasks.Task CloseAsync(System.Net.WebSockets.WebSocketCloseStatus closeStatus, string? statusDescription, System.Threading.CancellationToken cancellationToken) { throw null; } + public override System.Threading.Tasks.Task CloseOutputAsync(System.Net.WebSockets.WebSocketCloseStatus closeStatus, string? statusDescription, System.Threading.CancellationToken cancellationToken) { throw null; } public System.Threading.Tasks.Task ConnectAsync(System.Uri uri, System.Threading.CancellationToken cancellationToken) { throw null; } public override void Dispose() { } public override System.Threading.Tasks.Task ReceiveAsync(System.ArraySegment buffer, System.Threading.CancellationToken cancellationToken) { throw null; } @@ -29,15 +29,15 @@ public sealed partial class ClientWebSocketOptions { internal ClientWebSocketOptions() { } public System.Security.Cryptography.X509Certificates.X509CertificateCollection ClientCertificates { get { throw null; } set { } } - public System.Net.CookieContainer Cookies { get { throw null; } set { } } - public System.Net.ICredentials Credentials { get { throw null; } set { } } + public System.Net.CookieContainer? Cookies { get { throw null; } set { } } + public System.Net.ICredentials? Credentials { get { throw null; } set { } } public System.TimeSpan KeepAliveInterval { get { throw null; } set { } } - public System.Net.IWebProxy Proxy { get { throw null; } set { } } - public System.Net.Security.RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get { throw null; } set { } } + public System.Net.IWebProxy? Proxy { get { throw null; } set { } } + public System.Net.Security.RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get { throw null; } set { } } public bool UseDefaultCredentials { get { throw null; } set { } } public void AddSubProtocol(string subProtocol) { } public void SetBuffer(int receiveBufferSize, int sendBufferSize) { } public void SetBuffer(int receiveBufferSize, int sendBufferSize, System.ArraySegment buffer) { } - public void SetRequestHeader(string headerName, string headerValue) { } + public void SetRequestHeader(string headerName, string? headerValue) { } } } diff --git a/src/libraries/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.csproj b/src/libraries/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.csproj index 15c7d90f332a9c..7f5666d3064840 100644 --- a/src/libraries/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.csproj +++ b/src/libraries/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent) + enable diff --git a/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj b/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj index 2c9f05d7ff7fa1..60ee641776b69b 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj +++ b/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj @@ -3,7 +3,7 @@ True $(NoWarn);CS1573 $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix - annotations + enable diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs index 8d0146ea384a27..638422843e69ac 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs @@ -19,7 +19,7 @@ private enum InternalState } private readonly ClientWebSocketOptions _options; - private WebSocketHandle _innerWebSocket; // may be mutable struct; do not make readonly + private WebSocketHandle? _innerWebSocket; // may be mutable struct; do not make readonly // NOTE: this is really an InternalState value, but Interlocked doesn't support // operations on values of enum types. @@ -58,7 +58,7 @@ public override WebSocketCloseStatus? CloseStatus } } - public override string CloseStatusDescription + public override string? CloseStatusDescription { get { @@ -70,7 +70,7 @@ public override string CloseStatusDescription } } - public override string SubProtocol + public override string? SubProtocol { get { @@ -162,40 +162,38 @@ public override Task SendAsync(ArraySegment buffer, WebSocketMessageType m CancellationToken cancellationToken) { ThrowIfNotConnected(); - return _innerWebSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken); + return _innerWebSocket!.SendAsync(buffer, messageType, endOfMessage, cancellationToken); } public override ValueTask SendAsync(ReadOnlyMemory buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) { ThrowIfNotConnected(); - return _innerWebSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken); + return _innerWebSocket!.SendAsync(buffer, messageType, endOfMessage, cancellationToken); } public override Task ReceiveAsync(ArraySegment buffer, CancellationToken cancellationToken) { ThrowIfNotConnected(); - return _innerWebSocket.ReceiveAsync(buffer, cancellationToken); + return _innerWebSocket!.ReceiveAsync(buffer, cancellationToken); } public override ValueTask ReceiveAsync(Memory buffer, CancellationToken cancellationToken) { ThrowIfNotConnected(); - return _innerWebSocket.ReceiveAsync(buffer, cancellationToken); + return _innerWebSocket!.ReceiveAsync(buffer, cancellationToken); } - public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, - CancellationToken cancellationToken) + public override Task CloseAsync(WebSocketCloseStatus closeStatus, string? statusDescription, CancellationToken cancellationToken) { ThrowIfNotConnected(); - return _innerWebSocket.CloseAsync(closeStatus, statusDescription, cancellationToken); + return _innerWebSocket!.CloseAsync(closeStatus, statusDescription, cancellationToken); } - public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, - CancellationToken cancellationToken) + public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string? statusDescription, CancellationToken cancellationToken) { ThrowIfNotConnected(); - return _innerWebSocket.CloseOutputAsync(closeStatus, statusDescription, cancellationToken); + return _innerWebSocket!.CloseOutputAsync(closeStatus, statusDescription, cancellationToken); } public override void Abort() @@ -241,8 +239,8 @@ private void ThrowIfNotConnected() internal sealed class DefaultWebProxy : IWebProxy { public static DefaultWebProxy Instance { get; } = new DefaultWebProxy(); - public ICredentials Credentials { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } - public Uri GetProxy(Uri destination) => throw new NotSupportedException(); + public ICredentials? Credentials { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public Uri? GetProxy(Uri destination) => throw new NotSupportedException(); public bool IsBypassed(Uri host) => throw new NotSupportedException(); } } diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs index a5df90b0778efc..655ca3616fe55f 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Threading; @@ -16,23 +15,23 @@ public sealed class ClientWebSocketOptions private bool _isReadOnly; // After ConnectAsync is called the options cannot be modified. private TimeSpan _keepAliveInterval = WebSocket.DefaultKeepAliveInterval; private bool _useDefaultCredentials; - private ICredentials _credentials; - private IWebProxy _proxy; - private CookieContainer _cookies; + private ICredentials? _credentials; + private IWebProxy? _proxy; + private CookieContainer? _cookies; private int _receiveBufferSize = 0x1000; private ArraySegment? _buffer; - private RemoteCertificateValidationCallback _remoteCertificateValidationCallback; + private RemoteCertificateValidationCallback? _remoteCertificateValidationCallback; - internal X509CertificateCollection _clientCertificates; - internal WebHeaderCollection _requestHeaders; - internal List _requestedSubProtocols; + internal X509CertificateCollection? _clientCertificates; + internal WebHeaderCollection? _requestHeaders; + internal List? _requestedSubProtocols; internal ClientWebSocketOptions() { } // prevent external instantiation #region HTTP Settings // Note that some headers are restricted like Host. - public void SetRequestHeader(string headerName, string headerValue) + public void SetRequestHeader(string headerName, string? headerValue) { ThrowIfReadOnly(); @@ -40,18 +39,13 @@ public void SetRequestHeader(string headerName, string headerValue) RequestHeaders.Set(headerName, headerValue); } - internal WebHeaderCollection RequestHeaders => - _requestHeaders ?? (_requestHeaders = new WebHeaderCollection()); + internal WebHeaderCollection RequestHeaders => _requestHeaders ??= new WebHeaderCollection(); - internal List RequestedSubProtocols => - _requestedSubProtocols ?? (_requestedSubProtocols = new List()); + internal List RequestedSubProtocols => _requestedSubProtocols ??= new List(); public bool UseDefaultCredentials { - get - { - return _useDefaultCredentials; - } + get => _useDefaultCredentials; set { ThrowIfReadOnly(); @@ -59,12 +53,9 @@ public bool UseDefaultCredentials } } - public ICredentials Credentials + public ICredentials? Credentials { - get - { - return _credentials; - } + get => _credentials; set { ThrowIfReadOnly(); @@ -72,12 +63,9 @@ public ICredentials Credentials } } - public IWebProxy Proxy + public IWebProxy? Proxy { - get - { - return _proxy; - } + get => _proxy; set { ThrowIfReadOnly(); @@ -87,26 +75,15 @@ public IWebProxy Proxy public X509CertificateCollection ClientCertificates { - get - { - if (_clientCertificates == null) - { - _clientCertificates = new X509CertificateCollection(); - } - return _clientCertificates; - } + get => _clientCertificates ??= new X509CertificateCollection(); set { ThrowIfReadOnly(); - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _clientCertificates = value; + _clientCertificates = value ?? throw new ArgumentNullException(nameof(value)); } } - public RemoteCertificateValidationCallback RemoteCertificateValidationCallback + public RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get => _remoteCertificateValidationCallback; set @@ -116,12 +93,9 @@ public RemoteCertificateValidationCallback RemoteCertificateValidationCallback } } - public CookieContainer Cookies + public CookieContainer? Cookies { - get - { - return _cookies; - } + get => _cookies; set { ThrowIfReadOnly(); @@ -152,10 +126,7 @@ public void AddSubProtocol(string subProtocol) public TimeSpan KeepAliveInterval { - get - { - return _keepAliveInterval; - } + get => _keepAliveInterval; set { ThrowIfReadOnly(); diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs index 63dbd3b1b90308..893da94be67ee8 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Http; using System.Net.Http.Headers; @@ -21,23 +22,23 @@ internal sealed class WebSocketHandle private const string WSServerGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; /// Shared, lazily-initialized handler for when using default options. - private static SocketsHttpHandler s_defaultHandler; + private static SocketsHttpHandler? s_defaultHandler; private readonly CancellationTokenSource _abortSource = new CancellationTokenSource(); private WebSocketState _state = WebSocketState.Connecting; - private WebSocket _webSocket; + private WebSocket? _webSocket; public static WebSocketHandle Create() => new WebSocketHandle(); - public static bool IsValid(WebSocketHandle handle) => handle != null; + public static bool IsValid([NotNullWhen(true)] WebSocketHandle? handle) => handle != null; public WebSocketCloseStatus? CloseStatus => _webSocket?.CloseStatus; - public string CloseStatusDescription => _webSocket?.CloseStatusDescription; + public string? CloseStatusDescription => _webSocket?.CloseStatusDescription; public WebSocketState State => _webSocket?.State ?? _state; - public string SubProtocol => _webSocket?.SubProtocol; + public string? SubProtocol => _webSocket?.SubProtocol; public static void CheckPlatformSupport() { /* nop */ } @@ -54,36 +55,36 @@ public void Abort() } public Task SendAsync(ArraySegment buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) => - _webSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken); + _webSocket!.SendAsync(buffer, messageType, endOfMessage, cancellationToken); public ValueTask SendAsync(ReadOnlyMemory buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) => - _webSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken); + _webSocket!.SendAsync(buffer, messageType, endOfMessage, cancellationToken); public Task ReceiveAsync(ArraySegment buffer, CancellationToken cancellationToken) => - _webSocket.ReceiveAsync(buffer, cancellationToken); + _webSocket!.ReceiveAsync(buffer, cancellationToken); public ValueTask ReceiveAsync(Memory buffer, CancellationToken cancellationToken) => - _webSocket.ReceiveAsync(buffer, cancellationToken); + _webSocket!.ReceiveAsync(buffer, cancellationToken); - public Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) => - _webSocket.CloseAsync(closeStatus, statusDescription, cancellationToken); + public Task CloseAsync(WebSocketCloseStatus closeStatus, string? statusDescription, CancellationToken cancellationToken) => + _webSocket!.CloseAsync(closeStatus, statusDescription, cancellationToken); - public Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) => - _webSocket.CloseOutputAsync(closeStatus, statusDescription, cancellationToken); + public Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string? statusDescription, CancellationToken cancellationToken) => + _webSocket!.CloseOutputAsync(closeStatus, statusDescription, cancellationToken); public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { - HttpResponseMessage response = null; - SocketsHttpHandler handler = null; + HttpResponseMessage? response = null; + SocketsHttpHandler? handler = null; bool disposeHandler = true; try { var request = new HttpRequestMessage(HttpMethod.Get, uri); if (options._requestHeaders?.Count > 0) // use field to avoid lazily initializing the collection { - foreach (string key in options.RequestHeaders) + foreach (string? key in options.RequestHeaders) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/3214 { - request.Headers.TryAddWithoutValidation(key, options.RequestHeaders[key]); + request.Headers.TryAddWithoutValidation(key!, options.RequestHeaders[key!]); } } @@ -153,7 +154,8 @@ public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, } // Issue the request. The response must be status code 101. - CancellationTokenSource linkedCancellation, externalAndAbortCancellation; + CancellationTokenSource? linkedCancellation; + CancellationTokenSource externalAndAbortCancellation; if (cancellationToken.CanBeCanceled) // avoid allocating linked source if external token is not cancelable { linkedCancellation = @@ -185,9 +187,8 @@ public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, // The SecWebSocketProtocol header is optional. We should only get it with a non-empty value if we requested subprotocols, // and then it must only be one of the ones we requested. If we got a subprotocol other than one we requested (or if we // already got one in a previous header), fail. Otherwise, track which one we got. - string subprotocol = null; - IEnumerable subprotocolEnumerableValues; - if (response.Headers.TryGetValues(HttpKnownHeaderNames.SecWebSocketProtocol, out subprotocolEnumerableValues)) + string? subprotocol = null; + if (response.Headers.TryGetValues(HttpKnownHeaderNames.SecWebSocketProtocol, out IEnumerable? subprotocolEnumerableValues)) { Debug.Assert(subprotocolEnumerableValues is string[]); string[] subprotocolArray = (string[])subprotocolEnumerableValues; @@ -203,6 +204,11 @@ public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, } } + if (response.Content is null) + { + throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely); + } + // Get the response stream and wrap it in a web socket. Stream connectedStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); Debug.Assert(connectedStream.CanWrite); @@ -273,7 +279,7 @@ private static KeyValuePair CreateSecKeyAndSecWebSocketAccept() private static void ValidateHeader(HttpHeaders headers, string name, string expectedValue) { - if (!headers.TryGetValues(name, out IEnumerable values)) + if (!headers.TryGetValues(name, out IEnumerable? values)) { throw new WebSocketException(WebSocketError.Faulted, SR.Format(SR.net_WebSockets_MissingResponseHeader, name)); } diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Windows.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Windows.cs deleted file mode 100644 index 679b5e5d6db969..00000000000000 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Windows.cs +++ /dev/null @@ -1,139 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Diagnostics; -using System.Net; -using System.Security.Cryptography.X509Certificates; -using System.Threading; -using System.Threading.Tasks; - -using Microsoft.Win32.SafeHandles; - -namespace System.Net.WebSockets -{ - internal readonly partial struct WebSocketHandle - { - #region Properties - public static bool IsValid(WebSocketHandle handle) - { - return handle._webSocket != null; - } - - public WebSocketCloseStatus? CloseStatus - { - get - { - return _webSocket.CloseStatus; - } - } - - public string CloseStatusDescription - { - get - { - return _webSocket.CloseStatusDescription; - } - } - - public WebSocketState State - { - get - { - return _webSocket.State; - } - } - - public string SubProtocol - { - get - { - return _webSocket.SubProtocol; - } - } - #endregion - - public Task SendAsync( - ArraySegment buffer, - WebSocketMessageType messageType, - bool endOfMessage, - CancellationToken cancellationToken) - { - if (messageType != WebSocketMessageType.Text && messageType != WebSocketMessageType.Binary) - { - string errorMessage = SR.Format( - SR.net_WebSockets_Argument_InvalidMessageType, - nameof(WebSocketMessageType.Close), - nameof(SendAsync), - nameof(WebSocketMessageType.Binary), - nameof(WebSocketMessageType.Text), - nameof(CloseOutputAsync)); - throw new ArgumentException(errorMessage, nameof(messageType)); - } - - WebSocketValidate.ValidateArraySegment(buffer, nameof(buffer)); - - return _webSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken); - } - - public ValueTask SendAsync(ReadOnlyMemory buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) - { - if (messageType != WebSocketMessageType.Text && messageType != WebSocketMessageType.Binary) - { - string errorMessage = SR.Format( - SR.net_WebSockets_Argument_InvalidMessageType, - nameof(WebSocketMessageType.Close), - nameof(SendAsync), - nameof(WebSocketMessageType.Binary), - nameof(WebSocketMessageType.Text), - nameof(CloseOutputAsync)); - throw new ArgumentException(errorMessage, nameof(messageType)); - } - - return _webSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken); - } - - public Task ReceiveAsync( - ArraySegment buffer, - CancellationToken cancellationToken) - { - WebSocketValidate.ValidateArraySegment(buffer, nameof(buffer)); - return _webSocket.ReceiveAsync(buffer, cancellationToken); - } - - public ValueTask ReceiveAsync(Memory buffer, CancellationToken cancellationToken) => - _webSocket.ReceiveAsync(buffer, cancellationToken); - - public Task CloseAsync( - WebSocketCloseStatus closeStatus, - string statusDescription, - CancellationToken cancellationToken) - { - WebSocketValidate.ValidateCloseStatus(closeStatus, statusDescription); - return _webSocket.CloseAsync(closeStatus, statusDescription, cancellationToken); - } - - public Task CloseOutputAsync( - WebSocketCloseStatus closeStatus, - string statusDescription, - CancellationToken cancellationToken) - { - WebSocketValidate.ValidateCloseStatus(closeStatus, statusDescription); - return _webSocket.CloseOutputAsync(closeStatus, statusDescription, cancellationToken); - } - - public void Dispose() - { - _webSocket.Dispose(); - } - - public void Abort() - { - _webSocket.Abort(); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/Internal/Resources/WindowsRuntimeResourceManagerBase.cs b/src/libraries/System.Private.CoreLib/src/Internal/Resources/WindowsRuntimeResourceManagerBase.cs index 173b2372c95965..20b73ed41983eb 100644 --- a/src/libraries/System.Private.CoreLib/src/Internal/Resources/WindowsRuntimeResourceManagerBase.cs +++ b/src/libraries/System.Private.CoreLib/src/Internal/Resources/WindowsRuntimeResourceManagerBase.cs @@ -12,7 +12,7 @@ public abstract class WindowsRuntimeResourceManagerBase { public abstract bool Initialize(string libpath, string reswFilename, out PRIExceptionInfo? exceptionInfo); - public abstract string GetString(string stringName, string? startingCulture, string? neutralResourcesCulture); + public abstract string? GetString(string stringName, string? startingCulture, string? neutralResourcesCulture); public abstract CultureInfo? GlobalResourceContextBestFitCultureInfo { diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 7b306a46df9ca3..b5a654a61e63b7 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1293,9 +1293,6 @@ Common\Interop\Windows\Kernel32\Interop.GetTempPathW.cs - - Common\Interop\Windows\Kernel32\Interop.GetVersionExW.cs - Common\Interop\Windows\Kernel32\Interop.Globalization.cs @@ -1422,6 +1419,9 @@ Common\Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs + + Common\Interop\Windows\NtDll\Interop.RtlGetVersion.cs + Common\Interop\Windows\NtDll\Interop.SYSTEM_LEAP_SECOND_INFORMATION.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/BitConverter.cs b/src/libraries/System.Private.CoreLib/src/System/BitConverter.cs index 25719466ddb092..bf604f41a97d60 100644 --- a/src/libraries/System.Private.CoreLib/src/System/BitConverter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/BitConverter.cs @@ -4,6 +4,8 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; using Internal.Runtime.CompilerServices; @@ -449,24 +451,52 @@ public static bool ToBoolean(ReadOnlySpan value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe long DoubleToInt64Bits(double value) { + // Workaround for https://github.com/dotnet/runtime/issues/11413 + if (Sse2.X64.IsSupported) + { + Vector128 vec = Vector128.CreateScalarUnsafe(value).AsInt64(); + return Sse2.X64.ConvertToInt64(vec); + } + return *((long*)&value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe double Int64BitsToDouble(long value) { + // Workaround for https://github.com/dotnet/runtime/issues/11413 + if (Sse2.X64.IsSupported) + { + Vector128 vec = Vector128.CreateScalarUnsafe(value).AsDouble(); + return vec.ToScalar(); + } + return *((double*)&value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe int SingleToInt32Bits(float value) { + // Workaround for https://github.com/dotnet/runtime/issues/11413 + if (Sse2.IsSupported) + { + Vector128 vec = Vector128.CreateScalarUnsafe(value).AsInt32(); + return Sse2.ConvertToInt32(vec); + } + return *((int*)&value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe float Int32BitsToSingle(int value) { + // Workaround for https://github.com/dotnet/runtime/issues/11413 + if (Sse2.IsSupported) + { + Vector128 vec = Vector128.CreateScalarUnsafe(value).AsSingle(); + return vec.ToScalar(); + } + return *((float*)&value); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs index 88d349a4bd842e..77b10c44251131 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs @@ -166,7 +166,7 @@ private static bool TryParse(ReadOnlySpan s, NumberStyles style, NumberFor public override string ToString() { - return Number.UInt32ToDecStr(m_value, -1); + return Number.UInt32ToDecStr(m_value); } public string ToString(string? format) @@ -176,7 +176,7 @@ public string ToString(string? format) public string ToString(IFormatProvider? provider) { - return Number.FormatUInt32(m_value, null, provider); + return Number.UInt32ToDecStr(m_value); } public string ToString(string? format, IFormatProvider? provider) diff --git a/src/libraries/System.Private.CoreLib/src/System/Convert.cs b/src/libraries/System.Private.CoreLib/src/System/Convert.cs index 50ee261c32523d..ec6b92a96d569b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Convert.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Convert.cs @@ -528,11 +528,7 @@ public static char ToChar(ushort value) return (char)value; } - public static char ToChar(int value) - { - if (value < 0 || value > char.MaxValue) ThrowCharOverflowException(); - return (char)value; - } + public static char ToChar(int value) => ToChar((uint)value); [CLSCompliant(false)] public static char ToChar(uint value) @@ -541,11 +537,7 @@ public static char ToChar(uint value) return (char)value; } - public static char ToChar(long value) - { - if (value < 0 || value > char.MaxValue) ThrowCharOverflowException(); - return (char)value; - } + public static char ToChar(long value) => ToChar((ulong)value); [CLSCompliant(false)] public static char ToChar(ulong value) @@ -667,7 +659,7 @@ public static sbyte ToSByte(int value) [CLSCompliant(false)] public static sbyte ToSByte(uint value) { - if (value > sbyte.MaxValue) ThrowSByteOverflowException(); + if (value > (uint)sbyte.MaxValue) ThrowSByteOverflowException(); return (sbyte)value; } @@ -708,13 +700,13 @@ public static sbyte ToSByte(string? value) { if (value == null) return 0; - return sbyte.Parse(value, CultureInfo.CurrentCulture); + return sbyte.Parse(value); } [CLSCompliant(false)] public static sbyte ToSByte(string value, IFormatProvider? provider) { - return sbyte.Parse(value, NumberStyles.Integer, provider); + return sbyte.Parse(value, provider); } [CLSCompliant(false)] @@ -757,13 +749,13 @@ public static byte ToByte(char value) [CLSCompliant(false)] public static byte ToByte(sbyte value) { - if (value < byte.MinValue) ThrowByteOverflowException(); + if (value < 0) ThrowByteOverflowException(); return (byte)value; } public static byte ToByte(short value) { - if (value < byte.MinValue || value > byte.MaxValue) ThrowByteOverflowException(); + if ((uint)value > byte.MaxValue) ThrowByteOverflowException(); return (byte)value; } @@ -774,11 +766,7 @@ public static byte ToByte(ushort value) return (byte)value; } - public static byte ToByte(int value) - { - if (value < byte.MinValue || value > byte.MaxValue) ThrowByteOverflowException(); - return (byte)value; - } + public static byte ToByte(int value) => ToByte((uint)value); [CLSCompliant(false)] public static byte ToByte(uint value) @@ -787,11 +775,7 @@ public static byte ToByte(uint value) return (byte)value; } - public static byte ToByte(long value) - { - if (value < byte.MinValue || value > byte.MaxValue) ThrowByteOverflowException(); - return (byte)value; - } + public static byte ToByte(long value) => ToByte((ulong)value); [CLSCompliant(false)] public static byte ToByte(ulong value) @@ -819,14 +803,14 @@ public static byte ToByte(string? value) { if (value == null) return 0; - return byte.Parse(value, CultureInfo.CurrentCulture); + return byte.Parse(value); } public static byte ToByte(string? value, IFormatProvider? provider) { if (value == null) return 0; - return byte.Parse(value, NumberStyles.Integer, provider); + return byte.Parse(value, provider); } public static byte ToByte(DateTime value) @@ -887,7 +871,7 @@ public static short ToInt16(int value) [CLSCompliant(false)] public static short ToInt16(uint value) { - if (value > short.MaxValue) ThrowInt16OverflowException(); + if (value > (uint)short.MaxValue) ThrowInt16OverflowException(); return (short)value; } @@ -928,14 +912,14 @@ public static short ToInt16(string? value) { if (value == null) return 0; - return short.Parse(value, CultureInfo.CurrentCulture); + return short.Parse(value); } public static short ToInt16(string? value, IFormatProvider? provider) { if (value == null) return 0; - return short.Parse(value, NumberStyles.Integer, provider); + return short.Parse(value, provider); } public static short ToInt16(DateTime value) @@ -993,11 +977,7 @@ public static ushort ToUInt16(short value) } [CLSCompliant(false)] - public static ushort ToUInt16(int value) - { - if (value < 0 || value > ushort.MaxValue) ThrowUInt16OverflowException(); - return (ushort)value; - } + public static ushort ToUInt16(int value) => ToUInt16((uint)value); [CLSCompliant(false)] public static ushort ToUInt16(ushort value) @@ -1013,11 +993,7 @@ public static ushort ToUInt16(uint value) } [CLSCompliant(false)] - public static ushort ToUInt16(long value) - { - if (value < 0 || value > ushort.MaxValue) ThrowUInt16OverflowException(); - return (ushort)value; - } + public static ushort ToUInt16(long value) => ToUInt16((ulong)value); [CLSCompliant(false)] public static ushort ToUInt16(ulong value) @@ -1049,7 +1025,7 @@ public static ushort ToUInt16(string? value) { if (value == null) return 0; - return ushort.Parse(value, CultureInfo.CurrentCulture); + return ushort.Parse(value); } [CLSCompliant(false)] @@ -1057,7 +1033,7 @@ public static ushort ToUInt16(string? value, IFormatProvider? provider) { if (value == null) return 0; - return ushort.Parse(value, NumberStyles.Integer, provider); + return ushort.Parse(value, provider); } [CLSCompliant(false)] @@ -1116,7 +1092,7 @@ public static int ToInt32(ushort value) [CLSCompliant(false)] public static int ToInt32(uint value) { - if (value > int.MaxValue) ThrowInt32OverflowException(); + if ((int)value < 0) ThrowInt32OverflowException(); return (int)value; } @@ -1177,14 +1153,14 @@ public static int ToInt32(string? value) { if (value == null) return 0; - return int.Parse(value, CultureInfo.CurrentCulture); + return int.Parse(value); } public static int ToInt32(string? value, IFormatProvider? provider) { if (value == null) return 0; - return int.Parse(value, NumberStyles.Integer, provider); + return int.Parse(value, provider); } public static int ToInt32(DateTime value) @@ -1261,11 +1237,7 @@ public static uint ToUInt32(uint value) } [CLSCompliant(false)] - public static uint ToUInt32(long value) - { - if (value < 0 || value > uint.MaxValue) ThrowUInt32OverflowException(); - return (uint)value; - } + public static uint ToUInt32(long value) => ToUInt32((ulong)value); [CLSCompliant(false)] public static uint ToUInt32(ulong value) @@ -1304,7 +1276,7 @@ public static uint ToUInt32(string? value) { if (value == null) return 0; - return uint.Parse(value, CultureInfo.CurrentCulture); + return uint.Parse(value); } [CLSCompliant(false)] @@ -1312,7 +1284,7 @@ public static uint ToUInt32(string? value, IFormatProvider? provider) { if (value == null) return 0; - return uint.Parse(value, NumberStyles.Integer, provider); + return uint.Parse(value, provider); } [CLSCompliant(false)] @@ -1382,7 +1354,7 @@ public static long ToInt64(uint value) [CLSCompliant(false)] public static long ToInt64(ulong value) { - if (value > long.MaxValue) ThrowInt64OverflowException(); + if ((long)value < 0) ThrowInt64OverflowException(); return (long)value; } @@ -1410,14 +1382,14 @@ public static long ToInt64(string? value) { if (value == null) return 0; - return long.Parse(value, CultureInfo.CurrentCulture); + return long.Parse(value); } public static long ToInt64(string? value, IFormatProvider? provider) { if (value == null) return 0; - return long.Parse(value, NumberStyles.Integer, provider); + return long.Parse(value, provider); } public static long ToInt64(DateTime value) @@ -1529,7 +1501,7 @@ public static ulong ToUInt64(string? value) { if (value == null) return 0; - return ulong.Parse(value, CultureInfo.CurrentCulture); + return ulong.Parse(value); } [CLSCompliant(false)] @@ -1537,7 +1509,7 @@ public static ulong ToUInt64(string? value, IFormatProvider? provider) { if (value == null) return 0; - return ulong.Parse(value, NumberStyles.Integer, provider); + return ulong.Parse(value, provider); } [CLSCompliant(false)] @@ -1629,14 +1601,14 @@ public static float ToSingle(string? value) { if (value == null) return 0; - return float.Parse(value, CultureInfo.CurrentCulture); + return float.Parse(value); } public static float ToSingle(string? value, IFormatProvider? provider) { if (value == null) return 0; - return float.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider); + return float.Parse(value, provider); } public static float ToSingle(bool value) @@ -1732,14 +1704,14 @@ public static double ToDouble(string? value) { if (value == null) return 0; - return double.Parse(value, CultureInfo.CurrentCulture); + return double.Parse(value); } public static double ToDouble(string? value, IFormatProvider? provider) { if (value == null) return 0; - return double.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider); + return double.Parse(value, provider); } public static double ToDouble(bool value) @@ -1830,14 +1802,14 @@ public static decimal ToDecimal(string? value) { if (value == null) return 0m; - return decimal.Parse(value, CultureInfo.CurrentCulture); + return decimal.Parse(value); } public static decimal ToDecimal(string? value, IFormatProvider? provider) { if (value == null) return 0m; - return decimal.Parse(value, NumberStyles.Number, provider); + return decimal.Parse(value, provider); } public static decimal ToDecimal(decimal value) @@ -1879,7 +1851,7 @@ public static DateTime ToDateTime(string? value) { if (value == null) return new DateTime(0); - return DateTime.Parse(value, CultureInfo.CurrentCulture); + return DateTime.Parse(value); } public static DateTime ToDateTime(string? value, IFormatProvider? provider) @@ -2000,7 +1972,7 @@ public static string ToString(char value, IFormatProvider? provider) [CLSCompliant(false)] public static string ToString(sbyte value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } [CLSCompliant(false)] @@ -2011,7 +1983,7 @@ public static string ToString(sbyte value, IFormatProvider? provider) public static string ToString(byte value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(byte value, IFormatProvider? provider) @@ -2021,7 +1993,7 @@ public static string ToString(byte value, IFormatProvider? provider) public static string ToString(short value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(short value, IFormatProvider? provider) @@ -2032,7 +2004,7 @@ public static string ToString(short value, IFormatProvider? provider) [CLSCompliant(false)] public static string ToString(ushort value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } [CLSCompliant(false)] @@ -2043,7 +2015,7 @@ public static string ToString(ushort value, IFormatProvider? provider) public static string ToString(int value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(int value, IFormatProvider? provider) @@ -2054,7 +2026,7 @@ public static string ToString(int value, IFormatProvider? provider) [CLSCompliant(false)] public static string ToString(uint value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } [CLSCompliant(false)] @@ -2065,7 +2037,7 @@ public static string ToString(uint value, IFormatProvider? provider) public static string ToString(long value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(long value, IFormatProvider? provider) @@ -2076,7 +2048,7 @@ public static string ToString(long value, IFormatProvider? provider) [CLSCompliant(false)] public static string ToString(ulong value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } [CLSCompliant(false)] @@ -2087,7 +2059,7 @@ public static string ToString(ulong value, IFormatProvider? provider) public static string ToString(float value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(float value, IFormatProvider? provider) @@ -2097,7 +2069,7 @@ public static string ToString(float value, IFormatProvider? provider) public static string ToString(double value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(double value, IFormatProvider? provider) @@ -2107,7 +2079,7 @@ public static string ToString(double value, IFormatProvider? provider) public static string ToString(decimal value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(decimal value, IFormatProvider? provider) @@ -2157,7 +2129,7 @@ public static byte ToByte(string? value, int fromBase) } int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned); - if (r < byte.MinValue || r > byte.MaxValue) + if ((uint)r > byte.MaxValue) ThrowByteOverflowException(); return (byte)r; } @@ -2231,7 +2203,7 @@ public static ushort ToUInt16(string? value, int fromBase) } int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned); - if (r < ushort.MinValue || r > ushort.MaxValue) + if ((uint)r > ushort.MaxValue) ThrowUInt16OverflowException(); return (ushort)r; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs index da61628abb0643..72b85bfeaf44fe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs @@ -936,9 +936,9 @@ public static explicit operator char(decimal value) [CLSCompliant(false)] public static explicit operator ulong(decimal value) => ToUInt64(value); - public static explicit operator float(decimal value) => ToSingle(value); + public static explicit operator float(decimal value) => DecCalc.VarR4FromDec(in value); - public static explicit operator double(decimal value) => ToDouble(value); + public static explicit operator double(decimal value) => DecCalc.VarR8FromDec(in value); public static decimal operator +(decimal d) => d; @@ -1051,12 +1051,12 @@ ulong IConvertible.ToUInt64(IFormatProvider? provider) float IConvertible.ToSingle(IFormatProvider? provider) { - return Convert.ToSingle(this); + return DecCalc.VarR4FromDec(in this); } double IConvertible.ToDouble(IFormatProvider? provider) { - return Convert.ToDouble(this); + return DecCalc.VarR8FromDec(in this); } decimal IConvertible.ToDecimal(IFormatProvider? provider) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs index 0b24c01a76438e..35a59488cffed6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs @@ -125,4 +125,55 @@ sealed class DoesNotReturnIfAttribute : Attribute /// Gets the condition parameter value. public bool ParameterValue { get; } } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + [CLSCompliant(false)] + public +#endif + sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) + => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + [CLSCompliant(false)] + public +#endif + sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } + } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs index e4ac0a0e83211c..6a7bd32e4ccce2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs @@ -89,16 +89,16 @@ private static string ExpandEnvironmentVariablesCore(string name) private static unsafe OperatingSystem GetOSVersion() { - var version = new Interop.Kernel32.OSVERSIONINFOEX { dwOSVersionInfoSize = sizeof(Interop.Kernel32.OSVERSIONINFOEX) }; - if (!Interop.Kernel32.GetVersionExW(ref version)) + if (Interop.NtDll.RtlGetVersionEx(out Interop.NtDll.RTL_OSVERSIONINFOEX osvi) != 0) { throw new InvalidOperationException(SR.InvalidOperation_GetVersion); } - return new OperatingSystem( - PlatformID.Win32NT, - new Version(version.dwMajorVersion, version.dwMinorVersion, version.dwBuildNumber, (version.wServicePackMajor << 16) | version.wServicePackMinor), - Marshal.PtrToStringUni((IntPtr)version.szCSDVersion)); + var version = new Version((int)osvi.dwMajorVersion, (int)osvi.dwMinorVersion, (int)osvi.dwBuildNumber, 0); + + return osvi.szCSDVersion[0] != '\0' ? + new OperatingSystem(PlatformID.Win32NT, version, new string(&osvi.szCSDVersion[0])) : + new OperatingSystem(PlatformID.Win32NT, version); } public static string SystemDirectory diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs index e429353a0c83eb..f3c3e5d4a329f7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs @@ -418,5 +418,7 @@ private static string GetConsoleFallbackName(string cultureName) internal bool IsWin32Installed => false; internal bool IsReplacementCulture => false; + + internal static CultureData GetCurrentRegionData() => CultureInfo.CurrentCulture._cultureData; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs index b8ae4083724547..48e4552c520ef5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Internal.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace System.Globalization { @@ -714,5 +715,33 @@ internal bool IsReplacementCulture return false; } } + + internal static unsafe CultureData GetCurrentRegionData() + { + Span geoIso2Letters = stackalloc char[10]; + + int geoId = Interop.Kernel32.GetUserGeoID(Interop.Kernel32.GEOCLASS_NATION); + if (geoId != Interop.Kernel32.GEOID_NOT_AVAILABLE) + { + int geoIsoIdLength; + fixed (char* pGeoIsoId = geoIso2Letters) + { + geoIsoIdLength = Interop.Kernel32.GetGeoInfo(geoId, Interop.Kernel32.GEO_ISO2, pGeoIsoId, geoIso2Letters.Length, 0); + } + + if (geoIsoIdLength != 0) + { + geoIsoIdLength -= geoIso2Letters[geoIsoIdLength - 1] == 0 ? 1 : 0; // handle null termination and exclude it. + CultureData? cd = GetCultureDataForRegion(geoIso2Letters.Slice(0, geoIsoIdLength).ToString(), true); + if (cd != null) + { + return cd; + } + } + } + + // Fallback to current locale data. + return CultureInfo.CurrentCulture._cultureData; + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs index 90a502bfc455c9..70fc78879bbd80 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs @@ -152,135 +152,262 @@ internal partial class CultureData /// private static Dictionary RegionNames => s_regionNames ??= - new Dictionary(211 /* prime */) + new Dictionary(257 /* prime */) { + { "001", "en-001" }, { "029", "en-029" }, + { "150", "en-150" }, + { "419", "es-419" }, + { "AD", "ca-AD" }, { "AE", "ar-AE" }, { "AF", "prs-AF" }, + { "AG", "en-AG" }, + { "AI", "en-AI" }, { "AL", "sq-AL" }, { "AM", "hy-AM" }, + { "AO", "pt-AO" }, + { "AQ", "en-A" }, { "AR", "es-AR" }, + { "AS", "en-AS" }, { "AT", "de-AT" }, { "AU", "en-AU" }, + { "AW", "nl-AW" }, + { "AX", "sv-AX" }, { "AZ", "az-Cyrl-AZ" }, { "BA", "bs-Latn-BA" }, + { "BB", "en-BB" }, { "BD", "bn-BD" }, { "BE", "nl-BE" }, + { "BF", "fr-BF" }, { "BG", "bg-BG" }, { "BH", "ar-BH" }, + { "BI", "rn-BI" }, + { "BJ", "fr-BJ" }, + { "BL", "fr-BL" }, + { "BM", "en-BM" }, { "BN", "ms-BN" }, { "BO", "es-BO" }, + { "BQ", "nl-BQ" }, { "BR", "pt-BR" }, + { "BS", "en-BS" }, + { "BT", "dz-BT" }, + { "BV", "nb-B" }, + { "BW", "en-BW" }, { "BY", "be-BY" }, { "BZ", "en-BZ" }, { "CA", "en-CA" }, + { "CC", "en-CC" }, + { "CD", "fr-CD" }, + { "CF", "sg-CF" }, + { "CG", "fr-CG" }, { "CH", "it-CH" }, + { "CI", "fr-CI" }, + { "CK", "en-CK" }, { "CL", "es-CL" }, + { "CM", "fr-C" }, { "CN", "zh-CN" }, { "CO", "es-CO" }, { "CR", "es-CR" }, { "CS", "sr-Cyrl-CS" }, + { "CU", "es-CU" }, + { "CV", "pt-CV" }, + { "CW", "nl-CW" }, + { "CX", "en-CX" }, + { "CY", "el-CY" }, { "CZ", "cs-CZ" }, { "DE", "de-DE" }, + { "DJ", "fr-DJ" }, { "DK", "da-DK" }, + { "DM", "en-DM" }, { "DO", "es-DO" }, { "DZ", "ar-DZ" }, { "EC", "es-EC" }, { "EE", "et-EE" }, { "EG", "ar-EG" }, + { "ER", "tig-ER" }, { "ES", "es-ES" }, { "ET", "am-ET" }, { "FI", "fi-FI" }, + { "FJ", "en-FJ" }, + { "FK", "en-FK" }, + { "FM", "en-FM" }, { "FO", "fo-FO" }, { "FR", "fr-FR" }, + { "GA", "fr-GA" }, { "GB", "en-GB" }, + { "GD", "en-GD" }, { "GE", "ka-GE" }, + { "GF", "fr-GF" }, + { "GG", "en-GG" }, + { "GH", "en-GH" }, + { "GI", "en-GI" }, { "GL", "kl-GL" }, + { "GM", "en-GM" }, + { "GN", "fr-GN" }, + { "GP", "fr-GP" }, + { "GQ", "es-GQ" }, { "GR", "el-GR" }, + { "GS", "en-G" }, { "GT", "es-GT" }, + { "GU", "en-GU" }, + { "GW", "pt-GW" }, + { "GY", "en-GY" }, { "HK", "zh-HK" }, + { "HM", "en-H" }, { "HN", "es-HN" }, { "HR", "hr-HR" }, + { "HT", "fr-HT" }, { "HU", "hu-HU" }, { "ID", "id-ID" }, { "IE", "en-IE" }, { "IL", "he-IL" }, + { "IM", "gv-IM" }, { "IN", "hi-IN" }, + { "IO", "en-IO" }, { "IQ", "ar-IQ" }, { "IR", "fa-IR" }, { "IS", "is-IS" }, { "IT", "it-IT" }, { "IV", "" }, + { "JE", "en-JE" }, { "JM", "en-JM" }, { "JO", "ar-JO" }, { "JP", "ja-JP" }, { "KE", "sw-KE" }, { "KG", "ky-KG" }, { "KH", "km-KH" }, + { "KI", "en-KI" }, + { "KM", "ar-KM" }, + { "KN", "en-KN" }, + { "KP", "ko-KP" }, { "KR", "ko-KR" }, { "KW", "ar-KW" }, + { "KY", "en-KY" }, { "KZ", "kk-KZ" }, { "LA", "lo-LA" }, { "LB", "ar-LB" }, + { "LC", "en-LC" }, { "LI", "de-LI" }, { "LK", "si-LK" }, + { "LR", "en-LR" }, + { "LS", "st-LS" }, { "LT", "lt-LT" }, { "LU", "lb-LU" }, { "LV", "lv-LV" }, { "LY", "ar-LY" }, { "MA", "ar-MA" }, { "MC", "fr-MC" }, + { "MD", "ro-MD" }, { "ME", "sr-Latn-ME" }, + { "MF", "fr-MF" }, + { "MG", "mg-MG" }, + { "MH", "en-MH" }, { "MK", "mk-MK" }, + { "ML", "fr-ML" }, + { "MM", "my-MM" }, { "MN", "mn-MN" }, { "MO", "zh-MO" }, + { "MP", "en-MP" }, + { "MQ", "fr-MQ" }, + { "MR", "ar-MR" }, + { "MS", "en-MS" }, { "MT", "mt-MT" }, + { "MU", "en-MU" }, { "MV", "dv-MV" }, + { "MW", "en-MW" }, { "MX", "es-MX" }, { "MY", "ms-MY" }, + { "MZ", "pt-MZ" }, + { "NA", "en-NA" }, + { "NC", "fr-NC" }, + { "NE", "fr-NE" }, + { "NF", "en-NF" }, { "NG", "ig-NG" }, { "NI", "es-NI" }, { "NL", "nl-NL" }, { "NO", "nn-NO" }, { "NP", "ne-NP" }, + { "NR", "en-NR" }, + { "NU", "en-NU" }, { "NZ", "en-NZ" }, { "OM", "ar-OM" }, { "PA", "es-PA" }, { "PE", "es-PE" }, + { "PF", "fr-PF" }, + { "PG", "en-PG" }, { "PH", "en-PH" }, { "PK", "ur-PK" }, { "PL", "pl-PL" }, + { "PM", "fr-PM" }, + { "PN", "en-PN" }, { "PR", "es-PR" }, + { "PS", "ar-PS" }, { "PT", "pt-PT" }, + { "PW", "en-PW" }, { "PY", "es-PY" }, { "QA", "ar-QA" }, + { "RE", "fr-RE" }, { "RO", "ro-RO" }, { "RS", "sr-Latn-RS" }, { "RU", "ru-RU" }, { "RW", "rw-RW" }, { "SA", "ar-SA" }, + { "SB", "en-SB" }, + { "SC", "fr-SC" }, + { "SD", "ar-SD" }, { "SE", "sv-SE" }, { "SG", "zh-SG" }, + { "SH", "en-SH" }, { "SI", "sl-SI" }, + { "SJ", "nb-SJ" }, { "SK", "sk-SK" }, + { "SL", "en-SL" }, + { "SM", "it-SM" }, { "SN", "wo-SN" }, + { "SO", "so-SO" }, + { "SR", "nl-SR" }, + { "SS", "en-SS" }, + { "ST", "pt-ST" }, { "SV", "es-SV" }, + { "SX", "nl-SX" }, { "SY", "ar-SY" }, + { "SZ", "ss-SZ" }, + { "TC", "en-TC" }, + { "TD", "fr-TD" }, + { "TF", "fr-T" }, + { "TG", "fr-TG" }, { "TH", "th-TH" }, { "TJ", "tg-Cyrl-TJ" }, + { "TK", "en-TK" }, + { "TL", "pt-TL" }, { "TM", "tk-TM" }, { "TN", "ar-TN" }, + { "TO", "to-TO" }, { "TR", "tr-TR" }, { "TT", "en-TT" }, + { "TV", "en-TV" }, { "TW", "zh-TW" }, + { "TZ", "sw-TZ" }, { "UA", "uk-UA" }, + { "UG", "sw-UG" }, + { "UM", "en-UM" }, { "US", "en-US" }, { "UY", "es-UY" }, { "UZ", "uz-Cyrl-UZ" }, + { "VA", "it-VA" }, + { "VC", "en-VC" }, { "VE", "es-VE" }, + { "VG", "en-VG" }, + { "VI", "en-VI" }, { "VN", "vi-VN" }, + { "VU", "fr-VU" }, + { "WF", "fr-WF" }, + { "WS", "en-WS" }, + { "XK", "sq-XK" }, { "YE", "ar-YE" }, + { "YT", "fr-YT" }, { "ZA", "af-ZA" }, + { "ZM", "en-ZM" }, { "ZW", "en-ZW" } }; diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/RegionInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/RegionInfo.cs index ccaa806adb69ad..47894cc4a81cc8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/RegionInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/RegionInfo.cs @@ -96,7 +96,7 @@ public static RegionInfo CurrentRegion RegionInfo? temp = s_currentRegionInfo; if (temp == null) { - temp = new RegionInfo(CultureInfo.CurrentCulture._cultureData); + temp = new RegionInfo(CultureData.GetCurrentRegionData()); // Need full name for custom cultures temp._name = temp._cultureData.RegionName; diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs index 88bd953e8bb29f..8a45dbee02ba87 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs @@ -74,7 +74,7 @@ public override string ToString() public string ToString(IFormatProvider? provider) { - return ToString(null, provider); + return Number.FormatInt32(m_value, 0, null, provider); } public string ToString(string? format) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int32.cs b/src/libraries/System.Private.CoreLib/src/System/Int32.cs index 2e717736b660b2..9ecd926998bc91 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int32.cs @@ -89,7 +89,7 @@ public string ToString(string? format) public string ToString(IFormatProvider? provider) { - return ToString(null, provider); + return Number.FormatInt32(m_value, 0, null, provider); } public string ToString(string? format, IFormatProvider? provider) diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs index 231704868afb7e..74fe7c0c4863d6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -277,7 +277,8 @@ internal static partial class Number "($#)", "-$#", "$-#", "$#-", "(#$)", "-#$", "#-$", "#$-", "-# $", "-$ #", "# $-", "$ #-", - "$ -#", "#- $", "($ #)", "(# $)" + "$ -#", "#- $", "($ #)", "(# $)", + "$- #" }; private static readonly string[] s_posPercentFormats = @@ -698,7 +699,7 @@ public static string FormatInt32(int value, int hexMask, string? format, IFormat if (string.IsNullOrEmpty(format)) { return value >= 0 ? - UInt32ToDecStr((uint)value, digits: -1) : + UInt32ToDecStr((uint)value) : NegativeInt32ToDecStr(value, digits: -1, NumberFormatInfo.GetInstance(provider).NegativeSign); } @@ -800,7 +801,7 @@ public static string FormatUInt32(uint value, string? format, IFormatProvider? p // Fast path for default format if (string.IsNullOrEmpty(format)) { - return UInt32ToDecStr(value, digits: -1); + return UInt32ToDecStr(value); } return FormatUInt32Slow(value, format, provider); @@ -1122,7 +1123,7 @@ private static unsafe void Int32ToNumber(int value, ref NumberBuffer number) public static string Int32ToDecStr(int value) { return value >= 0 ? - UInt32ToDecStr((uint)value, -1) : + UInt32ToDecStr((uint)value) : NegativeInt32ToDecStr(value, -1, NumberFormatInfo.CurrentInfo.NegativeSign); } @@ -1267,9 +1268,9 @@ private static unsafe void UInt32ToNumber(uint value, ref NumberBuffer number) return bufferEnd; } - internal static unsafe string UInt32ToDecStr(uint value, int digits) + internal static unsafe string UInt32ToDecStr(uint value) { - int bufferLength = Math.Max(digits, FormattingHelpers.CountDigits(value)); + int bufferLength = FormattingHelpers.CountDigits(value); // For single-digit values that are very common, especially 0 and 1, just return cached strings. if (bufferLength == 1) @@ -1281,19 +1282,28 @@ internal static unsafe string UInt32ToDecStr(uint value, int digits) fixed (char* buffer = result) { char* p = buffer + bufferLength; - if (digits <= 1) - { - do - { - value = Math.DivRem(value, 10, out uint remainder); - *(--p) = (char)(remainder + '0'); - } - while (value != 0); - } - else + do { - p = UInt32ToDecChars(p, value, digits); + value = Math.DivRem(value, 10, out uint remainder); + *(--p) = (char)(remainder + '0'); } + while (value != 0); + Debug.Assert(p == buffer); + } + return result; + } + + private static unsafe string UInt32ToDecStr(uint value, int digits) + { + if (digits <= 1) + return UInt32ToDecStr(value); + + int bufferLength = Math.Max(digits, FormattingHelpers.CountDigits(value)); + string result = string.FastAllocateString(bufferLength); + fixed (char* buffer = result) + { + char* p = buffer + bufferLength; + p = UInt32ToDecChars(p, value, digits); Debug.Assert(p == buffer); } return result; @@ -2169,7 +2179,7 @@ private static unsafe void FormatFixed(ref ValueStringBuilder sb, ref NumberBuff { if (groupDigits != null) { - Debug.Assert(sGroup != null, "Must be nulll when groupDigits != null"); + Debug.Assert(sGroup != null, "Must be null when groupDigits != null"); int groupSizeIndex = 0; // Index into the groupDigits array. int bufferSize = digPos; // The length of the result buffer string. int groupSize = 0; // The current group size. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs index a51ae8b59dfd40..072b525b4b28d0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs @@ -604,6 +604,18 @@ internal Arm64() { } /// public static Vector128 Divide(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) + /// A64: FMLA Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vfmsq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) + /// A64: FMLS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// /// float64x2_t vmaxq_f64 (float64x2_t a, float64x2_t b) /// A64: FMAX Vd.2D, Vn.2D, Vm.2D @@ -1020,18 +1032,6 @@ internal Arm64() { } /// public static Vector128 Sqrt(Vector128 value) { throw new PlatformNotSupportedException(); } - /// - /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) - /// A64: FMLA Vd.2D, Vn.2D, Vm.2D - /// - public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } - - /// - /// float64x2_t vfmsq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) - /// A64: FMLS Vd.2D, Vn.2D, Vm.2D - /// - public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } - /// /// float64x2_t vsubq_f64 (float64x2_t a, float64x2_t b) /// A64: FSUB Vd.2D, Vn.2D, Vm.2D @@ -4656,6 +4656,146 @@ internal Arm64() { } /// public static Vector64 SqrtScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + /// + /// void vst1_u8 (uint8_t * ptr, uint8x8_t val) + /// A32: VST1.8 { Dd }, [Rn] + /// A64: ST1 { Vt.8B }, [Xn] + /// + public static unsafe void Store(byte* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_f64 (float64_t * ptr, float64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(double* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_s16 (int16_t * ptr, int16x4_t val) + /// A32: VST1.16 { Dd }, [Rn] + /// A64: ST1 {Vt.4H }, [Xn] + /// + public static unsafe void Store(short* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_s32 (int32_t * ptr, int32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(int* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_s64 (int64_t * ptr, int64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(long* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_s8 (int8_t * ptr, int8x8_t val) + /// A32: VST1.8 { Dd }, [Rn] + /// A64: ST1 { Vt.8B }, [Xn] + /// + public static unsafe void Store(sbyte* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_f32 (float32_t * ptr, float32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(float* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_u16 (uint16_t * ptr, uint16x4_t val) + /// A32: VST1.16 { Dd }, [Rn] + /// A64: ST1 { Vt.4H }, [Xn] + /// + public static unsafe void Store(ushort* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_u32 (uint32_t * ptr, uint32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(uint* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_u64 (uint64_t * ptr, uint64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(ulong* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_u8 (uint8_t * ptr, uint8x16_t val) + /// A32: VST1.8 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.16B }, [Xn] + /// + public static unsafe void Store(byte* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_f64 (float64_t * ptr, float64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(double* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_s16 (int16_t * ptr, int16x8_t val) + /// A32: VST1.16 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.8H }, [Xn] + /// + public static unsafe void Store(short* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_s32 (int32_t * ptr, int32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(int* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_s64 (int64_t * ptr, int64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(long* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_s8 (int8_t * ptr, int8x16_t val) + /// A32: VST1.8 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.16B }, [Xn] + /// + public static unsafe void Store(sbyte* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_f32 (float32_t * ptr, float32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(float* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_u16 (uint16_t * ptr, uint16x8_t val) + /// A32: VST1.16 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.8H }, [Xn] + /// + public static unsafe void Store(ushort* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_u32 (uint32_t * ptr, uint32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(uint* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_u64 (uint64_t * ptr, uint64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(ulong* address, Vector128 source) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t vsub_u8 (uint8x8_t a, uint8x8_t b) /// A32: VSUB.I8 Dd, Dn, Dm diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs index 112dc1e566d0f2..c000c31b5ed285 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs @@ -606,6 +606,18 @@ internal Arm64() { } /// public static Vector128 Divide(Vector128 left, Vector128 right) => Divide(left, right); + /// + /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) + /// A64: FMLA Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplyAdd(acc, left, right); + + /// + /// float64x2_t vfmsq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) + /// A64: FMLS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplySubtract(acc, left, right); + /// /// float64x2_t vmaxq_f64 (float64x2_t a, float64x2_t b) /// A64: FMAX Vd.2D, Vn.2D, Vm.2D @@ -1022,18 +1034,6 @@ internal Arm64() { } /// public static Vector128 Sqrt(Vector128 value) => Sqrt(value); - /// - /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) - /// A64: FMLA Vd.2D, Vn.2D, Vm.2D - /// - public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplyAdd(acc, left, right); - - /// - /// float64x2_t vfmsq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) - /// A64: FMLS Vd.2D, Vn.2D, Vm.2D - /// - public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplySubtract(acc, left, right); - /// /// float64x2_t vsubq_f64 (float64x2_t a, float64x2_t b) /// A64: FSUB Vd.2D, Vn.2D, Vm.2D @@ -4658,6 +4658,146 @@ internal Arm64() { } /// public static Vector64 SqrtScalar(Vector64 value) => SqrtScalar(value); + /// + /// void vst1_u8 (uint8_t * ptr, uint8x8_t val) + /// A32: VST1.8 { Dd }, [Rn] + /// A64: ST1 { Vt.8B }, [Xn] + /// + public static unsafe void Store(byte* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_f64 (float64_t * ptr, float64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(double* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_s16 (int16_t * ptr, int16x4_t val) + /// A32: VST1.16 { Dd }, [Rn] + /// A64: ST1 {Vt.4H }, [Xn] + /// + public static unsafe void Store(short* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_s32 (int32_t * ptr, int32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(int* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_s64 (int64_t * ptr, int64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(long* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_s8 (int8_t * ptr, int8x8_t val) + /// A32: VST1.8 { Dd }, [Rn] + /// A64: ST1 { Vt.8B }, [Xn] + /// + public static unsafe void Store(sbyte* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_f32 (float32_t * ptr, float32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(float* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_u16 (uint16_t * ptr, uint16x4_t val) + /// A32: VST1.16 { Dd }, [Rn] + /// A64: ST1 { Vt.4H }, [Xn] + /// + public static unsafe void Store(ushort* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_u32 (uint32_t * ptr, uint32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(uint* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_u64 (uint64_t * ptr, uint64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(ulong* address, Vector64 source) => Store(address, source); + + /// + /// void vst1q_u8 (uint8_t * ptr, uint8x16_t val) + /// A32: VST1.8 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.16B }, [Xn] + /// + public static unsafe void Store(byte* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_f64 (float64_t * ptr, float64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(double* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_s16 (int16_t * ptr, int16x8_t val) + /// A32: VST1.16 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.8H }, [Xn] + /// + public static unsafe void Store(short* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_s32 (int32_t * ptr, int32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(int* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_s64 (int64_t * ptr, int64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(long* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_s8 (int8_t * ptr, int8x16_t val) + /// A32: VST1.8 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.16B }, [Xn] + /// + public static unsafe void Store(sbyte* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_f32 (float32_t * ptr, float32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(float* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_u16 (uint16_t * ptr, uint16x8_t val) + /// A32: VST1.16 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.8H }, [Xn] + /// + public static unsafe void Store(ushort* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_u32 (uint32_t * ptr, uint32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(uint* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_u64 (uint64_t * ptr, uint64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(ulong* address, Vector128 source) => Store(address, source); + /// /// uint8x8_t vsub_u8 (uint8x8_t a, uint8x8_t b) /// A32: VSUB.I8 Dd, Dn, Dm diff --git a/src/libraries/System.Private.CoreLib/src/System/SByte.cs b/src/libraries/System.Private.CoreLib/src/System/SByte.cs index 4cba7c626460d6..effc14d26c520c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SByte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SByte.cs @@ -84,7 +84,7 @@ public string ToString(string? format) public string ToString(IFormatProvider? provider) { - return ToString(null, provider); + return Number.FormatInt32(m_value, 0, null, provider); } public string ToString(string? format, IFormatProvider? provider) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.cs index 4a2f9c77e85267..e3c0a66e3806a5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.cs @@ -44,9 +44,7 @@ public static EventWaitHandle OpenExisting(string name) } } - public static bool TryOpenExisting(string name, [NotNullWhen(true)] out EventWaitHandle? result) - { - return OpenExistingWorker(name, out result) == OpenExistingResult.Success; - } + public static bool TryOpenExisting(string name, [NotNullWhen(true)] out EventWaitHandle? result) => + OpenExistingWorker(name, out result!) == OpenExistingResult.Success; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.cs index 1effbc63bd1b68..2f4756dbbe1fdc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.cs @@ -57,6 +57,6 @@ public static Mutex OpenExisting(string name) } public static bool TryOpenExisting(string name, [NotNullWhen(true)] out Mutex? result) => - OpenExistingWorker(name, out result) == OpenExistingResult.Success; + OpenExistingWorker(name, out result!) == OpenExistingResult.Success; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.cs index a9ed317b3c2937..5a6a58620da357 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.cs @@ -50,7 +50,7 @@ public static Semaphore OpenExisting(string name) } public static bool TryOpenExisting(string name, [NotNullWhen(true)] out Semaphore? result) => - OpenExistingWorker(name, out result) == OpenExistingResult.Success; + OpenExistingWorker(name, out result!) == OpenExistingResult.Success; public int Release() => ReleaseCore(1); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs index c99cf64dbf8d44..a0041bea683775 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs @@ -68,12 +68,12 @@ public override int GetHashCode() // Converts the current value to a String in base-10 with no extra padding. public override string ToString() { - return Number.UInt32ToDecStr(m_value, -1); + return Number.UInt32ToDecStr(m_value); } public string ToString(IFormatProvider? provider) { - return Number.FormatUInt32(m_value, null, provider); + return Number.UInt32ToDecStr(m_value); } public string ToString(string? format) diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs index 00c4e55930ef29..aebd3e51217866 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs @@ -78,12 +78,12 @@ public override int GetHashCode() // The base 10 representation of the number with no extra padding. public override string ToString() { - return Number.UInt32ToDecStr(m_value, -1); + return Number.UInt32ToDecStr(m_value); } public string ToString(IFormatProvider? provider) { - return Number.FormatUInt32(m_value, null, provider); + return Number.UInt32ToDecStr(m_value); } public string ToString(string? format) diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs index 050c256cc37708..dcb4141bd87345 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs @@ -82,7 +82,7 @@ public override string ToString() public string ToString(IFormatProvider? provider) { - return Number.FormatUInt64(m_value, null, provider); + return Number.UInt64ToDecStr(m_value, -1); } public string ToString(string? format) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs index d2f5cee6ef5f87..b274fa84fff095 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs @@ -270,32 +270,29 @@ private void AddCollectionItemContractsToKnownDataContracts() { foreach (KeyValuePair knownDataContract in _traditionalDataContract.KnownDataContracts) { - if (!object.ReferenceEquals(knownDataContract, null)) + CollectionDataContract collectionDataContract = knownDataContract.Value as CollectionDataContract; + while (collectionDataContract != null) { - CollectionDataContract collectionDataContract = knownDataContract.Value as CollectionDataContract; - while (collectionDataContract != null) + DataContract itemContract = collectionDataContract.ItemContract; + if (_knownDataContracts == null) { - DataContract itemContract = collectionDataContract.ItemContract; - if (_knownDataContracts == null) - { - _knownDataContracts = new Dictionary(); - } - - _knownDataContracts.TryAdd(itemContract.StableName, itemContract); - - if (collectionDataContract.ItemType.IsGenericType - && collectionDataContract.ItemType.GetGenericTypeDefinition() == typeof(KeyValue<,>)) - { - DataContract itemDataContract = DataContract.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionDataContract.ItemType.GenericTypeArguments)); - _knownDataContracts.TryAdd(itemDataContract.StableName, itemDataContract); - } - - if (!(itemContract is CollectionDataContract)) - { - break; - } - collectionDataContract = itemContract as CollectionDataContract; + _knownDataContracts = new Dictionary(); } + + _knownDataContracts.TryAdd(itemContract.StableName, itemContract); + + if (collectionDataContract.ItemType.IsGenericType + && collectionDataContract.ItemType.GetGenericTypeDefinition() == typeof(KeyValue<,>)) + { + DataContract itemDataContract = DataContract.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionDataContract.ItemType.GenericTypeArguments)); + _knownDataContracts.TryAdd(itemDataContract.StableName, itemDataContract); + } + + if (!(itemContract is CollectionDataContract)) + { + break; + } + collectionDataContract = itemContract as CollectionDataContract; } } } diff --git a/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj b/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj index 12a87116c3b281..651e9b6959c89c 100644 --- a/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj +++ b/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj @@ -4,7 +4,6 @@ true - diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/TypeNameComparer.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/TypeNameComparer.cs index 64191f6cc46894..82b19492035e9c 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/TypeNameComparer.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/TypeNameComparer.cs @@ -53,7 +53,9 @@ private static bool IsMscorlib(ReadOnlySpan assemblyName) // Compare two type names ignoring version // If a type name is missing assembly, we assume it came from mscorlib // since this is what Type.GetType will do. +#pragma warning disable CS8767 // This API member has [AllowNull] implemented interface, but we don't want to accept nulls here. public bool Equals(string assemblyQualifiedTypeName1, string assemblyQualifiedTypeName2) +#pragma warning restore CS8767 { if (assemblyQualifiedTypeName1 == null) throw new ArgumentNullException(nameof(assemblyQualifiedTypeName1)); diff --git a/src/libraries/System.Runtime.InteropServices.RuntimeInformation/src/System.Runtime.InteropServices.RuntimeInformation.csproj b/src/libraries/System.Runtime.InteropServices.RuntimeInformation/src/System.Runtime.InteropServices.RuntimeInformation.csproj index 4b8fb9f1a6d2b3..4536cd4853ea04 100644 --- a/src/libraries/System.Runtime.InteropServices.RuntimeInformation/src/System.Runtime.InteropServices.RuntimeInformation.csproj +++ b/src/libraries/System.Runtime.InteropServices.RuntimeInformation/src/System.Runtime.InteropServices.RuntimeInformation.csproj @@ -31,14 +31,6 @@ Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Windows\NtDll\Interop.RtlGetVersion.cs - - - Common\Interop\Windows\NtDll\Interop.RTL_OSVERSIONINFOEX.cs - - diff --git a/src/libraries/System.Runtime.InteropServices.RuntimeInformation/src/System/Runtime/InteropServices/RuntimeInformation/RuntimeInformation.Windows.cs b/src/libraries/System.Runtime.InteropServices.RuntimeInformation/src/System/Runtime/InteropServices/RuntimeInformation/RuntimeInformation.Windows.cs index bc733dfa47bed0..c5818719918e6d 100644 --- a/src/libraries/System.Runtime.InteropServices.RuntimeInformation/src/System/Runtime/InteropServices/RuntimeInformation/RuntimeInformation.Windows.cs +++ b/src/libraries/System.Runtime.InteropServices.RuntimeInformation/src/System/Runtime/InteropServices/RuntimeInformation/RuntimeInformation.Windows.cs @@ -19,7 +19,25 @@ public static bool IsOSPlatform(OSPlatform osPlatform) return OSPlatform.Windows == osPlatform; } - public static string OSDescription => s_osDescription ??= Interop.NtDll.RtlGetVersion(); + public static string OSDescription + { + get + { + string? osDescription = s_osDescription; + if (osDescription is null) + { + OperatingSystem os = Environment.OSVersion; + Version v = os.Version; + + const string Version = "Microsoft Windows"; + s_osDescription = osDescription = string.IsNullOrEmpty(os.ServicePack) ? + $"{Version} {(uint)v.Major}.{(uint)v.Minor}.{(uint)v.Build}" : + $"{Version} {(uint)v.Major}.{(uint)v.Minor}.{(uint)v.Build} {os.ServicePack}"; + } + + return osDescription; + } + } public static Architecture OSArchitecture { diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/DestroyStructureTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/DestroyStructureTests.cs index c0e26a720ad592..7ca8b00f6450d6 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/DestroyStructureTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/DestroyStructureTests.cs @@ -106,6 +106,28 @@ public void DestroyStructure_AutoLayout_ThrowsArgumentException() AssertExtensions.Throws("structureType", () => Marshal.DestroyStructure((IntPtr)1, typeof(AutoLayoutStruct))); } + [Fact] + public void DestroyStructure_NestedNonBlittableStruct_Success() + { + WINTRUST_BLOB_INFO wbi = new WINTRUST_BLOB_INFO(); + byte[] contentBytes = System.Text.Encoding.Unicode.GetBytes("foo"); + + wbi.gSubject.Data1 = 0x603bcc1f; + wbi.gSubject.Data2 = 0x4b59; + wbi.gSubject.Data3 = 0x4e08; + wbi.gSubject.Data4 = new byte[] { 0xb7, 0x24, 0xd2, 0xc6, 0x29, 0x7e, 0xf3, 0x51 }; + + wbi.cbStruct = (uint)Marshal.SizeOf(wbi); + wbi.pcwszDisplayName = "bar"; + + IntPtr pBlob = Marshal.AllocCoTaskMem(Marshal.SizeOf(wbi)); + Marshal.StructureToPtr(wbi, pBlob, false); + + Marshal.DestroyStructure(pBlob); + + Marshal.FreeCoTaskMem(pBlob); + } + [StructLayout(LayoutKind.Sequential)] public struct TestStruct { @@ -118,5 +140,30 @@ public struct AutoLayoutStruct { public int i; } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal struct GUID + { + internal uint Data1; + internal ushort Data2; + internal ushort Data3; + + /// unsigned char[8] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + internal byte[] Data4; + } + [StructLayout(LayoutKind.Sequential)] + internal struct WINTRUST_BLOB_INFO + { + internal uint cbStruct; + + /// GUID->_GUID + internal GUID gSubject; + //[MarshalAs(UnmanagedType.Struct)] + //internal Guid gSubject; + + [MarshalAsAttribute(UnmanagedType.LPWStr)] + internal string pcwszDisplayName; + } } } diff --git a/src/libraries/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.cs b/src/libraries/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.cs index 16f106bab39179..5dfad90cdc15bf 100644 --- a/src/libraries/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.cs +++ b/src/libraries/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.cs @@ -433,6 +433,26 @@ internal AdvSimd() { } public static System.Runtime.Intrinsics.Vector64 PopCount(System.Runtime.Intrinsics.Vector64 value) { throw null; } public static System.Runtime.Intrinsics.Vector64 SqrtScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } public static System.Runtime.Intrinsics.Vector64 SqrtScalar(System.Runtime.Intrinsics.Vector64 value) { throw null; } + public unsafe static void Store(byte* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(byte* address, System.Runtime.Intrinsics.Vector64 source) { } + public unsafe static void Store(double* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(double* address, System.Runtime.Intrinsics.Vector64 source) { } + public unsafe static void Store(short* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(short* address, System.Runtime.Intrinsics.Vector64 source) { } + public unsafe static void Store(int* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(int* address, System.Runtime.Intrinsics.Vector64 source) { } + public unsafe static void Store(long* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(long* address, System.Runtime.Intrinsics.Vector64 source) { } + public unsafe static void Store(sbyte* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(sbyte* address, System.Runtime.Intrinsics.Vector64 source) { } + public unsafe static void Store(float* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(float* address, System.Runtime.Intrinsics.Vector64 source) { } + public unsafe static void Store(ushort* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(ushort* address, System.Runtime.Intrinsics.Vector64 source) { } + public unsafe static void Store(uint* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(uint* address, System.Runtime.Intrinsics.Vector64 source) { } + public unsafe static void Store(ulong* address, System.Runtime.Intrinsics.Vector128 source) { } + public unsafe static void Store(ulong* address, System.Runtime.Intrinsics.Vector64 source) { } public static System.Runtime.Intrinsics.Vector128 Subtract(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Subtract(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Subtract(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } diff --git a/src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectReader.cs b/src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectReader.cs index b775b980745b04..e418bc2044305f 100644 --- a/src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectReader.cs +++ b/src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryObjectReader.cs @@ -650,13 +650,6 @@ private void ParseArrayMember(ParseRecord pr) ParseString(pr, objectPr); var = pr._value; } - else if (ReferenceEquals(pr._dtTypeCode, InternalPrimitiveTypeE.Invalid)) - { - Debug.Assert(pr._dtType != null); - CheckSerializable(pr._dtType); - // Not nested and invalid, so it is an empty object - var = FormatterServices.GetUninitializedObject(pr._dtType); - } else { var = pr._varValue != null ? diff --git a/src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/Converter.cs b/src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/Converter.cs index 86bd72736eeb15..5bab39b8902fce 100644 --- a/src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/Converter.cs +++ b/src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/Converter.cs @@ -204,8 +204,6 @@ private static void InitArrayTypeA() internal static bool IsPrimitiveArray(Type? type, [NotNullWhen(true)] out object? typeInformation) { - bool bIsPrimitive = true; - if (ReferenceEquals(type, s_typeofBooleanArray)) typeInformation = InternalPrimitiveTypeE.Boolean; else if (ReferenceEquals(type, s_typeofByteArray)) typeInformation = InternalPrimitiveTypeE.Byte; else if (ReferenceEquals(type, s_typeofCharArray)) typeInformation = InternalPrimitiveTypeE.Char; @@ -221,10 +219,10 @@ internal static bool IsPrimitiveArray(Type? type, [NotNullWhen(true)] out object else { typeInformation = null; - bIsPrimitive = false; + return false; } - return bIsPrimitive; + return true; } private static void InitValueA() diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/System.Runtime.WindowsRuntime.UI.Xaml.sln b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/System.Runtime.WindowsRuntime.UI.Xaml.sln index e2a35b04d6d63a..261d24e643dd18 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/System.Runtime.WindowsRuntime.UI.Xaml.sln +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/System.Runtime.WindowsRuntime.UI.Xaml.sln @@ -26,6 +26,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {69FC7EB5-64FD-4464-88B1-B8ADD3870640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {69FC7EB5-64FD-4464-88B1-B8ADD3870640}.Debug|Any CPU.Build.0 = Debug|Any CPU + {69FC7EB5-64FD-4464-88B1-B8ADD3870640}.Release|Any CPU.ActiveCfg = Release|Any CPU + {69FC7EB5-64FD-4464-88B1-B8ADD3870640}.Release|Any CPU.Build.0 = Release|Any CPU {263DA4F1-C3BC-4B43-98E7-9F38B419A131}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {263DA4F1-C3BC-4B43-98E7-9F38B419A131}.Debug|Any CPU.Build.0 = Debug|Any CPU {263DA4F1-C3BC-4B43-98E7-9F38B419A131}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/ref/System.Runtime.WindowsRuntime.UI.Xaml.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/ref/System.Runtime.WindowsRuntime.UI.Xaml.cs index 0f26e08a051f6f..3a5592add9dc8c 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/ref/System.Runtime.WindowsRuntime.UI.Xaml.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/ref/System.Runtime.WindowsRuntime.UI.Xaml.cs @@ -16,7 +16,7 @@ public partial struct CornerRadius public double BottomRight { get { throw null; } set { } } public double TopLeft { get { throw null; } set { } } public double TopRight { get { throw null; } set { } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public bool Equals(Windows.UI.Xaml.CornerRadius cornerRadius) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(Windows.UI.Xaml.CornerRadius cr1, Windows.UI.Xaml.CornerRadius cr2) { throw null; } @@ -33,7 +33,7 @@ public partial struct Duration public System.TimeSpan TimeSpan { get { throw null; } } public Windows.UI.Xaml.Duration Add(Windows.UI.Xaml.Duration duration) { throw null; } public static int Compare(Windows.UI.Xaml.Duration t1, Windows.UI.Xaml.Duration t2) { throw null; } - public override bool Equals(object value) { throw null; } + public override bool Equals(object? value) { throw null; } public bool Equals(Windows.UI.Xaml.Duration duration) { throw null; } public static bool Equals(Windows.UI.Xaml.Duration t1, Windows.UI.Xaml.Duration t2) { throw null; } public override int GetHashCode() { throw null; } @@ -67,7 +67,7 @@ public partial struct GridLength public bool IsAuto { get { throw null; } } public bool IsStar { get { throw null; } } public double Value { get { throw null; } } - public override bool Equals(object oCompare) { throw null; } + public override bool Equals(object? oCompare) { throw null; } public bool Equals(Windows.UI.Xaml.GridLength gridLength) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(Windows.UI.Xaml.GridLength gl1, Windows.UI.Xaml.GridLength gl2) { throw null; } @@ -84,8 +84,8 @@ public partial class LayoutCycleException : System.Exception { public LayoutCycleException() { } protected LayoutCycleException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } - public LayoutCycleException(string message) { } - public LayoutCycleException(string message, System.Exception innerException) { } + public LayoutCycleException(string? message) { } + public LayoutCycleException(string? message, System.Exception? innerException) { } } public partial struct Thickness { @@ -96,7 +96,7 @@ public partial struct Thickness public double Left { get { throw null; } set { } } public double Right { get { throw null; } set { } } public double Top { get { throw null; } set { } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public bool Equals(Windows.UI.Xaml.Thickness thickness) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(Windows.UI.Xaml.Thickness t1, Windows.UI.Xaml.Thickness t2) { throw null; } @@ -110,14 +110,14 @@ public partial class ElementNotAvailableException : System.Exception { public ElementNotAvailableException() { } protected ElementNotAvailableException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } - public ElementNotAvailableException(string message) { } - public ElementNotAvailableException(string message, System.Exception innerException) { } + public ElementNotAvailableException(string? message) { } + public ElementNotAvailableException(string? message, System.Exception? innerException) { } } public partial class ElementNotEnabledException : System.Exception { public ElementNotEnabledException() { } - public ElementNotEnabledException(string message) { } - public ElementNotEnabledException(string message, System.Exception innerException) { } + public ElementNotEnabledException(string? message) { } + public ElementNotEnabledException(string? message, System.Exception? innerException) { } } } namespace Windows.UI.Xaml.Controls.Primitives @@ -128,7 +128,7 @@ public partial struct GeneratorPosition public GeneratorPosition(int index, int offset) { throw null; } public int Index { get { throw null; } set { } } public int Offset { get { throw null; } set { } } - public override bool Equals(object o) { throw null; } + public override bool Equals(object? o) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(Windows.UI.Xaml.Controls.Primitives.GeneratorPosition gp1, Windows.UI.Xaml.Controls.Primitives.GeneratorPosition gp2) { throw null; } public static bool operator !=(Windows.UI.Xaml.Controls.Primitives.GeneratorPosition gp1, Windows.UI.Xaml.Controls.Primitives.GeneratorPosition gp2) { throw null; } @@ -140,8 +140,8 @@ namespace Windows.UI.Xaml.Markup public partial class XamlParseException : System.Exception { public XamlParseException() { } - public XamlParseException(string message) { } - public XamlParseException(string message, System.Exception innerException) { } + public XamlParseException(string? message) { } + public XamlParseException(string? message, System.Exception? innerException) { } } } namespace Windows.UI.Xaml.Media @@ -158,14 +158,14 @@ public partial struct Matrix : System.IFormattable public double M22 { get { throw null; } set { } } public double OffsetX { get { throw null; } set { } } public double OffsetY { get { throw null; } set { } } - public override bool Equals(object o) { throw null; } + public override bool Equals(object? o) { throw null; } public bool Equals(Windows.UI.Xaml.Media.Matrix value) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(Windows.UI.Xaml.Media.Matrix matrix1, Windows.UI.Xaml.Media.Matrix matrix2) { throw null; } public static bool operator !=(Windows.UI.Xaml.Media.Matrix matrix1, Windows.UI.Xaml.Media.Matrix matrix2) { throw null; } - string System.IFormattable.ToString(string format, System.IFormatProvider provider) { throw null; } + string System.IFormattable.ToString(string? format, System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } - public string ToString(System.IFormatProvider provider) { throw null; } + public string ToString(System.IFormatProvider? provider) { throw null; } public Windows.Foundation.Point Transform(Windows.Foundation.Point point) { throw null; } } } @@ -175,7 +175,7 @@ public partial struct KeyTime { private int _dummyPrimitive; public System.TimeSpan TimeSpan { get { throw null; } } - public override bool Equals(object value) { throw null; } + public override bool Equals(object? value) { throw null; } public bool Equals(Windows.UI.Xaml.Media.Animation.KeyTime value) { throw null; } public static bool Equals(Windows.UI.Xaml.Media.Animation.KeyTime keyTime1, Windows.UI.Xaml.Media.Animation.KeyTime keyTime2) { throw null; } public static Windows.UI.Xaml.Media.Animation.KeyTime FromTimeSpan(System.TimeSpan timeSpan) { throw null; } @@ -196,15 +196,15 @@ public partial struct RepeatBehavior : System.IFormattable public bool HasCount { get { throw null; } } public bool HasDuration { get { throw null; } } public Windows.UI.Xaml.Media.Animation.RepeatBehaviorType Type { get { throw null; } set { } } - public override bool Equals(object value) { throw null; } + public override bool Equals(object? value) { throw null; } public bool Equals(Windows.UI.Xaml.Media.Animation.RepeatBehavior repeatBehavior) { throw null; } public static bool Equals(Windows.UI.Xaml.Media.Animation.RepeatBehavior repeatBehavior1, Windows.UI.Xaml.Media.Animation.RepeatBehavior repeatBehavior2) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(Windows.UI.Xaml.Media.Animation.RepeatBehavior repeatBehavior1, Windows.UI.Xaml.Media.Animation.RepeatBehavior repeatBehavior2) { throw null; } public static bool operator !=(Windows.UI.Xaml.Media.Animation.RepeatBehavior repeatBehavior1, Windows.UI.Xaml.Media.Animation.RepeatBehavior repeatBehavior2) { throw null; } - string System.IFormattable.ToString(string format, System.IFormatProvider formatProvider) { throw null; } + string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; } public override string ToString() { throw null; } - public string ToString(System.IFormatProvider formatProvider) { throw null; } + public string ToString(System.IFormatProvider? formatProvider) { throw null; } } public enum RepeatBehaviorType { @@ -238,15 +238,15 @@ public partial struct Matrix3D : System.IFormattable public double OffsetX { get { throw null; } set { } } public double OffsetY { get { throw null; } set { } } public double OffsetZ { get { throw null; } set { } } - public override bool Equals(object o) { throw null; } + public override bool Equals(object? o) { throw null; } public bool Equals(Windows.UI.Xaml.Media.Media3D.Matrix3D value) { throw null; } public override int GetHashCode() { throw null; } public void Invert() { } public static bool operator ==(Windows.UI.Xaml.Media.Media3D.Matrix3D matrix1, Windows.UI.Xaml.Media.Media3D.Matrix3D matrix2) { throw null; } public static bool operator !=(Windows.UI.Xaml.Media.Media3D.Matrix3D matrix1, Windows.UI.Xaml.Media.Media3D.Matrix3D matrix2) { throw null; } public static Windows.UI.Xaml.Media.Media3D.Matrix3D operator *(Windows.UI.Xaml.Media.Media3D.Matrix3D matrix1, Windows.UI.Xaml.Media.Media3D.Matrix3D matrix2) { throw null; } - string System.IFormattable.ToString(string format, System.IFormatProvider provider) { throw null; } + string System.IFormattable.ToString(string? format, System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } - public string ToString(System.IFormatProvider provider) { throw null; } + public string ToString(System.IFormatProvider? provider) { throw null; } } } diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/ref/System.Runtime.WindowsRuntime.UI.Xaml.csproj b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/ref/System.Runtime.WindowsRuntime.UI.Xaml.csproj index 39f6c306e7ef7e..aac97c06c2dc00 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/ref/System.Runtime.WindowsRuntime.UI.Xaml.csproj +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/ref/System.Runtime.WindowsRuntime.UI.Xaml.csproj @@ -2,6 +2,7 @@ $(NetCoreAppCurrent);netstandard2.0 true + enable diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System.Runtime.WindowsRuntime.UI.Xaml.csproj b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System.Runtime.WindowsRuntime.UI.Xaml.csproj index 8247ba71245a9e..99aded3293dee8 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System.Runtime.WindowsRuntime.UI.Xaml.csproj +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System.Runtime.WindowsRuntime.UI.Xaml.csproj @@ -7,6 +7,7 @@ $(NetCoreAppCurrent)-Windows_NT;netstandard1.1;netstandard2.0;netcoreapp3.0-Windows_NT true + enable diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Automation/ElementNotAvailableException.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Automation/ElementNotAvailableException.cs index 2d5c21a9c6721e..5daa094cce6a5c 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Automation/ElementNotAvailableException.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Automation/ElementNotAvailableException.cs @@ -26,13 +26,13 @@ public ElementNotAvailableException() HResult = HResults.E_ELEMENTNOTAVAILABLE; } - public ElementNotAvailableException(string message) + public ElementNotAvailableException(string? message) : base(message) { HResult = HResults.E_ELEMENTNOTAVAILABLE; } - public ElementNotAvailableException(string message, Exception innerException) + public ElementNotAvailableException(string? message, Exception? innerException) : base(message, innerException) { HResult = HResults.E_ELEMENTNOTAVAILABLE; diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Automation/ElementNotEnabledException.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Automation/ElementNotEnabledException.cs index 74e4c8ebd07cb2..4c3d1ac76c771b 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Automation/ElementNotEnabledException.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Automation/ElementNotEnabledException.cs @@ -24,13 +24,13 @@ public ElementNotEnabledException() HResult = HResults.E_ELEMENTNOTENABLED; } - public ElementNotEnabledException(string message) + public ElementNotEnabledException(string? message) : base(message) { HResult = HResults.E_ELEMENTNOTENABLED; } - public ElementNotEnabledException(string message, Exception innerException) + public ElementNotEnabledException(string? message, Exception? innerException) : base(message, innerException) { HResult = HResults.E_ELEMENTNOTENABLED; diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Controls/Primitives/GeneratorPosition.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Controls/Primitives/GeneratorPosition.cs index 49532fdcc1095a..7ef8cce0376169 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Controls/Primitives/GeneratorPosition.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Controls/Primitives/GeneratorPosition.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -// - using System; using System.Globalization; using System.Runtime.InteropServices; @@ -47,7 +43,7 @@ public override string ToString() return string.Concat("GeneratorPosition (", _index.ToString(CultureInfo.InvariantCulture), ",", _offset.ToString(CultureInfo.InvariantCulture), ")"); } - public override bool Equals(object o) + public override bool Equals(object? o) { if (o is GeneratorPosition) { diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/CornerRadius.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/CornerRadius.cs index e0d658a42db2f8..1ecc2019b9d6aa 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/CornerRadius.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/CornerRadius.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -// - using System; using System.Globalization; using System.Runtime.InteropServices; @@ -66,7 +62,7 @@ public override string ToString() return ToString(CultureInfo.InvariantCulture); } - internal string ToString(CultureInfo cultureInfo) + internal string ToString(CultureInfo? cultureInfo) { char listSeparator = TokenizerHelper.GetNumericListSeparator(cultureInfo); @@ -86,13 +82,13 @@ internal string ToString(CultureInfo cultureInfo) return sb.ToString(); } - internal string InternalToString(double l, CultureInfo cultureInfo) + internal string InternalToString(double l, CultureInfo? cultureInfo) { if (double.IsNaN(l)) return "Auto"; return Convert.ToString(l, cultureInfo); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is CornerRadius) { diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Duration.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Duration.cs index b80b134186cbfd..569f585f662851 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Duration.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Duration.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -// - using System; using System.Runtime.InteropServices; @@ -254,7 +250,7 @@ public Duration Add(Duration duration) return this + duration; } - public override bool Equals(object value) + public override bool Equals(object? value) { return value is Duration && Equals((Duration)value); } diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/GridLength.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/GridLength.cs index 077e054637a1c0..cdced48afcae7f 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/GridLength.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/GridLength.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -// - using System; using System.Globalization; using System.Runtime.InteropServices; @@ -87,7 +83,7 @@ public static GridLength Auto || gl1.Value != gl2.Value); } - public override bool Equals(object oCompare) + public override bool Equals(object? oCompare) { if (oCompare is GridLength) { @@ -113,7 +109,7 @@ public override string ToString() return this.ToString(CultureInfo.InvariantCulture); } - internal string ToString(CultureInfo cultureInfo) + internal string ToString(CultureInfo? cultureInfo) { char listSeparator = TokenizerHelper.GetNumericListSeparator(cultureInfo); diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/LayoutCycleException.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/LayoutCycleException.cs index bd3f7b8b07148b..96c1bbbb600408 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/LayoutCycleException.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/LayoutCycleException.cs @@ -26,13 +26,13 @@ public LayoutCycleException() HResult = HResults.E_LAYOUTCYCLE; } - public LayoutCycleException(string message) + public LayoutCycleException(string? message) : base(message) { HResult = HResults.E_LAYOUTCYCLE; } - public LayoutCycleException(string message, Exception innerException) + public LayoutCycleException(string? message, Exception? innerException) : base(message, innerException) { HResult = HResults.E_LAYOUTCYCLE; diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Markup/XamlParseException.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Markup/XamlParseException.cs index 0e027de1fd0ae8..989cd8e4509cc3 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Markup/XamlParseException.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Markup/XamlParseException.cs @@ -25,13 +25,13 @@ public XamlParseException() HResult = HResults.E_XAMLPARSEFAILED; } - public XamlParseException(string message) + public XamlParseException(string? message) : base(message) { HResult = HResults.E_XAMLPARSEFAILED; } - public XamlParseException(string message, Exception innerException) + public XamlParseException(string? message, Exception? innerException) : base(message, innerException) { HResult = HResults.E_XAMLPARSEFAILED; diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Animation/KeyTime.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Animation/KeyTime.cs index 2942b2a1886b2d..f216f349ebaa9f 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Animation/KeyTime.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Animation/KeyTime.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -// - using System; using System.Runtime.InteropServices; @@ -60,7 +56,7 @@ public bool Equals(KeyTime value) return KeyTime.Equals(this, value); } - public override bool Equals(object value) + public override bool Equals(object? value) { return value is KeyTime && this == (KeyTime)value; } diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Animation/RepeatBehavior.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Animation/RepeatBehavior.cs index c297e6879cc1df..615723fa07d062 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Animation/RepeatBehavior.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Animation/RepeatBehavior.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -// - using System; using System.Runtime.InteropServices; using System.Text; @@ -113,17 +109,17 @@ public override string ToString() return InternalToString(null, null); } - public string ToString(IFormatProvider formatProvider) + public string ToString(IFormatProvider? formatProvider) { return InternalToString(null, formatProvider); } - string IFormattable.ToString(string format, IFormatProvider formatProvider) + string IFormattable.ToString(string? format, IFormatProvider? formatProvider) { return InternalToString(format, formatProvider); } - internal string InternalToString(string format, IFormatProvider formatProvider) + internal string InternalToString(string? format, IFormatProvider? formatProvider) { switch (_Type) { @@ -147,11 +143,11 @@ internal string InternalToString(string format, IFormatProvider formatProvider) return _Duration.ToString(); default: - return null; + return string.Empty; } } - public override bool Equals(object value) + public override bool Equals(object? value) { if (value is RepeatBehavior) { diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Matrix.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Matrix.cs index 2460c841931983..6fdf70d5b15535 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Matrix.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Matrix.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -// - using System; using System.Runtime.InteropServices; using Point = Windows.Foundation.Point; @@ -136,19 +132,19 @@ public override string ToString() return ConvertToString(null /* format string */, null /* format provider */); } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(null /* format string */, provider); } - string IFormattable.ToString(string format, IFormatProvider provider) + string IFormattable.ToString(string? format, IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(format, provider); } - private string ConvertToString(string format, IFormatProvider provider) + private string ConvertToString(string? format, IFormatProvider? provider) { if (IsIdentity) { @@ -188,7 +184,7 @@ public override int GetHashCode() OffsetY.GetHashCode(); } - public override bool Equals(object o) + public override bool Equals(object? o) { return o is Matrix && Matrix.Equals(this, (Matrix)o); } diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Media3D/Matrix3D.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Media3D/Matrix3D.cs index af001abafe6276..dfd7d462d218eb 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Media3D/Matrix3D.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Media/Media3D/Matrix3D.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -// - using System; using System.Runtime.InteropServices; @@ -408,19 +404,19 @@ public override string ToString() return ConvertToString(null /* format string */, null /* format provider */); } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(null /* format string */, provider); } - string IFormattable.ToString(string format, IFormatProvider provider) + string IFormattable.ToString(string? format, IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(format, provider); } - private string ConvertToString(string format, IFormatProvider provider) + private string ConvertToString(string? format, IFormatProvider? provider) { if (IsIdentity) { @@ -461,7 +457,7 @@ public override int GetHashCode() M44.GetHashCode(); } - public override bool Equals(object o) + public override bool Equals(object? o) { return o is Matrix3D && Matrix3D.Equals(this, (Matrix3D)o); } diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Thickness.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Thickness.cs index 3c22ebe9742d62..2a3a4b745cce36 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Thickness.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/Thickness.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - -// - using System; using System.Globalization; using System.Runtime.InteropServices; @@ -72,7 +68,7 @@ public override string ToString() return ToString(CultureInfo.InvariantCulture); } - internal string ToString(CultureInfo cultureInfo) + internal string ToString(CultureInfo? cultureInfo) { char listSeparator = TokenizerHelper.GetNumericListSeparator(cultureInfo); @@ -92,13 +88,13 @@ internal string ToString(CultureInfo cultureInfo) return sb.ToString(); } - internal string InternalToString(double l, CultureInfo cultureInfo) + internal string InternalToString(double l, CultureInfo? cultureInfo) { if (double.IsNaN(l)) return "Auto"; return Convert.ToString(l, cultureInfo); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is Thickness) { diff --git a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/TokenizerHelper.cs b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/TokenizerHelper.cs index ad3207b4765402..8ddd773f400730 100644 --- a/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/TokenizerHelper.cs +++ b/src/libraries/System.Runtime.WindowsRuntime.UI.Xaml/src/System/Windows/TokenizerHelper.cs @@ -20,7 +20,7 @@ namespace Windows.UI.Xaml internal static class TokenizerHelper { - internal static char GetNumericListSeparator(IFormatProvider provider) + internal static char GetNumericListSeparator(IFormatProvider? provider) { char numericSeparator = ','; diff --git a/src/libraries/System.Runtime.WindowsRuntime/System.Runtime.WindowsRuntime.sln b/src/libraries/System.Runtime.WindowsRuntime/System.Runtime.WindowsRuntime.sln index a6e472ea214751..8a3e707333186a 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/System.Runtime.WindowsRuntime.sln +++ b/src/libraries/System.Runtime.WindowsRuntime/System.Runtime.WindowsRuntime.sln @@ -26,6 +26,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C4854B44-ABFE-4BB5-8F89-F35FE6201338}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4854B44-ABFE-4BB5-8F89-F35FE6201338}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4854B44-ABFE-4BB5-8F89-F35FE6201338}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4854B44-ABFE-4BB5-8F89-F35FE6201338}.Release|Any CPU.Build.0 = Release|Any CPU {844A2A0B-4169-49C3-B367-AFDC4894E487}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {844A2A0B-4169-49C3-B367-AFDC4894E487}.Debug|Any CPU.Build.0 = Debug|Any CPU {844A2A0B-4169-49C3-B367-AFDC4894E487}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.Manual.cs b/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.Manual.cs index f0152a32e4e834..f7ef82e270693d 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.Manual.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.Manual.cs @@ -18,17 +18,17 @@ namespace Windows.Foundation { public partial struct Point : IFormattable { - string IFormattable.ToString(string format, IFormatProvider provider) { throw null; } + string IFormattable.ToString(string? format, IFormatProvider? provider) { throw null; } } public partial struct Rect : IFormattable { - string IFormattable.ToString(string format, IFormatProvider provider) { throw null; } + string IFormattable.ToString(string? format, IFormatProvider? provider) { throw null; } } } namespace Windows.UI { public partial struct Color : IFormattable { - string IFormattable.ToString(string format, IFormatProvider provider) { throw null; } + string IFormattable.ToString(string? format, IFormatProvider? provider) { throw null; } } } diff --git a/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.cs b/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.cs index 1210eb6fa06900..c3e6e2fd32d184 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.cs @@ -15,15 +15,15 @@ public static partial class WindowsRuntimeSystemExtensions public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncAction source) { throw null; } public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncAction source, System.Threading.CancellationToken cancellationToken) { throw null; } public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncActionWithProgress source) { throw null; } - public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncActionWithProgress source, System.IProgress progress) { throw null; } + public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncActionWithProgress source, System.IProgress? progress) { throw null; } public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncActionWithProgress source, System.Threading.CancellationToken cancellationToken) { throw null; } - public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncActionWithProgress source, System.Threading.CancellationToken cancellationToken, System.IProgress progress) { throw null; } + public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncActionWithProgress source, System.Threading.CancellationToken cancellationToken, System.IProgress? progress) { throw null; } public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncOperation source) { throw null; } public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncOperation source, System.Threading.CancellationToken cancellationToken) { throw null; } public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncOperationWithProgress source) { throw null; } - public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncOperationWithProgress source, System.IProgress progress) { throw null; } + public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncOperationWithProgress source, System.IProgress? progress) { throw null; } public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncOperationWithProgress source, System.Threading.CancellationToken cancellationToken) { throw null; } - public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncOperationWithProgress source, System.Threading.CancellationToken cancellationToken, System.IProgress progress) { throw null; } + public static System.Threading.Tasks.Task AsTask(this global::Windows.Foundation.IAsyncOperationWithProgress source, System.Threading.CancellationToken cancellationToken, System.IProgress? progress) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Runtime.CompilerServices.TaskAwaiter GetAwaiter(this global::Windows.Foundation.IAsyncAction source) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] @@ -122,7 +122,7 @@ public static void CopyTo(this global::Windows.Storage.Streams.IBuffer source, g [System.CLSCompliantAttribute(false)] public static global::Windows.Storage.Streams.IBuffer GetWindowsRuntimeBuffer(this System.IO.MemoryStream underlyingStream, int positionInStream, int length) { throw null; } [System.CLSCompliantAttribute(false)] - public static bool IsSameData(this global::Windows.Storage.Streams.IBuffer buffer, global::Windows.Storage.Streams.IBuffer otherBuffer) { throw null; } + public static bool IsSameData(this global::Windows.Storage.Streams.IBuffer buffer, global::Windows.Storage.Streams.IBuffer? otherBuffer) { throw null; } [System.CLSCompliantAttribute(false)] public static byte[] ToArray(this global::Windows.Storage.Streams.IBuffer source) { throw null; } [System.CLSCompliantAttribute(false)] @@ -137,13 +137,13 @@ public partial struct Point : global::System.IFormattable public Point(double x, double y) { throw null; } public double X { get { throw null; } set { } } public double Y { get { throw null; } set { } } - public override bool Equals(object o) { throw null; } + public override bool Equals(object? o) { throw null; } public bool Equals(global::Windows.Foundation.Point value) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(global::Windows.Foundation.Point point1, global::Windows.Foundation.Point point2) { throw null; } public static bool operator !=(global::Windows.Foundation.Point point1, global::Windows.Foundation.Point point2) { throw null; } public override string ToString() { throw null; } - public string ToString(global::System.IFormatProvider provider) { throw null; } + public string ToString(global::System.IFormatProvider? provider) { throw null; } } public partial struct Rect : global::System.IFormattable { @@ -162,14 +162,14 @@ public partial struct Rect : global::System.IFormattable public double X { get { throw null; } set { } } public double Y { get { throw null; } set { } } public bool Contains(global::Windows.Foundation.Point point) { throw null; } - public override bool Equals(object o) { throw null; } + public override bool Equals(object? o) { throw null; } public bool Equals(global::Windows.Foundation.Rect value) { throw null; } public override int GetHashCode() { throw null; } public void Intersect(global::Windows.Foundation.Rect rect) { } public static bool operator ==(global::Windows.Foundation.Rect rect1, global::Windows.Foundation.Rect rect2) { throw null; } public static bool operator !=(global::Windows.Foundation.Rect rect1, global::Windows.Foundation.Rect rect2) { throw null; } public override string ToString() { throw null; } - public string ToString(global::System.IFormatProvider provider) { throw null; } + public string ToString(global::System.IFormatProvider? provider) { throw null; } public void Union(global::Windows.Foundation.Point point) { } public void Union(global::Windows.Foundation.Rect rect) { } } @@ -181,7 +181,7 @@ public partial struct Size public double Height { get { throw null; } set { } } public bool IsEmpty { get { throw null; } } public double Width { get { throw null; } set { } } - public override bool Equals(object o) { throw null; } + public override bool Equals(object? o) { throw null; } public bool Equals(global::Windows.Foundation.Size value) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(global::Windows.Foundation.Size size1, global::Windows.Foundation.Size size2) { throw null; } @@ -198,13 +198,13 @@ public partial struct Color : global::System.IFormattable public byte B { get { throw null; } set { } } public byte G { get { throw null; } set { } } public byte R { get { throw null; } set { } } - public override bool Equals(object o) { throw null; } + public override bool Equals(object? o) { throw null; } public bool Equals(global::Windows.UI.Color color) { throw null; } public static global::Windows.UI.Color FromArgb(byte a, byte r, byte g, byte b) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(global::Windows.UI.Color color1, global::Windows.UI.Color color2) { throw null; } public static bool operator !=(global::Windows.UI.Color color1, global::Windows.UI.Color color2) { throw null; } public override string ToString() { throw null; } - public string ToString(global::System.IFormatProvider provider) { throw null; } + public string ToString(global::System.IFormatProvider? provider) { throw null; } } } diff --git a/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.csproj b/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.csproj index 08655bbddfe08f..3885371c63fd3b 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.csproj +++ b/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.csproj @@ -12,6 +12,7 @@ $(NoWarn);1698 $(NetCoreAppCurrent);netstandard2.0 true + enable diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj b/src/libraries/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj index 60f7f32e4794b7..b8714d9479b2cc 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj @@ -10,6 +10,7 @@ $(DefineConstants);FEATURE_APPX $(NetCoreAppCurrent)-Windows_NT;netstandard1.0;netstandard1.2;netstandard2.0 true + enable SR.PlatformNotSupported_WindowsRuntime diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/NetFxToWinRtStreamAdapter.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/NetFxToWinRtStreamAdapter.cs index 2b1a2e8deb56ef..b9402ac2e354af 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/NetFxToWinRtStreamAdapter.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/NetFxToWinRtStreamAdapter.cs @@ -10,6 +10,7 @@ using System.Threading; using Windows.Foundation; using Windows.Storage.Streams; +using System.Diagnostics.CodeAnalysis; namespace System.IO { @@ -128,7 +129,7 @@ private static StreamReadOperationOptimization DetermineStreamReadOptimization(S private static bool CanApplyReadMemoryStreamOptimization(Stream stream) { - MemoryStream memStream = stream as MemoryStream; + MemoryStream? memStream = stream as MemoryStream; if (memStream == null) return false; @@ -154,7 +155,7 @@ private NetFxToWinRtStreamAdapter(Stream stream, StreamReadOperationOptimization #region Instance variables - private Stream _managedStream = null; + private Stream? _managedStream = null; private bool _leaveUnderlyingStreamOpen = true; private readonly StreamReadOperationOptimization _readOptimization; @@ -176,7 +177,7 @@ internal void SetWonInitializationRace() } - public Stream GetManagedStream() + public Stream? GetManagedStream() { return _managedStream; } @@ -184,7 +185,7 @@ public Stream GetManagedStream() private Stream EnsureNotDisposed() { - Stream str = _managedStream; + Stream? str = _managedStream; if (str == null) { @@ -204,7 +205,7 @@ private Stream EnsureNotDisposed() /// Implements IDisposable.Dispose (IClosable.Close in WinRT) void IDisposable.Dispose() { - Stream str = _managedStream; + Stream? str = _managedStream; if (str == null) return; @@ -412,7 +413,7 @@ public ulong Size // for IRandonAccessStream. // Cloning can be added in future, however, it would be quite complex // to support it correctly for generic streams. - + [DoesNotReturn] private static void ThrowCloningNotSupported(string methodName) { NotSupportedException nse = new NotSupportedException(SR.Format(SR.NotSupported_CloningNotSupported, methodName)); diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationAsyncResult.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationAsyncResult.cs index 8a58356b6032bf..c94c172a1241ed 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationAsyncResult.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationAsyncResult.cs @@ -11,6 +11,7 @@ using System.Threading; using Windows.Foundation; using Windows.Storage.Streams; +using System.Diagnostics.CodeAnalysis; namespace System.IO { @@ -18,25 +19,25 @@ namespace System.IO internal abstract partial class StreamOperationAsyncResult : IAsyncResult { - private readonly AsyncCallback _userCompletionCallback = null; - private readonly object _userAsyncStateInfo = null; + private readonly AsyncCallback? _userCompletionCallback = null; + private readonly object? _userAsyncStateInfo = null; - private IAsyncInfo _asyncStreamOperation = null; + private IAsyncInfo? _asyncStreamOperation = null; private volatile bool _completed = false; private volatile bool _callbackInvoked = false; - private volatile ManualResetEvent _waitHandle = null; + private volatile ManualResetEvent? _waitHandle = null; private long _bytesCompleted = 0; - private ExceptionDispatchInfo _errorInfo = null; + private ExceptionDispatchInfo? _errorInfo = null; private readonly bool _processCompletedOperationInCallback; - private IAsyncInfo _completedOperation = null; + private IAsyncInfo? _completedOperation = null; protected internal StreamOperationAsyncResult(IAsyncInfo asyncStreamOperation, - AsyncCallback userCompletionCallback, object userAsyncStateInfo, + AsyncCallback? userCompletionCallback, object? userAsyncStateInfo, bool processCompletedOperationInCallback) { if (asyncStreamOperation == null) @@ -58,7 +59,7 @@ protected internal StreamOperationAsyncResult(IAsyncInfo asyncStreamOperation, } - public object AsyncState + public object? AsyncState { get { return _userAsyncStateInfo; } } @@ -74,7 +75,7 @@ public WaitHandle AsyncWaitHandle { get { - ManualResetEvent wh = _waitHandle; + ManualResetEvent? wh = _waitHandle; if (wh != null) return wh; @@ -82,7 +83,7 @@ public WaitHandle AsyncWaitHandle // > Use 'completed' in the ctor - this way the handle wait will return as appropriate. wh = new ManualResetEvent(_completed); - ManualResetEvent otherHandle = Interlocked.CompareExchange(ref _waitHandle, wh, null); + ManualResetEvent? otherHandle = Interlocked.CompareExchange(ref _waitHandle, wh, null); // We lost the race. Dispose OUR handle and return OTHER handle: if (otherHandle != null) @@ -177,10 +178,10 @@ internal void CloseStreamOperation() internal abstract void ProcessConcreteCompletedOperation(IAsyncInfo completedOperation, out long bytesCompleted); - - private static void ProcessCompletedOperation_InvalidOperationThrowHelper(ExceptionDispatchInfo errInfo, string errMsg) + [DoesNotReturn] + private static void ProcessCompletedOperation_InvalidOperationThrowHelper(ExceptionDispatchInfo? errInfo, string errMsg) { - Exception errInfoSrc = (errInfo == null) ? null : errInfo.SourceException; + Exception? errInfoSrc = (errInfo == null) ? null : errInfo.SourceException; if (errInfoSrc == null) throw new InvalidOperationException(errMsg); @@ -209,14 +210,14 @@ internal void ProcessCompletedOperation() if (_completedOperation == null) { - ExceptionDispatchInfo errInfo = _errorInfo; - Exception errInfoSrc = (errInfo == null) ? null : errInfo.SourceException; + ExceptionDispatchInfo? errInfo = _errorInfo; + Exception? errInfoSrc = (errInfo == null) ? null : errInfo.SourceException; // See if errorInfo is set because we observed completedOperation == null previously (being slow is Ok on error path): if (errInfoSrc != null && errInfoSrc is NullReferenceException && SR.NullReference_IOCompletionCallbackCannotProcessNullAsyncInfo.Equals(errInfoSrc.Message)) { - errInfo.Throw(); + errInfo!.Throw(); } else { @@ -224,7 +225,7 @@ internal void ProcessCompletedOperation() } } - if (_completedOperation.Id != _asyncStreamOperation.Id) + if (_completedOperation.Id != _asyncStreamOperation!.Id) ProcessCompletedOperation_InvalidOperationThrowHelper(_errorInfo, SR.InvalidOperation_UnexpectedAsyncOperationID); if (_completedOperation.Status == AsyncStatus.Error) @@ -285,7 +286,7 @@ internal void StreamOperationCompletedCallback(IAsyncInfo completedOperation, As private void ThrowWithIOExceptionDispatchInfo(Exception e) { - WinRtIOHelper.NativeExceptionToIOExceptionInfo(ExceptionSupport.AttachRestrictedErrorInfo(_completedOperation.ErrorCode)).Throw(); + WinRtIOHelper.NativeExceptionToIOExceptionInfo(ExceptionSupport.AttachRestrictedErrorInfo(_completedOperation!.ErrorCode)!).Throw(); } } // class StreamOperationAsyncResult @@ -296,10 +297,10 @@ private void ThrowWithIOExceptionDispatchInfo(Exception e) internal class StreamReadAsyncResult : StreamOperationAsyncResult { - private readonly IBuffer _userBuffer = null; + private readonly IBuffer _userBuffer; internal StreamReadAsyncResult(IAsyncOperationWithProgress asyncStreamReadOperation, IBuffer buffer, - AsyncCallback userCompletionCallback, object userAsyncStateInfo, + AsyncCallback? userCompletionCallback, object? userAsyncStateInfo, bool processCompletedOperationInCallback) : base(asyncStreamReadOperation, userCompletionCallback, userAsyncStateInfo, processCompletedOperationInCallback) @@ -323,8 +324,8 @@ private void ProcessConcreteCompletedOperation(IAsyncOperationWithProgress asyncStreamWriteOperation, - AsyncCallback userCompletionCallback, object userAsyncStateInfo, + AsyncCallback? userCompletionCallback, object? userAsyncStateInfo, bool processCompletedOperationInCallback) : base(asyncStreamWriteOperation, userCompletionCallback, userAsyncStateInfo, processCompletedOperationInCallback) diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationsImplementation.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationsImplementation.cs index 252eb6965bb17b..9414d9f042cc2b 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationsImplementation.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationsImplementation.cs @@ -41,7 +41,7 @@ internal static IAsyncOperationWithProgress ReadAsync_MemoryStrea // The user specified buffer will not have any data put into it: buffer.Length = 0; - MemoryStream memStream = stream as MemoryStream; + MemoryStream? memStream = stream as MemoryStream; Debug.Assert(memStream != null); try @@ -82,7 +82,7 @@ internal static IAsyncOperationWithProgress ReadAsync_AbstractStr // Note: the allocation costs we are paying for the new buffer are unavoidable anyway, as we would need to create // an array to read into either way. - IBuffer dataBuffer = buffer as WindowsRuntimeBuffer; + IBuffer? dataBuffer = buffer as WindowsRuntimeBuffer; if (dataBuffer == null) dataBuffer = WindowsRuntimeBuffer.Create((int)Math.Min((uint)int.MaxValue, buffer.Capacity)); @@ -94,7 +94,7 @@ internal static IAsyncOperationWithProgress ReadAsync_AbstractStr dataBuffer.Length = 0; // Get the buffer backing array: - byte[] data; + byte[]? data; int offset; bool managedBufferAssert = dataBuffer.TryGetUnderlyingData(out data, out offset); Debug.Assert(managedBufferAssert); @@ -111,7 +111,7 @@ internal static IAsyncOperationWithProgress ReadAsync_AbstractStr try { // Read asynchronously: - bytesRead = await stream.ReadAsync(data, offset + bytesCompleted, bytesRequested - bytesCompleted, cancelToken) + bytesRead = await stream.ReadAsync(data!, offset + bytesCompleted, bytesRequested - bytesCompleted, cancelToken) .ConfigureAwait(continueOnCapturedContext: false); // We will continue here on a different thread when read async completed: @@ -166,7 +166,7 @@ internal static IAsyncOperationWithProgress WriteAsync_AbstractStrea // Choose the optimal writing strategy for the kind of buffer supplied: Func, Task> writeOperation; - byte[] data; + byte[]? data; int offset; // If buffer is backed by a managed array: diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WinRtToNetFxStreamAdapter.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WinRtToNetFxStreamAdapter.cs index d7d5fe851a884e..5da6d2bd0cafbf 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WinRtToNetFxStreamAdapter.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WinRtToNetFxStreamAdapter.cs @@ -10,6 +10,7 @@ using System.Threading; using Windows.Foundation; using Windows.Storage.Streams; +using System.Diagnostics.CodeAnalysis; namespace System.IO { @@ -93,10 +94,10 @@ private WinRtToNetFxStreamAdapter(object winRtStream, bool canRead, bool canWrit #region Instance variables - private byte[] _oneByteBuffer = null; + private byte[]? _oneByteBuffer = null; private bool _leaveUnderlyingStreamOpen = true; - private object _winRtStream; + private object? _winRtStream; private readonly bool _canRead; private readonly bool _canWrite; private readonly bool _canSeek; @@ -119,9 +120,9 @@ internal void SetWonInitializationRace() } - public TWinRtStream GetWindowsRuntimeStream() where TWinRtStream : class + public TWinRtStream? GetWindowsRuntimeStream() where TWinRtStream : class { - object wrtStr = _winRtStream; + object? wrtStr = _winRtStream; if (wrtStr == null) return null; @@ -138,26 +139,16 @@ private byte[] OneByteBuffer { get { - byte[] obb = _oneByteBuffer; + byte[]? obb = _oneByteBuffer; if (obb == null) // benign race for multiple init _oneByteBuffer = obb = new byte[1]; return obb; } } - -#if DEBUG - private static void AssertValidStream(object winRtStream) - { - Debug.Assert(winRtStream != null, - "This to-NetFx Stream adapter must not be disposed and the underlying WinRT stream must be of compatible type for this operation"); - } -#endif // DEBUG - - - private TWinRtStream EnsureNotDisposed() where TWinRtStream : class + private TWinRtStream? EnsureNotDisposed() where TWinRtStream : class { - object wrtStr = _winRtStream; + object? wrtStr = _winRtStream; if (wrtStr == null) throw new ObjectDisposedException(SR.ObjectDisposed_CannotPerformOperation); @@ -196,7 +187,7 @@ protected override void Dispose(bool disposing) // WinRT streams should implement IDisposable (IClosable in WinRT), but let's be defensive: if (disposing && _winRtStream != null && !_leaveUnderlyingStreamOpen) { - IDisposable disposableWinRtStream = _winRtStream as IDisposable; // benign race on winRtStream + IDisposable? disposableWinRtStream = _winRtStream as IDisposable; // benign race on winRtStream if (disposableWinRtStream != null) disposableWinRtStream.Dispose(); } @@ -238,14 +229,12 @@ public override long Length { get { - IRandomAccessStream wrtStr = EnsureNotDisposed(); + IRandomAccessStream? wrtStr = EnsureNotDisposed(); if (!_canSeek) throw new NotSupportedException(SR.NotSupported_CannotUseLength_StreamNotSeekable); -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); ulong size = wrtStr.Size; @@ -262,14 +251,12 @@ public override long Position { get { - IRandomAccessStream wrtStr = EnsureNotDisposed(); + IRandomAccessStream? wrtStr = EnsureNotDisposed(); if (!_canSeek) throw new NotSupportedException(SR.NotSupported_CannotUsePosition_StreamNotSeekable); -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); ulong pos = wrtStr.Position; @@ -285,14 +272,12 @@ public override long Position if (value < 0) throw new ArgumentOutOfRangeException(nameof(Position), SR.ArgumentOutOfRange_IO_CannotSeekToNegativePosition); - IRandomAccessStream wrtStr = EnsureNotDisposed(); + IRandomAccessStream? wrtStr = EnsureNotDisposed(); if (!_canSeek) throw new NotSupportedException(SR.NotSupported_CannotUsePosition_StreamNotSeekable); -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); wrtStr.Seek(unchecked((ulong)value)); } @@ -301,14 +286,12 @@ public override long Position public override long Seek(long offset, SeekOrigin origin) { - IRandomAccessStream wrtStr = EnsureNotDisposed(); + IRandomAccessStream? wrtStr = EnsureNotDisposed(); if (!_canSeek) throw new NotSupportedException(SR.NotSupported_CannotSeekInStream); -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); switch (origin) { @@ -387,16 +370,14 @@ public override void SetLength(long value) if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_CannotResizeStreamToNegative); - IRandomAccessStream wrtStr = EnsureNotDisposed(); + IRandomAccessStream? wrtStr = EnsureNotDisposed(); if (!_canSeek) throw new NotSupportedException(SR.NotSupported_CannotSeekInStream); EnsureCanWrite(); -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); wrtStr.Size = unchecked((ulong)value); @@ -411,7 +392,7 @@ public override void SetLength(long value) #region Reading - private IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state, bool usedByBlockingWrapper) + private IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state, bool usedByBlockingWrapper) { // This method is somewhat tricky: We could consider just calling ReadAsync (recall that Task implements IAsyncResult). // It would be OK for cases where BeginRead is invoked directly by the public user. @@ -448,12 +429,10 @@ private IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallba if (buffer.Length - offset < count) throw new ArgumentException(SR.Argument_InsufficientSpaceInTargetBuffer); - IInputStream wrtStr = EnsureNotDisposed(); + IInputStream? wrtStr = EnsureNotDisposed(); EnsureCanRead(); -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); IBuffer userBuffer = buffer.AsBuffer(offset, count); IAsyncOperationWithProgress asyncReadOperation = wrtStr.ReadAsync(userBuffer, @@ -480,7 +459,7 @@ public override int EndRead(IAsyncResult asyncResult) EnsureNotDisposed(); EnsureCanRead(); - StreamOperationAsyncResult streamAsyncResult = asyncResult as StreamOperationAsyncResult; + StreamOperationAsyncResult? streamAsyncResult = asyncResult as StreamOperationAsyncResult; if (streamAsyncResult == null) throw new ArgumentException(SR.Argument_UnexpectedAsyncResult, nameof(asyncResult)); @@ -570,12 +549,12 @@ public override int ReadByte() #region Writing - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { return BeginWrite(buffer, offset, count, callback, state, usedByBlockingWrapper: false); } - private IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state, bool usedByBlockingWrapper) + private IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state, bool usedByBlockingWrapper) { // See the large comment in BeginRead about why we are not using this.WriteAsync, // and instead using a custom implementation of IAsyncResult. @@ -592,12 +571,10 @@ private IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallb if (buffer.Length - offset < count) throw new ArgumentException(SR.Argument_InsufficientArrayElementsAfterOffset); - IOutputStream wrtStr = EnsureNotDisposed(); + IOutputStream? wrtStr = EnsureNotDisposed(); EnsureCanWrite(); -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); IBuffer asyncWriteBuffer = buffer.AsBuffer(offset, count); @@ -623,7 +600,7 @@ public override void EndWrite(IAsyncResult asyncResult) EnsureNotDisposed(); EnsureCanWrite(); - StreamOperationAsyncResult streamAsyncResult = asyncResult as StreamOperationAsyncResult; + StreamOperationAsyncResult? streamAsyncResult = asyncResult as StreamOperationAsyncResult; if (streamAsyncResult == null) throw new ArgumentException(SR.Argument_UnexpectedAsyncResult, nameof(asyncResult)); @@ -666,12 +643,10 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati if (buffer.Length - offset < count) throw new ArgumentException(SR.Argument_InsufficientArrayElementsAfterOffset); - IOutputStream wrtStr = EnsureNotDisposed(); + IOutputStream? wrtStr = EnsureNotDisposed(); EnsureCanWrite(); -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); // If already cancelled, bail early: cancellationToken.ThrowIfCancellationRequested(); @@ -717,15 +692,13 @@ public override void Flush() // See the large comment in BeginRead about why we are not using this.FlushAsync, // and instead using a custom implementation of IAsyncResult. - IOutputStream wrtStr = EnsureNotDisposed(); + IOutputStream? wrtStr = EnsureNotDisposed(); // Calling Flush in a non-writable stream is a no-op, not an error: if (!_canWrite) return; -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); IAsyncOperation asyncFlushOperation = wrtStr.FlushAsync(); StreamFlushAsyncResult asyncResult = new StreamFlushAsyncResult(asyncFlushOperation, processCompletedOperationInCallback: false); @@ -755,15 +728,13 @@ public override void Flush() public override Task FlushAsync(CancellationToken cancellationToken) { - IOutputStream wrtStr = EnsureNotDisposed(); + IOutputStream? wrtStr = EnsureNotDisposed(); // Calling Flush in a non-writable stream is a no-op, not an error: if (!_canWrite) return Task.CompletedTask; -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); cancellationToken.ThrowIfCancellationRequested(); @@ -787,11 +758,9 @@ private async Task ReadAsyncInternal(byte[] buffer, int offset, int count, Debug.Assert(buffer.Length - offset >= count); Debug.Assert(_canRead); - IInputStream wrtStr = EnsureNotDisposed(); + IInputStream? wrtStr = EnsureNotDisposed(); -#if DEBUG - AssertValidStream(wrtStr); -#endif // DEBUG + Debug.Assert(wrtStr != null); try { diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WindowsRuntimeStorageExtensions.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WindowsRuntimeStorageExtensions.cs index dad2ca5e37deee..09f870bfdb5070 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WindowsRuntimeStorageExtensions.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WindowsRuntimeStorageExtensions.cs @@ -176,7 +176,7 @@ private static async Task OpenStreamForWriteAsyncCore(this IStorageFolde } [CLSCompliant(false)] - public static SafeFileHandle CreateSafeFileHandle( + public static SafeFileHandle? CreateSafeFileHandle( this IStorageFile windowsRuntimeFile, FileAccess access = FileAccess.ReadWrite, FileShare share = FileShare.Read, @@ -189,7 +189,7 @@ public static SafeFileHandle CreateSafeFileHandle( HANDLE_SHARING_OPTIONS sharingOptions = FileShareToHandleSharingOptions(share); HANDLE_OPTIONS handleOptions = FileOptionsToHandleOptions(options); - IStorageItemHandleAccess handleAccess = ((object)windowsRuntimeFile) as IStorageItemHandleAccess; + IStorageItemHandleAccess? handleAccess = ((object)windowsRuntimeFile) as IStorageItemHandleAccess; if (handleAccess == null) return null; @@ -210,7 +210,7 @@ public static SafeFileHandle CreateSafeFileHandle( } [CLSCompliant(false)] - public static SafeFileHandle CreateSafeFileHandle( + public static SafeFileHandle? CreateSafeFileHandle( this IStorageFolder rootDirectory, string relativePath, FileMode mode) @@ -219,7 +219,7 @@ public static SafeFileHandle CreateSafeFileHandle( } [CLSCompliant(false)] - public static SafeFileHandle CreateSafeFileHandle( + public static SafeFileHandle? CreateSafeFileHandle( this IStorageFolder rootDirectory, string relativePath, FileMode mode, @@ -237,7 +237,7 @@ public static SafeFileHandle CreateSafeFileHandle( HANDLE_SHARING_OPTIONS sharingOptions = FileShareToHandleSharingOptions(share); HANDLE_OPTIONS handleOptions = FileOptionsToHandleOptions(options); - IStorageFolderHandleAccess handleAccess = ((object)rootDirectory) as IStorageFolderHandleAccess; + IStorageFolderHandleAccess? handleAccess = ((object)rootDirectory) as IStorageFolderHandleAccess; if (handleAccess == null) return null; diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WindowsRuntimeStreamExtensions.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WindowsRuntimeStreamExtensions.cs index d96db30843705d..e84c3a83f4ef46 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WindowsRuntimeStreamExtensions.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/WindowsRuntimeStreamExtensions.cs @@ -40,7 +40,7 @@ private static void AssertMapContains(ConditionalWeakTable(ConditionalWeakTableNetFx, but not vice versa (time constraints). // Once we added the reverse direction, we will be able replce this entire section with just a few lines. - NetFxToWinRtStreamAdapter sAdptr = windowsRuntimeStream as NetFxToWinRtStreamAdapter; + NetFxToWinRtStreamAdapter? sAdptr = windowsRuntimeStream as NetFxToWinRtStreamAdapter; if (sAdptr != null) { - Stream wrappedNetFxStream = sAdptr.GetManagedStream(); + Stream? wrappedNetFxStream = sAdptr.GetManagedStream(); if (wrappedNetFxStream == null) throw new ObjectDisposedException(nameof(windowsRuntimeStream), SR.ObjectDisposed_CannotPerformOperation); @@ -159,7 +159,7 @@ private static Stream AsStreamInternal(object windowsRuntimeStream, int bufferSi // We have a real WinRT stream. - Stream adapter; + Stream? adapter; bool adapterExists = s_winRtToNetFxAdapterMap.TryGetValue(windowsRuntimeStream, out adapter); // There is already an adapter: @@ -215,11 +215,11 @@ private static Stream AsStreamInternalFactoryHelper(object windowsRuntimeStream, if (forceBufferSize) EnsureAdapterBufferSize(adapter, bufferSize, invokedMethodName); - WinRtToNetFxStreamAdapter actualAdapter = adapter as WinRtToNetFxStreamAdapter; + WinRtToNetFxStreamAdapter? actualAdapter = adapter as WinRtToNetFxStreamAdapter; if (actualAdapter == null) actualAdapter = ((BufferedStream)adapter).UnderlyingStream as WinRtToNetFxStreamAdapter; - actualAdapter.SetWonInitializationRace(); + actualAdapter!.SetWonInitializationRace(); return adapter; } @@ -240,7 +240,7 @@ public static IInputStream AsInputStream(this Stream stream) object adapter = AsWindowsRuntimeStreamInternal(stream); - IInputStream winRtStream = adapter as IInputStream; + IInputStream? winRtStream = adapter as IInputStream; Debug.Assert(winRtStream != null); return winRtStream; @@ -258,7 +258,7 @@ public static IOutputStream AsOutputStream(this Stream stream) object adapter = AsWindowsRuntimeStreamInternal(stream); - IOutputStream winRtStream = adapter as IOutputStream; + IOutputStream? winRtStream = adapter as IOutputStream; Debug.Assert(winRtStream != null); return winRtStream; @@ -276,7 +276,7 @@ public static IRandomAccessStream AsRandomAccessStream(this Stream stream) object adapter = AsWindowsRuntimeStreamInternal(stream); - IRandomAccessStream winRtStream = adapter as IRandomAccessStream; + IRandomAccessStream? winRtStream = adapter as IRandomAccessStream; Debug.Assert(winRtStream != null); return winRtStream; @@ -287,10 +287,10 @@ private static object AsWindowsRuntimeStreamInternal(Stream stream) { // Check to see if the managed stream is actually a wrapper of a WinRT stream: // (This can be either an adapter directly, or an adapter wrapped in a BufferedStream.) - WinRtToNetFxStreamAdapter sAdptr = stream as WinRtToNetFxStreamAdapter; + WinRtToNetFxStreamAdapter? sAdptr = stream as WinRtToNetFxStreamAdapter; if (sAdptr == null) { - BufferedStream buffAdptr = stream as BufferedStream; + BufferedStream? buffAdptr = stream as BufferedStream; if (buffAdptr != null) sAdptr = buffAdptr.UnderlyingStream as WinRtToNetFxStreamAdapter; } @@ -299,7 +299,7 @@ private static object AsWindowsRuntimeStreamInternal(Stream stream) // In that case we do not need to put the wrapper into the map. if (sAdptr != null) { - object wrappedWinRtStream = sAdptr.GetWindowsRuntimeStream(); + object? wrappedWinRtStream = sAdptr.GetWindowsRuntimeStream(); if (wrappedWinRtStream == null) throw new ObjectDisposedException(nameof(stream), SR.ObjectDisposed_CannotPerformOperation); @@ -312,12 +312,12 @@ private static object AsWindowsRuntimeStreamInternal(Stream stream) // We have a real managed Stream. // See if the managed stream already has an adapter: - NetFxToWinRtStreamAdapter adapter; + NetFxToWinRtStreamAdapter? adapter; bool adapterExists = s_netFxToWinRtAdapterMap.TryGetValue(stream, out adapter); // There is already an adapter: if (adapterExists) - return adapter; + return adapter!; // We do not have an adapter for this managed stream yet and we need to create one. // Do that in a thread-safe manner in a separate method such that we only have to pay for the compiler allocating diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Resources/WindowsRuntimeResourceManager.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Resources/WindowsRuntimeResourceManager.cs index 3cf8427aba3643..3e9de88776996d 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Resources/WindowsRuntimeResourceManager.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Resources/WindowsRuntimeResourceManager.cs @@ -29,34 +29,34 @@ internal sealed class WindowsRuntimeResourceManager : WindowsRuntimeResourceMana // invariant name is an empty string. We will use the private invariant culture name x-VL instead. private const string c_InvariantCulturePrivateName = "x-VL"; - private ResourceMap _resourceMap; - private ResourceContext _clonedResourceContext; - private string _clonedResourceContextFallBackList; + private ResourceMap? _resourceMap; + private ResourceContext? _clonedResourceContext; + private string? _clonedResourceContextFallBackList; - private static char[] s_charCultureSeparator; + private static char[]? s_charCultureSeparator; private struct PackageInfo { - public string Path; - public string Name; - public string FullName; + public string? Path; + public string? Name; + public string? FullName; } private static PackageInfo s_currentPackageInfo; - private static List s_dependentPackageInfoList; + private static List? s_dependentPackageInfoList; - private static ResourceContext s_globalResourceContext; // Read from it but do not modify it or call Reset() on it as that would affect the app-wide state + private static ResourceContext? s_globalResourceContext; // Read from it but do not modify it or call Reset() on it as that would affect the app-wide state - private static volatile string s_globalResourceContextFallBackList; - private static volatile CultureInfo s_globalResourceContextBestFitCultureInfo; - private static volatile global::Windows.ApplicationModel.Resources.Core.ResourceManager s_globalResourceManager; + private static volatile string? s_globalResourceContextFallBackList; + private static volatile CultureInfo? s_globalResourceContextBestFitCultureInfo; + private static volatile global::Windows.ApplicationModel.Resources.Core.ResourceManager? s_globalResourceManager; private static readonly object s_objectForLock = new object(); // Used by InitializeStatics private static bool InitializeStatics() { - global::Windows.ApplicationModel.Resources.Core.ResourceManager globalResourceManager = null; + global::Windows.ApplicationModel.Resources.Core.ResourceManager? globalResourceManager = null; if (s_globalResourceManager == null) { @@ -104,7 +104,7 @@ private static bool InitializeStatics() return s_globalResourceManager != null; } - private static void InitializeStaticGlobalResourceContext(global::Windows.ApplicationModel.Resources.Core.ResourceManager resourceManager) + private static void InitializeStaticGlobalResourceContext(global::Windows.ApplicationModel.Resources.Core.ResourceManager? resourceManager) { if (s_globalResourceContext == null) { @@ -137,7 +137,7 @@ private static void InitializeStaticGlobalResourceContext(global::Windows.Applic // Returns the CultureInfo representing the first language in the list that we can construct a CultureInfo for or null if // no such culture exists. - private static unsafe CultureInfo GetBestFitCultureFromLanguageList(List languages) + private static unsafe CultureInfo? GetBestFitCultureFromLanguageList(List languages) { char* localeNameBuffer = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH]; // LOCALE_NAME_MAX_LENGTH includes null terminator @@ -285,7 +285,7 @@ private static bool LibpathContainsPackagename(string libpath, string packagenam } #endif - private static string FindPackageSimpleNameForFilename(string libpath) + private static string? FindPackageSimpleNameForFilename(string libpath) { Debug.Assert(libpath != null); Debug.Assert(s_currentPackageInfo.Path != null); // Set in InitializeStatics() @@ -298,9 +298,9 @@ private static string FindPackageSimpleNameForFilename(string libpath) InitializeStaticsForDependentPackages(); // s_dependentPackageInfoList is empty (but non-null) if there are no dependent packages. - foreach (PackageInfo dependentPackageInfo in s_dependentPackageInfoList) + foreach (PackageInfo dependentPackageInfo in s_dependentPackageInfoList!) { - if (LibpathMatchesPackagepath(libpath, dependentPackageInfo.Path)) + if (LibpathMatchesPackagepath(libpath, dependentPackageInfo.Path!)) return dependentPackageInfo.Name; // This may be null, in which case we failed to get the name (in InitializeStaticsForDependentPackages), but matched the path, so stop looking. } } @@ -312,14 +312,14 @@ find the package to which the library belongs. We assume that NI paths usually h package name as subfolder in its path. Based on this assumption we can find the package to which an NI belongs. Below code does that. */ - if (LibpathContainsPackagename(libpath, s_currentPackageInfo.FullName)) + if (LibpathContainsPackagename(libpath, s_currentPackageInfo.FullName!)) return s_currentPackageInfo.Name; else // Look at dependent packages { // s_dependentPackageInfoList is empty (but non-null) if there are no dependent packages. foreach (PackageInfo dependentPackageInfo in s_dependentPackageInfoList) { - if (LibpathContainsPackagename(libpath, dependentPackageInfo.FullName)) + if (LibpathContainsPackagename(libpath, dependentPackageInfo.FullName!)) return dependentPackageInfo.Name; } } @@ -339,7 +339,7 @@ to which an NI belongs. Below code does that. // Only returns true if the function succeeded completely. // Outputs exceptionInfo since it may be needed for debugging purposes // if an exception is thrown by one of Initialize's callees. - public override bool Initialize(string libpath, string reswFilename, out PRIExceptionInfo exceptionInfo) + public override bool Initialize(string libpath, string reswFilename, out PRIExceptionInfo? exceptionInfo) { Debug.Assert(libpath != null); Debug.Assert(reswFilename != null); @@ -357,11 +357,11 @@ public override bool Initialize(string libpath, string reswFilename, out PRIExce // reliable information to include in it. IReadOnlyDictionary - resourceMapDictionary = s_globalResourceManager.AllResourceMaps; + resourceMapDictionary = s_globalResourceManager!.AllResourceMaps; if (resourceMapDictionary != null) { - string packageSimpleName = FindPackageSimpleNameForFilename(libpath); + string? packageSimpleName = FindPackageSimpleNameForFilename(libpath); #if NETSTANDARD2_0 || NETCOREAPP // If we have found a simple package name for the assembly, lets make sure it is not *.resource.dll that @@ -379,7 +379,7 @@ public override bool Initialize(string libpath, string reswFilename, out PRIExce #endif if (packageSimpleName != null) { - ResourceMap packageResourceMap = null; + ResourceMap? packageResourceMap = null; // Win8 enforces that package simple names are unique (for example, the App Store will not // allow two apps with the same package simple name). That is why the Modern Resource Manager @@ -391,7 +391,7 @@ public override bool Initialize(string libpath, string reswFilename, out PRIExce // GetSubtree returns null when it cannot find resource strings // named "reswFilename/*" for the package we are looking up. - reswFilename = UriUtility.UriEncode(reswFilename); + reswFilename = UriUtility.UriEncode(reswFilename)!; _resourceMap = packageResourceMap.GetSubtree(reswFilename); if (_resourceMap == null) @@ -402,7 +402,7 @@ public override bool Initialize(string libpath, string reswFilename, out PRIExce } else { - _clonedResourceContext = s_globalResourceContext.Clone(); + _clonedResourceContext = s_globalResourceContext!.Clone(); if (_clonedResourceContext != null) { @@ -443,7 +443,7 @@ public override CultureInfo GlobalResourceContextBestFitCultureInfo get { InitializeStaticGlobalResourceContext(null); - return s_globalResourceContextBestFitCultureInfo; + return s_globalResourceContextBestFitCultureInfo!; } } @@ -501,15 +501,14 @@ public override bool SetGlobalResourceContextDefaultCulture(CultureInfo ci) // continue to be thread-safe. // Throws exceptions - public override string GetString(string stringName, - string startingCulture, string neutralResourcesCulture) + public override string? GetString(string stringName, string? startingCulture, string? neutralResourcesCulture) { Debug.Assert(stringName != null); Debug.Assert(_resourceMap != null); // Should have been initialized by now - ResourceCandidate resourceCandidate = null; + ResourceCandidate? resourceCandidate = null; - stringName = UriUtility.UriEncode(stringName); + stringName = UriUtility.UriEncode(stringName)!; if (startingCulture == null && neutralResourcesCulture == null) { @@ -528,7 +527,7 @@ public override string GetString(string stringName, // The starting culture has to be looked up first, and neutral resources culture has // to be looked up last. - string newResourceFallBackList = null; + string? newResourceFallBackList = null; newResourceFallBackList = (startingCulture == null ? "" : startingCulture + ";") + @@ -577,7 +576,7 @@ internal static class UriUtility // Adapted from the UrlEncode methods originally // in file:ndp\fx\src\xsp\system\web\httpserverutility.cs // and file:ndp\fx\src\xsp\system\web\util\httpencoder.cs - public static string UriEncode(string str) + public static string? UriEncode(string str) { if (str == null) return null; @@ -598,7 +597,7 @@ public static string UriEncode(string str) cBytesToEncode++; } - byte[] expandedBytes = null; + byte[]? expandedBytes = null; // nothing to expand? if (cBytesToEncode == 0) diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/MarshalingHelpers.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/MarshalingHelpers.cs index 484bd84bc9e05c..9daa7cf75c1220 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/MarshalingHelpers.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/MarshalingHelpers.cs @@ -88,7 +88,7 @@ internal interface INotifyCollectionChangedEventArgsFactory // The return type for this function is actually an INotifyCollectionChangedEventArgs* // but we need to make sure we don't accidentally project our native object back to managed // when marshalling it to native (which happens when correctly typing the return type as an INotifyCollectionChangedEventArgs). - IntPtr CreateInstanceWithAllParameters(int action, IList newItems, IList oldItems, int newIndex, int oldIndex, object outer, ref object inner); + IntPtr CreateInstanceWithAllParameters(int action, IList? newItems, IList? oldItems, int newIndex, int oldIndex, object? outer, ref object? inner); } // Local definition of Windows.UI.Xaml.Data.INotifyCollectionChangedEventArgsFactory @@ -100,14 +100,14 @@ internal interface IPropertyChangedEventArgsFactory // The return type for this function is actually an IPropertyChangedEventArgs* // but we need to make sure we don't accidentally project our native object back to managed // when marshalling it to native (which happens when correctly typing the return type as an IPropertyChangedEventArgs). - IntPtr CreateInstance(string name, object outer, ref object inner); + IntPtr CreateInstance(string? name, object? outer, ref object? inner); } internal static class NotifyCollectionChangedEventArgsMarshaler { private const string WinRTNotifyCollectionChangedEventArgsName = "Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs"; - private static INotifyCollectionChangedEventArgsFactory s_EventArgsFactory; + private static INotifyCollectionChangedEventArgsFactory? s_EventArgsFactory; // Extracts properties from a managed NotifyCollectionChangedEventArgs and passes them to // a VM-implemented helper that creates a WinRT NotifyCollectionChangedEventArgs instance. @@ -119,7 +119,7 @@ internal static IntPtr ConvertToNative(NotifyCollectionChangedEventArgs managedA if (s_EventArgsFactory == null) { - object factory = null; + object? factory = null; Guid guid = typeof(INotifyCollectionChangedEventArgsFactory).GUID; int hr = Interop.mincore.RoGetActivationFactory(WinRTNotifyCollectionChangedEventArgsName, ref guid, out factory); if (hr < 0) @@ -128,14 +128,14 @@ internal static IntPtr ConvertToNative(NotifyCollectionChangedEventArgs managedA s_EventArgsFactory = (INotifyCollectionChangedEventArgsFactory)factory; } - object inner = null; + object? inner = null; return s_EventArgsFactory.CreateInstanceWithAllParameters((int)managedArgs.Action, managedArgs.NewItems, managedArgs.OldItems, managedArgs.NewStartingIndex, managedArgs.OldStartingIndex, null, ref inner); } // Extracts properties from a WinRT NotifyCollectionChangedEventArgs and creates a new // managed NotifyCollectionChangedEventArgs instance. // This method is called from IL stubs and needs to have its token stabilized. - internal static NotifyCollectionChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP) + internal static NotifyCollectionChangedEventArgs? ConvertToManaged(IntPtr nativeArgsIP) { if (nativeArgsIP == IntPtr.Zero) return null; @@ -168,7 +168,7 @@ internal static class PropertyChangedEventArgsMarshaler { private const string WinRTPropertyChangedEventArgsName = "Windows.UI.Xaml.Data.PropertyChangedEventArgs"; - private static IPropertyChangedEventArgsFactory s_pPCEventArgsFactory; + private static IPropertyChangedEventArgsFactory? s_pPCEventArgsFactory; // Extracts PropertyName from a managed PropertyChangedEventArgs and passes them to // a VM-implemented helper that creates a WinRT PropertyChangedEventArgs instance. @@ -180,7 +180,7 @@ internal static IntPtr ConvertToNative(PropertyChangedEventArgs managedArgs) if (s_pPCEventArgsFactory == null) { - object factory = null; + object? factory = null; Guid guid = typeof(IPropertyChangedEventArgsFactory).GUID; int hr = Interop.mincore.RoGetActivationFactory(WinRTPropertyChangedEventArgsName, ref guid, out factory); if (hr < 0) @@ -189,14 +189,14 @@ internal static IntPtr ConvertToNative(PropertyChangedEventArgs managedArgs) s_pPCEventArgsFactory = (IPropertyChangedEventArgsFactory)factory; } - object inner = null; + object? inner = null; return s_pPCEventArgsFactory.CreateInstance(managedArgs.PropertyName, null, ref inner); } // Extracts properties from a WinRT PropertyChangedEventArgs and creates a new // managed PropertyChangedEventArgs instance. // This method is called from IL stubs and needs to have its token stabilized. - internal static PropertyChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP) + internal static PropertyChangedEventArgs? ConvertToManaged(IntPtr nativeArgsIP) { if (nativeArgsIP == IntPtr.Zero) return null; @@ -282,7 +282,7 @@ internal void remove_CollectionChanged(EventRegistrationToken token) INotifyCollectionChanged _this = Unsafe.As(this); EventRegistrationTokenTable table = s_weakTable.GetOrCreateValue(_this); - if (table.RemoveEventHandler(token, out NotifyCollectionChangedEventHandler handler)) + if (table.RemoveEventHandler(token, out NotifyCollectionChangedEventHandler? handler)) { _this.CollectionChanged -= handler; } @@ -363,7 +363,7 @@ internal void remove_PropertyChanged(EventRegistrationToken token) INotifyPropertyChanged _this = Unsafe.As(this); EventRegistrationTokenTable table = s_weakTable.GetOrCreateValue(_this); - if (table.RemoveEventHandler(token, out PropertyChangedEventHandler handler)) + if (table.RemoveEventHandler(token, out PropertyChangedEventHandler? handler)) { _this.PropertyChanged -= handler; } @@ -470,7 +470,7 @@ private void remove_CanExecuteChanged(EventRegistrationToken token) ICommand _this = Unsafe.As(this); EventRegistrationTokenTable table = s_weakTable.GetOrCreateValue(_this); - if (table.RemoveEventHandler(token, out EventHandler handler)) + if (table.RemoveEventHandler(token, out EventHandler? handler)) { _this.CanExecuteChanged -= handler; } @@ -496,16 +496,16 @@ internal static EventHandler CreateWrapperHandler(EventHandler handler) { // Check whether it is a round-tripping case i.e. the sender is of the type eventArgs, // If so we use it else we pass EventArgs.Empty - return (object sender, object e) => + return (object? sender, object e) => { - EventArgs eventArgs = e as EventArgs; + EventArgs? eventArgs = e as EventArgs; handler(sender, (eventArgs == null ? System.EventArgs.Empty : eventArgs)); }; } internal static EventHandler CreateWrapperHandler(EventHandler handler) { - return (object sender, EventArgs e) => handler(sender, e); + return (object? sender, EventArgs e) => handler(sender, e); } internal static EventHandler GetValueFromEquivalentKey( diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBuffer.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBuffer.cs index 93507d87312b58..04847a738805e4 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBuffer.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBuffer.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; @@ -63,7 +64,7 @@ public static IBuffer Create(byte[] data, int offset, int length, int capacity) // This object handles IMarshal calls for us: [ThreadStatic] - private static IMarshal t_winRtMarshalProxy = null; + private static IMarshal? t_winRtMarshalProxy = null; private static void EnsureHasMarshalProxy() { @@ -99,7 +100,7 @@ private static void EnsureHasMarshalProxy() #region Fields - private readonly byte[] _data = null; + private readonly byte[] _data; private readonly int _dataStartOffs = 0; private int _usefulDataLength = 0; private readonly int _maxDataCapacity = 0; @@ -148,9 +149,9 @@ internal WindowsRuntimeBuffer(byte[] data, int offset, int length, int capacity) #region Helpers - internal void GetUnderlyingData(out byte[] underlyingDataArray, out int underlyingDataArrayStartOffset) + internal void GetUnderlyingData([NotNull] out byte[]? underlyingDataArray, out int underlyingDataArrayStartOffset) { - underlyingDataArray = _data; + underlyingDataArray = _data!; underlyingDataArrayStartOffset = _dataStartOffs; } @@ -262,42 +263,42 @@ unsafe IntPtr IBufferByteAccess.GetBuffer() void IMarshal.DisconnectObject(uint dwReserved) { EnsureHasMarshalProxy(); - t_winRtMarshalProxy.DisconnectObject(dwReserved); + t_winRtMarshalProxy!.DisconnectObject(dwReserved); } void IMarshal.GetMarshalSizeMax(ref Guid riid, IntPtr pv, uint dwDestContext, IntPtr pvDestContext, uint mshlflags, out uint pSize) { EnsureHasMarshalProxy(); - t_winRtMarshalProxy.GetMarshalSizeMax(ref riid, pv, dwDestContext, pvDestContext, mshlflags, out pSize); + t_winRtMarshalProxy!.GetMarshalSizeMax(ref riid, pv, dwDestContext, pvDestContext, mshlflags, out pSize); } void IMarshal.GetUnmarshalClass(ref Guid riid, IntPtr pv, uint dwDestContext, IntPtr pvDestContext, uint mshlFlags, out Guid pCid) { EnsureHasMarshalProxy(); - t_winRtMarshalProxy.GetUnmarshalClass(ref riid, pv, dwDestContext, pvDestContext, mshlFlags, out pCid); + t_winRtMarshalProxy!.GetUnmarshalClass(ref riid, pv, dwDestContext, pvDestContext, mshlFlags, out pCid); } void IMarshal.MarshalInterface(IntPtr pStm, ref Guid riid, IntPtr pv, uint dwDestContext, IntPtr pvDestContext, uint mshlflags) { EnsureHasMarshalProxy(); - t_winRtMarshalProxy.MarshalInterface(pStm, ref riid, pv, dwDestContext, pvDestContext, mshlflags); + t_winRtMarshalProxy!.MarshalInterface(pStm, ref riid, pv, dwDestContext, pvDestContext, mshlflags); } void IMarshal.ReleaseMarshalData(IntPtr pStm) { EnsureHasMarshalProxy(); - t_winRtMarshalProxy.ReleaseMarshalData(pStm); + t_winRtMarshalProxy!.ReleaseMarshalData(pStm); } void IMarshal.UnmarshalInterface(IntPtr pStm, ref Guid riid, out IntPtr ppv) { EnsureHasMarshalProxy(); - t_winRtMarshalProxy.UnmarshalInterface(pStm, ref riid, out ppv); + t_winRtMarshalProxy!.UnmarshalInterface(pStm, ref riid, out ppv); } #endregion Implementation of IMarshal diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBufferExtensions.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBufferExtensions.cs index 9e757f539e01f7..35a4bae5e64e4c 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBufferExtensions.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeBufferExtensions.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using Windows.Foundation; using Windows.Storage.Streams; @@ -94,7 +95,7 @@ public static void CopyTo(this byte[] source, int sourceIndex, IBuffer destinati if (destination.Capacity - destinationIndex < count) throw new ArgumentException(SR.Argument_InsufficientSpaceInTargetBuffer); // If destination is backed by a managed array, use the array instead of the pointer as it does not require pinning: - byte[] destDataArr; + byte[]? destDataArr; int destDataOffs; if (destination.TryGetUnderlyingData(out destDataArr, out destDataOffs)) { @@ -164,7 +165,7 @@ public static void CopyTo(this IBuffer source, uint sourceIndex, byte[] destinat if (destination.Length - destinationIndex < count) throw new ArgumentException(SR.Argument_InsufficientArrayElementsAfterOffset); // If source is backed by a managed array, use the array instead of the pointer as it does not require pinning: - byte[] srcDataArr; + byte[]? srcDataArr; int srcDataOffs; if (source.TryGetUnderlyingData(out srcDataArr, out srcDataOffs)) { @@ -202,7 +203,7 @@ public static void CopyTo(this IBuffer source, uint sourceIndex, IBuffer destina if (destination.Capacity - destinationIndex < count) throw new ArgumentException(SR.Argument_InsufficientSpaceInTargetBuffer); // If source are destination are backed by managed arrays, use the arrays instead of the pointers as it does not require pinning: - byte[] srcDataArr, destDataArr; + byte[]? srcDataArr, destDataArr; int srcDataOffs, destDataOffs; bool srcIsManaged = source.TryGetUnderlyingData(out srcDataArr, out srcDataOffs); @@ -214,7 +215,7 @@ public static void CopyTo(this IBuffer source, uint sourceIndex, IBuffer destina Debug.Assert(sourceIndex <= int.MaxValue); Debug.Assert(destinationIndex <= int.MaxValue); - Buffer.BlockCopy(srcDataArr, srcDataOffs + (int)sourceIndex, destDataArr, destDataOffs + (int)destinationIndex, (int)count); + Buffer.BlockCopy(srcDataArr!, srcDataOffs + (int)sourceIndex, destDataArr!, destDataOffs + (int)destinationIndex, (int)count); return; } @@ -226,7 +227,7 @@ public static void CopyTo(this IBuffer source, uint sourceIndex, IBuffer destina Debug.Assert(sourceIndex <= int.MaxValue); destPtr = destination.GetPointerAtOffset(destinationIndex); - Marshal.Copy(srcDataArr, srcDataOffs + (int)sourceIndex, destPtr, (int)count); + Marshal.Copy(srcDataArr!, srcDataOffs + (int)sourceIndex, destPtr, (int)count); return; } @@ -236,7 +237,7 @@ public static void CopyTo(this IBuffer source, uint sourceIndex, IBuffer destina Debug.Assert(destinationIndex <= int.MaxValue); srcPtr = source.GetPointerAtOffset(sourceIndex); - Marshal.Copy(srcPtr, destDataArr, destDataOffs + (int)destinationIndex, (int)count); + Marshal.Copy(srcPtr, destDataArr!, destDataOffs + (int)destinationIndex, (int)count); return; } @@ -263,12 +264,12 @@ public static void CopyTo(this IBuffer source, uint sourceIndex, IBuffer destina /// Will be set to the start offset of the buffer data in the backing array /// or to -1. /// Whether the IBuffer is backed by a managed byte array. - internal static bool TryGetUnderlyingData(this IBuffer buffer, out byte[] underlyingDataArray, out int underlyingDataArrayStartOffset) + internal static bool TryGetUnderlyingData(this IBuffer buffer, [NotNullWhen(true)] out byte[]? underlyingDataArray, out int underlyingDataArrayStartOffset) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); - WindowsRuntimeBuffer winRtBuffer = buffer as WindowsRuntimeBuffer; + WindowsRuntimeBuffer? winRtBuffer = buffer as WindowsRuntimeBuffer; if (winRtBuffer == null) { underlyingDataArray = null; @@ -292,7 +293,7 @@ internal static bool TryGetUnderlyingData(this IBuffer buffer, out byte[] underl /// true if the underlying Buffer memory pointer is the same for both specified /// IBuffer instances (i.e. if they are backed by the same memory); false otherwise. [CLSCompliant(false)] - public static bool IsSameData(this IBuffer buffer, IBuffer otherBuffer) + public static bool IsSameData(this IBuffer buffer, IBuffer? otherBuffer) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); @@ -303,7 +304,7 @@ public static bool IsSameData(this IBuffer buffer, IBuffer otherBuffer) if (buffer == otherBuffer) return true; - byte[] thisDataArr, otherDataArr; + byte[]? thisDataArr, otherDataArr; int thisDataOffs, otherDataOffs; bool thisIsManaged = buffer.TryGetUnderlyingData(out thisDataArr, out thisDataOffs); @@ -351,7 +352,7 @@ public static IBuffer GetWindowsRuntimeBuffer(this MemoryStream underlyingStream { throw new UnauthorizedAccessException(SR.UnauthorizedAccess_InternalBuffer); } - return new WindowsRuntimeBuffer(streamData.Array, (int)streamData.Offset, (int)underlyingStream.Length, underlyingStream.Capacity); + return new WindowsRuntimeBuffer(streamData.Array!, (int)streamData.Offset, (int)underlyingStream.Length, underlyingStream.Capacity); } @@ -401,7 +402,7 @@ public static IBuffer GetWindowsRuntimeBuffer(this MemoryStream underlyingStream int originInStream = streamData.Offset; int buffCapacity = Math.Min(length, underlyingStream.Capacity - positionInStream); int buffLength = Math.Max(0, Math.Min(length, ((int)underlyingStream.Length) - positionInStream)); - return new WindowsRuntimeBuffer(streamData.Array, originInStream + positionInStream, buffLength, buffCapacity); + return new WindowsRuntimeBuffer(streamData.Array!, originInStream + positionInStream, buffLength, buffCapacity); } @@ -411,7 +412,7 @@ public static Stream AsStream(this IBuffer source) if (source == null) throw new ArgumentNullException(nameof(source)); - byte[] dataArr; + byte[]? dataArr; int dataOffs; if (source.TryGetUnderlyingData(out dataArr, out dataOffs)) { @@ -437,7 +438,7 @@ public static byte GetByte(this IBuffer source, uint byteOffset) if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Capacity <= byteOffset) throw new ArgumentException(SR.Argument_BufferIndexExceedsCapacity, nameof(byteOffset)); - byte[] srcDataArr; + byte[]? srcDataArr; int srcDataOffs; if (source.TryGetUnderlyingData(out srcDataArr, out srcDataOffs)) { diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.cs index a2d1038473f18f..ff8f1f01dbdc24 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.cs @@ -53,7 +53,7 @@ internal void RegisterForCancellation(IAsyncInfo asyncInfo) { if (_ct.CanBeCanceled && !_completing) { // benign race on m_completing... it's ok if it's not up-to-date. - var ctr = _ct.Register(ai => ((IAsyncInfo)ai).Cancel(), asyncInfo); // delegate cached by compiler + var ctr = _ct.Register(ai => ((IAsyncInfo)ai!).Cancel(), asyncInfo); // delegate cached by compiler // The operation may already be completing by this time, in which case // we might need to dispose of our new cancellation registration here. @@ -114,7 +114,7 @@ internal void CompleteFromAsyncOperationWithProgress(IAsyncOperationWithProgress /// The asynchronous operation. /// A function used to retrieve the TResult from the async operation; may be null. /// The status of the asynchronous operation. - private void Complete(IAsyncInfo asyncInfo, Func getResultsFunction, AsyncStatus asyncStatus) + private void Complete(IAsyncInfo asyncInfo, Func? getResultsFunction, AsyncStatus asyncStatus) { if (asyncInfo == null) throw new ArgumentNullException(nameof(asyncInfo)); @@ -160,7 +160,7 @@ private void Complete(IAsyncInfo asyncInfo, Func getResults // Retrieve the completion data from the IAsyncInfo. TResult result = default(TResult); - Exception error = null; + Exception? error = null; if (asyncStatus == AsyncStatus.Error) { error = asyncInfo.ErrorCode; @@ -199,7 +199,7 @@ private void Complete(IAsyncInfo asyncInfo, Func getResults case AsyncStatus.Completed: if (AsyncCausalitySupport.LoggingOn) AsyncCausalitySupport.TraceOperationCompletedSuccess(this.Task); - success = base.TrySetResult(result); + success = base.TrySetResult(result!); break; case AsyncStatus.Error: diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/ExceptionDispatchHelper.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/ExceptionDispatchHelper.cs index ff4afa79f27f9b..6d1f215e61941e 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/ExceptionDispatchHelper.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/ExceptionDispatchHelper.cs @@ -10,7 +10,7 @@ namespace System.Threading.Tasks { internal static class ExceptionDispatchHelper { - internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext) + internal static void ThrowAsync(Exception? exception, SynchronizationContext? targetContext) { if (exception == null) return; @@ -26,7 +26,7 @@ internal static void ThrowAsync(Exception exception, SynchronizationContext targ { try { - targetContext.Post((edi) => ((ExceptionDispatchInfo)edi).Throw(), exceptionDispatchInfo); + targetContext.Post((edi) => ((ExceptionDispatchInfo)edi!).Throw(), exceptionDispatchInfo); } catch { @@ -39,7 +39,7 @@ internal static void ThrowAsync(Exception exception, SynchronizationContext targ bool scheduled = true; try { - new SynchronizationContext().Post((edi) => ((ExceptionDispatchInfo)edi).Throw(), exceptionDispatchInfo); + new SynchronizationContext().Post((edi) => ((ExceptionDispatchInfo)edi!).Throw(), exceptionDispatchInfo); } catch { diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncActionAdapter.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncActionAdapter.cs index 6400a8a7a25f0e..2869fd612e6560 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncActionAdapter.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncActionAdapter.cs @@ -21,7 +21,7 @@ internal TaskToAsyncActionAdapter(Delegate taskGenerator) } - internal TaskToAsyncActionAdapter(Task underlyingTask, CancellationTokenSource underlyingCancelTokenSource) + internal TaskToAsyncActionAdapter(Task underlyingTask, CancellationTokenSource? underlyingCancelTokenSource) : base(underlyingTask, underlyingCancelTokenSource, underlyingProgressDispatcher: null) { diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncInfoAdapter.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncInfoAdapter.cs index f6b13ea23599e9..6b3b8bdee24d37 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncInfoAdapter.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncInfoAdapter.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; @@ -66,8 +67,7 @@ internal class TaskToAsyncInfoAdapterThe token source used to cancel running operations. - private CancellationTokenSource _cancelTokenSource = null; + private CancellationTokenSource? _cancelTokenSource = null; /// The async info's ID. InvalidAsyncId stands for not yet been initialised. private uint _id = AsyncInfoIdGenerator.InvalidId; @@ -90,7 +90,7 @@ private static InvalidOperationException CreateCannotGetResultsFromIncompleteOpe /// The cached error code used to avoid creating several exception objects if the ErrorCode /// property is accessed several times. null indicates either no error or that ErrorCode /// has not yet been called. - private Exception _error = null; + private Exception? _error = null; /// The state of the async info. Interlocked operations are used to manipulate this field. private volatile int _state = STATE_NOT_INITIALIZED; @@ -101,16 +101,16 @@ private static InvalidOperationException CreateCannotGetResultsFromIncompleteOpe /// or to one of Task or Task{TResult} in the latter case. This approach allows us to save a field on all IAsyncInfos. /// Notably, this makes us pay the added cost of boxing for synchronously completing IAsyncInfos where TResult is a /// value type, however, this is expected to occur rather rare compared to non-synchronously completed user-IAsyncInfos. - private object _dataContainer; + private object? _dataContainer; /// Registered completed handler. - private TCompletedHandler _completedHandler; + private TCompletedHandler? _completedHandler; /// Registered progress handler. - private TProgressHandler _progressHandler; + private TProgressHandler? _progressHandler; /// The synchronization context on which this instance was created/started. Used to callback invocations. - private SynchronizationContext _startingContext; + private SynchronizationContext? _startingContext; #endregion Instance variables @@ -146,7 +146,7 @@ internal TaskToAsyncInfoAdapter(Delegate taskProvider) // Set the completion routine and let the task running: task.ContinueWith( - (_, this_) => ((TaskToAsyncInfoAdapter)this_).TaskCompleted(), + (_, this_) => ((TaskToAsyncInfoAdapter)this_!).TaskCompleted(), this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } @@ -162,7 +162,7 @@ internal TaskToAsyncInfoAdapter(Delegate taskProvider) /// A progress listener/pugblisher that receives progress notifications /// form underlyingTask. internal TaskToAsyncInfoAdapter(Task underlyingTask, - CancellationTokenSource underlyingCancelTokenSource, Progress underlyingProgressDispatcher) + CancellationTokenSource? underlyingCancelTokenSource, Progress? underlyingProgressDispatcher) { if (underlyingTask == null) throw new ArgumentNullException(nameof(underlyingTask)); @@ -189,7 +189,7 @@ internal TaskToAsyncInfoAdapter(Task underlyingTask, _state = (STATEFLAG_COMPLETION_HNDL_NOT_YET_INVOKED | STATE_STARTED); underlyingTask.ContinueWith( - (_, this_) => ((TaskToAsyncInfoAdapter)this_).TaskCompleted(), + (_, this_) => ((TaskToAsyncInfoAdapter)this_!).TaskCompleted(), this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } @@ -199,7 +199,7 @@ internal TaskToAsyncInfoAdapter(Task underlyingTask, /// specified synchronousResult is used as the result value. /// /// The result of this synchronously completed IAsyncInfo. - internal TaskToAsyncInfoAdapter(TResult synchronousResult) + internal TaskToAsyncInfoAdapter([AllowNull] TResult synchronousResult) { // We already completed. There will be no progress callback invokations and a potential completed handler invokation will be synchronous. // We do not need the starting SynchronizationContext: @@ -342,7 +342,7 @@ private bool CheckUniqueAsyncState(int state) #region Infrastructure methods - private SynchronizationContext GetStartingContext() + private SynchronizationContext? GetStartingContext() { #if DESKTOP // as a reminder that on most platforms we want a different behavior return SynchronizationContext.CurrentNoFlow; @@ -352,7 +352,7 @@ private SynchronizationContext GetStartingContext() } - internal Task Task + internal Task? Task { get { @@ -361,12 +361,12 @@ internal Task Task if (CompletedSynchronously) return null; - return (Task)_dataContainer; + return (Task?)_dataContainer; } } - internal CancellationTokenSource CancelTokenSource + internal CancellationTokenSource? CancelTokenSource { get { return _cancelTokenSource; } } @@ -403,7 +403,7 @@ private void OnCompletedInvoker(AsyncStatus status) bool conditionFailed; // Get the handler: - TCompletedHandler handler = Volatile.Read(ref _completedHandler); + TCompletedHandler? handler = Volatile.Read(ref _completedHandler); // If we might not run the handler now, we need to remember that if it is set later, it will need to be run then: if (handler == null) @@ -444,7 +444,7 @@ private void OnProgressInvokerCrossContext(TProgressHandler handler, TProgressIn { var tuple = (Tuple, TProgressHandler, - TProgressInfo>)tupleObject; + TProgressInfo>)tupleObject!; tuple.Item1.OnProgress(tuple.Item2, tuple.Item3); }, Tuple.Create(this, handler, progressInfo)); @@ -456,7 +456,7 @@ private void OnProgressInvokerCrossContext(TProgressHandler handler, TProgressIn void IProgress.Report(TProgressInfo value) { // If no progress handler is set, there is nothing to do: - TProgressHandler handler = Volatile.Read(ref _progressHandler); + TProgressHandler? handler = Volatile.Read(ref _progressHandler); if (handler == null) return; @@ -479,7 +479,7 @@ void IProgress.Report(TProgressInfo value) } - private void OnReportChainedProgress(object sender, TProgressInfo progressInfo) + private void OnReportChainedProgress(object? sender, TProgressInfo progressInfo) { ((IProgress)this).Report(progressInfo); } @@ -577,7 +577,7 @@ private int TransitionToTerminalState() Debug.Assert(IsInRunningState); Debug.Assert(!CompletedSynchronously); - Task task = _dataContainer as Task; + Task? task = _dataContainer as Task; Debug.Assert(task != null); Debug.Assert(task.IsCompleted); @@ -652,7 +652,7 @@ private void TaskCompleted() // Invoke callback in the right context (delegate cached by compiler): _startingContext.Post((tupleObject) => { - var tuple = (Tuple, AsyncStatus>)tupleObject; + var tuple = (Tuple, AsyncStatus>)tupleObject!; tuple.Item1.OnCompletedInvoker(tuple.Item2); }, Tuple.Create(this, terminationStatus)); } @@ -698,7 +698,6 @@ private AsyncStatus GetStatus(int state) return AsyncStatus.Error; } - internal TResult GetResultsInternal() { EnsureNotClosed(); @@ -706,7 +705,7 @@ internal TResult GetResultsInternal() // If this IAsyncInfo has actually faulted, GetResults will throw the same error as returned by ErrorCode: if (IsInErrorState) { - Exception error = ErrorCode; + Exception? error = ErrorCode; Debug.Assert(error != null); ExceptionDispatchInfo.Capture(error).Throw(); } @@ -718,16 +717,16 @@ internal TResult GetResultsInternal() // If this is a synchronous operation, use the cached result: if (CompletedSynchronously) - return (TResult)_dataContainer; + return (TResult)_dataContainer!; // The operation is asynchronous: - Task task = _dataContainer as Task; + Task? task = _dataContainer as Task; // Since CompletedSynchronously is false and EnsureNotClosed() did not throw, task can only be null if: // - this IAsyncInfo has completed synchronously, however we checked for this above; // - it was not converted to Task, which means it is a non-generic Task. In that case we cannot get a result from Task. if (task == null) - return default(TResult); + return default(TResult)!; Debug.Assert(IsInRunToCompletionState); @@ -815,11 +814,11 @@ private void TransitionToClosed() /// If we the completion handler is set AFTER this IAsyncInfo already completed, then this setter will invoke the handler synchronously /// on the current context. /// - public virtual TCompletedHandler Completed + public virtual TCompletedHandler? Completed { get { - TCompletedHandler handler = Volatile.Read(ref _completedHandler); + TCompletedHandler? handler = Volatile.Read(ref _completedHandler); EnsureNotClosed(); return handler; } @@ -833,7 +832,7 @@ public virtual TCompletedHandler Completed // Some other WinRT projection languages do not allow setting the Completed handler more than once, even if it is set to null. // We could do the same by introducing a new STATEFLAG_COMPLETION_HNDL_SET bit-flag constant and saving a this state into // the m_state field to indicate that the completion handler has been set previously, but we choose not to do this.) - TCompletedHandler handlerBefore = Interlocked.CompareExchange(ref _completedHandler, value, null); + TCompletedHandler? handlerBefore = Interlocked.CompareExchange(ref _completedHandler, value, null); if (handlerBefore != null) { InvalidOperationException ex = new InvalidOperationException(SR.InvalidOperation_CannotSetCompletionHanlderMoreThanOnce); @@ -864,11 +863,11 @@ public virtual TCompletedHandler Completed /// Gets or sets the progress handler. - public virtual TProgressHandler Progress + public virtual TProgressHandler? Progress { get { - TProgressHandler handler = Volatile.Read(ref _progressHandler); + TProgressHandler? handler = Volatile.Read(ref _progressHandler); EnsureNotClosed(); return handler; @@ -930,7 +929,7 @@ public virtual void Close() /// Gets the error code for the async info. - public virtual Exception ErrorCode + public virtual Exception? ErrorCode { get { @@ -942,17 +941,17 @@ public virtual Exception ErrorCode if (!IsInErrorState) return null; - Exception error = Volatile.Read(ref _error); + Exception? error = Volatile.Read(ref _error); // ERROR is a terminal state. SO if we have an error, just return it. // If we completed synchronously, we return the current error iven if it is null since we do not expect this to change: if (error != null || CompletedSynchronously) return error; - Task task = _dataContainer as Task; + Task? task = _dataContainer as Task; Debug.Assert(task != null); - AggregateException aggregateException = task.Exception; + AggregateException? aggregateException = task.Exception; // By spec, if task.IsFaulted is true, then task.Exception must not be null and its InnerException must // also not be null. However, in case something is unexpected on the Task side of the road, let?s be defensive @@ -965,7 +964,7 @@ public virtual Exception ErrorCode } else { - Exception innerException = aggregateException.InnerException; + Exception? innerException = aggregateException.InnerException; error = (innerException == null) ? aggregateException @@ -974,7 +973,7 @@ public virtual Exception ErrorCode // If m_error was set concurrently, setError will be non-null. Then we use that - as it is the first m_error // that was set. If setError we know that we won any races and we can return error: - Exception setError = Interlocked.CompareExchange(ref _error, error, null); + Exception? setError = Interlocked.CompareExchange(ref _error, error, null); return setError ?? error; } } diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncOperationAdapter.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncOperationAdapter.cs index 6292a78273c6ad..63744b68d95bca 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncOperationAdapter.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncOperationAdapter.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Windows.Foundation; @@ -21,20 +22,19 @@ internal TaskToAsyncOperationAdapter(Delegate taskGenerator) } - internal TaskToAsyncOperationAdapter(Task underlyingTask, CancellationTokenSource underlyingCancelTokenSource) + internal TaskToAsyncOperationAdapter(Task underlyingTask, CancellationTokenSource? underlyingCancelTokenSource) : base(underlyingTask, underlyingCancelTokenSource, underlyingProgressDispatcher: null) { } - internal TaskToAsyncOperationAdapter(TResult synchronousResult) + internal TaskToAsyncOperationAdapter([AllowNull] TResult synchronousResult) : base(synchronousResult) { } - public virtual TResult GetResults() { return GetResultsInternal(); diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncOperationWithProgressAdapter.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncOperationWithProgressAdapter.cs index da729f10b4c48f..7a1ce71ebbe9c9 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncOperationWithProgressAdapter.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/TaskToAsyncOperationWithProgressAdapter.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Windows.Foundation; @@ -33,13 +34,12 @@ internal TaskToAsyncOperationWithProgressAdapter(Delegate taskGenerator) //} - internal TaskToAsyncOperationWithProgressAdapter(TResult synchronousResult) + internal TaskToAsyncOperationWithProgressAdapter([AllowNull] TResult synchronousResult) : base(synchronousResult) { } - public virtual TResult GetResults() { return GetResultsInternal(); diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/WindowsRuntimeSynchronizationContext.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/WindowsRuntimeSynchronizationContext.cs index 229f6d8fd61fd8..da60f6a1831039 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/WindowsRuntimeSynchronizationContext.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Threading/WindowsRuntimeSynchronizationContext.cs @@ -113,7 +113,7 @@ internal WinRTCoreDispatcherBasedSynchronizationContext(CoreDispatcher dispatche _dispatcher = dispatcher; } - public override void Post(SendOrPostCallback d, object state) + public override void Post(SendOrPostCallback d, object? state) { if (d == null) throw new ArgumentNullException(nameof(d)); @@ -135,7 +135,7 @@ internal WinRTDispatcherQueueBasedSynchronizationContext(IDispatcherQueue dispat _dispatcherQueue = dispatcherQueue; } - public override void Post(SendOrPostCallback d, object state) + public override void Post(SendOrPostCallback d, object? state) { if (d == null) throw new ArgumentNullException(nameof(d)); @@ -158,13 +158,13 @@ internal abstract class WinRTSynchronizationContextBase : SynchronizationContext protected class Invoker { - private readonly ExecutionContext _executionContext; + private readonly ExecutionContext? _executionContext; private readonly SendOrPostCallback _callback; - private readonly object _state; + private readonly object? _state; private static readonly ContextCallback s_contextCallback = new ContextCallback(InvokeInContext); - public Invoker(SendOrPostCallback callback, object state) + public Invoker(SendOrPostCallback callback, object? state) { _executionContext = ExecutionContext.Capture(); _callback = callback; @@ -179,9 +179,9 @@ public void Invoke() ExecutionContext.Run(_executionContext, s_contextCallback, this); } - private static void InvokeInContext(object thisObj) + private static void InvokeInContext(object? thisObj) { - ((Invoker)thisObj).InvokeCore(); + ((Invoker)thisObj!).InvokeCore(); } private void InvokeCore() @@ -203,7 +203,7 @@ private void InvokeCore() if (!ExceptionSupport.ReportUnhandledError(ex)) { var edi = ExceptionDispatchInfo.Capture(ex); - ThreadPool.QueueUserWorkItem(o => ((ExceptionDispatchInfo)o).Throw(), edi); + ThreadPool.QueueUserWorkItem(o => ((ExceptionDispatchInfo)o!).Throw(), edi); } } } @@ -212,7 +212,7 @@ private void InvokeCore() #endregion class WinRTSynchronizationContext.Invoker - public override void Send(SendOrPostCallback d, object state) + public override void Send(SendOrPostCallback d, object? state) { throw new NotSupportedException(SR.InvalidOperation_SendNotSupportedOnWindowsRTSynchronizationContext); } diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Point.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Point.cs index 25b3461c90ae9b..505b40d255b70d 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Point.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Point.cs @@ -60,19 +60,19 @@ public override string ToString() return ConvertToString(null /* format string */, null /* format provider */); } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(null /* format string */, provider); } - string IFormattable.ToString(string format, IFormatProvider provider) + string IFormattable.ToString(string? format, IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(format, provider); } - private string ConvertToString(string format, IFormatProvider provider) + private string ConvertToString(string? format, IFormatProvider? provider) { // Helper to get the numeric list separator for a given culture. char separator = TokenizerHelper.GetNumericListSeparator(provider); @@ -94,7 +94,7 @@ private string ConvertToString(string format, IFormatProvider provider) return !(point1 == point2); } - public override bool Equals(object o) + public override bool Equals(object? o) { return o is Point && this == (Point)o; } diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Rect.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Rect.cs index e4d6dbe3574255..4ea7cb853f61d1 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Rect.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Rect.cs @@ -281,19 +281,19 @@ public override string ToString() return ConvertToString(null /* format string */, null /* format provider */); } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(null /* format string */, provider); } - string IFormattable.ToString(string format, IFormatProvider provider) + string IFormattable.ToString(string? format, IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(format, provider); } - internal string ConvertToString(string format, IFormatProvider provider) + internal string ConvertToString(string? format, IFormatProvider? provider) { if (IsEmpty) { @@ -329,7 +329,7 @@ public bool Equals(Rect value) return !(rect1 == rect2); } - public override bool Equals(object o) + public override bool Equals(object? o) { return o is Rect && this == (Rect)o; } diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Size.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Size.cs index b0c6cdee6ef69e..39e73f9059436f 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Size.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/Size.cs @@ -103,7 +103,7 @@ private static Size CreateEmptySize() return !(size1 == size2); } - public override bool Equals(object o) + public override bool Equals(object? o) { return o is Size && Size.Equals(this, (Size)o); } diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/TokenizerHelper.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/TokenizerHelper.cs index 2481429785eceb..c93ce565e6b805 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/TokenizerHelper.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/TokenizerHelper.cs @@ -29,7 +29,7 @@ namespace Windows.Foundation internal static class TokenizerHelper { - internal static char GetNumericListSeparator(IFormatProvider provider) + internal static char GetNumericListSeparator(IFormatProvider? provider) { char numericSeparator = ','; diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/UI/Color.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/UI/Color.cs index 9866532006bd57..72574c445908d2 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/UI/Color.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/Windows/UI/Color.cs @@ -81,19 +81,19 @@ public override string ToString() return ConvertToString(null, null); } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(null, provider); } - string IFormattable.ToString(string format, IFormatProvider provider) + string IFormattable.ToString(string? format, IFormatProvider? provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(format, provider); } - internal string ConvertToString(string format, IFormatProvider provider) + internal string ConvertToString(string? format, IFormatProvider? provider) { StringBuilder sb = new StringBuilder(); @@ -122,7 +122,7 @@ public override int GetHashCode() return _A.GetHashCode() ^ _R.GetHashCode() ^ _G.GetHashCode() ^ _B.GetHashCode(); } - public override bool Equals(object o) + public override bool Equals(object? o) { return o is Color && this == (Color)o; } diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/WindowsRuntimeSystemExtensions.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/WindowsRuntimeSystemExtensions.cs index 4dadcfa6f63348..6a0f150141be9e 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/WindowsRuntimeSystemExtensions.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/WindowsRuntimeSystemExtensions.cs @@ -32,10 +32,10 @@ private static void ConcatenateCancelTokens(CancellationToken source, Cancellati { Debug.Assert(sink != null); - CancellationTokenRegistration ctReg = source.Register((state) => { ((CancellationTokenSource)state).Cancel(); }, + CancellationTokenRegistration ctReg = source.Register((state) => { ((CancellationTokenSource)state!).Cancel(); }, sink); - concatenationLifetime.ContinueWith((_, state) => { ((CancellationTokenRegistration)state).Dispose(); }, + concatenationLifetime.ContinueWith((_, state) => { ((CancellationTokenRegistration)state!).Dispose(); }, ctReg, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } @@ -90,7 +90,7 @@ public static Task AsTask(this IAsyncAction source, CancellationToken cancellati var wrapper = source as TaskToAsyncActionAdapter; if (wrapper != null && !wrapper.CompletedSynchronously) { - Task innerTask = wrapper.Task; + Task? innerTask = wrapper.Task; Debug.Assert(innerTask != null); Debug.Assert(innerTask.Status != TaskStatus.Created); @@ -164,7 +164,7 @@ public static Task AsTask(this IAsyncOperation source var wrapper = source as TaskToAsyncOperationAdapter; if (wrapper != null && !wrapper.CompletedSynchronously) { - Task innerTask = wrapper.Task as Task; + Task? innerTask = wrapper.Task as Task; Debug.Assert(innerTask != null); Debug.Assert(innerTask.Status != TaskStatus.Created); // Is WaitingForActivation a legal state at this moment? @@ -240,7 +240,7 @@ public static Task AsTask(this IAsyncActionWithProgress so /// The asynchronous operation. /// The progress object used to receive progress updates. /// The Task representing the asynchronous operation. - public static Task AsTask(this IAsyncActionWithProgress source, IProgress progress) + public static Task AsTask(this IAsyncActionWithProgress source, IProgress? progress) { return AsTask(source, CancellationToken.None, progress); } @@ -252,7 +252,7 @@ public static Task AsTask(this IAsyncActionWithProgress so /// The progress object used to receive progress updates. /// The Task representing the asynchronous operation. public static Task AsTask(this IAsyncActionWithProgress source, - CancellationToken cancellationToken, IProgress progress) + CancellationToken cancellationToken, IProgress? progress) { if (source == null) throw new ArgumentNullException(nameof(source)); @@ -261,7 +261,7 @@ public static Task AsTask(this IAsyncActionWithProgress so var wrapper = source as TaskToAsyncActionWithProgressAdapter; if (wrapper != null && !wrapper.CompletedSynchronously) { - Task innerTask = wrapper.Task; + Task? innerTask = wrapper.Task; Debug.Assert(innerTask != null); Debug.Assert(innerTask.Status != TaskStatus.Created); // Is WaitingForActivation a legal state at this moment? @@ -347,7 +347,7 @@ public static Task AsTask(this IAsyncOperationWithP /// The progress object used to receive progress updates. /// The Task representing the asynchronous operation. public static Task AsTask(this IAsyncOperationWithProgress source, - IProgress progress) + IProgress? progress) { return AsTask(source, CancellationToken.None, progress); } @@ -359,7 +359,7 @@ public static Task AsTask(this IAsyncOperationWithP /// The progress object used to receive progress updates. /// The Task representing the asynchronous operation. public static Task AsTask(this IAsyncOperationWithProgress source, - CancellationToken cancellationToken, IProgress progress) + CancellationToken cancellationToken, IProgress? progress) { if (source == null) throw new ArgumentNullException(nameof(source)); @@ -368,7 +368,7 @@ public static Task AsTask(this IAsyncOperationWithP var wrapper = source as TaskToAsyncOperationWithProgressAdapter; if (wrapper != null && !wrapper.CompletedSynchronously) { - Task innerTask = wrapper.Task as Task; + Task? innerTask = wrapper.Task as Task; Debug.Assert(innerTask != null); Debug.Assert(innerTask.Status != TaskStatus.Created); // Is WaitingForActivation a legal state at this moment? @@ -446,14 +446,14 @@ private static void CommonlyUsedGenericInstantiations() { // This method is an aid for NGen to save common generic // instantiations into the ngen image. - ((IAsyncOperation)null).AsTask(); - ((IAsyncOperation)null).AsTask(); - ((IAsyncOperation)null).AsTask(); - ((IAsyncOperation)null).AsTask(); - - ((IAsyncOperationWithProgress)null).AsTask(); - ((IAsyncOperationWithProgress)null).AsTask(); - ((IAsyncOperationWithProgress)null).AsTask(); + ((IAsyncOperation)null!).AsTask(); + ((IAsyncOperation)null!).AsTask(); + ((IAsyncOperation)null!).AsTask(); + ((IAsyncOperation)null!).AsTask(); + + ((IAsyncOperationWithProgress)null!).AsTask(); + ((IAsyncOperationWithProgress)null!).AsTask(); + ((IAsyncOperationWithProgress)null!).AsTask(); } } // class WindowsRuntimeSystemExtensions } // namespace diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index da3de891234920..4771f2414098a0 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2029,6 +2029,8 @@ public static partial class GC { public static int MaxGeneration { get { throw null; } } public static void AddMemoryPressure(long bytesAllocated) { } + public static T[] AllocateArray(int length, bool pinned = false) { throw null; } + public static T[] AllocateUninitializedArray(int length, bool pinned = false) { throw null; } public static void CancelFullGCNotification() { } public static void Collect() { } public static void Collect(int generation) { } @@ -5616,6 +5618,21 @@ public sealed partial class NotNullWhenAttribute : System.Attribute public NotNullWhenAttribute(bool returnValue) { } public bool ReturnValue { get { throw null; } } } + [System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Property, Inherited = false)] + [System.CLSCompliant(false)] + public sealed class MemberNotNullAttribute : System.Attribute + { + public MemberNotNullAttribute(params string[] members) { } + public string[] Members { get { throw null; } } + } + [System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Property, Inherited = false)] + [System.CLSCompliant(false)] + public sealed class MemberNotNullWhenAttribute : System.Attribute + { + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { } + public bool ReturnValue { get { throw null; } } + public string[] Members { get { throw null; } } + } [System.AttributeUsageAttribute(System.AttributeTargets.All, Inherited=false, AllowMultiple=true)] [System.Diagnostics.ConditionalAttribute("CODE_ANALYSIS")] public sealed partial class SuppressMessageAttribute : System.Attribute diff --git a/src/libraries/System.Runtime/tests/System/GCTests.cs b/src/libraries/System.Runtime/tests/System/GCTests.cs index 4f65939d769c1b..b7e3070bc11a7f 100644 --- a/src/libraries/System.Runtime/tests/System/GCTests.cs +++ b/src/libraries/System.Runtime/tests/System/GCTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Diagnostics; @@ -424,7 +425,8 @@ public static void LatencyRoundtrips(GCLatencyMode value) public static void LatencyRoundtrips_LowLatency(GCLatencyMode value) => LatencyRoundtrips(value); } - public class GCExtendedTests { + public class GCExtendedTests + { private const int TimeoutMilliseconds = 10 * 30 * 1000; //if full GC is triggered it may take a while /// @@ -892,5 +894,178 @@ long CallGetTotalAllocatedBytes(long previous) previous = CallGetTotalAllocatedBytes(previous); } } + + [Fact] + [OuterLoop] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33583", TestRuntimes.Mono)] + private static void AllocateUninitializedArray() + { + // allocate a bunch of SOH byte arrays and touch them. + var r = new Random(1234); + for (int i = 0; i < 10000; i++) + { + int size = r.Next(10000); + var arr = GC.AllocateUninitializedArray(size, pinned: i % 2 == 1); + + if (size > 1) + { + arr[0] = 5; + arr[size - 1] = 17; + Assert.True(arr[0] == 5 && arr[size - 1] == 17); + } + } + + // allocate a bunch of LOH int arrays and touch them. + for (int i = 0; i < 1000; i++) + { + int size = r.Next(100000, 1000000); + var arr = GC.AllocateUninitializedArray(size, pinned: i % 2 == 1); + + arr[0] = 5; + arr[size - 1] = 17; + Assert.True(arr[0] == 5 && arr[size - 1] == 17); + } + + // allocate a string array + { + int i = 100; + var arr = GC.AllocateUninitializedArray(i); + + arr[0] = "5"; + arr[i - 1] = "17"; + Assert.True(arr[0] == "5" && arr[i - 1] == "17"); + } + + // allocate max size byte array + { + if (IntPtr.Size == 8) + { + int i = 0x7FFFFFC7; + var arr = GC.AllocateUninitializedArray(i); + + arr[0] = 5; + arr[i - 1] = 17; + Assert.True(arr[0] == 5 && arr[i - 1] == 17); + } + } + } + + [Fact] + [OuterLoop] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33583", TestRuntimes.Mono)] + private static void AllocateArray() + { + // allocate a bunch of SOH byte arrays and touch them. + var r = new Random(1234); + for (int i = 0; i < 10000; i++) + { + int size = r.Next(10000); + var arr = GC.AllocateArray(size, pinned: i % 2 == 1); + + if (size > 1) + { + arr[0] = 5; + arr[size - 1] = 17; + Assert.True(arr[0] == 5 && arr[size - 1] == 17); + } + } + + // allocate a bunch of LOH int arrays and touch them. + for (int i = 0; i < 1000; i++) + { + int size = r.Next(100000, 1000000); + var arr = GC.AllocateArray(size, pinned: i % 2 == 1); + + arr[0] = 5; + arr[size - 1] = 17; + Assert.True(arr[0] == 5 && arr[size - 1] == 17); + } + + // allocate a string array + { + int i = 100; + var arr = GC.AllocateArray(i); + + arr[0] = "5"; + arr[i - 1] = "17"; + Assert.True(arr[0] == "5" && arr[i - 1] == "17"); + } + + // allocate max size byte array + { + if (IntPtr.Size == 8) + { + int i = 0x7FFFFFC7; + var arr = GC.AllocateArray(i); + + arr[0] = 5; + arr[i - 1] = 17; + Assert.True(arr[0] == 5 && arr[i - 1] == 17); + } + } + } + + [Theory] + [InlineData(-1)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33583", TestRuntimes.Mono)] + private static void AllocateArrayNegativeSize(int negValue) + { + Assert.Throws(() => GC.AllocateUninitializedArray(-1)); + Assert.Throws(() => GC.AllocateUninitializedArray(negValue)); + Assert.Throws(() => GC.AllocateUninitializedArray(-1, pinned: true)); + Assert.Throws(() => GC.AllocateUninitializedArray(negValue, pinned: true)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33583", TestRuntimes.Mono)] + private static void AllocateArrayTooLarge() + { + Assert.Throws(() => GC.AllocateUninitializedArray(int.MaxValue)); + Assert.Throws(() => GC.AllocateUninitializedArray(int.MaxValue, pinned: true)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33583", TestRuntimes.Mono)] + private static void AllocateArrayRefType() + { + GC.AllocateUninitializedArray(100); + Assert.Throws(() => GC.AllocateUninitializedArray(100, pinned: true)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33583", TestRuntimes.Mono)] + private unsafe static void AllocateArrayCheckPinning() + { + var list = new List(); + + var r = new Random(1234); + for (int i = 0; i < 10000; i++) + { + int size = r.Next(2, 100); + var arr = i % 2 == 1 ? + GC.AllocateArray(size, pinned: true) : + GC.AllocateUninitializedArray(size, pinned: true) ; + + fixed (long* pElem = &arr[0]) + { + *pElem = (long)pElem; + } + + if (r.Next(100) % 2 == 0) + { + list.Add(arr); + } + } + + GC.Collect(); + + foreach (var arr in list) + { + fixed (long* pElem = &arr[0]) + { + Assert.Equal(*pElem, (long)pElem); + } + } + } } } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.cs b/src/libraries/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.cs index ead364c3d32ae7..fe1cafe80e8164 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.cs @@ -126,8 +126,11 @@ protected DSA() { } public static System.Security.Cryptography.DSA Create(System.Security.Cryptography.DSAParameters parameters) { throw null; } public static new System.Security.Cryptography.DSA? Create(string algName) { throw null; } public abstract byte[] CreateSignature(byte[] rgbHash); + public byte[] CreateSignature(byte[] rgbHash, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual byte[] CreateSignatureCore(System.ReadOnlySpan hash, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public abstract System.Security.Cryptography.DSAParameters ExportParameters(bool includePrivateParameters); public override void FromXmlString(string xmlString) { } + public int GetMaxSignatureSize(System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } protected virtual byte[] HashData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } protected virtual byte[] HashData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } public override void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan passwordBytes, System.ReadOnlySpan source, out int bytesRead) { throw null; } @@ -136,22 +139,40 @@ public override void FromXmlString(string xmlString) { } public override void ImportPkcs8PrivateKey(System.ReadOnlySpan source, out int bytesRead) { throw null; } public override void ImportSubjectPublicKeyInfo(System.ReadOnlySpan source, out int bytesRead) { throw null; } public virtual byte[] SignData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public byte[] SignData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public byte[] SignData(byte[] data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public byte[] SignData(byte[] data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual byte[] SignData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public byte[] SignData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual byte[] SignDataCore(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual byte[] SignDataCore(System.ReadOnlySpan data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public override string ToXmlString(bool includePrivateParameters) { throw null; } public virtual bool TryCreateSignature(System.ReadOnlySpan hash, System.Span destination, out int bytesWritten) { throw null; } + public bool TryCreateSignature(System.ReadOnlySpan hash, System.Span destination, System.Security.Cryptography.DSASignatureFormat signatureFormat, out int bytesWritten) { throw null; } + protected virtual bool TryCreateSignatureCore(System.ReadOnlySpan hash, System.Span destination, System.Security.Cryptography.DSASignatureFormat signatureFormat, out int bytesWritten) { throw null; } public override bool TryExportEncryptedPkcs8PrivateKey(System.ReadOnlySpan passwordBytes, System.Security.Cryptography.PbeParameters pbeParameters, System.Span destination, out int bytesWritten) { throw null; } public override bool TryExportEncryptedPkcs8PrivateKey(System.ReadOnlySpan password, System.Security.Cryptography.PbeParameters pbeParameters, System.Span destination, out int bytesWritten) { throw null; } public override bool TryExportPkcs8PrivateKey(System.Span destination, out int bytesWritten) { throw null; } public override bool TryExportSubjectPublicKeyInfo(System.Span destination, out int bytesWritten) { throw null; } protected virtual bool TryHashData(System.ReadOnlySpan data, System.Span destination, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; } public virtual bool TrySignData(System.ReadOnlySpan data, System.Span destination, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; } + public bool TrySignData(System.ReadOnlySpan data, System.Span destination, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat, out int bytesWritten) { throw null; } + protected virtual bool TrySignDataCore(System.ReadOnlySpan data, System.Span destination, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat, out int bytesWritten) { throw null; } public bool VerifyData(byte[] data, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public bool VerifyData(byte[] data, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public bool VerifyData(byte[] data, int offset, int count, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual bool VerifyData(System.IO.Stream data, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public bool VerifyData(System.IO.Stream data, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual bool VerifyData(System.ReadOnlySpan data, System.ReadOnlySpan signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public bool VerifyData(System.ReadOnlySpan data, System.ReadOnlySpan signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual bool VerifyDataCore(System.IO.Stream data, System.ReadOnlySpan signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual bool VerifyDataCore(System.ReadOnlySpan data, System.ReadOnlySpan signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public abstract bool VerifySignature(byte[] rgbHash, byte[] rgbSignature); + public bool VerifySignature(byte[] rgbHash, byte[] rgbSignature, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual bool VerifySignature(System.ReadOnlySpan hash, System.ReadOnlySpan signature) { throw null; } + public bool VerifySignature(System.ReadOnlySpan hash, System.ReadOnlySpan signature, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual bool VerifySignatureCore(System.ReadOnlySpan hash, System.ReadOnlySpan signature, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } } public partial struct DSAParameters { @@ -172,6 +193,11 @@ public override void SetHashAlgorithm(string strName) { } public override void SetKey(System.Security.Cryptography.AsymmetricAlgorithm key) { } public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) { throw null; } } + public enum DSASignatureFormat + { + IeeeP1363FixedFieldConcatenation = 0, + Rfc3279DerSequence = 1, + } public partial class DSASignatureFormatter : System.Security.Cryptography.AsymmetricSignatureFormatter { public DSASignatureFormatter() { } @@ -292,6 +318,7 @@ protected ECDsa() { } public virtual System.Security.Cryptography.ECParameters ExportParameters(bool includePrivateParameters) { throw null; } public override void FromXmlString(string xmlString) { } public virtual void GenerateKey(System.Security.Cryptography.ECCurve curve) { } + public int GetMaxSignatureSize(System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } protected virtual byte[] HashData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } protected virtual byte[] HashData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } public virtual void ImportECPrivateKey(System.ReadOnlySpan source, out int bytesRead) { throw null; } @@ -301,9 +328,16 @@ public virtual void ImportParameters(System.Security.Cryptography.ECParameters p public override void ImportPkcs8PrivateKey(System.ReadOnlySpan source, out int bytesRead) { throw null; } public override void ImportSubjectPublicKeyInfo(System.ReadOnlySpan source, out int bytesRead) { throw null; } public virtual byte[] SignData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public byte[] SignData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual byte[] SignData(byte[] data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public byte[] SignData(byte[] data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual byte[] SignData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public byte[] SignData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual byte[] SignDataCore(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual byte[] SignDataCore(System.ReadOnlySpan data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public abstract byte[] SignHash(byte[] hash); + public byte[] SignHash(byte[] hash, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual byte[] SignHashCore(System.ReadOnlySpan hash, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public override string ToXmlString(bool includePrivateParameters) { throw null; } public virtual bool TryExportECPrivateKey(System.Span destination, out int bytesWritten) { throw null; } public override bool TryExportEncryptedPkcs8PrivateKey(System.ReadOnlySpan passwordBytes, System.Security.Cryptography.PbeParameters pbeParameters, System.Span destination, out int bytesWritten) { throw null; } @@ -312,13 +346,26 @@ public virtual void ImportParameters(System.Security.Cryptography.ECParameters p public override bool TryExportSubjectPublicKeyInfo(System.Span destination, out int bytesWritten) { throw null; } protected virtual bool TryHashData(System.ReadOnlySpan data, System.Span destination, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; } public virtual bool TrySignData(System.ReadOnlySpan data, System.Span destination, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; } + public bool TrySignData(System.ReadOnlySpan data, System.Span destination, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat, out int bytesWritten) { throw null; } + protected virtual bool TrySignDataCore(System.ReadOnlySpan data, System.Span destination, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat, out int bytesWritten) { throw null; } public virtual bool TrySignHash(System.ReadOnlySpan hash, System.Span destination, out int bytesWritten) { throw null; } + public bool TrySignHash(System.ReadOnlySpan hash, System.Span destination, System.Security.Cryptography.DSASignatureFormat signatureFormat, out int bytesWritten) { throw null; } + protected virtual bool TrySignHashCore(System.ReadOnlySpan hash, System.Span destination, System.Security.Cryptography.DSASignatureFormat signatureFormat, out int bytesWritten) { throw null; } public bool VerifyData(byte[] data, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public bool VerifyData(byte[] data, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public bool VerifyData(byte[] data, int offset, int count, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public bool VerifyData(System.IO.Stream data, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public bool VerifyData(System.IO.Stream data, byte[] signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual bool VerifyData(System.ReadOnlySpan data, System.ReadOnlySpan signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } + public bool VerifyData(System.ReadOnlySpan data, System.ReadOnlySpan signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual bool VerifyDataCore(System.IO.Stream data, System.ReadOnlySpan signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual bool VerifyDataCore(System.ReadOnlySpan data, System.ReadOnlySpan signature, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public abstract bool VerifyHash(byte[] hash, byte[] signature); + public bool VerifyHash(byte[] hash, byte[] signature, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } public virtual bool VerifyHash(System.ReadOnlySpan hash, System.ReadOnlySpan signature) { throw null; } + public bool VerifyHash(System.ReadOnlySpan hash, System.ReadOnlySpan signature, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } + protected virtual bool VerifyHashCore(System.ReadOnlySpan hash, System.ReadOnlySpan signature, System.Security.Cryptography.DSASignatureFormat signatureFormat) { throw null; } } public partial struct ECParameters { diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx index 593d64c456de89..878856832fbabf 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx @@ -306,6 +306,9 @@ Unknown padding mode used. + + The signature format '{0}' is unknown. + CNG provider unexpectedly terminated encryption or decryption prematurely. diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj index 61c8b31a0c8923..bc999132acccc1 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj @@ -6,7 +6,7 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS enable - + @@ -30,6 +30,7 @@ + @@ -85,6 +86,9 @@ + + Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs + Internal\Cryptography\BasicSymmetricCipher.cs @@ -697,9 +701,6 @@ Common\Interop\Unix\Interop.Libraries.cs - - Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs - Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs index 23391a0fb7a34a..69b260cc715500 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs @@ -5,8 +5,6 @@ using System.Buffers; using System.Diagnostics; using System.IO; -using System.Numerics; -using System.Runtime.InteropServices; using System.Security.Cryptography.Asn1; using Internal.Cryptography; @@ -14,6 +12,14 @@ namespace System.Security.Cryptography { public abstract partial class DSA : AsymmetricAlgorithm { + // As of FIPS 186-4 the maximum Q size is 256 bits (32 bytes). + // The DER signature format thus maxes out at 2 + 3 + 33 + 3 + 33 => 74 bytes. + // So 128 should always work. + private const int SignatureStackSize = 128; + // The biggest supported hash algorithm is SHA-2-512, which is only 64 bytes. + // One power of two bigger should cover most unknown algorithms, too. + private const int HashBufferStackSize = 128; + public abstract DSAParameters ExportParameters(bool includePrivateParameters); public abstract void ImportParameters(DSAParameters parameters); @@ -76,32 +82,210 @@ protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) public byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) { if (data == null) - { throw new ArgumentNullException(nameof(data)); - } + // hashAlgorithm is verified in the overload + return SignData(data, 0, data.Length, hashAlgorithm); } + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The DSA signature for the specified data. + /// + /// + /// is . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or signing operation. + /// + public byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return SignDataCore(data, hashAlgorithm, signatureFormat); + } + public virtual byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) { - if (data == null) { throw new ArgumentNullException(nameof(data)); } - if (offset < 0 || offset > data.Length) { throw new ArgumentOutOfRangeException(nameof(offset)); } - if (count < 0 || count > data.Length - offset) { throw new ArgumentOutOfRangeException(nameof(count)); } - if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (offset < 0 || offset > data.Length) + throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0 || count > data.Length - offset) + throw new ArgumentOutOfRangeException(nameof(count)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); byte[] hash = HashData(data, offset, count, hashAlgorithm); return CreateSignature(hash); } + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The offset into at which to begin hashing. + /// The number of bytes to read from . + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The DSA signature for the specified data. + /// + /// + /// is . + /// + /// + /// is not a known format. + /// + /// -or- + /// + /// is less than zero. + /// + /// -or- + /// + /// is less than zero. + /// + /// -or- + /// + /// + - 1 results in an index that is + /// beyond the upper bound of . + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or signing operation. + /// + public byte[] SignData( + byte[] data, + int offset, + int count, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (offset < 0 || offset > data.Length) + throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0 || count > data.Length - offset) + throw new ArgumentOutOfRangeException(nameof(count)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return SignDataCore(new ReadOnlySpan(data, offset, count), hashAlgorithm, signatureFormat); + } + + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The DSA signature for the specified data. + /// + /// + /// An error occurred in the hashing or signing operation. + /// + protected virtual byte[] SignDataCore( + ReadOnlySpan data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + Span signature = stackalloc byte[SignatureStackSize]; + + if (TrySignDataCore(data, signature, hashAlgorithm, signatureFormat, out int bytesWritten)) + { + return signature.Slice(0, bytesWritten).ToArray(); + } + + // If that didn't work, fall back on older approaches. + + byte[] hash = HashSpanToArray(data, hashAlgorithm); + byte[] sig = CreateSignature(hash); + return AsymmetricAlgorithmHelpers.ConvertFromIeeeP1363Signature(sig, signatureFormat); + } + public virtual byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm) { - if (data == null) { throw new ArgumentNullException(nameof(data)); } - if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); byte[] hash = HashData(data, hashAlgorithm); return CreateSignature(hash); } + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The DSA signature for the specified data. + /// + /// + /// is . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or signing operation. + /// + public byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return SignDataCore(data, hashAlgorithm, signatureFormat); + } + + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The DSA signature for the specified data. + /// + /// + /// An error occurred in the hashing or signing operation. + /// + protected virtual byte[] SignDataCore(Stream data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) + { + byte[] hash = HashData(data, hashAlgorithm); + return CreateSignatureCore(hash, signatureFormat); + } + public bool VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm) { if (data == null) @@ -114,75 +298,238 @@ public bool VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgo public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm) { - if (data == null) { throw new ArgumentNullException(nameof(data)); } - if (offset < 0 || offset > data.Length) { throw new ArgumentOutOfRangeException(nameof(offset)); } - if (count < 0 || count > data.Length - offset) { throw new ArgumentOutOfRangeException(nameof(count)); } - if (signature == null) { throw new ArgumentNullException(nameof(signature)); } - if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (offset < 0 || offset > data.Length) + throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0 || count > data.Length - offset) + throw new ArgumentOutOfRangeException(nameof(count)); + if (signature == null) + throw new ArgumentNullException(nameof(signature)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); byte[] hash = HashData(data, offset, count, hashAlgorithm); return VerifySignature(hash, signature); } + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// An array that contains the signed data. + /// The starting index of the signed portion of . + /// The number of bytes in that were signed. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// or is . + /// + /// + /// is not a known format. + /// + /// -or- + /// + /// is less than zero. + /// + /// -or- + /// + /// is less than zero. + /// + /// -or- + /// + /// + - 1 results in an index that is + /// beyond the upper bound of . + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + public bool VerifyData( + byte[] data, + int offset, + int count, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (offset < 0 || offset > data.Length) + throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0 || count > data.Length - offset) + throw new ArgumentOutOfRangeException(nameof(count)); + if (signature == null) + throw new ArgumentNullException(nameof(signature)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyDataCore(new ReadOnlySpan(data, offset, count), signature, hashAlgorithm, signatureFormat); + } + public virtual bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm) { - if (data == null) { throw new ArgumentNullException(nameof(data)); } - if (signature == null) { throw new ArgumentNullException(nameof(signature)); } - if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (signature == null) + throw new ArgumentNullException(nameof(signature)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); byte[] hash = HashData(data, hashAlgorithm); return VerifySignature(hash, signature); } - public virtual bool TryCreateSignature(ReadOnlySpan hash, Span destination, out int bytesWritten) + /// + /// Creates the DSA signature for the specified hash value in the indicated format. + /// + /// The hash value to sign. + /// The encoding format to use for the signature. + /// + /// The DSA signature for the specified data. + /// + /// + /// is . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the signing operation. + /// + public byte[] CreateSignature(byte[] rgbHash, DSASignatureFormat signatureFormat) { - byte[] sig = CreateSignature(hash.ToArray()); - if (sig.Length <= destination.Length) - { - new ReadOnlySpan(sig).CopyTo(destination); - bytesWritten = sig.Length; - return true; - } - else - { - bytesWritten = 0; - return false; - } + if (rgbHash == null) + throw new ArgumentNullException(nameof(rgbHash)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return CreateSignatureCore(rgbHash, signatureFormat); } - protected virtual bool TryHashData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) + /// + /// Creates the DSA signature for the specified hash value in the indicated format. + /// + /// The hash value to sign. + /// The encoding format to use for the signature. + /// + /// The DSA signature for the specified data. + /// + /// + /// An error occurred in the signing operation. + /// + protected virtual byte[] CreateSignatureCore(ReadOnlySpan hash, DSASignatureFormat signatureFormat) { - // Use ArrayPool.Shared instead of CryptoPool because the array is passed out. - byte[] array = ArrayPool.Shared.Rent(data.Length); - try + Span signature = stackalloc byte[SignatureStackSize]; + + if (TryCreateSignatureCore(hash, signature, signatureFormat, out int bytesWritten)) { - data.CopyTo(array); - byte[] hash = HashData(array, 0, data.Length, hashAlgorithm); - if (destination.Length >= hash.Length) - { - new ReadOnlySpan(hash).CopyTo(destination); - bytesWritten = hash.Length; - return true; - } - else - { - bytesWritten = 0; - return false; - } + return signature.Slice(0, bytesWritten).ToArray(); } - finally + + // If that didn't work, fall back to the older overload and convert formats. + byte[] sig = CreateSignature(hash.ToArray()); + return AsymmetricAlgorithmHelpers.ConvertFromIeeeP1363Signature(sig, signatureFormat); + } + + public virtual bool TryCreateSignature(ReadOnlySpan hash, Span destination, out int bytesWritten) + => TryCreateSignatureCore(hash, destination, DSASignatureFormat.IeeeP1363FixedFieldConcatenation, out bytesWritten); + + /// + /// Attempts to create the DSA signature for the specified hash value in the indicated format + /// into the provided buffer. + /// + /// The hash value to sign. + /// The buffer to receive the signature. + /// The encoding format to use for the signature. + /// + /// When this method returns, contains a value that indicates the number of bytes written to + /// . This parameter is treated as uninitialized. + /// + /// + /// if is big enough to receive the signature; + /// otherwise, . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the signing operation. + /// + public bool TryCreateSignature( + ReadOnlySpan hash, + Span destination, + DSASignatureFormat signatureFormat, + out int bytesWritten) + { + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return TryCreateSignatureCore(hash, destination, signatureFormat, out bytesWritten); + } + + /// + /// Attempts to create the DSA signature for the specified hash value in the indicated format + /// into the provided buffer. + /// + /// The hash value to sign. + /// The buffer to receive the signature. + /// The encoding format to use for the signature. + /// + /// When this method returns, contains a value that indicates the number of bytes written to + /// . This parameter is treated as uninitialized. + /// + /// + /// if is big enough to receive the signature; + /// otherwise, . + /// + /// + /// An error occurred in the signing operation. + /// + protected virtual bool TryCreateSignatureCore( + ReadOnlySpan hash, + Span destination, + DSASignatureFormat signatureFormat, + out int bytesWritten) + { + // This method is expected to be overriden with better implementation + + // The only available implementation here is abstract method, use it + byte[] sig = CreateSignature(hash.ToArray()); + + if (signatureFormat != DSASignatureFormat.IeeeP1363FixedFieldConcatenation) { - Array.Clear(array, 0, data.Length); - ArrayPool.Shared.Return(array); + sig = AsymmetricAlgorithmHelpers.ConvertFromIeeeP1363Signature(sig, signatureFormat); } + + return Helpers.TryCopyToDestination(sig, destination, out bytesWritten); + } + + protected virtual bool TryHashData( + ReadOnlySpan data, + Span destination, + HashAlgorithmName hashAlgorithm, + out int bytesWritten) + { + byte[] hash = HashSpanToArray(data, hashAlgorithm); + return Helpers.TryCopyToDestination(hash, destination, out bytesWritten); } - public virtual bool TrySignData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) + public virtual bool TrySignData( + ReadOnlySpan data, + Span destination, + HashAlgorithmName hashAlgorithm, + out int bytesWritten) { if (string.IsNullOrEmpty(hashAlgorithm.Name)) - { throw HashAlgorithmNameNullOrEmpty(); - } if (TryHashData(data, destination, hashAlgorithm, out int hashLength) && TryCreateSignature(destination.Slice(0, hashLength), destination, out bytesWritten)) @@ -194,46 +541,379 @@ public virtual bool TrySignData(ReadOnlySpan data, Span destination, return false; } - public virtual bool VerifyData(ReadOnlySpan data, ReadOnlySpan signature, HashAlgorithmName hashAlgorithm) + /// + /// Attempts to create the DSA signature for the specified data in the indicated format + /// into the provided buffer. + /// + /// The data to hash and sign. + /// The buffer to receive the signature. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// When this method returns, contains a value that indicates the number of bytes written to + /// . This parameter is treated as uninitialized. + /// + /// + /// if is big enough to receive the signature; + /// otherwise, . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the signing operation. + /// + public bool TrySignData( + ReadOnlySpan data, + Span destination, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat, + out int bytesWritten) { if (string.IsNullOrEmpty(hashAlgorithm.Name)) - { throw HashAlgorithmNameNullOrEmpty(); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return TrySignDataCore(data, destination, hashAlgorithm, signatureFormat, out bytesWritten); + } + + /// + /// Attempts to create the DSA signature for the specified data in the indicated format + /// into the provided buffer. + /// + /// The data to hash and sign. + /// The buffer to receive the signature. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// When this method returns, contains a value that indicates the number of bytes written to + /// . This parameter is treated as uninitialized. + /// + /// + /// if is big enough to receive the signature; + /// otherwise, . + /// + /// + /// An error occurred in the signing operation. + /// + protected virtual bool TrySignDataCore( + ReadOnlySpan data, + Span destination, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat, + out int bytesWritten) + { + Span tmp = stackalloc byte[HashBufferStackSize]; + ReadOnlySpan hash = HashSpanToTmp(data, hashAlgorithm, tmp); + + return TryCreateSignatureCore(hash, destination, signatureFormat, out bytesWritten); + } + + public virtual bool VerifyData( + ReadOnlySpan data, + ReadOnlySpan signature, + HashAlgorithmName hashAlgorithm) + { + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); + + return VerifyDataCore(data, signature, hashAlgorithm, DSASignatureFormat.IeeeP1363FixedFieldConcatenation); + } + + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// or is . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + public bool VerifyData( + byte[] data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (signature == null) + throw new ArgumentNullException(nameof(signature)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyDataCore(data, signature, hashAlgorithm, signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// or is . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + public bool VerifyData( + Stream data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (signature == null) + throw new ArgumentNullException(nameof(signature)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyDataCore(data, signature, hashAlgorithm, signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + protected virtual bool VerifyDataCore( + Stream data, + ReadOnlySpan signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + byte[] hash = HashData(data, hashAlgorithm); + return VerifySignatureCore(hash, signature, signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the hashing or verification operation. + /// + public bool VerifyData( + ReadOnlySpan data, + ReadOnlySpan signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw HashAlgorithmNameNullOrEmpty(); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyDataCore(data, signature, hashAlgorithm, signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + protected virtual bool VerifyDataCore( + ReadOnlySpan data, + ReadOnlySpan signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + Span tmp = stackalloc byte[HashBufferStackSize]; + ReadOnlySpan hash = HashSpanToTmp(data, hashAlgorithm, tmp); + + return VerifySignatureCore(hash, signature, signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided hash. + /// + /// The signed hash. + /// The signature to verify. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// or is . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the verification operation. + /// + public bool VerifySignature(byte[] rgbHash, byte[] rgbSignature, DSASignatureFormat signatureFormat) + { + if (rgbHash == null) + throw new ArgumentNullException(nameof(rgbHash)); + if (rgbSignature == null) + throw new ArgumentNullException(nameof(rgbSignature)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifySignatureCore(rgbHash, rgbSignature, signatureFormat); + } + + public virtual bool VerifySignature(ReadOnlySpan hash, ReadOnlySpan signature) => + VerifySignature(hash.ToArray(), signature.ToArray()); + + /// + /// Verifies that a digital signature is valid for the provided hash. + /// + /// The signed hash. + /// The signature to verify. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the verification operation. + /// + public bool VerifySignature( + ReadOnlySpan hash, + ReadOnlySpan signature, + DSASignatureFormat signatureFormat) + { + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifySignatureCore(hash, signature, signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided hash. + /// + /// The signed hash. + /// The signature to verify. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// An error occurred in the verification operation. + /// + protected virtual bool VerifySignatureCore( + ReadOnlySpan hash, + ReadOnlySpan signature, + DSASignatureFormat signatureFormat) + { + // This method is expected to be overriden with better implementation + + byte[]? sig = this.ConvertSignatureToIeeeP1363(signatureFormat, signature); + + // If the signature failed normalization to IEEE P1363 then it + // obviously doesn't verify. + if (sig == null) + { + return false; + } + + // The only available implementation here is abstract method, use it. + // Since it requires an exactly-sized array, skip pooled arrays. + return VerifySignature(hash, sig); + } + + private ReadOnlySpan HashSpanToTmp( + ReadOnlySpan data, + HashAlgorithmName hashAlgorithm, + Span tmp) + { + Debug.Assert(tmp.Length == HashBufferStackSize); + + if (TryHashData(data, tmp, hashAlgorithm, out int hashSize)) + { + return tmp.Slice(0, hashSize); } - // The biggest hash algorithm supported is SHA512, which is only 64 bytes (512 bits). - // So this should realistically never hit the fallback - // (it'd require a derived type to add support for a different hash algorithm, and that - // algorithm to have a large output.) - Span buf = stackalloc byte[128]; - ReadOnlySpan hash = stackalloc byte[0]; + // This is not expected, but a poor virtual implementation of TryHashData, + // or an exotic new algorithm, will hit this fallback. + return HashSpanToArray(data, hashAlgorithm); + } - if (TryHashData(data, buf, hashAlgorithm, out int hashLength)) + private byte[] HashSpanToArray(ReadOnlySpan data, HashAlgorithmName hashAlgorithm) + { + // Use ArrayPool.Shared instead of CryptoPool because the array is passed out. + byte[] array = ArrayPool.Shared.Rent(data.Length); + bool returnArray = false; + try { - hash = buf.Slice(0, hashLength); + data.CopyTo(array); + byte[] ret = HashData(array, 0, data.Length, hashAlgorithm); + returnArray = true; + return ret; } - else + finally { - // Use ArrayPool.Shared instead of CryptoPool because the array is passed out. - byte[] array = ArrayPool.Shared.Rent(data.Length); - try - { - data.CopyTo(array); - hash = HashData(array, 0, data.Length, hashAlgorithm); - } - finally + Array.Clear(array, 0, data.Length); + + if (returnArray) { - Array.Clear(array, 0, data.Length); ArrayPool.Shared.Return(array); } } - - return VerifySignature(hash, signature); } - public virtual bool VerifySignature(ReadOnlySpan hash, ReadOnlySpan signature) => - VerifySignature(hash.ToArray(), signature.ToArray()); - private static Exception DerivedClassMustOverride() => new NotImplementedException(SR.NotSupported_SubclassOverride); @@ -419,5 +1099,31 @@ public override void ImportSubjectPublicKeyInfo( ImportParameters(key); bytesRead = localRead; } + + /// + /// Gets the largest size, in bytes, for a signature produced by this key in the indicated format. + /// + /// The encoding format for a signature. + /// + /// The largest size, in bytes, for a signature produced by this key in the indicated format. + /// + /// + /// is not a known format. + /// + public int GetMaxSignatureSize(DSASignatureFormat signatureFormat) + { + DSAParameters dsaParameters = ExportParameters(false); + int qLength = dsaParameters.Q!.Length; + + switch (signatureFormat) + { + case DSASignatureFormat.IeeeP1363FixedFieldConcatenation: + return qLength * 2; + case DSASignatureFormat.Rfc3279DerSequence: + return AsymmetricAlgorithmHelpers.GetMaxDerSignatureSize(fieldSizeBits: qLength * 8); + default: + throw new ArgumentOutOfRangeException(nameof(signatureFormat)); + } + } } } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSASignatureFormat.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSASignatureFormat.cs new file mode 100644 index 00000000000000..3b1f1565886e5c --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSASignatureFormat.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Security.Cryptography +{ + /// + /// Specifies the data format for signatures with the DSA family of algorithms. + /// + public enum DSASignatureFormat + { + /// + /// The signature format from IEEE P1363, which produces a fixed size signature for a given key. + /// + /// + /// This signature format encodes the `(r, s)` tuple as the concatenation of the + /// big-endian representation of `r` and the big-endian representation of `s`, each + /// value encoding using the number of bytes required for encoding the maximum integer + /// value in the key's mathematical field. For example, an ECDSA signature from the curve + /// `secp521r1`, a 521-bit field, will encode each of `r` and `s` as 66 bytes, producing + /// a signature output of 132 bytes. + /// + IeeeP1363FixedFieldConcatenation, + + /// + /// The signature format from IETF RFC 3279, which produces a variably-sized signature. + /// + /// + /// This signature format encodes the `(r, s)` tuple as the DER encoding of + /// `SEQUENCE(INTEGER(r), INTEGER(s))`. Because the length of a DER INTEGER encoding + /// varies according to the value being encoded, this signature format does not produce + /// a consistent signature length. Signatures in this format always start with `0x30`, + /// and on average are 7 bytes longer than signatures in the + /// format. + /// + Rfc3279DerSequence, + } + + internal static class DSASignatureFormatHelpers + { + internal static bool IsKnownValue(this DSASignatureFormat signatureFormat) => + signatureFormat >= DSASignatureFormat.IeeeP1363FixedFieldConcatenation && + signatureFormat <= DSASignatureFormat.Rfc3279DerSequence; + + internal static Exception CreateUnknownValueException(DSASignatureFormat signatureFormat) => + new ArgumentOutOfRangeException( + nameof(signatureFormat), + SR.Format(SR.Cryptography_UnknownSignatureFormat, signatureFormat)); + } +} diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs index 9d04547242b417..01d1109e6edd31 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Internal.Cryptography; using System.Buffers; +using System.Diagnostics; using System.IO; using System.Security.Cryptography.Asn1; @@ -10,6 +12,12 @@ namespace System.Security.Cryptography { public abstract partial class ECDsa : AsymmetricAlgorithm { + // secp521r1 maxes out at 139 bytes in the DER format, so 256 should always be enough + private const int SignatureStackBufSize = 256; + // The biggest supported hash algorithm is SHA-2-512, which is only 64 bytes. + // One power of two bigger should cover most unknown algorithms, too. + private const int HashBufferStackSize = 128; + private static readonly string[] s_validOids = { Oids.EcPublicKey, @@ -71,6 +79,7 @@ public virtual byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) { if (data == null) throw new ArgumentNullException(nameof(data)); + // hashAlgorithm is verified in the overload return SignData(data, 0, data.Length, hashAlgorithm); } @@ -90,21 +99,369 @@ public virtual byte[] SignData(byte[] data, int offset, int count, HashAlgorithm return SignHash(hash); } - public virtual bool TrySignData(ReadOnlySpan data, Span destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The offset into at which to begin hashing. + /// The number of bytes to read from . + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The ECDSA signature for the specified data. + /// + /// + /// is . + /// + /// + /// is not a known format. + /// + /// -or- + /// + /// is less than zero. + /// + /// -or- + /// + /// is less than zero. + /// + /// -or- + /// + /// + - 1 results in an index that is + /// beyond the upper bound of . + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or signing operation. + /// + public byte[] SignData( + byte[] data, + int offset, + int count, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (offset < 0 || offset > data.Length) + throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0 || count > data.Length - offset) + throw new ArgumentOutOfRangeException(nameof(count)); if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return SignDataCore(new ReadOnlySpan(data, offset, count), hashAlgorithm, signatureFormat); + } + + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The ECDSA signature for the specified data. + /// + /// + /// An error occurred in the hashing or signing operation. + /// + protected virtual byte[] SignDataCore( + ReadOnlySpan data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + Span signature = stackalloc byte[SignatureStackBufSize]; + int maxSignatureSize = GetMaxSignatureSize(signatureFormat); + byte[]? rented = null; + bool returnArray = false; + int bytesWritten = 0; + + if (maxSignatureSize > signature.Length) { + // Use the shared pool because the buffer is passed out. + rented = ArrayPool.Shared.Rent(maxSignatureSize); + signature = rented; + } + + try + { + if (!TrySignDataCore(data, signature, hashAlgorithm, signatureFormat, out bytesWritten)) + { + Debug.Fail($"GetMaxSignatureSize returned insufficient size for format {signatureFormat}"); + throw new CryptographicException(); + } + + byte[] ret = signature.Slice(0, bytesWritten).ToArray(); + returnArray = true; + return ret; + } + finally + { + if (rented != null) + { + CryptographicOperations.ZeroMemory(rented.AsSpan(0, bytesWritten)); + + if (returnArray) + { + ArrayPool.Shared.Return(rented); + } + } + } + } + + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The ECDSA signature for the specified data. + /// + /// + /// is . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or signing operation. + /// + public byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return SignDataCore(data, hashAlgorithm, signatureFormat); + } + + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The ECDSA signature for the specified data. + /// + /// + /// is . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or signing operation. + /// + public byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return SignDataCore(data, hashAlgorithm, signatureFormat); + } + + /// + /// Computes the hash value of the specified data and signs it using the specified signature format. + /// + /// The data to sign. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// The ECDSA signature for the specified data. + /// + /// + /// An error occurred in the hashing or signing operation. + /// + protected virtual byte[] SignDataCore( + Stream data, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + byte[] hash = HashData(data, hashAlgorithm); + return SignHashCore(hash, signatureFormat); + } + + /// + /// Computes the ECDSA signature for the specified hash value in the indicated format. + /// + /// The hash value to sign. + /// The encoding format to use for the signature. + /// + /// The ECDSA signature for the specified data. + /// + /// + /// is . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the signing operation. + /// + public byte[] SignHash(byte[] hash, DSASignatureFormat signatureFormat) + { + if (hash == null) + throw new ArgumentNullException(nameof(hash)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return SignHashCore(hash, signatureFormat); + } + + /// + /// Computes the ECDSA signature for the specified hash value in the indicated format. + /// + /// The hash value to sign. + /// The encoding format to use for the signature. + /// + /// The ECDSA signature for the specified data. + /// + /// + /// An error occurred in the signing operation. + /// + protected virtual byte[] SignHashCore(ReadOnlySpan hash, DSASignatureFormat signatureFormat) + { + Span signature = stackalloc byte[SignatureStackBufSize]; + int maxSignatureSize = GetMaxSignatureSize(signatureFormat); + byte[]? rented = null; + bool returnArray = false; + int bytesWritten = 0; + + if (maxSignatureSize > signature.Length) + { + // Use the shared pool because the buffer is passed out. + rented = ArrayPool.Shared.Rent(maxSignatureSize); + signature = rented; } - if (TryHashData(data, destination, hashAlgorithm, out int hashLength) && - TrySignHash(destination.Slice(0, hashLength), destination, out bytesWritten)) + try { - return true; + if (!TrySignHashCore(hash, signature, signatureFormat, out bytesWritten)) + { + Debug.Fail($"GetMaxSignatureSize returned insufficient size for format {signatureFormat}"); + throw new CryptographicException(); + } + + byte[] ret = signature.Slice(0, bytesWritten).ToArray(); + returnArray = true; + return ret; } + finally + { + if (rented != null) + { + CryptographicOperations.ZeroMemory(rented.AsSpan(0, bytesWritten)); - bytesWritten = 0; - return false; + if (returnArray) + { + ArrayPool.Shared.Return(rented); + } + } + } + } + + public virtual bool TrySignData( + ReadOnlySpan data, + Span destination, + HashAlgorithmName hashAlgorithm, + out int bytesWritten) + { + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); + + Span hashTmp = stackalloc byte[HashBufferStackSize]; + ReadOnlySpan hash = HashSpanToTmp(data, hashAlgorithm, hashTmp); + return TrySignHash(hash, destination, out bytesWritten); + } + + /// + /// Attempts to create the ECDSA signature for the specified data in the indicated format + /// into the provided buffer. + /// + /// The data to hash and sign. + /// The buffer to receive the signature. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// When this method returns, contains a value that indicates the number of bytes written to + /// . This parameter is treated as uninitialized. + /// + /// + /// if is big enough to receive the signature; + /// otherwise, . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the signing operation. + /// + public bool TrySignData( + ReadOnlySpan data, + Span destination, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat, + out int bytesWritten) + { + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return TrySignDataCore(data, destination, hashAlgorithm, signatureFormat, out bytesWritten); + } + + /// + /// Attempts to create the ECDSA signature for the specified data in the indicated format + /// into the provided buffer. + /// + /// The data to hash and sign. + /// The buffer to receive the signature. + /// The hash algorithm to use to create the hash value. + /// The encoding format to use for the signature. + /// + /// When this method returns, contains a value that indicates the number of bytes written to + /// . This parameter is treated as uninitialized. + /// + /// + /// if is big enough to receive the signature; + /// otherwise, . + /// + /// + /// An error occurred in the signing operation. + /// + protected virtual bool TrySignDataCore( + ReadOnlySpan data, + Span destination, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat, + out int bytesWritten) + { + Span hashTmp = stackalloc byte[HashBufferStackSize]; + ReadOnlySpan hash = HashSpanToTmp(data, hashAlgorithm, hashTmp); + + return TrySignHashCore(hash, destination, signatureFormat, out bytesWritten); } public virtual byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm) @@ -143,41 +500,181 @@ public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signat return VerifyHash(hash, signature); } + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// An array that contains the signed data. + /// The starting index of the signed portion of . + /// The number of bytes in that were signed. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// or is . + /// + /// + /// is not a known format. + /// + /// -or- + /// + /// is less than zero. + /// + /// -or- + /// + /// is less than zero. + /// + /// -or- + /// + /// + - 1 results in an index that is + /// beyond the upper bound of . + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + public bool VerifyData( + byte[] data, + int offset, + int count, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (offset < 0 || offset > data.Length) + throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0 || count > data.Length - offset) + throw new ArgumentOutOfRangeException(nameof(count)); + if (signature == null) + throw new ArgumentNullException(nameof(signature)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyDataCore( + new ReadOnlySpan(data, offset, count), + signature, + hashAlgorithm, + signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// or is . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + public bool VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (signature == null) + throw new ArgumentNullException(nameof(signature)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyDataCore(data, signature, hashAlgorithm, signatureFormat); + } + public virtual bool VerifyData(ReadOnlySpan data, ReadOnlySpan signature, HashAlgorithmName hashAlgorithm) { if (string.IsNullOrEmpty(hashAlgorithm.Name)) - { throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); - } - // The biggest hash algorithm supported is SHA512, which is only 64 bytes (512 bits). - // So this should realistically never hit the fallback - // (it'd require a derived type to add support for a different hash algorithm, and that - // algorithm to have a large output.) - Span buf = stackalloc byte[128]; - ReadOnlySpan hash = stackalloc byte[0]; + Span hashTmp = stackalloc byte[HashBufferStackSize]; + ReadOnlySpan hash = HashSpanToTmp(data, hashAlgorithm, hashTmp); + return VerifyHash(hash, signature); + } + + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the hashing or verification operation. + /// + public bool VerifyData( + ReadOnlySpan data, + ReadOnlySpan signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyDataCore(data, signature, hashAlgorithm, signatureFormat); + } - if (TryHashData(data, buf, hashAlgorithm, out int hashLength)) + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + protected virtual bool VerifyDataCore( + ReadOnlySpan data, + ReadOnlySpan signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + // SHA-2-512 is the biggest hash we know about. + Span hashSpan = stackalloc byte[512 / 8]; + + if (TryHashData(data, hashSpan, hashAlgorithm, out int bytesWritten)) { - hash = buf.Slice(0, hashLength); + hashSpan = hashSpan.Slice(0, bytesWritten); } else { - // Use ArrayPool.Shared instead of CryptoPool because the array is passed out. - byte[] array = ArrayPool.Shared.Rent(data.Length); - try - { - data.CopyTo(array); - hash = HashData(array, 0, data.Length, hashAlgorithm); - } - finally - { - Array.Clear(array, 0, data.Length); - ArrayPool.Shared.Return(array); - } + // TryHashData didn't work, the algorithm must be exotic, + // call the array-returning variant. + hashSpan = HashData(data.ToArray(), 0, data.Length, hashAlgorithm); } - return VerifyHash(hash, signature); + return VerifyHashCore(hashSpan, signature, signatureFormat); } public bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm) @@ -193,6 +690,69 @@ public bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgo return VerifyHash(hash, signature); } + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// or is . + /// + /// + /// is not a known format. + /// + /// + /// has a or empty . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + public bool VerifyData( + Stream data, + byte[] signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (signature == null) + throw new ArgumentNullException(nameof(signature)); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyDataCore(data, signature, hashAlgorithm, signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided data. + /// + /// The signed data. + /// The signature to verify. + /// The hash algorithm used to hash the data for the verification process. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// An error occurred in the hashing or verification operation. + /// + protected virtual bool VerifyDataCore( + Stream data, + ReadOnlySpan signature, + HashAlgorithmName hashAlgorithm, + DSASignatureFormat signatureFormat) + { + byte[] hash = HashData(data, hashAlgorithm); + return VerifyHashCore(hash, signature, signatureFormat); + } + public abstract byte[] SignHash(byte[] hash); public abstract bool VerifyHash(byte[] hash, byte[] signature); @@ -213,10 +773,14 @@ protected virtual bool TryHashData(ReadOnlySpan data, Span destinati { // Use ArrayPool.Shared instead of CryptoPool because the array is passed out. byte[] array = ArrayPool.Shared.Rent(data.Length); + bool returnArray = false; + try { data.CopyTo(array); byte[] hash = HashData(array, 0, data.Length, hashAlgorithm); + returnArray = true; + if (hash.Length <= destination.Length) { new ReadOnlySpan(hash).CopyTo(destination); @@ -232,28 +796,211 @@ protected virtual bool TryHashData(ReadOnlySpan data, Span destinati finally { Array.Clear(array, 0, data.Length); - ArrayPool.Shared.Return(array); + + if (returnArray) + { + ArrayPool.Shared.Return(array); + } } } public virtual bool TrySignHash(ReadOnlySpan hash, Span destination, out int bytesWritten) + => TrySignHashCore(hash, destination, DSASignatureFormat.IeeeP1363FixedFieldConcatenation, out bytesWritten); + + /// + /// Attempts to create the ECDSA signature for the specified hash value in the indicated format + /// into the provided buffer. + /// + /// The hash value to sign. + /// The buffer to receive the signature. + /// The encoding format to use for the signature. + /// + /// When this method returns, contains a value that indicates the number of bytes written to + /// . This parameter is treated as uninitialized. + /// + /// + /// if is big enough to receive the signature; + /// otherwise, . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the signing operation. + /// + public bool TrySignHash( + ReadOnlySpan hash, + Span destination, + DSASignatureFormat signatureFormat, + out int bytesWritten) + { + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return TrySignHashCore(hash, destination, signatureFormat, out bytesWritten); + } + + /// + /// Attempts to create the ECDSA signature for the specified hash value in the indicated format + /// into the provided buffer. + /// + /// The hash value to sign. + /// The buffer to receive the signature. + /// The encoding format to use for the signature. + /// + /// When this method returns, contains a value that indicates the number of bytes written to + /// . This parameter is treated as uninitialized. + /// + /// + /// if is big enough to receive the signature; + /// otherwise, . + /// + /// + /// An error occurred in the signing operation. + /// + protected virtual bool TrySignHashCore( + ReadOnlySpan hash, + Span destination, + DSASignatureFormat signatureFormat, + out int bytesWritten) { + // This method is expected to be overriden with better implementation + + // The only available implementation here is abstract method, use it byte[] result = SignHash(hash.ToArray()); - if (result.Length <= destination.Length) + byte[] converted = AsymmetricAlgorithmHelpers.ConvertFromIeeeP1363Signature(result, signatureFormat); + return Helpers.TryCopyToDestination(converted, destination, out bytesWritten); + } + + public virtual bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan signature) => + VerifyHashCore(hash, signature, DSASignatureFormat.IeeeP1363FixedFieldConcatenation); + + /// + /// Verifies that a digital signature is valid for the provided hash. + /// + /// The signed hash. + /// The signature to verify. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// or is . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the verification operation. + /// + public bool VerifyHash(byte[] hash, byte[] signature, DSASignatureFormat signatureFormat) + { + if (hash == null) + throw new ArgumentNullException(nameof(hash)); + if (signature == null) + throw new ArgumentNullException(nameof(signature)); + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyHashCore(hash, signature, signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided hash. + /// + /// The signed hash. + /// The signature to verify. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// is not a known format. + /// + /// + /// An error occurred in the verification operation. + /// + public bool VerifyHash( + ReadOnlySpan hash, + ReadOnlySpan signature, + DSASignatureFormat signatureFormat) + { + if (!signatureFormat.IsKnownValue()) + throw DSASignatureFormatHelpers.CreateUnknownValueException(signatureFormat); + + return VerifyHashCore(hash, signature, signatureFormat); + } + + /// + /// Verifies that a digital signature is valid for the provided hash. + /// + /// The signed hash. + /// The signature to verify. + /// The encoding format for . + /// + /// if the digital signature is valid for the provided data; otherwise, . + /// + /// + /// An error occurred in the verification operation. + /// + protected virtual bool VerifyHashCore( + ReadOnlySpan hash, + ReadOnlySpan signature, + DSASignatureFormat signatureFormat) + { + // This method is expected to be overriden with better implementation + + byte[]? sig = this.ConvertSignatureToIeeeP1363(signatureFormat, signature); + + // If the signature failed normalization to P1363, it obviously doesn't verify. + if (sig == null) { - new ReadOnlySpan(result).CopyTo(destination); - bytesWritten = result.Length; - return true; + return false; } - else + + // The only available implementation here is abstract method, use it + return VerifyHash(hash.ToArray(), sig); + } + + private ReadOnlySpan HashSpanToTmp( + ReadOnlySpan data, + HashAlgorithmName hashAlgorithm, + Span tmp) + { + Debug.Assert(tmp.Length == HashBufferStackSize); + + if (TryHashData(data, tmp, hashAlgorithm, out int hashSize)) { - bytesWritten = 0; - return false; + return tmp.Slice(0, hashSize); } + + // This is not expected, but a poor virtual implementation of TryHashData, + // or an exotic new algorithm, will hit this fallback. + return HashSpanToArray(data, hashAlgorithm); } - public virtual bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan signature) => - VerifyHash(hash.ToArray(), signature.ToArray()); + private byte[] HashSpanToArray(ReadOnlySpan data, HashAlgorithmName hashAlgorithm) + { + // Use ArrayPool.Shared instead of CryptoPool because the array is passed out. + byte[] array = ArrayPool.Shared.Rent(data.Length); + bool returnArray = false; + try + { + data.CopyTo(array); + byte[] ret = HashData(array, 0, data.Length, hashAlgorithm); + returnArray = true; + return ret; + } + finally + { + Array.Clear(array, 0, data.Length); + + if (returnArray) + { + ArrayPool.Shared.Return(array); + } + } + } public override unsafe bool TryExportEncryptedPkcs8PrivateKey( ReadOnlySpan passwordBytes, @@ -512,5 +1259,44 @@ public virtual unsafe bool TryExportECPrivateKey(Span destination, out int } } } + + /// + /// Gets the largest size, in bytes, for a signature produced by this key in the indicated format. + /// + /// The encoding format for a signature. + /// + /// The largest size, in bytes, for a signature produced by this key in the indicated format. + /// + /// + /// is not a known format. + /// + public int GetMaxSignatureSize(DSASignatureFormat signatureFormat) + { + int fieldSizeBits = KeySize; + + if (fieldSizeBits == 0) + { + // Coerce the key/key-size into existence + ExportParameters(false); + + fieldSizeBits = KeySize; + + // This implementation of ECDsa doesn't set KeySize, we can't + if (fieldSizeBits == 0) + { + throw new NotSupportedException(SR.Cryptography_InvalidKeySize); + } + } + + switch (signatureFormat) + { + case DSASignatureFormat.IeeeP1363FixedFieldConcatenation: + return AsymmetricAlgorithmHelpers.BitsToBytes(fieldSizeBits) * 2; + case DSASignatureFormat.Rfc3279DerSequence: + return AsymmetricAlgorithmHelpers.GetMaxDerSignatureSize(fieldSizeBits); + default: + throw new ArgumentOutOfRangeException(nameof(signatureFormat)); + } + } } } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/tests/ECDsaTests.cs b/src/libraries/System.Security.Cryptography.Algorithms/tests/ECDsaTests.cs index 217467798f8a49..ad178b4930c403 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/tests/ECDsaTests.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/tests/ECDsaTests.cs @@ -138,6 +138,12 @@ private sealed class OverrideAbstractECDsa : ECDsa public OverrideAbstractECDsa(ECDsa ecdsa) => _ecdsa = ecdsa; + public override int KeySize + { + get => _ecdsa.KeySize; + set => _ecdsa.KeySize = value; + } + public override byte[] SignHash(byte[] hash) => _ecdsa.SignHash(hash); public override bool VerifyHash(byte[] hash, byte[] signature) => _ecdsa.VerifyHash(hash, signature); diff --git a/src/libraries/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj b/src/libraries/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj index e02f232788561e..aa25b8f7bab7d5 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj @@ -51,6 +51,9 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaImportExport.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaSignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaStub.cs @@ -218,9 +221,15 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAFactory.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DsaFamilySignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatter.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAImportExport.cs diff --git a/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj b/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj index 530ecb139c24ec..658286dbfb998a 100644 --- a/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj @@ -277,6 +277,9 @@ Common\System\Security\Cryptography\ECDsaCng.SignVerify.cs + + Common\System\Security\Cryptography\KeyBlobHelpers.cs + Common\System\Security\Cryptography\KeyFormatHelper.cs @@ -413,4 +416,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj index 71360589443362..b78e98c57e348c 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj @@ -105,6 +105,9 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAFactory.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DsaFamilySignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAImportExport.cs @@ -117,6 +120,9 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatter.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignVerify.cs @@ -138,6 +144,9 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyFileTests.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaSignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaXml.cs @@ -203,4 +212,4 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Xml.cs - \ No newline at end of file + diff --git a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Unix.cs b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Unix.cs index 76777a033c31c6..52fdfcd17c56a0 100644 --- a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Unix.cs +++ b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Unix.cs @@ -5,6 +5,7 @@ using Internal.Cryptography; using Internal.NativeCrypto; using System.IO; +using System.Diagnostics; namespace System.Security.Cryptography { diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/ShimHelpers.cs b/src/libraries/System.Security.Cryptography.Csp/tests/ShimHelpers.cs index 8edcbd5667e900..63dc763b5ef09d 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/ShimHelpers.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/ShimHelpers.cs @@ -68,6 +68,13 @@ public static void VerifyAllBaseMembersOverloaded(Type shimType) "TryExportSubjectPublicKeyInfo", "TryExportPkcs8PrivateKey", "TryExportEncryptedPkcs8PrivateKey", + // DSASignatureFormat methods defer to older methods. + "CreateSignatureCore", + "SignDataCore", + "TryCreateSignatureCore", + "TrySignDataCore", + "VerifyDataCore", + "VerifySignatureCore", }; IEnumerable baseMethods = shimType. diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj b/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj index beaae7dac1c160..df8ab9e89365c3 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj @@ -66,6 +66,9 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAFactory.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DsaFamilySignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAImportExport.cs @@ -78,6 +81,9 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatter.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignVerify.cs @@ -115,4 +121,4 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.netcoreapp.cs - \ No newline at end of file + diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj b/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj index 2575a5472b7216..6f9f04c70d5743 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj +++ b/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj @@ -24,6 +24,9 @@ Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs + + Internal\Cryptography\Helpers.cs + Common\Interop\Unix\Interop.Libraries.cs diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj b/src/libraries/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj index 7a4b8afc4e12e8..147d63cbfdd744 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj @@ -51,6 +51,9 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaImportExport.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaSignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaStub.cs @@ -96,6 +99,9 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAFactory.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DsaFamilySignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAImportExport.cs @@ -105,6 +111,9 @@ CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatter.cs + + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatTests.cs + CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignVerify.cs diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertIdV2.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertIdV2.xml.cs index cfff6e464007b5..df54bc64b5efe7 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertIdV2.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertIdV2.xml.cs @@ -13,7 +13,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct EssCertIdV2 { - private static readonly byte[] s_defaultHashAlgorithm = { 0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 }; + private static ReadOnlySpan DefaultHashAlgorithm => new byte[] { 0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 }; internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm; internal ReadOnlyMemory Hash; @@ -26,7 +26,7 @@ static EssCertIdV2() ReadOnlyMemory rebind = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultHashAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashAlgorithm); reader.ThrowIfNotEmpty(); } @@ -49,7 +49,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) HashAlgorithm.Encode(tmp); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultHashAlgorithm)) + if (!encoded.SequenceEqual(DefaultHashAlgorithm)) { writer.WriteEncodedValue(encoded); } @@ -101,7 +101,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultHashAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashAlgorithm); } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampReq.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampReq.xml.cs index d31c8fc0236610..f99b08c3121c5f 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampReq.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampReq.xml.cs @@ -14,7 +14,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct Rfc3161TimeStampReq { - private static readonly byte[] s_defaultCertReq = { 0x01, 0x01, 0x00 }; + private static ReadOnlySpan DefaultCertReq => new byte[] { 0x01, 0x01, 0x00 }; internal int Version; internal System.Security.Cryptography.Pkcs.Asn1.MessageImprint MessageImprint; @@ -29,7 +29,7 @@ static Rfc3161TimeStampReq() Rfc3161TimeStampReq decoded = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultCertReq, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultCertReq, AsnEncodingRules.DER); decoded.CertReq = reader.ReadBoolean(); reader.ThrowIfNotEmpty(); } @@ -66,7 +66,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) tmp.WriteBoolean(CertReq); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultCertReq)) + if (!encoded.SequenceEqual(DefaultCertReq)) { writer.WriteEncodedValue(encoded); } @@ -145,7 +145,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultCertReq, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultCertReq, AsnEncodingRules.DER); decoded.CertReq = defaultReader.ReadBoolean(); } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.xml.cs index ff0a95b202a62e..8bf7ca2a8a65fb 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.xml.cs @@ -14,7 +14,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct Rfc3161TstInfo { - private static readonly byte[] s_defaultOrdering = { 0x01, 0x01, 0x00 }; + private static ReadOnlySpan DefaultOrdering => new byte[] { 0x01, 0x01, 0x00 }; internal int Version; internal Oid Policy; @@ -33,7 +33,7 @@ static Rfc3161TstInfo() Rfc3161TstInfo decoded = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultOrdering, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultOrdering, AsnEncodingRules.DER); decoded.Ordering = reader.ReadBoolean(); reader.ThrowIfNotEmpty(); } @@ -67,7 +67,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) tmp.WriteBoolean(Ordering); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultOrdering)) + if (!encoded.SequenceEqual(DefaultOrdering)) { writer.WriteEncodedValue(encoded); } @@ -161,7 +161,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultOrdering, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultOrdering, AsnEncodingRules.DER); decoded.Ordering = defaultReader.ReadBoolean(); } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs index d431a2bf5bbf6d..958308bd6d3494 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs @@ -86,14 +86,13 @@ public bool VerifySignatureForData( return false; } - bool ret = VerifyData(data); - - if (ret) + if (VerifyData(data)) { signerCertificate = cert; + return true; } - return ret; + return false; } public bool VerifySignatureForHash( @@ -111,14 +110,13 @@ public bool VerifySignatureForHash( return false; } - bool ret = VerifyHash(hash, PkcsHelpers.GetOidFromHashAlgorithm(hashAlgorithm)); - - if (ret) + if (VerifyHash(hash, PkcsHelpers.GetOidFromHashAlgorithm(hashAlgorithm))) { signerCertificate = cert; + return true; } - return ret; + return false; } public bool VerifySignatureForHash( @@ -141,18 +139,17 @@ public bool VerifySignatureForHash( return false; } - bool ret = VerifyHash(hash, hashAlgorithmId.Value); - - if (ret) + if (VerifyHash(hash, hashAlgorithmId.Value)) { // REVIEW: Should this return the cert, or new X509Certificate2(cert.RawData)? // SignedCms.SignerInfos builds new objects each call, which makes // ReferenceEquals(cms.SignerInfos[0].Certificate, cms.SignerInfos[0].Certificate) be false. // So maybe it's weird to give back a cert we've copied from that? signerCertificate = cert; + return true; } - return ret; + return false; } public bool VerifySignatureForSignerInfo( diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/PkcsFormatReader.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/PkcsFormatReader.cs index 2d428528a91bc6..cca2ef96316cda 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/PkcsFormatReader.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/PkcsFormatReader.cs @@ -109,7 +109,7 @@ internal static bool TryReadPkcs7Der(SafeBioHandle bio, [NotNullWhen(true)] out private static bool TryReadPkcs7Der( byte[] rawData, bool single, - [NotNullWhen(true)] out ICertificatePal? certPal, + out ICertificatePal? certPal, [NotNullWhen(true)] out List? certPals) { using (SafePkcs7Handle pkcs7 = Interop.Crypto.DecodePkcs7(rawData, rawData.Length)) @@ -217,7 +217,7 @@ private static bool TryReadPkcs7( SafePkcs7Handle pkcs7, bool single, out ICertificatePal? certPal, - out List certPals) + [NotNullWhen(true)] out List certPals) { List? readPals = single ? null : new List(); @@ -237,7 +237,7 @@ private static bool TryReadPkcs7( throw new CryptographicException(SR.Cryptography_X509_PKCS7_NoSigner); } - Debug.Assert(readPals != null); // null iff single == true + Debug.Assert(readPals != null); // null if single == true for (int i = 0; i < count; i++) { @@ -274,7 +274,7 @@ private static bool TryReadPkcs12( bool single, out ICertificatePal? readPal, out List? readCerts, - [NotNullWhen(false)] out Exception? openSslException) + out Exception? openSslException) { // DER-PKCS12 OpenSslPkcs12Reader? pfx; diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/BasicConstraintsAsn.xml.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/BasicConstraintsAsn.xml.cs index abd25078a0c366..400b063f8c7398 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/BasicConstraintsAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/BasicConstraintsAsn.xml.cs @@ -13,7 +13,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct BasicConstraintsAsn { - private static readonly byte[] s_defaultCA = { 0x01, 0x01, 0x00 }; + private static ReadOnlySpan DefaultCA => new byte[] { 0x01, 0x01, 0x00 }; internal bool CA; internal int? PathLengthConstraint; @@ -24,7 +24,7 @@ static BasicConstraintsAsn() BasicConstraintsAsn decoded = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultCA, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultCA, AsnEncodingRules.DER); decoded.CA = reader.ReadBoolean(); reader.ThrowIfNotEmpty(); } @@ -47,7 +47,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) tmp.WriteBoolean(CA); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultCA)) + if (!encoded.SequenceEqual(DefaultCA)) { writer.WriteEncodedValue(encoded); } @@ -95,7 +95,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultCA, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultCA, AsnEncodingRules.DER); decoded.CA = defaultReader.ReadBoolean(); } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/TbsCertificateAsn.xml.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/TbsCertificateAsn.xml.cs index 241ba953bb7747..cdebe2a89be97d 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/TbsCertificateAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/TbsCertificateAsn.xml.cs @@ -14,7 +14,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct TbsCertificateAsn { - private static readonly byte[] s_defaultVersion = { 0x02, 0x01, 0x00 }; + private static ReadOnlySpan DefaultVersion => new byte[] { 0x02, 0x01, 0x00 }; internal int Version; internal ReadOnlyMemory SerialNumber; @@ -33,7 +33,7 @@ static TbsCertificateAsn() TbsCertificateAsn decoded = default; AsnValueReader reader; - reader = new AsnValueReader(s_defaultVersion, AsnEncodingRules.DER); + reader = new AsnValueReader(DefaultVersion, AsnEncodingRules.DER); if (!reader.TryReadInt32(out decoded.Version)) { @@ -61,7 +61,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag) tmp.WriteInteger(Version); ReadOnlySpan encoded = tmp.EncodeAsSpan(); - if (!encoded.SequenceEqual(s_defaultVersion)) + if (!encoded.SequenceEqual(DefaultVersion)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); writer.WriteEncodedValue(encoded); @@ -168,7 +168,7 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, Read } else { - defaultReader = new AsnValueReader(s_defaultVersion, AsnEncodingRules.DER); + defaultReader = new AsnValueReader(DefaultVersion, AsnEncodingRules.DER); if (!defaultReader.TryReadInt32(out decoded.Version)) { diff --git a/src/libraries/System.Text.Json/docs/ParameterizedCtorSpec.md b/src/libraries/System.Text.Json/docs/ParameterizedCtorSpec.md new file mode 100644 index 00000000000000..3ac0a9e3995734 --- /dev/null +++ b/src/libraries/System.Text.Json/docs/ParameterizedCtorSpec.md @@ -0,0 +1,593 @@ +# Deserializing objects using parameterized constructors with `JsonSerializer` + +## Motivation + +`JsonSerializer` deserializes instances of objects (`class`es and `struct`s) using public parameterless +constructors. If none is present, and deserialization is attempted, the serializer throws a `NotSupportedException` +with a message stating that objects without public parameterless constructors, including `interface`s and `abstract` +types, are not supported for deserialization. There is no way to deserialize an instance of an object using a parameterized constructor. + +A common pattern is to make data objects immutable for various reasons. For example, given `Point`: + +```C# +public struct Point +{ + public int X { get; } + + public int Y { get; } + + public Point(int x, int y) => (X, Y) = (x, y); +} +``` + +It would be beneficial if `JsonSerializer` could deserialize `Point` instances using the parameterized constructor above, given that mapping JSON properties into readonly members is not supported. + +Also consider `User`: + +```C# +public class User +{ + public string UserName { get; private set; } + + public bool Enabled { get; private set; } + + public User() { } + + public User(string userName, bool enabled) + { + UserName = userName; + Enabled = enabled; + } +} +``` + +`User` instances will be deserialized using the parameterless constructor above, and the `UserName` and `Enabled` properties will be ignored, even if there is JSON that maps to them in the payload. + +Although there is work scheduled to support deserializing JSON directly into properties with private setters +(https://github.com/dotnet/runtime/issues/29743), providing parameterized constructor support as an option +increases the scope of support for customers with varying design needs. + +Deserializing with parameterized constructors also gives the opportunity to do JSON "argument" validation once on the creation of the instance. + +This feature enables deserialization support for `Tuple<...>` instances, using their parameterized constructors. + +This feature is designed to support round-tripping of such "immutable" types. + +There are no easy workarounds for the scenarios this feature enables: + +- Support for immutable classes and structs (https://github.com/dotnet/runtime/issues/29895) +- Choosing which constructor to use +- Support for `Tuple<...>` types + +Only public constructors are supported. + +## New API Proposal + +```C# +namespace System.Text.Json.Serialization +{ + /// + /// When placed on a constructor, indicates that the constructor should be used to create + /// instances of the type on deserialization. + /// The construtor must be public. The attribute cannot be placed on multiple constructors. + /// + [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)] + public sealed partial class JsonConstructorAttribute : JsonAttribute + { + public JsonConstructorAttribute() { } + } +} +``` + +### Example usage + +Given an immutable class `Point`, + +```C# +public class Point +{ + public int X { get; } + + public int Y { get; } + + public Point() {} + + [JsonConstructor] + public Point(int x, int y) => (X, Y) = (x, y); +} +``` + +We can deserialize JSON into an instance of `Point` using `JsonSerializer`: + +```C# +Point point = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2}"); +Console.WriteLine(point.X); // 1 +Console.WriteLine(point.Y); // 2 +``` + +## Solutions by other libraries + +### `Newtonsoft.Json` (.NET) + +`Newtonsoft.Json` provides a `[JsonConstructor]` attribute that allows users to specify which constructor to use. The attribute can be applied to only one constructor, which may be non-`public`. + +`Newtonsoft.Json` also provides a globally applied +[`ConstructorHandling`](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_ConstructorHandling.htm) which determines which constructor is used if none is specified with the attribute. The options are: + +`Default`: First attempt to use the public default constructor, then fall back to a single parameterized constructor, +then to the non-`public` default constructor. + +`AllowNonPublicDefaultConstructor`: Newtonsoft.NET will use a non-`public` default constructor before falling back to a +parameterized constructor. + +Non-`public` support is not provided by `JsonSerializer` by default, so configuring selection precedence involving non-`public` constructors is not applicable. + + +### `Utf8Json` + +`Utf8Json` chooses the constructor with the most matched arguments by name (case insensitive). This best-fit matching approach can be considered by `JsonSerializer` in the future. + +The constructor to use can also be specified with a `[SerializationConstructor]` attribute. + +`Utf8Json` does not support non-`public` constructors, even with the attribute. + +### `Jil` (.NET) + +`Jil` supports deserialization exclusively by using a parameterless constructor (may be non-`public`), and doesn't provide options to configure the behavior. + +### `Jackson` (Java) + +`Jackson` provides an annotation type called +[`JsonCreator`](https://fasterxml.github.io/jackson-annotations/javadoc/2.7/com/fasterxml/jackson/annotation/JsonCreator.html) +which is very similar in functionality to the `JsonConstructor` attributes in `Newtonsoft.Json` +and proposed in this spec. + +```Java +@JsonCreator +public BeanWithCreator( + @JsonProperty("id") int id, + @JsonProperty("theName") String name) { + this.id = id; + this.name = name; +} +``` + +As shown, a `@JsonProperty` annotation can be placed on a parameter to indicate the JSON name. Adding +`JsonParameterName` attribute to be placed on constructor parameters was considered, but `Newtonsoft.Json` does not have an equivalent for this. There's probably not a big customer need for this behavior. + +In addition to constructors, the `JsonCreator` can be applied to factory creator methods. There +hasn't been any demand for this from the .NET community. Support for object deserialization with factory +creation methods can be considered in the future. + +## Feature behavior + +### Attribute presence + +#### Without `[JsonConstructor]` + +##### A public parameterless constructor will always be used if present + +Given `Point`, + +```C# +public class Point +{ + public int X { get; } + + public int Y { get; } + + public Point() {} + + public Point(int x, int y) => (X, Y) = (x, y); +} +``` + +The public parameterless constructor is used: + +```C# +Point point = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2}"); +Console.WriteLine(point.X); // 0 +Console.WriteLine(point.Y); // 0 +``` + +##### `struct`s will always be deserialized using the default constructor if `[JsonConstructor]` is not used + +Given `Point`, + +```C# +public struct Point +{ + public int X { get; } + + public int Y { get; } + + public Point(int x, int y) => (X, Y) = (x, y); +} +``` + +The default constructor is used: + +```C# +Point point = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2}"); +Console.WriteLine(point.X); // 0 +Console.WriteLine(point.Y); // 0 +``` + +##### A single public parameterized constructor will always be used if there's no public parameterless constructor + +Given `Point`, + +```C# +public class Point +{ + public int X { get; } + + public int Y { get; } + + public Point(int x, int y) => (X, Y) = (x, y); +} +``` + +The singular parameterized constructor is used: + +```C# +Point point = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2}"); +Console.WriteLine(point.X); // 1 +Console.WriteLine(point.Y); // 2 +``` + +This rule does not apply to `struct`s as there's always a public parameterless constructor. + +##### `NotSupportedException` is thrown when there are multiple parameterized ctors, but no public parameterless ctor + +Given another definition for `Point`, + +```C# +public class Point +{ + public int X { get; } + + public int Y { get; } + + public int Z { get; } + + public Point(int x, int y) => (X, Y) = (x, y); + + public Point(int x, int y, int z = 3) => (X, Y, Z) = (x, y, z); +} +``` + +A `NotSupportedException` is thrown because it is not clear which constructor to use. This may be resolved by using the `[JsonConstructor]`, or by adding a +public parameterless constructor. + +```C# +Point point = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2,""Z"":3}"); // Throws `NotSupportedException` +``` + +This rule does not apply to `struct`s as there's always a public parameterless constructor. + +#### Using [JsonConstructor] + +##### `[JsonConstructor]` can only be used on one constructor + +Given `Point`, + +```C# +public class Point +{ + public int X { get; } + + public int Y { get; } + + public int Z { get; } + + [JsonConstructor] + public Point() {} + + [JsonConstructor] + public Point(int x, int y) => (X, Y) = (x, y); +} +``` + +An `InvalidOperationException` is thrown: + +```C# +Point point = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2,""Z"":3}"); // Throws `InvalidOperationException` +``` + +### Parameter name matching + +#### Constructor parameters that bind to object properties will use their Json property names for deserialization. + +Each property's CLR name will be converted with the `camelCase` naming policy to find its matching constructor parameter. The constructor parameter will use the cached JSON property name to find a match on deserialization, and the object property will be ignored on deserialization. + +This matching mechanism is optimized for object definitions that follow the +C# guidelines for naming properties and method parameters. + +This proposal does not include an extension point for users to specify a policy to determine the match, but it can be considered in the future. + +Consider `Point`: + +```C# +public class Point +{ + public int X { get; } + + public int Y { get; } + + public Point(int x, int y) => (X, Y) = (x, y); +} +``` + +The `int X` property matches with the `int x` parameter, and the `int Y` property matches with the `int y` property. +With default serializer options, the properties would normally match with their exact pascal case representations. The +constructor arguments will be configured to bind with the JSON instead: + +```C# +Point point = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2}"); + +Console.WriteLine(point.X); // 1 +Console.WriteLine(point.Y); // 2 +``` + +This means that the JSON property name(s) specified for each property will be properly applied to each +matching parameter constructor. ASP.NET default settings of `camelCase` casing (and case-insensitivity) will work fine without needing extra configuration. + +The benefit of this approach is that a `JsonPropertyName` attribute placed on a property would be honored by its matching constructor parameter on deserialziation, +enabling roundtripping scenarios: + +```C# +public class Point +{ + [JsonPropertyName("XValue")] + public int X { get; } + + [JsonPropertyName("YValue")] + public int Y { get; } + + public Point(int x, int y) => (X, Y) = (x, y); +} +``` + +```C# +Point point = new Point(1,2); + +string json = JsonSerializer.Serialize(point); +Console.WriteLine(json); // {"XValue":1,"YValue":2} + +point = JsonSerializer.Deserialize(json); +Console.WriteLine(point.X); // 1 +Console.WriteLine(point.Y); // 2 +``` + +**If a constructor parameter does not match with a property, `InvalidOperationException` will be thrown if deserialization is attempted.** + +**Parameter naming matching is case sensitive by default**. This can be toggled by users with the `options.PropertyNameCaseInsensitive` option. + +**Constructor argument deserialization will honor the `[JsonPropertyName]`, `[JsonIgnore]`, and `[JsonConverter]` attributes placed on the matching object property.** + +#### If no JSON maps to a constructor parameter, then default values are used. + +This is consistent with `Newtonsoft.Json`. If no JSON maps to a constructor parameter, the following fallbacks are used in order: + +- default value on constructor parameter +- CLR `default` value for the parameter type + +Given `Person`, + +```C# +public struct Person +{ + + public string Name { get; } + + public int Age { get; } + + public Point Point { get; } + + public Person(string name, int age, Point point = new Point(1, 2)) + { + Name = name; + Age = age; + Point = point; + } +} +``` + +When there are no matches for a constructor parameter, a default value is used: + +```C# +Person person = JsonSerializer.Deserialize("{}"); +Console.WriteLine(person.Name); // null +Console.WriteLine(person.Age); // 0 +Console.WriteLine(person.Point.X); 1 +Console.WriteLine(person.Point.Y); 2 +``` + +#### Members are never set with JSON properties that matched with constructor parameters + +Doing this can override modifications done in constructor. `Newtonsoft.Json` has the same behavior. + +Given `Point`, + +```C# +public struct Point +{ + public int X { get; set; } + + public int Y { get; set; } + + [JsonConstructor] + public Point(int x, int y) + { + X = 40; + Y = 60; + } +} +``` + +We can expect the following behavior: + +```C# +Point obj = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2}"); +Assert.Equal(40, obj.X); // Would be 1 if property were set directly after object construction. +Assert.Equal(60, obj.Y); // Would be 2 if property were set directly after object construction. +``` + +This behavior also applies to property name matches (from JSON properties to object properties) due +to naming policy. + +#### JSON properties that don't map to constructor parameters or object properties go to extension data, if present + +This is in keeping with the established serializer handling of extension data. + +#### Serializer uses "last one wins" semantics for constructor parameter names + +This is consistent with how object properties are deserialized. + +```C# +Point point = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2,""X"":4}"); +Assert.Equal(4, point.X); // Note, the value isn't 1. +Assert.Equal(2, point.Y); +``` + +The serializer will not store any extra JSON values that map to constructor arguments in extension data. + +Given `Person: + +```C# +public class Person +{ + public string FirstName { get; set; } + + public string LastName { get; set; } + + public Guid Id { get; } + + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } + + public Person(Guid id) => Id = id; +} +``` + +We can expect the following behavior with `JsonSerializer`: + +```C# +string json = @"{ + ""FirstName"":""Jet"", + ""Id"":""270bb22b-4816-4bd9-9acd-8ec5b1a896d3"", + ""EmailAddress"":""jetdoe@outlook.com"", + ""Id"":""0b3aa420-2e98-47f7-8a49-fea233b89416"", + ""LastName"":""Doe"", + ""Id"":""63cf821d-fd47-4782-8345-576d9228a534"" + }"; + +Person person = JsonSerializer.Deserialize(json); +Console.WriteLine(person.FirstName); // Jet +Console.WriteLine(person.LastName); // Doe +Console.WriteLine(person.Id); // 63cf821d-fd47-4782-8345-576d9228a534 (note that the first matching JSON property "won") +Console.WriteLine(person.ExtensionData["EmailAddress"].GetString()); // jetdoe@outlook.com +Console.WriteLine(person.ExtensionData.ContainsKey("Id")); // False +``` + +This is consistent with `Newtonsoft.Json` behavior. + +#### `options.IgnoreNullValues` is honored when deserializing constructor arguments + +This is helpful to avoid a `JsonException` when null is applied to value types. + +Given `PointWrapper` and `Point_3D`: + +```C# +public class PointWrapper +{ + public Point_3D Point { get; } + + public PointWrapper(Point_3D point) {} +} + +public struct Point_3D +{ + public int X { get; } + + public int Y { get; } + + public int Z { get; } +} +``` + +We can ignore `null` tokens and not pass them as arguments to a non-nullable parameter. A default value will be passed instead. + The behavior if the serializer does not honor the `IgnoreNullValue` option would be to preemptively throw a `JsonException`, rather than leaking an `InvalidCastException` thrown by the CLR. + +```C# +JsonSerializerOptions options = new JsonSerializerOptions +{ + IgnoreNullValues = true +}; +PointWrapper obj = JsonSerializer.Deserialize(@"{""Point"":null}"); // obj.Point is `default` +``` + +In the same scenario, `Newtonsoft.Json` fails with error: + +```C# +JsonSerializerSettings settings = new JsonSerializerSettings { NullValueHandling = true }; +PointWrapper obj = JsonConvert.DeserializeObject(@"{""Point"":null}"); + +// Unhandled exception. Newtonsoft.Json.JsonSerializationException: Error converting value {null} to type 'Program+Point_3D'. Path 'Point', line 1, position 21. +``` + +#### Specified constructors cannot have more than 64 parameters + +This is an implementation detail. If deserialization is attempted with a constructor that has more than +64 parameters, a `NotSupportedException` will be thrown. + +We expect most users to have significantly less than 64 parameters, but we can respond to user feedback. + +#### [`ReferenceHandling` semantics](https://github.com/dotnet/runtime/blob/13c1e65a9f7aab201fe77e3daba11946aeb7cbaa/src/libraries/System.Text.Json/docs/ReferenceHandling_spec.md) will not be applied to objects deserialized with parameterized constructors + +`NotSupportedException` will be thrown if any properties named "$id", "$ref", or "$values" are found in the payload, and `options.ReferenceHandling` is set to +`ReferenceHandling.Preserve`. If the feature is off, these properties will be treated like any other (likely end up in extension data property). +This behavior prevents us from breaking people if we implement this feature in the future. + +`Newtonsoft.Json` does not not honor reference metadata within objects deserialized with parameterized constructors. They are ignored and treated like any other property. + +Consider an `Employee` class: + +```C# +public class Employee +{ + public string FullName { get; set; } + + public Employee Manager { get; internal set; } + + public Employee(Employee manager = null) + { + Manager = manager; + } +} +``` + +Serializing an `Employee` instance with `ReferenceHandling.Preserve` semantics may look like this: + +```C# +Employee employee = new Employee(); +employee.FullName = "Jet Doe"; +employee.Manager = employee; + +JsonSerializerOptions options = new JsonSerializerOptions +{ + ReferenceHandling = ReferenceHandling.Preserve +}; + +string json = JsonSerializer.Serialize(employee, options); +Console.WriteLine(json); // {"$id":"1","Manager":{"$ref":"1"},"FullName":"Jet Doe"} +``` + +It might be non-trivial work to resolve such scenarios on deserialization and handle error cases. + +### Deserialization with parameterized constructor does not apply to enumerables + +The semantics described in this document does not apply to any type that implements `IEnumerable`. +This may change in the future, particularly if an +[option to treat enumerables as objects](https://github.com/dotnet/runtime/issues/1808) with members is provided. diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 135345f8e856c7..e7ef98216e31c5 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -753,6 +753,11 @@ protected internal JsonConverter() { } public abstract T Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options); public abstract void Write(System.Text.Json.Utf8JsonWriter writer, [System.Diagnostics.CodeAnalysis.DisallowNull] T value, System.Text.Json.JsonSerializerOptions options); } + [System.AttributeUsageAttribute(System.AttributeTargets.Constructor, AllowMultiple = false)] + public sealed partial class JsonConstructorAttribute : System.Text.Json.Serialization.JsonAttribute + { + public JsonConstructorAttribute() { } + } [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false)] public sealed partial class JsonExtensionDataAttribute : System.Text.Json.Serialization.JsonAttribute { diff --git a/src/libraries/System.Text.Json/src/Resources/Strings.resx b/src/libraries/System.Text.Json/src/Resources/Strings.resx index 11363d9fa5e01e..167f357d124499 100644 --- a/src/libraries/System.Text.Json/src/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/src/Resources/Strings.resx @@ -375,8 +375,8 @@ Comments cannot be stored when deserializing objects, only the Skip and Disallow comment handling modes are supported. - - Deserialization of reference types without parameterless constructor is not supported. Type '{0}' + + Deserialization of reference types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with '{0}' is not supported. Type '{1}' Deserialization of interface types is not supported. Type '{0}' @@ -482,10 +482,25 @@ Properties that start with '$' are not allowed on preserve mode, either escape the character or turn off preserve references by setting ReferenceHandling to ReferenceHandling.Default. + + Members '{0}' and '{1}' on type '{2}' cannot both bind with parameter '{3}' in constructor '{4}' on deserialization. + + + Each parameter in constructor '{0}' on type '{1}' must bind to an object member on deserialization. Each parameter name must be the camel case equivalent of an object member named with the pascal case naming convention. + + + The constructor '{0}' on type '{1}' may not have more than 64 parameters for deserialization. + + + Reference metadata is not honored when deserializing types using parameterized constructors. See type '{0}'. + The converter '{0}' cannot return a null value. The unsupported member type is located on type '{0}'. + + The extension data property '{0}' on type '{1}' cannot bind with a parameter in constructor '{2}'. + \ No newline at end of file diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 461572bf70c7e9..39786bdc4a4b12 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -1,4 +1,4 @@ - + true $(OutputPath)$(MSBuildProjectName).xml @@ -53,7 +53,9 @@ + + @@ -80,6 +82,9 @@ + + + @@ -111,9 +116,10 @@ - + + @@ -127,6 +133,8 @@ + + @@ -151,6 +159,7 @@ + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs index 9a1805c3706e74..1d13e73cdda8dd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs @@ -98,5 +98,12 @@ internal static class JsonConstants public const int LowSurrogateStartValue = 0xDC00; public const int LowSurrogateEndValue = 0xDFFF; public const int BitShiftBy10 = 0x400; + + // The maximum number of parameters a constructor can have where it can be considered + // for a path on deserialization where we don't box the constructor arguments. + public const int UnboxedParameterCountThreshold = 4; + + // The maximum number of parameters a constructor can have where it can be supported. + public const int MaxParameterCount = 64; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.Unescaping.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.Unescaping.cs index 0f0c7711f02940..62c0410bcea487 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.Unescaping.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderHelper.Unescaping.cs @@ -25,14 +25,13 @@ public static bool TryGetUnescapedBase64Bytes(ReadOnlySpan utf8Source, int utf8Unescaped = utf8Unescaped.Slice(0, written); Debug.Assert(!utf8Unescaped.IsEmpty); - bool result = TryDecodeBase64InPlace(utf8Unescaped, out bytes); + bool result = TryDecodeBase64InPlace(utf8Unescaped, out bytes!); if (unescapedArray != null) { utf8Unescaped.Clear(); ArrayPool.Shared.Return(unescapedArray); } - return result; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ArgumentState.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ArgumentState.cs new file mode 100644 index 00000000000000..71f4d2f68dbe0c --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ArgumentState.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +using FoundProperties = System.ValueTuple; +using FoundPropertiesAsync = System.ValueTuple; + +namespace System.Text.Json +{ + /// + /// Holds relevant state when deserializing objects with parameterized constructors. + /// Lives on the current ReadStackFrame. + /// + internal class ArgumentState + { + // Cache for parsed constructor arguments. + public object Arguments = null!; + + // When deserializing objects with parameterized ctors, the properties we find on the first pass. + public FoundProperties[]? FoundProperties; + + // When deserializing objects with parameterized ctors asynchronously, the properties we find on the first pass. + public FoundPropertiesAsync[]? FoundPropertiesAsync; + public int FoundPropertyCount; + + // Current constructor parameter value. + public JsonParameterInfo? JsonParameterInfo; + + // For performance, we order the parameters by the first deserialize and PropertyIndex helps find the right slot quicker. + public int ParameterIndex; + public List? ParameterRefCache; + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Arguments.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Arguments.cs new file mode 100644 index 00000000000000..2d4c7375d5abee --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Arguments.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Text.Json +{ + /// + /// Constructor arguments for objects with parameterized ctors with less than 5 parameters. + /// This is to avoid boxing for small, immutable objects. + /// + internal sealed class Arguments + { + public TArg0 Arg0 = default!; + public TArg1 Arg1 = default!; + public TArg2 Arg2 = default!; + public TArg3 Arg3 = default!; + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ICollectionOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ICollectionOfTConverter.cs index 67600151d0cc34..7fb4f32449d584 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ICollectionOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ICollectionOfTConverter.cs @@ -28,7 +28,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = new List(); @@ -37,7 +37,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryConverter.cs index 5702bd2da362a7..6bc612fdf1af38 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryConverter.cs @@ -32,7 +32,7 @@ protected override void CreateCollection(ref ReadStack state) { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = new Dictionary(); @@ -41,7 +41,7 @@ protected override void CreateCollection(ref ReadStack state) { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryOfStringTValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryOfStringTValueConverter.cs index fd912fa799b1d9..63c329e1ed3de1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryOfStringTValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryOfStringTValueConverter.cs @@ -31,7 +31,7 @@ protected override void CreateCollection(ref ReadStack state) { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = new Dictionary(); @@ -40,7 +40,7 @@ protected override void CreateCollection(ref ReadStack state) { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverter.cs index af72f48957ecd3..72db89fa02c950 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverter.cs @@ -26,7 +26,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = new List(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableOfTConverter.cs index 21045a86e10ddb..8dd71331bdb6e6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableOfTConverter.cs @@ -25,7 +25,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = new List(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs index ab11eca64f3203..cff243c13fbea3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs @@ -24,7 +24,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti if (constructorDelegate == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = constructorDelegate(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListConverter.cs index b33a217ca58b11..cee12dc48df44e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListConverter.cs @@ -27,7 +27,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = new List(); @@ -36,7 +36,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListOfTConverter.cs index a682d0e0510bf5..fa61b4abd88147 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListOfTConverter.cs @@ -28,7 +28,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = new List(); @@ -37,7 +37,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IReadOnlyDictionaryOfStringTValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IReadOnlyDictionaryOfStringTValueConverter.cs index 74b70802ea022c..0517525343c5fb 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IReadOnlyDictionaryOfStringTValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IReadOnlyDictionaryOfStringTValueConverter.cs @@ -23,7 +23,7 @@ protected override void CreateCollection(ref ReadStack state) { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = new Dictionary(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ISetOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ISetOfTConverter.cs index 02b77ad099e008..f0fcd783e04f6c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ISetOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ISetOfTConverter.cs @@ -25,7 +25,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } state.Current.ReturnValue = new HashSet(); @@ -34,7 +34,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectConverterFactory.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectConverterFactory.cs index 431c6fd75d3d3a..813969989e32f9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectConverterFactory.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectConverterFactory.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Diagnostics; using System.Reflection; +using System.Runtime.CompilerServices; namespace System.Text.Json.Serialization.Converters { @@ -21,16 +22,117 @@ public override bool CanConvert(Type typeToConvert) return true; } + [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1")] + [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.LargeObjectWithParameterizedConstructorConverter`1")] + [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.SmallObjectWithParameterizedConstructorConverter`5")] public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { - JsonConverter converter = (JsonConverter)Activator.CreateInstance( - typeof(ObjectDefaultConverter<>).MakeGenericType(typeToConvert), - BindingFlags.Instance | BindingFlags.Public, - binder: null, - args: null, - culture: null)!; + JsonConverter converter; + Type converterType; + ConstructorInfo? constructor = GetDeserializationConstructor(typeToConvert); + ParameterInfo[]? parameters = constructor?.GetParameters(); + + if (constructor == null || typeToConvert.IsAbstract || parameters!.Length == 0) + { + converterType = typeof(ObjectDefaultConverter<>).MakeGenericType(typeToConvert); + } + else + { + int parameterCount = parameters.Length; + + if (parameterCount <= JsonConstants.UnboxedParameterCountThreshold) + { + Type placeHolderType = typeof(object); + Type[] typeArguments = new Type[JsonConstants.UnboxedParameterCountThreshold + 1]; + + typeArguments[0] = typeToConvert; + for (int i = 0; i < JsonConstants.UnboxedParameterCountThreshold; i++) + { + if (i < parameterCount) + { + typeArguments[i + 1] = parameters[i].ParameterType; + } + else + { + // Use placeholder arguments if there are less args than the threshold. + typeArguments[i + 1] = placeHolderType; + } + } + + converterType = typeof(SmallObjectWithParameterizedConstructorConverter<,,,,>).MakeGenericType(typeArguments); + } + else + { + converterType = typeof(LargeObjectWithParameterizedConstructorConverter<>).MakeGenericType(typeToConvert); + } + } + + converter = (JsonConverter)Activator.CreateInstance( + converterType, + BindingFlags.Instance | BindingFlags.Public, + binder: null, + args: null, + culture: null)!; + + converter.ConstructorInfo = constructor!; return converter; } + + private ConstructorInfo? GetDeserializationConstructor(Type type) + { + ConstructorInfo? ctorWithAttribute = null; + ConstructorInfo? publicParameterlessCtor = null; + ConstructorInfo? lonePublicCtor = null; + + ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance); + + if (constructors.Length == 1) + { + lonePublicCtor = constructors[0]; + } + + foreach (ConstructorInfo constructor in constructors) + { + if (constructor.GetCustomAttribute() != null) + { + if (ctorWithAttribute != null) + { + ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(type); + } + + ctorWithAttribute = constructor; + } + else if (constructor.GetParameters().Length == 0) + { + publicParameterlessCtor = constructor; + } + } + + // For correctness, throw if multiple ctors have [JsonConstructor], even if one or more are non-public. + ConstructorInfo? dummyCtorWithAttribute = ctorWithAttribute; + + constructors = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance); + foreach (ConstructorInfo constructor in constructors) + { + if (constructor.GetCustomAttribute() != null) + { + if (dummyCtorWithAttribute != null) + { + ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(type); + } + + dummyCtorWithAttribute = constructor; + } + } + + // Structs will use default constructor if attribute isn't used. + if (type.IsValueType && ctorWithAttribute == null) + { + return null; + } + + return ctorWithAttribute ?? publicParameterlessCtor ?? lonePublicCtor; + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs index 0c2d13974e892b..640088d64e2bb6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs @@ -10,7 +10,7 @@ namespace System.Text.Json.Serialization.Converters /// /// Default base class implementation of JsonObjectConverter{T}. /// - internal sealed class ObjectDefaultConverter : JsonObjectConverter where T : notnull + internal class ObjectDefaultConverter : JsonObjectConverter where T : notnull { internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNullWhen(false)] out T value) { @@ -28,7 +28,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, if (state.Current.JsonClassInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(state.Current.JsonClassInfo.Type); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(state.Current.JsonClassInfo.Type); } obj = state.Current.JsonClassInfo.CreateObject!()!; @@ -40,15 +40,14 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, reader.ReadWithVerify(); JsonTokenType tokenType = reader.TokenType; + if (tokenType == JsonTokenType.EndObject) { break; } - if (tokenType != JsonTokenType.PropertyName) - { - ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); - } + // Read method would have thrown if otherwise. + Debug.Assert(tokenType == JsonTokenType.PropertyName); JsonPropertyInfo jsonPropertyInfo = JsonSerializer.LookupProperty( obj, @@ -57,28 +56,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, ref state, out bool useExtensionProperty); - // Skip the property if not found. - if (!jsonPropertyInfo.ShouldDeserialize) - { - reader.Skip(); - state.Current.EndProperty(); - continue; - } - - // Set the property value. - reader.ReadWithVerify(); - - if (!useExtensionProperty) - { - jsonPropertyInfo.ReadJsonAndSetMember(obj, ref state, ref reader); - } - else - { - jsonPropertyInfo.ReadJsonAndAddExtensionProperty(obj, ref state, ref reader); - } - - // Ensure any exception thrown in the next read does not have a property in its JsonPath. - state.Current.EndProperty(); + ReadPropertyValue(obj, ref state, ref reader, jsonPropertyInfo, useExtensionProperty); } } else @@ -122,7 +100,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, { if (state.Current.JsonClassInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(state.Current.JsonClassInfo.Type); + ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(state.Current.JsonClassInfo.Type); } obj = state.Current.JsonClassInfo.CreateObject!()!; @@ -169,13 +147,11 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonTokenType tokenType = reader.TokenType; if (tokenType == JsonTokenType.EndObject) { - // We are done reading properties. break; } - else if (tokenType != JsonTokenType.PropertyName) - { - ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); - } + + // Read method would have thrown if otherwise. + Debug.Assert(tokenType == JsonTokenType.PropertyName); jsonPropertyInfo = JsonSerializer.LookupProperty( obj, @@ -207,27 +183,11 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, continue; } - // Returning false below will cause the read-ahead functionality to finish the read. - state.Current.PropertyState = StackFramePropertyState.ReadValue; - - if (!state.Current.UseExtensionProperty) + if (!ReadAheadPropertyValue(ref state, ref reader, jsonPropertyInfo)) { - if (!SingleValueReadWithReadAhead(jsonPropertyInfo.ConverterBase.ClassType, ref reader, ref state)) - { - state.Current.ReturnValue = obj; - value = default; - return false; - } - } - else - { - // The actual converter is JsonElement, so force a read-ahead. - if (!SingleValueReadWithReadAhead(ClassType.Value, ref reader, ref state)) - { - state.Current.ReturnValue = obj; - value = default; - return false; - } + state.Current.ReturnValue = obj; + value = default; + return false; } } @@ -270,7 +230,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, return true; } - internal override bool OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state) + internal sealed override bool OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state) { // Minimize boxing for structs by only boxing once here object objectValue = value!; @@ -396,5 +356,60 @@ internal override bool OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializer return true; } } + + protected void ReadPropertyValue( + object obj, + ref ReadStack state, + ref Utf8JsonReader reader, + JsonPropertyInfo jsonPropertyInfo, + bool useExtensionProperty) + { + // Skip the property if not found. + if (!jsonPropertyInfo.ShouldDeserialize) + { + reader.Skip(); + } + else + { + // Set the property value. + reader.ReadWithVerify(); + + if (!useExtensionProperty) + { + jsonPropertyInfo.ReadJsonAndSetMember(obj, ref state, ref reader); + } + else + { + jsonPropertyInfo.ReadJsonAndAddExtensionProperty(obj, ref state, ref reader); + } + } + + // Ensure any exception thrown in the next read does not have a property in its JsonPath. + state.Current.EndProperty(); + } + + protected bool ReadAheadPropertyValue(ref ReadStack state, ref Utf8JsonReader reader, JsonPropertyInfo jsonPropertyInfo) + { + // Returning false below will cause the read-ahead functionality to finish the read. + state.Current.PropertyState = StackFramePropertyState.ReadValue; + + if (!state.Current.UseExtensionProperty) + { + if (!SingleValueReadWithReadAhead(jsonPropertyInfo.ConverterBase.ClassType, ref reader, ref state)) + { + return false; + } + } + else + { + // The actual converter is JsonElement, so force a read-ahead. + if (!SingleValueReadWithReadAhead(ClassType.Value, ref reader, ref state)) + { + return false; + } + } + + return true; + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Large.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Large.cs new file mode 100644 index 00000000000000..f4fabaf4a588c5 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Large.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; + +namespace System.Text.Json.Serialization.Converters +{ + /// + /// Implementation of JsonObjectConverter{T} that supports the deserialization + /// of JSON objects using parameterized constructors. + /// + internal sealed class LargeObjectWithParameterizedConstructorConverter : ObjectWithParameterizedConstructorConverter where T : notnull + { + private JsonClassInfo.ParameterizedConstructorDelegate? _createObject; + + internal override void CreateConstructorDelegate(JsonSerializerOptions options) + { + _createObject = options.MemberAccessorStrategy.CreateParameterizedConstructor(ConstructorInfo)!; + } + + protected override bool ReadAndCacheConstructorArgument(ref ReadStack state, ref Utf8JsonReader reader, JsonParameterInfo jsonParameterInfo) + { + bool success = jsonParameterInfo.ReadJson(ref state, ref reader, out object? arg0); + + if (success) + { + ((object[])state.Current.CtorArgumentState!.Arguments!)[jsonParameterInfo.Position] = arg0!; + } + + return success; + } + + protected override object CreateObject(ref ReadStackFrame frame) + { + object[] arguments = (object[])frame.CtorArgumentState!.Arguments!; + + if (_createObject == null) + { + // This means this constructor has more than 64 parameters. + ThrowHelper.ThrowNotSupportedException_ConstructorMaxOf64Parameters(ConstructorInfo, TypeToConvert); + } + + object obj = _createObject(arguments)!; + + ArrayPool.Shared.Return(arguments, clearArray: true); + return obj; + } + + protected override void InitializeConstructorArgumentCaches(ref ReadStack state, JsonSerializerOptions options) + { + object[] arguments = ArrayPool.Shared.Rent(state.Current.JsonClassInfo.ParameterCount); + foreach (JsonParameterInfo jsonParameterInfo in state.Current.JsonClassInfo.ParameterCache!.Values) + { + if (jsonParameterInfo.ShouldDeserialize) + { + arguments[jsonParameterInfo.Position] = jsonParameterInfo.DefaultValue!; + } + } + + state.Current.CtorArgumentState!.Arguments = arguments; + } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Small.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Small.cs new file mode 100644 index 00000000000000..fb852b81ad88d0 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Small.cs @@ -0,0 +1,107 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace System.Text.Json.Serialization.Converters +{ + /// + /// Implementation of JsonObjectConverter{T} that supports the deserialization + /// of JSON objects using parameterized constructors. + /// + internal sealed class SmallObjectWithParameterizedConstructorConverter : ObjectWithParameterizedConstructorConverter where T : notnull + { + private JsonClassInfo.ParameterizedConstructorDelegate? _createObject; + + internal override void CreateConstructorDelegate(JsonSerializerOptions options) + { + _createObject = options.MemberAccessorStrategy.CreateParameterizedConstructor(ConstructorInfo)!; + } + + protected override object CreateObject(ref ReadStackFrame frame) + { + var arguments = (Arguments)frame.CtorArgumentState!.Arguments!; + return _createObject!(arguments.Arg0, arguments.Arg1, arguments.Arg2, arguments.Arg3)!; + } + + protected override bool ReadAndCacheConstructorArgument(ref ReadStack state, ref Utf8JsonReader reader, JsonParameterInfo jsonParameterInfo) + { + Debug.Assert(state.Current.CtorArgumentState!.Arguments != null); + var arguments = (Arguments)state.Current.CtorArgumentState.Arguments; + + bool success; + + switch (jsonParameterInfo.Position) + { + case 0: + success = ((JsonParameterInfo)jsonParameterInfo).ReadJsonTyped(ref state, ref reader, out TArg0 arg0); + if (success) + { + arguments.Arg0 = arg0; + } + break; + case 1: + success = ((JsonParameterInfo)jsonParameterInfo).ReadJsonTyped(ref state, ref reader, out TArg1 arg1); + if (success) + { + arguments.Arg1 = arg1; + } + break; + case 2: + success = ((JsonParameterInfo)jsonParameterInfo).ReadJsonTyped(ref state, ref reader, out TArg2 arg2); + if (success) + { + arguments.Arg2 = arg2; + } + break; + case 3: + success = ((JsonParameterInfo)jsonParameterInfo).ReadJsonTyped(ref state, ref reader, out TArg3 arg3); + if (success) + { + arguments.Arg3 = arg3; + } + break; + default: + Debug.Fail("This should never happen."); + throw new InvalidOperationException(); + } + + return success; + } + + protected override void InitializeConstructorArgumentCaches(ref ReadStack state, JsonSerializerOptions options) + { + var arguments = new Arguments(); + + foreach (JsonParameterInfo parameterInfo in state.Current.JsonClassInfo.ParameterCache!.Values) + { + if (parameterInfo.ShouldDeserialize) + { + int position = parameterInfo.Position; + + switch (position) + { + case 0: + arguments.Arg0 = ((JsonParameterInfo)parameterInfo).TypedDefaultValue!; + break; + case 1: + arguments.Arg1 = ((JsonParameterInfo)parameterInfo).TypedDefaultValue!; + break; + case 2: + arguments.Arg2 = ((JsonParameterInfo)parameterInfo).TypedDefaultValue!; + break; + case 3: + arguments.Arg3 = ((JsonParameterInfo)parameterInfo).TypedDefaultValue!; + break; + default: + Debug.Fail("We should never get here."); + break; + } + } + } + + state.Current.CtorArgumentState!.Arguments = arguments; + } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs new file mode 100644 index 00000000000000..40424126c11520 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs @@ -0,0 +1,496 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +using FoundProperties = System.ValueTuple; +using FoundPropertiesAsync = System.ValueTuple; + +namespace System.Text.Json.Serialization.Converters +{ + /// + /// Implementation of JsonObjectConverter{T} that supports the deserialization + /// of JSON objects using parameterized constructors. + /// + internal abstract partial class ObjectWithParameterizedConstructorConverter : ObjectDefaultConverter where T : notnull + { + internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNullWhen(false)] out T value) + { + bool shouldReadPreservedReferences = options.ReferenceHandling.ShouldReadPreservedReferences(); + object obj; + + if (!state.SupportContinuation && !shouldReadPreservedReferences) + { + // Fast path that avoids maintaining state variables and dealing with preserved references. + + ReadOnlySpan originalSpan = reader.OriginalSpan; + + ReadConstructorArguments(ref state, ref reader, options); + + obj = CreateObject(ref state.Current); + + if (state.Current.PropertyIndex > 0) + { + Utf8JsonReader tempReader; + + for (int i = 0; i < state.Current.PropertyIndex; i++) + { + JsonPropertyInfo jsonPropertyInfo = state.Current.CtorArgumentState!.FoundProperties![i].Item1; + long resumptionByteIndex = state.Current.CtorArgumentState.FoundProperties[i].Item3; + byte[]? propertyNameArray = state.Current.CtorArgumentState.FoundProperties[i].Item4; + string? dataExtKey = state.Current.CtorArgumentState.FoundProperties[i].Item5; + + tempReader = new Utf8JsonReader( + originalSpan.Slice(checked((int)resumptionByteIndex)), + isFinalBlock: true, + state: state.Current.CtorArgumentState.FoundProperties[i].Item2); + + Debug.Assert(tempReader.TokenType == JsonTokenType.PropertyName); + + state.Current.JsonPropertyName = propertyNameArray; + state.Current.JsonPropertyInfo = jsonPropertyInfo; + + bool useExtensionProperty = dataExtKey != null; + + if (useExtensionProperty) + { + Debug.Assert(jsonPropertyInfo == state.Current.JsonClassInfo.DataExtensionProperty); + state.Current.JsonPropertyNameAsString = dataExtKey; + JsonSerializer.CreateDataExtensionProperty(obj, jsonPropertyInfo); + } + + ReadPropertyValue(obj, ref state, ref tempReader, jsonPropertyInfo, useExtensionProperty); + } + + ArrayPool.Shared.Return(state.Current.CtorArgumentState!.FoundProperties!, clearArray: true); + } + } + else + { + // Slower path that supports continuation and preserved references. + + if (state.Current.ObjectState == StackFrameObjectState.None) + { + state.Current.ObjectState = StackFrameObjectState.StartToken; + BeginRead(ref state, ref reader, options); + } + + if (!ReadConstructorArgumentsWithContinuation(ref state, ref reader, options)) + { + value = default; + return false; + } + + obj = CreateObject(ref state.Current); + + if (state.Current.CtorArgumentState!.FoundPropertyCount > 0) + { + // Set the properties we've parsed so far. + for (int i = 0; i < state.Current.CtorArgumentState!.FoundPropertyCount; i++) + { + JsonPropertyInfo jsonPropertyInfo = state.Current.CtorArgumentState!.FoundPropertiesAsync![i].Item1; + object? propValue = state.Current.CtorArgumentState!.FoundPropertiesAsync![i].Item2; + string? dataExtKey = state.Current.CtorArgumentState!.FoundPropertiesAsync![i].Item3; + + if (dataExtKey == null) + { + jsonPropertyInfo.SetValueAsObject(obj, propValue); + } + else + { + Debug.Assert(jsonPropertyInfo == state.Current.JsonClassInfo.DataExtensionProperty); + + JsonSerializer.CreateDataExtensionProperty(obj, jsonPropertyInfo); + object extDictionary = jsonPropertyInfo.GetValueAsObject(obj)!; + + if (extDictionary is IDictionary dict) + { + dict[dataExtKey] = (JsonElement)propValue!; + } + else + { + ((IDictionary)extDictionary)[dataExtKey] = propValue!; + } + } + } + + ArrayPool.Shared.Return(state.Current.CtorArgumentState!.FoundPropertiesAsync!, clearArray: true); + } + } + + // Check if we are trying to build the sorted cache. + if (state.Current.PropertyRefCache != null) + { + state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current); + } + + // Check if we are trying to build the sorted parameter cache. + if (state.Current.CtorArgumentState!.ParameterRefCache != null) + { + state.Current.JsonClassInfo.UpdateSortedParameterCache(ref state.Current); + } + + value = (T)obj; + + return true; + } + + protected abstract void InitializeConstructorArgumentCaches(ref ReadStack state, JsonSerializerOptions options); + + protected abstract bool ReadAndCacheConstructorArgument(ref ReadStack state, ref Utf8JsonReader reader, JsonParameterInfo jsonParameterInfo); + + protected abstract object CreateObject(ref ReadStackFrame frame); + + /// + /// Performs a full first pass of the JSON input and deserializes the ctor args. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReadConstructorArguments(ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptions options) + { + BeginRead(ref state, ref reader, options); + + while (true) + { + // Read the next property name or EndObject. + reader.ReadWithVerify(); + + JsonTokenType tokenType = reader.TokenType; + + if (tokenType == JsonTokenType.EndObject) + { + return; + } + + // Read method would have thrown if otherwise. + Debug.Assert(tokenType == JsonTokenType.PropertyName); + + if (TryLookupConstructorParameter(ref state, ref reader, options, out JsonParameterInfo? jsonParameterInfo)) + { + // Set the property value. + reader.ReadWithVerify(); + + if (!(jsonParameterInfo!.ShouldDeserialize)) + { + reader.TrySkip(); + state.Current.EndConstructorParameter(); + continue; + } + + ReadAndCacheConstructorArgument(ref state, ref reader, jsonParameterInfo); + + state.Current.EndConstructorParameter(); + } + else + { + JsonPropertyInfo jsonPropertyInfo = JsonSerializer.LookupProperty( + obj: null!, + ref reader, + options, + ref state, + out _, + createExtensionProperty: false); + + if (state.Current.CtorArgumentState!.FoundProperties == null) + { + state.Current.CtorArgumentState.FoundProperties = + ArrayPool.Shared.Rent(Math.Max(1, state.Current.JsonClassInfo.PropertyCache!.Count)); + } + else if (state.Current.PropertyIndex - 1 == state.Current.CtorArgumentState.FoundProperties!.Length) + { + // Rare case where we can't fit all the JSON properties in the rented pool; we have to grow. + // This could happen if there are duplicate properties in the JSON. + + var newCache = ArrayPool.Shared.Rent(state.Current.CtorArgumentState.FoundProperties!.Length * 2); + + state.Current.CtorArgumentState.FoundProperties!.CopyTo(newCache, 0); + + ArrayPool.Shared.Return(state.Current.CtorArgumentState.FoundProperties!, clearArray: true); + + state.Current.CtorArgumentState.FoundProperties = newCache!; + } + + state.Current.CtorArgumentState!.FoundProperties![state.Current.PropertyIndex - 1] = ( + jsonPropertyInfo, + reader.CurrentState, + reader.BytesConsumed, + state.Current.JsonPropertyName, + state.Current.JsonPropertyNameAsString); + + reader.Skip(); + + state.Current.EndProperty(); + } + } + } + + private bool ReadConstructorArgumentsWithContinuation(ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptions options) + { + // Process all properties. + while (true) + { + // Determine the property. + if (state.Current.PropertyState == StackFramePropertyState.None) + { + state.Current.PropertyState = StackFramePropertyState.ReadName; + + if (!reader.Read()) + { + // The read-ahead functionality will do the Read(). + return false; + } + } + + JsonParameterInfo? jsonParameterInfo; + JsonPropertyInfo? jsonPropertyInfo; + + if (state.Current.PropertyState < StackFramePropertyState.Name) + { + state.Current.PropertyState = StackFramePropertyState.Name; + + JsonTokenType tokenType = reader.TokenType; + + if (tokenType == JsonTokenType.EndObject) + { + return true; + } + + // Read method would have thrown if otherwise. + Debug.Assert(tokenType == JsonTokenType.PropertyName); + + if (TryLookupConstructorParameter( + ref state, + ref reader, + options, + out jsonParameterInfo)) + { + jsonPropertyInfo = null; + } + else + { + jsonPropertyInfo = JsonSerializer.LookupProperty( + obj: null!, + ref reader, + options, + ref state, + out bool useExtensionProperty, + createExtensionProperty: false); + + state.Current.UseExtensionProperty = useExtensionProperty; + } + } + else + { + jsonParameterInfo = state.Current.CtorArgumentState!.JsonParameterInfo; + jsonPropertyInfo = state.Current.JsonPropertyInfo; + } + + if (jsonParameterInfo != null) + { + Debug.Assert(jsonPropertyInfo == null); + + if (!HandleConstructorArgumentWithContinuation(ref state, ref reader, jsonParameterInfo)) + { + return false; + } + } + else + { + if (!HandlePropertyWithContinuation(ref state, ref reader, jsonPropertyInfo!)) + { + return false; + } + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool HandleConstructorArgumentWithContinuation( + ref ReadStack state, + ref Utf8JsonReader reader, + JsonParameterInfo jsonParameterInfo) + { + if (state.Current.PropertyState < StackFramePropertyState.ReadValue) + { + if (!jsonParameterInfo.ShouldDeserialize) + { + if (!reader.TrySkip()) + { + return false; + } + + state.Current.EndConstructorParameter(); + return true; + } + + // Returning false below will cause the read-ahead functionality to finish the read. + state.Current.PropertyState = StackFramePropertyState.ReadValue; + + if (!SingleValueReadWithReadAhead(jsonParameterInfo.ConverterBase.ClassType, ref reader, ref state)) + { + return false; + } + } + + if (!ReadAndCacheConstructorArgument(ref state, ref reader, jsonParameterInfo)) + { + return false; + } + + state.Current.EndConstructorParameter(); + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool HandlePropertyWithContinuation( + ref ReadStack state, + ref Utf8JsonReader reader, + JsonPropertyInfo jsonPropertyInfo) + { + if (state.Current.PropertyState < StackFramePropertyState.ReadValue) + { + if (!jsonPropertyInfo.ShouldDeserialize) + { + if (!reader.TrySkip()) + { + return false; + } + + state.Current.EndProperty(); + return true; + } + + if (!ReadAheadPropertyValue(ref state, ref reader, jsonPropertyInfo)) + { + return false; + } + } + + object? propValue; + + if (state.Current.UseExtensionProperty) + { + if (!jsonPropertyInfo.ReadJsonExtensionDataValue(ref state, ref reader, out propValue)) + { + return false; + } + } + else + { + if (!jsonPropertyInfo.ReadJsonAsObject(ref state, ref reader, out propValue)) + { + return false; + } + } + + // Ensure that the cache has enough capacity to add this property. + + if (state.Current.CtorArgumentState!.FoundPropertiesAsync == null) + { + state.Current.CtorArgumentState.FoundPropertiesAsync = + ArrayPool.Shared.Rent(Math.Max(1, state.Current.JsonClassInfo.PropertyCache!.Count)); + } + else if (state.Current.CtorArgumentState.FoundPropertyCount == state.Current.CtorArgumentState.FoundPropertiesAsync!.Length) + { + // Rare case where we can't fit all the JSON properties in the rented pool; we have to grow. + // This could happen if there are duplicate properties in the JSON. + var newCache = ArrayPool.Shared.Rent( + state.Current.CtorArgumentState.FoundPropertiesAsync!.Length * 2); + + state.Current.CtorArgumentState.FoundPropertiesAsync!.CopyTo(newCache, 0); + + ArrayPool.Shared.Return( + state.Current.CtorArgumentState.FoundPropertiesAsync!, clearArray: true); + + state.Current.CtorArgumentState.FoundPropertiesAsync = newCache!; + } + + // Cache the property name and value. + state.Current.CtorArgumentState.FoundPropertiesAsync[state.Current.CtorArgumentState.FoundPropertyCount++] = ( + jsonPropertyInfo, + propValue, + state.Current.JsonPropertyNameAsString); + + state.Current.EndProperty(); + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void BeginRead(ref ReadStack state, ref Utf8JsonReader reader, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); + } + + if (state.Current.JsonClassInfo.ParameterCount != state.Current.JsonClassInfo.ParameterCache!.Count) + { + ThrowHelper.ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(ConstructorInfo, TypeToConvert); + } + + // Set current JsonPropertyInfo to null to avoid conflicts on push. + state.Current.JsonPropertyInfo = null; + + Debug.Assert(state.Current.CtorArgumentState != null); + + InitializeConstructorArgumentCaches(ref state, options); + } + + /// + /// Lookup the constructor parameter given its name in the reader. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryLookupConstructorParameter( + ref ReadStack state, + ref Utf8JsonReader reader, + JsonSerializerOptions options, + out JsonParameterInfo? jsonParameterInfo) + { + Debug.Assert(state.Current.JsonClassInfo.ClassType == ClassType.Object); + + ReadOnlySpan unescapedPropertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options); + + if (!state.Current.JsonClassInfo.TryGetParameter(unescapedPropertyName, ref state.Current, out jsonParameterInfo)) + { + return false; + } + + Debug.Assert(jsonParameterInfo != null); + + // Increment ConstructorParameterIndex so GetProperty() starts with the next parameter the next time this function is called. + state.Current.CtorArgumentState!.ParameterIndex++; + + // Support JsonException.Path. + Debug.Assert( + jsonParameterInfo.JsonPropertyName == null || + options.PropertyNameCaseInsensitive || + unescapedPropertyName.SequenceEqual(jsonParameterInfo.JsonPropertyName)); + + if (jsonParameterInfo.JsonPropertyName == null) + { + byte[] propertyNameArray = unescapedPropertyName.ToArray(); + if (options.PropertyNameCaseInsensitive) + { + // Each payload can have a different name here; remember the value on the temporary stack. + state.Current.JsonPropertyName = propertyNameArray; + } + else + { + //Prevent future allocs by caching globally on the JsonPropertyInfo which is specific to a Type+PropertyName + // so it will match the incoming payload except when case insensitivity is enabled(which is handled above). + jsonParameterInfo.JsonPropertyName = propertyNameArray; + } + } + + state.Current.CtorArgumentState.JsonParameterInfo = jsonParameterInfo; + + return true; + } + + internal override bool ConstructorIsParameterized => true; + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs deleted file mode 100644 index a5d3e98d1ad228..00000000000000 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Reflection; -using System.Text.Json.Serialization; - -namespace System.Text.Json -{ - internal partial class JsonClassInfo - { - private JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options) - { - bool hasIgnoreAttribute = (JsonPropertyInfo.GetAttribute(propertyInfo) != null); - if (hasIgnoreAttribute) - { - return JsonPropertyInfo.CreateIgnoredPropertyPlaceholder(propertyInfo, options); - } - - JsonConverter converter = GetConverter( - propertyType, - parentClassType, - propertyInfo, - out Type runtimeType, - options); - - return CreateProperty( - declaredPropertyType: propertyType, - runtimePropertyType: runtimeType, - propertyInfo, - parentClassType, - converter, - options); - } - - internal static JsonPropertyInfo CreateProperty( - Type declaredPropertyType, - Type? runtimePropertyType, - PropertyInfo? propertyInfo, - Type parentClassType, - JsonConverter converter, - JsonSerializerOptions options) - { - // Create the JsonPropertyInfo instance. - JsonPropertyInfo jsonPropertyInfo = converter.CreateJsonPropertyInfo(); - - jsonPropertyInfo.Initialize( - parentClassType, - declaredPropertyType, - runtimePropertyType, - runtimeClassType: converter.ClassType, - propertyInfo, - converter, - options); - - return jsonPropertyInfo; - } - - /// - /// Create a for a given Type. - /// See . - /// - internal static JsonPropertyInfo CreatePropertyInfoForClassInfo( - Type declaredPropertyType, - Type runtimePropertyType, - JsonConverter converter, - JsonSerializerOptions options) - { - return CreateProperty( - declaredPropertyType: declaredPropertyType, - runtimePropertyType: runtimePropertyType, - propertyInfo: null, // Not a real property so this is null. - parentClassType: typeof(object), // a dummy value (not used) - converter : converter, - options); - } - } -} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs new file mode 100644 index 00000000000000..2f8dd30dc04833 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs @@ -0,0 +1,580 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text.Json.Serialization; + +namespace System.Text.Json +{ + [DebuggerDisplay("ClassType.{ClassType}, {Type.Name}")] + internal sealed partial class JsonClassInfo + { + // The length of the property name embedded in the key (in bytes). + // The key is a ulong (8 bytes) containing the first 7 bytes of the property name + // followed by a byte representing the length. + private const int PropertyNameKeyLength = 7; + + // The limit to how many constructor parameter names from the JSON are cached in _parameterRefsSorted before using _parameterCache. + private const int ParameterNameCountCacheThreshold = 32; + + // The limit to how many property names from the JSON are cached in _propertyRefsSorted before using PropertyCache. + private const int PropertyNameCountCacheThreshold = 64; + + // The number of parameters the deserialization constructor has. If this is not equal to ParameterCache.Count, this means + // that not all parameters are bound to object properties, and an exception will be thrown if deserialization is attempted. + public int ParameterCount { get; private set; } + + // All of the serializable parameters on a POCO constructor keyed on parameter name. + // Only paramaters which bind to properties are cached. + public volatile Dictionary? ParameterCache; + + // All of the serializable properties on a POCO (except the optional extension property) keyed on property name. + public volatile Dictionary? PropertyCache; + + // All of the serializable properties on a POCO including the optional extension property. + // Used for performance during serialization instead of 'PropertyCache' above. + public volatile JsonPropertyInfo[]? PropertyCacheArray; + + // Fast cache of constructor parameters by first JSON ordering; may not contain all parameters. Accessed before ParameterCache. + // Use an array (instead of List) for highest performance. + private volatile ParameterRef[]? _parameterRefsSorted; + + // Fast cache of properties by first JSON ordering; may not contain all properties. Accessed before PropertyCache. + // Use an array (instead of List) for highest performance. + private volatile PropertyRef[]? _propertyRefsSorted; + + private Dictionary CreatePropertyCache(int capacity) + { + StringComparer comparer; + + if (Options.PropertyNameCaseInsensitive) + { + comparer = StringComparer.OrdinalIgnoreCase; + } + else + { + comparer = StringComparer.Ordinal; + } + + return new Dictionary(capacity, comparer); + } + + public Dictionary CreateParameterCache(int capacity, JsonSerializerOptions options) + { + if (options.PropertyNameCaseInsensitive) + { + return new Dictionary(capacity, StringComparer.OrdinalIgnoreCase); + } + else + { + return new Dictionary(capacity); + } + } + + public static JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options) + { + bool hasIgnoreAttribute = (JsonPropertyInfo.GetAttribute(propertyInfo) != null); + if (hasIgnoreAttribute) + { + return JsonPropertyInfo.CreateIgnoredPropertyPlaceholder(propertyInfo, options); + } + + JsonConverter converter = GetConverter( + propertyType, + parentClassType, + propertyInfo, + out Type runtimeType, + options); + + return CreateProperty( + declaredPropertyType: propertyType, + runtimePropertyType: runtimeType, + propertyInfo, + parentClassType, + converter, + options); + } + + internal static JsonPropertyInfo CreateProperty( + Type declaredPropertyType, + Type? runtimePropertyType, + PropertyInfo? propertyInfo, + Type parentClassType, + JsonConverter converter, + JsonSerializerOptions options) + { + // Create the JsonPropertyInfo instance. + JsonPropertyInfo jsonPropertyInfo = converter.CreateJsonPropertyInfo(); + + jsonPropertyInfo.Initialize( + parentClassType, + declaredPropertyType, + runtimePropertyType, + runtimeClassType: converter.ClassType, + propertyInfo, + converter, + options); + + return jsonPropertyInfo; + } + + /// + /// Create a for a given Type. + /// See . + /// + internal static JsonPropertyInfo CreatePropertyInfoForClassInfo( + Type declaredPropertyType, + Type runtimePropertyType, + JsonConverter converter, + JsonSerializerOptions options) + { + return CreateProperty( + declaredPropertyType: declaredPropertyType, + runtimePropertyType: runtimePropertyType, + propertyInfo: null, // Not a real property so this is null. + parentClassType: typeof(object), // a dummy value (not used) + converter : converter, + options); + } + + // AggressiveInlining used although a large method it is only called from one location and is on a hot path. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public JsonPropertyInfo GetProperty(ReadOnlySpan propertyName, ref ReadStackFrame frame) + { + JsonPropertyInfo? info = null; + + // Keep a local copy of the cache in case it changes by another thread. + PropertyRef[]? localPropertyRefsSorted = _propertyRefsSorted; + + ulong key = GetKey(propertyName); + + // If there is an existing cache, then use it. + if (localPropertyRefsSorted != null) + { + // Start with the current property index, and then go forwards\backwards. + int propertyIndex = frame.PropertyIndex; + + int count = localPropertyRefsSorted.Length; + int iForward = Math.Min(propertyIndex, count); + int iBackward = iForward - 1; + + while (true) + { + if (iForward < count) + { + PropertyRef propertyRef = localPropertyRefsSorted[iForward]; + if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info)) + { + return info; + } + + ++iForward; + + if (iBackward >= 0) + { + propertyRef = localPropertyRefsSorted[iBackward]; + if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info)) + { + return info; + } + + --iBackward; + } + } + else if (iBackward >= 0) + { + PropertyRef propertyRef = localPropertyRefsSorted[iBackward]; + if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info)) + { + return info; + } + + --iBackward; + } + else + { + // Property was not found. + break; + } + } + } + + // No cached item was found. Try the main list which has all of the properties. + + string stringPropertyName = JsonHelpers.Utf8GetString(propertyName); + + Debug.Assert(PropertyCache != null); + + if (!PropertyCache.TryGetValue(stringPropertyName, out info)) + { + info = JsonPropertyInfo.s_missingProperty; + } + + Debug.Assert(info != null); + + // Three code paths to get here: + // 1) info == s_missingProperty. Property not found. + // 2) key == info.PropertyNameKey. Exact match found. + // 3) key != info.PropertyNameKey. Match found due to case insensitivity. + Debug.Assert(info == JsonPropertyInfo.s_missingProperty || key == info.PropertyNameKey || Options.PropertyNameCaseInsensitive); + + // Check if we should add this to the cache. + // Only cache up to a threshold length and then just use the dictionary when an item is not found in the cache. + int cacheCount = 0; + if (localPropertyRefsSorted != null) + { + cacheCount = localPropertyRefsSorted.Length; + } + + // Do a quick check for the stable (after warm-up) case. + if (cacheCount < PropertyNameCountCacheThreshold) + { + // Do a slower check for the warm-up case. + if (frame.PropertyRefCache != null) + { + cacheCount += frame.PropertyRefCache.Count; + } + + // Check again to append the cache up to the threshold. + if (cacheCount < PropertyNameCountCacheThreshold) + { + if (frame.PropertyRefCache == null) + { + frame.PropertyRefCache = new List(); + } + + PropertyRef propertyRef = new PropertyRef(key, info); + frame.PropertyRefCache.Add(propertyRef); + } + } + + return info; + } + + // AggressiveInlining used although a large method it is only called from one location and is on a hot path. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetParameter( + ReadOnlySpan propertyName, + ref ReadStackFrame frame, + out JsonParameterInfo? jsonParameterInfo) + { + JsonParameterInfo? info = null; + + // Keep a local copy of the cache in case it changes by another thread. + ParameterRef[]? localParameterRefsSorted = _parameterRefsSorted; + + ulong key = GetKey(propertyName); + + // If there is an existing cache, then use it. + if (localParameterRefsSorted != null) + { + // Start with the current parameter index, and then go forwards\backwards. + int parameterIndex = frame.CtorArgumentState!.ParameterIndex; + + int count = localParameterRefsSorted.Length; + int iForward = Math.Min(parameterIndex, count); + int iBackward = iForward - 1; + + while (true) + { + if (iForward < count) + { + ParameterRef parameterRef = localParameterRefsSorted[iForward]; + if (TryIsParameterRefEqual(parameterRef, propertyName, key, ref info)) + { + jsonParameterInfo = info; + return true; + } + + ++iForward; + + if (iBackward >= 0) + { + parameterRef = localParameterRefsSorted[iBackward]; + if (TryIsParameterRefEqual(parameterRef, propertyName, key, ref info)) + { + jsonParameterInfo = info; + return true; + } + + --iBackward; + } + } + else if (iBackward >= 0) + { + ParameterRef parameterRef = localParameterRefsSorted[iBackward]; + if (TryIsParameterRefEqual(parameterRef, propertyName, key, ref info)) + { + jsonParameterInfo = info; + return true; + } + + --iBackward; + } + else + { + // Property was not found. + break; + } + } + } + + string propertyNameAsString = JsonHelpers.Utf8GetString(propertyName); + + Debug.Assert(ParameterCache != null); + + if (!ParameterCache.TryGetValue(propertyNameAsString, out info)) + { + // Constructor parameter not found. We'll check if it's a property next. + jsonParameterInfo = null; + return false; + } + + jsonParameterInfo = info; + Debug.Assert(info != null); + + // Two code paths to get here: + // 1) key == info.PropertyNameKey. Exact match found. + // 2) key != info.PropertyNameKey. Match found due to case insensitivity. + // TODO: recheck these conditions + Debug.Assert(key == info.ParameterNameKey || + propertyNameAsString.Equals(info.NameAsString, StringComparison.OrdinalIgnoreCase)); + + // Check if we should add this to the cache. + // Only cache up to a threshold length and then just use the dictionary when an item is not found in the cache. + int cacheCount = 0; + if (localParameterRefsSorted != null) + { + cacheCount = localParameterRefsSorted.Length; + } + + // Do a quick check for the stable (after warm-up) case. + if (cacheCount < ParameterNameCountCacheThreshold) + { + // Do a slower check for the warm-up case. + if (frame.CtorArgumentState!.ParameterRefCache != null) + { + cacheCount += frame.CtorArgumentState.ParameterRefCache.Count; + } + + // Check again to append the cache up to the threshold. + if (cacheCount < ParameterNameCountCacheThreshold) + { + if (frame.CtorArgumentState.ParameterRefCache == null) + { + frame.CtorArgumentState.ParameterRefCache = new List(); + } + + ParameterRef parameterRef = new ParameterRef(key, jsonParameterInfo); + frame.CtorArgumentState.ParameterRefCache.Add(parameterRef); + } + } + + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryIsPropertyRefEqual(in PropertyRef propertyRef, ReadOnlySpan propertyName, ulong key, [NotNullWhen(true)] ref JsonPropertyInfo? info) + { + if (key == propertyRef.Key) + { + // We compare the whole name, although we could skip the first 7 bytes (but it's not any faster) + if (propertyName.Length <= PropertyNameKeyLength || + propertyName.SequenceEqual(propertyRef.Info.Name)) + { + info = propertyRef.Info; + return true; + } + } + + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryIsParameterRefEqual(in ParameterRef parameterRef, ReadOnlySpan parameterName, ulong key, [NotNullWhen(true)] ref JsonParameterInfo? info) + { + if (key == parameterRef.Key) + { + // We compare the whole name, although we could skip the first 7 bytes (but it's not any faster) + if (parameterName.Length <= PropertyNameKeyLength || + parameterName.SequenceEqual(parameterRef.Info.ParameterName)) + { + info = parameterRef.Info; + return true; + } + } + + return false; + } + + /// + /// Get a key from the property name. + /// The key consists of the first 7 bytes of the property name and then the length. + /// + // AggressiveInlining used since this method is only called from two locations and is on a hot path. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong GetKey(ReadOnlySpan propertyName) + { + const int BitsInByte = 8; + ulong key; + int length = propertyName.Length; + + if (length > 7) + { + key = MemoryMarshal.Read(propertyName); + + // Max out the length byte. + // This will cause the comparison logic to always test for equality against the full contents + // when the first 7 bytes are the same. + key |= 0xFF00000000000000; + + // It is also possible to include the length up to 0xFF in order to prevent false positives + // when the first 7 bytes match but a different length (up to 0xFF). However the extra logic + // slows key generation in the majority of cases: + // key &= 0x00FFFFFFFFFFFFFF; + // key |= (ulong) 7 << Math.Max(length, 0xFF); + } + else if (length > 3) + { + key = MemoryMarshal.Read(propertyName); + + if (length == 7) + { + key |= (ulong)propertyName[6] << (6 * BitsInByte) + | (ulong)propertyName[5] << (5 * BitsInByte) + | (ulong)propertyName[4] << (4 * BitsInByte) + | (ulong)7 << (7 * BitsInByte); + } + else if (length == 6) + { + key |= (ulong)propertyName[5] << (5 * BitsInByte) + | (ulong)propertyName[4] << (4 * BitsInByte) + | (ulong)6 << (7 * BitsInByte); + } + else if (length == 5) + { + key |= (ulong)propertyName[4] << (4 * BitsInByte) + | (ulong)5 << (7 * BitsInByte); + } + else + { + key |= (ulong)4 << (7 * BitsInByte); + } + } + else if (length > 1) + { + key = MemoryMarshal.Read(propertyName); + + if (length == 3) + { + key |= (ulong)propertyName[2] << (2 * BitsInByte) + | (ulong)3 << (7 * BitsInByte); + } + else + { + key |= (ulong)2 << (7 * BitsInByte); + } + } + else if (length == 1) + { + key = propertyName[0] + | (ulong)1 << (7 * BitsInByte); + } + else + { + // An empty name is valid. + key = 0; + } + + // Verify key contains the embedded bytes as expected. + Debug.Assert( + (length < 1 || propertyName[0] == ((key & ((ulong)0xFF << 8 * 0)) >> 8 * 0)) && + (length < 2 || propertyName[1] == ((key & ((ulong)0xFF << 8 * 1)) >> 8 * 1)) && + (length < 3 || propertyName[2] == ((key & ((ulong)0xFF << 8 * 2)) >> 8 * 2)) && + (length < 4 || propertyName[3] == ((key & ((ulong)0xFF << 8 * 3)) >> 8 * 3)) && + (length < 5 || propertyName[4] == ((key & ((ulong)0xFF << 8 * 4)) >> 8 * 4)) && + (length < 6 || propertyName[5] == ((key & ((ulong)0xFF << 8 * 5)) >> 8 * 5)) && + (length < 7 || propertyName[6] == ((key & ((ulong)0xFF << 8 * 6)) >> 8 * 6))); + + return key; + } + + public void UpdateSortedPropertyCache(ref ReadStackFrame frame) + { + Debug.Assert(frame.PropertyRefCache != null); + + // frame.PropertyRefCache is only read\written by a single thread -- the thread performing + // the deserialization for a given object instance. + + List listToAppend = frame.PropertyRefCache; + + // _propertyRefsSorted can be accessed by multiple threads, so replace the reference when + // appending to it. No lock() is necessary. + + if (_propertyRefsSorted != null) + { + List replacementList = new List(_propertyRefsSorted); + Debug.Assert(replacementList.Count <= PropertyNameCountCacheThreshold); + + // Verify replacementList will not become too large. + while (replacementList.Count + listToAppend.Count > PropertyNameCountCacheThreshold) + { + // This code path is rare; keep it simple by using RemoveAt() instead of RemoveRange() which requires calculating index\count. + listToAppend.RemoveAt(listToAppend.Count - 1); + } + + // Add the new items; duplicates are possible but that is tolerated during property lookup. + replacementList.AddRange(listToAppend); + _propertyRefsSorted = replacementList.ToArray(); + } + else + { + _propertyRefsSorted = listToAppend.ToArray(); + } + + frame.PropertyRefCache = null; + } + + public void UpdateSortedParameterCache(ref ReadStackFrame frame) + { + Debug.Assert(frame.CtorArgumentState!.ParameterRefCache != null); + + // frame.PropertyRefCache is only read\written by a single thread -- the thread performing + // the deserialization for a given object instance. + + List listToAppend = frame.CtorArgumentState.ParameterRefCache; + + // _parameterRefsSorted can be accessed by multiple threads, so replace the reference when + // appending to it. No lock() is necessary. + + if (_parameterRefsSorted != null) + { + List replacementList = new List(_parameterRefsSorted); + Debug.Assert(replacementList.Count <= ParameterNameCountCacheThreshold); + + // Verify replacementList will not become too large. + while (replacementList.Count + listToAppend.Count > ParameterNameCountCacheThreshold) + { + // This code path is rare; keep it simple by using RemoveAt() instead of RemoveRange() which requires calculating index\count. + listToAppend.RemoveAt(listToAppend.Count - 1); + } + + // Add the new items; duplicates are possible but that is tolerated during property lookup. + replacementList.AddRange(listToAppend); + _parameterRefsSorted = replacementList.ToArray(); + } + else + { + _parameterRefsSorted = listToAppend.ToArray(); + } + + frame.CtorArgumentState.ParameterRefCache = null; + } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs index ab59358c9c0217..8f35740b459a2d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs @@ -4,10 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Text.Json.Serialization; namespace System.Text.Json @@ -15,26 +12,12 @@ namespace System.Text.Json [DebuggerDisplay("ClassType.{ClassType}, {Type.Name}")] internal sealed partial class JsonClassInfo { - // The length of the property name embedded in the key (in bytes). - // The key is a ulong (8 bytes) containing the first 7 bytes of the property name - // followed by a byte representing the length. - private const int PropertyNameKeyLength = 7; - - // The limit to how many property names from the JSON are cached in _propertyRefsSorted before using PropertyCache. - private const int PropertyNameCountCacheThreshold = 64; - - // All of the serializable properties on a POCO (except the optional extension property) keyed on property name. - public volatile Dictionary? PropertyCache; + public delegate object? ConstructorDelegate(); - // All of the serializable properties on a POCO including the optional extension property. - // Used for performance during serialization instead of 'PropertyCache' above. - public volatile JsonPropertyInfo[]? PropertyCacheArray; + public delegate T ParameterizedConstructorDelegate(object[] arguments); - // Fast cache of properties by first JSON ordering; may not contain all properties. Accessed before PropertyCache. - // Use an array (instead of List) for highest performance. - private volatile PropertyRef[]? _propertyRefsSorted; + public delegate T ParameterizedConstructorDelegate(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3); - public delegate object? ConstructorDelegate(); public ConstructorDelegate? CreateObject { get; private set; } public ClassType ClassType { get; private set; } @@ -73,41 +56,23 @@ public JsonClassInfo? ElementClassInfo public Type Type { get; private set; } - public void UpdateSortedPropertyCache(ref ReadStackFrame frame) - { - Debug.Assert(frame.PropertyRefCache != null); - - // frame.PropertyRefCache is only read\written by a single thread -- the thread performing - // the deserialization for a given object instance. - - List listToAppend = frame.PropertyRefCache; - - // _propertyRefsSorted can be accessed by multiple threads, so replace the reference when - // appending to it. No lock() is necessary. - - if (_propertyRefsSorted != null) - { - List replacementList = new List(_propertyRefsSorted); - Debug.Assert(replacementList.Count <= PropertyNameCountCacheThreshold); - - // Verify replacementList will not become too large. - while (replacementList.Count + listToAppend.Count > PropertyNameCountCacheThreshold) - { - // This code path is rare; keep it simple by using RemoveAt() instead of RemoveRange() which requires calculating index\count. - listToAppend.RemoveAt(listToAppend.Count - 1); - } - - // Add the new items; duplicates are possible but that is tolerated during property lookup. - replacementList.AddRange(listToAppend); - _propertyRefsSorted = replacementList.ToArray(); - } - else - { - _propertyRefsSorted = listToAppend.ToArray(); - } - - frame.PropertyRefCache = null; - } + /// + /// The JsonPropertyInfo for this JsonClassInfo. It is used to obtain the converter for the ClassInfo. + /// + /// + /// The returned JsonPropertyInfo does not represent a real property; instead it represents either: + /// a collection element type, + /// a generic type parameter, + /// a property type (if pushed to a new stack frame), + /// or the root type passed into the root serialization APIs. + /// For example, for a property returning where T is a string, + /// a JsonClassInfo will be created with .Type=typeof(string) and .PropertyInfoForClassInfo=JsonPropertyInfo{string}. + /// Without this property, a "Converter" property would need to be added to JsonClassInfo and there would be several more + /// `if` statements to obtain the converter from either the actual JsonPropertyInfo (for a real property) or from the + /// ClassInfo (for the cases mentioned above). In addition, methods that have a JsonPropertyInfo argument would also likely + /// need to add an argument for JsonClassInfo. + /// + public JsonPropertyInfo PropertyInfoForClassInfo { get; private set; } public JsonClassInfo(Type type, JsonSerializerOptions options) { @@ -128,6 +93,9 @@ public JsonClassInfo(Type type, JsonSerializerOptions options) { case ClassType.Object: { + // Create the policy property. + PropertyInfoForClassInfo = CreatePropertyInfoForClassInfo(type, runtimeType, converter!, options); + CreateObject = options.MemberAccessorStrategy.CreateConstructor(type); PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); @@ -161,7 +129,7 @@ public JsonClassInfo(Type type, JsonSerializerOptions options) } else if (jsonPropertyInfo.ShouldDeserialize == true || jsonPropertyInfo.ShouldSerialize == true) { - ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(this, jsonPropertyInfo); + ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, jsonPropertyInfo); } // else ignore jsonPropertyInfo since it has [JsonIgnore]. } @@ -188,6 +156,12 @@ public JsonClassInfo(Type type, JsonSerializerOptions options) PropertyCache = cache; cache.Values.CopyTo(cacheArray, 0); PropertyCacheArray = cacheArray; + + if (converter.ConstructorIsParameterized) + { + converter.CreateConstructorDelegate(options); + InitializeConstructorParameters(converter.ConstructorInfo); + } } break; case ClassType.Enumerable: @@ -214,308 +188,141 @@ public JsonClassInfo(Type type, JsonSerializerOptions options) } } - private bool DetermineExtensionDataProperty(Dictionary cache) + private void InitializeConstructorParameters(ConstructorInfo constructorInfo) { - JsonPropertyInfo? jsonPropertyInfo = GetPropertyWithUniqueAttribute(typeof(JsonExtensionDataAttribute), cache); - if (jsonPropertyInfo != null) - { - Type declaredPropertyType = jsonPropertyInfo.DeclaredPropertyType; - if (typeof(IDictionary).IsAssignableFrom(declaredPropertyType) || - typeof(IDictionary).IsAssignableFrom(declaredPropertyType)) - { - JsonConverter converter = Options.GetConverter(declaredPropertyType); - Debug.Assert(converter != null); - } - else - { - ThrowHelper.ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(this, jsonPropertyInfo); - } - - DataExtensionProperty = jsonPropertyInfo; + ParameterInfo[] parameters = constructorInfo!.GetParameters(); + Dictionary parameterCache = CreateParameterCache(parameters.Length, Options); - return true; - } + Dictionary propertyCache = PropertyCache!; - return false; - } - - private JsonPropertyInfo? GetPropertyWithUniqueAttribute(Type attributeType, Dictionary cache) - { - JsonPropertyInfo? property = null; - - foreach (JsonPropertyInfo jsonPropertyInfo in cache.Values) + foreach (ParameterInfo parameterInfo in parameters) { - Debug.Assert(jsonPropertyInfo.PropertyInfo != null); - Attribute? attribute = jsonPropertyInfo.PropertyInfo.GetCustomAttribute(attributeType); - if (attribute != null) - { - if (property != null) - { - ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(Type, attributeType); - } - - property = jsonPropertyInfo; - } - } - - return property; - } - - // AggressiveInlining used although a large method it is only called from one location and is on a hot path. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public JsonPropertyInfo GetProperty(ReadOnlySpan propertyName, ref ReadStackFrame frame) - { - JsonPropertyInfo? info = null; - - // Keep a local copy of the cache in case it changes by another thread. - PropertyRef[]? localPropertyRefsSorted = _propertyRefsSorted; + PropertyInfo? firstMatch = null; + bool isBound = false; - ulong key = GetKey(propertyName); - - // If there is an existing cache, then use it. - if (localPropertyRefsSorted != null) - { - // Start with the current property index, and then go forwards\backwards. - int propertyIndex = frame.PropertyIndex; + foreach (JsonPropertyInfo jsonPropertyInfo in PropertyCacheArray!) + { + // This is not null because it is an actual + // property on a type, not a "policy property". + PropertyInfo propertyInfo = jsonPropertyInfo.PropertyInfo!; - int count = localPropertyRefsSorted.Length; - int iForward = Math.Min(propertyIndex, count); - int iBackward = iForward - 1; + string camelCasePropName = JsonNamingPolicy.CamelCase.ConvertName(propertyInfo.Name); - while (true) - { - if (iForward < count) + if (parameterInfo.Name == camelCasePropName && + parameterInfo.ParameterType == propertyInfo.PropertyType) { - PropertyRef propertyRef = localPropertyRefsSorted[iForward]; - if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info)) + if (isBound) { - return info; + Debug.Assert(firstMatch != null); + + // Multiple object properties cannot bind to the same + // constructor parameter. + ThrowHelper.ThrowInvalidOperationException_MultiplePropertiesBindToConstructorParameters( + Type, + parameterInfo, + firstMatch, + propertyInfo, + constructorInfo); } - ++iForward; + JsonParameterInfo jsonParameterInfo = AddConstructorParameter(parameterInfo, jsonPropertyInfo, Options); - if (iBackward >= 0) - { - propertyRef = localPropertyRefsSorted[iBackward]; - if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info)) - { - return info; - } + // One object property cannot map to multiple constructor + // parameters (ConvertName above can't return multiple strings). + parameterCache.Add(jsonParameterInfo.NameAsString, jsonParameterInfo); - --iBackward; - } - } - else if (iBackward >= 0) - { - PropertyRef propertyRef = localPropertyRefsSorted[iBackward]; - if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info)) - { - return info; - } + // Remove property from deserialization cache to reduce the number of JsonPropertyInfos considered during JSON matching. + propertyCache.Remove(jsonPropertyInfo.NameAsString!); - --iBackward; - } - else - { - // Property was not found. - break; + isBound = true; + firstMatch = propertyInfo; } } } - // No cached item was found. Try the main list which has all of the properties. - - string stringPropertyName = JsonHelpers.Utf8GetString(propertyName); - - Debug.Assert(PropertyCache != null); - - if (!PropertyCache.TryGetValue(stringPropertyName, out info)) + // It is invalid for the extension data property to bind with a constructor argument. + if (DataExtensionProperty != null && + parameterCache.ContainsKey(DataExtensionProperty.NameAsString!)) { - info = JsonPropertyInfo.s_missingProperty; + ThrowHelper.ThrowInvalidOperationException_ExtensionDataCannotBindToCtorParam(DataExtensionProperty.PropertyInfo!, Type, constructorInfo); } - Debug.Assert(info != null); - - // Three code paths to get here: - // 1) info == s_missingProperty. Property not found. - // 2) key == info.PropertyNameKey. Exact match found. - // 3) key != info.PropertyNameKey. Match found due to case insensitivity. - Debug.Assert(info == JsonPropertyInfo.s_missingProperty || key == info.PropertyNameKey || Options.PropertyNameCaseInsensitive); + ParameterCache = parameterCache; + ParameterCount = parameters.Length; - // Check if we should add this to the cache. - // Only cache up to a threshold length and then just use the dictionary when an item is not found in the cache. - int cacheCount = 0; - if (localPropertyRefsSorted != null) - { - cacheCount = localPropertyRefsSorted.Length; - } + PropertyCache = propertyCache; + } - // Do a quick check for the stable (after warm-up) case. - if (cacheCount < PropertyNameCountCacheThreshold) + public bool DetermineExtensionDataProperty(Dictionary cache) + { + JsonPropertyInfo? jsonPropertyInfo = GetPropertyWithUniqueAttribute(Type, typeof(JsonExtensionDataAttribute), cache); + if (jsonPropertyInfo != null) { - // Do a slower check for the warm-up case. - if (frame.PropertyRefCache != null) + Type declaredPropertyType = jsonPropertyInfo.DeclaredPropertyType; + if (typeof(IDictionary).IsAssignableFrom(declaredPropertyType) || + typeof(IDictionary).IsAssignableFrom(declaredPropertyType)) { - cacheCount += frame.PropertyRefCache.Count; + JsonConverter converter = Options.GetConverter(declaredPropertyType); + Debug.Assert(converter != null); } - - // Check again to append the cache up to the threshold. - if (cacheCount < PropertyNameCountCacheThreshold) + else { - if (frame.PropertyRefCache == null) - { - frame.PropertyRefCache = new List(); - } - - PropertyRef propertyRef = new PropertyRef(key, info); - frame.PropertyRefCache.Add(propertyRef); + ThrowHelper.ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(Type, jsonPropertyInfo); } - } - - return info; - } - private Dictionary CreatePropertyCache(int capacity) - { - StringComparer comparer; - - if (Options.PropertyNameCaseInsensitive) - { - comparer = StringComparer.OrdinalIgnoreCase; - } - else - { - comparer = StringComparer.Ordinal; + DataExtensionProperty = jsonPropertyInfo; + return true; } - return new Dictionary(capacity, comparer); + return false; } - /// - /// The JsonPropertyInfo for this JsonClassInfo. It is used to obtain the converter for the ClassInfo. - /// - /// - /// The returned JsonPropertyInfo does not represent a real property; instead it represents either: - /// a collection element type, - /// a generic type parameter, - /// a property type (if pushed to a new stack frame), - /// or the root type passed into the root serialization APIs. - /// For example, for a property returning where T is a string, - /// a JsonClassInfo will be created with .Type=typeof(string) and .PropertyInfoForClassInfo=JsonPropertyInfo{string}. - /// Without this property, a "Converter" property would need to be added to JsonClassInfo and there would be several more - /// `if` statements to obtain the converter from either the actual JsonPropertyInfo (for a real property) or from the - /// ClassInfo (for the cases mentioned above). In addition, methods that have a JsonPropertyInfo argument would also likely - /// need to add an argument for JsonClassInfo. - /// - public JsonPropertyInfo PropertyInfoForClassInfo { get; private set; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryIsPropertyRefEqual(in PropertyRef propertyRef, ReadOnlySpan propertyName, ulong key, [NotNullWhen(true)] ref JsonPropertyInfo? info) + private static JsonPropertyInfo? GetPropertyWithUniqueAttribute(Type classType, Type attributeType, Dictionary cache) { - if (key == propertyRef.Key) + JsonPropertyInfo? property = null; + + foreach (JsonPropertyInfo jsonPropertyInfo in cache.Values) { - // We compare the whole name, although we could skip the first 7 bytes (but it's not any faster) - if (propertyName.Length <= PropertyNameKeyLength || - propertyName.SequenceEqual(propertyRef.Info.Name)) + Debug.Assert(jsonPropertyInfo.PropertyInfo != null); + Attribute? attribute = jsonPropertyInfo.PropertyInfo.GetCustomAttribute(attributeType); + if (attribute != null) { - info = propertyRef.Info; - return true; + if (property != null) + { + ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(classType, attributeType); + } + + property = jsonPropertyInfo; } } - return false; + return property; } - /// - /// Get a key from the property name. - /// The key consists of the first 7 bytes of the property name and then the length. - /// - // AggressiveInlining used since this method is only called from two locations and is on a hot path. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong GetKey(ReadOnlySpan propertyName) + private static JsonParameterInfo AddConstructorParameter( + ParameterInfo parameterInfo, + JsonPropertyInfo jsonPropertyInfo, + JsonSerializerOptions options) { - const int BitsInByte = 8; - ulong key; - int length = propertyName.Length; + string matchingPropertyName = jsonPropertyInfo.NameAsString!; - if (length > 7) + if (jsonPropertyInfo.IsIgnored) { - key = MemoryMarshal.Read(propertyName); - - // Max out the length byte. - // This will cause the comparison logic to always test for equality against the full contents - // when the first 7 bytes are the same. - key |= 0xFF00000000000000; - - // It is also possible to include the length up to 0xFF in order to prevent false positives - // when the first 7 bytes match but a different length (up to 0xFF). However the extra logic - // slows key generation in the majority of cases: - // key &= 0x00FFFFFFFFFFFFFF; - // key |= (ulong) 7 << Math.Max(length, 0xFF); + return JsonParameterInfo.CreateIgnoredParameterPlaceholder(matchingPropertyName, parameterInfo, options); } - else if (length > 3) - { - key = MemoryMarshal.Read(propertyName); - if (length == 7) - { - key |= (ulong)propertyName[6] << (6 * BitsInByte) - | (ulong)propertyName[5] << (5 * BitsInByte) - | (ulong)propertyName[4] << (4 * BitsInByte) - | (ulong)7 << (7 * BitsInByte); - } - else if (length == 6) - { - key |= (ulong)propertyName[5] << (5 * BitsInByte) - | (ulong)propertyName[4] << (4 * BitsInByte) - | (ulong)6 << (7 * BitsInByte); - } - else if (length == 5) - { - key |= (ulong)propertyName[4] << (4 * BitsInByte) - | (ulong)5 << (7 * BitsInByte); - } - else - { - key |= (ulong)4 << (7 * BitsInByte); - } - } - else if (length > 1) - { - key = MemoryMarshal.Read(propertyName); + JsonConverter converter = jsonPropertyInfo.ConverterBase; - if (length == 3) - { - key |= (ulong)propertyName[2] << (2 * BitsInByte) - | (ulong)3 << (7 * BitsInByte); - } - else - { - key |= (ulong)2 << (7 * BitsInByte); - } - } - else if (length == 1) - { - key = propertyName[0] - | (ulong)1 << (7 * BitsInByte); - } - else - { - // An empty name is valid. - key = 0; - } + JsonParameterInfo jsonParameterInfo = converter.CreateJsonParameterInfo(); + jsonParameterInfo.Initialize( + matchingPropertyName, + jsonPropertyInfo.DeclaredPropertyType, + jsonPropertyInfo.RuntimePropertyType!, + parameterInfo, + converter, + options); - // Verify key contains the embedded bytes as expected. - Debug.Assert( - (length < 1 || propertyName[0] == ((key & ((ulong)0xFF << 8 * 0)) >> 8 * 0)) && - (length < 2 || propertyName[1] == ((key & ((ulong)0xFF << 8 * 1)) >> 8 * 1)) && - (length < 3 || propertyName[2] == ((key & ((ulong)0xFF << 8 * 2)) >> 8 * 2)) && - (length < 4 || propertyName[3] == ((key & ((ulong)0xFF << 8 * 3)) >> 8 * 3)) && - (length < 5 || propertyName[4] == ((key & ((ulong)0xFF << 8 * 4)) >> 8 * 4)) && - (length < 6 || propertyName[5] == ((key & ((ulong)0xFF << 8 * 5)) >> 8 * 5)) && - (length < 7 || propertyName[6] == ((key & ((ulong)0xFF << 8 * 6)) >> 8 * 6))); - - return key; + return jsonParameterInfo; } // This method gets the runtime information for a given type or property. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConstructorAttribute.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConstructorAttribute.cs new file mode 100644 index 00000000000000..eb02466632ba78 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConstructorAttribute.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Text.Json.Serialization +{ + /// + /// When placed on a constructor, indicates that the constructor should be used to create + /// instances of the type on deserialization. + /// + [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)] + public sealed class JsonConstructorAttribute : JsonAttribute + { + /// + /// Initializes a new instance of . + /// + public JsonConstructorAttribute() { } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs index 8d7b4bbb9a915d..be1cbd5650f968 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Reflection; + namespace System.Text.Json.Serialization { /// @@ -34,6 +36,8 @@ internal JsonConverter() { } internal abstract JsonPropertyInfo CreateJsonPropertyInfo(); + internal abstract JsonParameterInfo CreateJsonParameterInfo(); + internal abstract Type? ElementType { get; } /// @@ -70,5 +74,12 @@ internal bool ShouldFlush(Utf8JsonWriter writer, ref WriteStack state) /// Loosely-typed WriteCore() that forwards to strongly-typed WriteCore(). /// internal abstract bool WriteCoreAsObject(Utf8JsonWriter writer, object? value, JsonSerializerOptions options, ref WriteStack state); + + // Whether a type (ClassType.Object) is deserialized using a parameterized constructor. + internal virtual bool ConstructorIsParameterized => false; + + internal ConstructorInfo ConstructorInfo { get; set; } = null!; + + internal virtual void CreateConstructorDelegate(JsonSerializerOptions options) { } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs index 63faf511eadf00..caea89aa57450e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs @@ -46,6 +46,11 @@ internal override JsonPropertyInfo CreateJsonPropertyInfo() throw new InvalidOperationException(); } + internal override JsonParameterInfo CreateJsonParameterInfo() + { + throw new InvalidOperationException(); + } + internal sealed override Type? ElementType => null; internal JsonConverter GetConverterInternal(Type typeToConvert, JsonSerializerOptions options) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs index 0bd354c2714458..c7fc17917af9f8 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs @@ -47,6 +47,11 @@ internal sealed override JsonPropertyInfo CreateJsonPropertyInfo() return new JsonPropertyInfo(); } + internal override sealed JsonParameterInfo CreateJsonParameterInfo() + { + return new JsonParameterInfo(); + } + internal override Type? ElementType => null; // Allow a converter that can't be null to return a null value representation, such as JsonElement or Nullable<>. @@ -75,7 +80,7 @@ internal virtual bool OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerO } // Provide a default implementation for value converters. - internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, out T value) + internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNullWhen(false)] out T value) { value = Read(ref reader, typeToConvert, options); return true; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfo.cs new file mode 100644 index 00000000000000..7f5076277c9b12 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfo.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Reflection; +using System.Text.Json.Serialization; + +namespace System.Text.Json +{ + /// + /// Holds relevant state about a method parameter, like the default value of + /// the parameter, and the position in the method's parameter list. + /// + [DebuggerDisplay("ParameterInfo={ParameterInfo}")] + internal abstract class JsonParameterInfo + { + private Type _runtimePropertyType = null!; + + public abstract JsonConverter ConverterBase { get; } + + // The default value of the parameter. This is `DefaultValue` of the `ParameterInfo`, if specified, or the CLR `default` for the `ParameterType`. + public object? DefaultValue { get; protected set; } + + // The name from a Json value. This is cached for performance on first deserialize. + public byte[]? JsonPropertyName { get; set; } + + // Options can be referenced here since all JsonPropertyInfos originate from a JsonClassInfo that is cached on JsonSerializerOptions. + protected JsonSerializerOptions Options { get; set; } = null!; // initialized in Init method + + public ParameterInfo ParameterInfo { get; private set; } = null!; + + // The name of the parameter as UTF-8 bytes. + public byte[] ParameterName { get; private set; } = null!; + + // The name of the parameter. + public string NameAsString { get; private set; } = null!; + + // Key for fast property name lookup. + public ulong ParameterNameKey { get; private set; } + + // The zero-based position of the parameter in the formal parameter list. + public int Position { get; private set; } + + private JsonClassInfo? _runtimeClassInfo; + public JsonClassInfo RuntimeClassInfo + { + get + { + if (_runtimeClassInfo == null) + { + _runtimeClassInfo = Options.GetOrAddClass(_runtimePropertyType); + } + + return _runtimeClassInfo; + } + } + + public bool ShouldDeserialize { get; private set; } + + public virtual void Initialize( + string matchingPropertyName, + Type declaredPropertyType, + Type runtimePropertyType, + ParameterInfo parameterInfo, + JsonConverter converter, + JsonSerializerOptions options) + { + _runtimePropertyType = runtimePropertyType; + + Options = options; + ParameterInfo = parameterInfo; + Position = parameterInfo.Position; + ShouldDeserialize = true; + + DetermineParameterName(matchingPropertyName); + } + + private void DetermineParameterName(string matchingPropertyName) + { + NameAsString = matchingPropertyName; + + // `NameAsString` is valid UTF16, so just call the simple UTF16->UTF8 encoder. + ParameterName = Encoding.UTF8.GetBytes(NameAsString); + + ParameterNameKey = JsonClassInfo.GetKey(ParameterName); + } + + // Create a parameter that is ignored at run-time. It uses the same type (typeof(sbyte)) to help + // prevent issues with unsupported types and helps ensure we don't accidently (de)serialize it. + public static JsonParameterInfo CreateIgnoredParameterPlaceholder( + string matchingPropertyName, + ParameterInfo parameterInfo, + JsonSerializerOptions options) + { + JsonParameterInfo jsonParameterInfo = new JsonParameterInfo(); + jsonParameterInfo.Options = options; + jsonParameterInfo.ParameterInfo = parameterInfo; + jsonParameterInfo.ShouldDeserialize = false; + + jsonParameterInfo.DetermineParameterName(matchingPropertyName); + + return jsonParameterInfo; + } + + public abstract bool ReadJson(ref ReadStack state, ref Utf8JsonReader reader, out object? argument); + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfoOfT.cs new file mode 100644 index 00000000000000..b2444779146c1b --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfoOfT.cs @@ -0,0 +1,112 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Reflection; +using System.Text.Json.Serialization; + +namespace System.Text.Json +{ + /// + /// Represents a strongly-typed parameter to prevent boxing where have less than 4 parameters. + /// Holds relevant state like the default value of the parameter, and the position in the method's parameter list. + /// + internal class JsonParameterInfo : JsonParameterInfo + { + private JsonConverter _converter = null!; + private Type _runtimePropertyType = null!; + + public override JsonConverter ConverterBase => _converter; + + public T TypedDefaultValue { get; private set; } = default!; + + public override void Initialize( + string matchingPropertyName, + Type declaredPropertyType, + Type runtimePropertyType, + ParameterInfo parameterInfo, + JsonConverter converter, + JsonSerializerOptions options) + { + base.Initialize( + matchingPropertyName, + declaredPropertyType, + runtimePropertyType, + parameterInfo, + converter, + options); + + _converter = (JsonConverter)converter; + _runtimePropertyType = runtimePropertyType; + + if (parameterInfo.HasDefaultValue) + { + DefaultValue = parameterInfo.DefaultValue; + TypedDefaultValue = (T)parameterInfo.DefaultValue!; + } + else + { + DefaultValue = TypedDefaultValue; + } + } + + public override bool ReadJson(ref ReadStack state, ref Utf8JsonReader reader, out object? value) + { + bool success; + bool isNullToken = reader.TokenType == JsonTokenType.Null; + + if (isNullToken && + ((!_converter.HandleNullValue && !state.IsContinuation) || Options.IgnoreNullValues)) + { + // Don't have to check for IgnoreNullValue option here because we set the default value (likely null) regardless + value = DefaultValue; + return true; + } + else + { + // Optimize for internal converters by avoiding the extra call to TryRead. + if (_converter.CanUseDirectReadOrWrite) + { + value = _converter.Read(ref reader, _runtimePropertyType, Options); + return true; + } + else + { + success = _converter.TryRead(ref reader, _runtimePropertyType, Options, ref state, out T typedValue); + value = typedValue; + } + } + + return success; + } + + public bool ReadJsonTyped(ref ReadStack state, ref Utf8JsonReader reader, out T value) + { + bool success; + bool isNullToken = reader.TokenType == JsonTokenType.Null; + + if (isNullToken && + ((!_converter.HandleNullValue && !state.IsContinuation) || Options.IgnoreNullValues)) + { + // Don't have to check for IgnoreNullValue option here because we set the default value (likely null) regardless + value = TypedDefaultValue; + return true; + } + else + { + // Optimize for internal converters by avoiding the extra call to TryRead. + if (_converter.CanUseDirectReadOrWrite) + { + value = _converter.Read(ref reader, _runtimePropertyType, Options); + return true; + } + else + { + success = _converter.TryRead(ref reader, _runtimePropertyType, Options, ref state, out value); + } + } + + return success; + } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs index 66fca5d59dea68..c519d624711055 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json.Serialization; @@ -38,6 +37,7 @@ public static JsonPropertyInfo CreateIgnoredPropertyPlaceholder(PropertyInfo pro jsonPropertyInfo.Options = options; jsonPropertyInfo.PropertyInfo = propertyInfo; jsonPropertyInfo.DeterminePropertyName(); + jsonPropertyInfo.IsIgnored = true; Debug.Assert(!jsonPropertyInfo.ShouldDeserialize); Debug.Assert(!jsonPropertyInfo.ShouldSerialize); @@ -228,6 +228,30 @@ public bool ReadJsonAndAddExtensionProperty(object obj, ref ReadStack state, ref public abstract bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref Utf8JsonReader reader); + public abstract bool ReadJsonAsObject(ref ReadStack state, ref Utf8JsonReader reader, out object? value); + + public bool ReadJsonExtensionDataValue(ref ReadStack state, ref Utf8JsonReader reader, out object? value) + { + Debug.Assert(this == state.Current.JsonClassInfo.DataExtensionProperty); + + if (RuntimeClassInfo.ElementType == typeof(object) && reader.TokenType == JsonTokenType.Null) + { + value = null; + return true; + } + + JsonConverter converter = (JsonConverter)Options.GetConverter(typeof(JsonElement)); + if (!converter.TryRead(ref reader, typeof(JsonElement), Options, ref state, out JsonElement jsonElement)) + { + // JsonElement is a struct that must be read in full. + value = null; + return false; + } + + value = jsonElement; + return true; + } + public Type ParentClassType { get; private set; } = null!; public PropertyInfo? PropertyInfo { get; private set; } @@ -251,5 +275,6 @@ public JsonClassInfo RuntimeClassInfo public bool ShouldSerialize { get; private set; } public bool ShouldDeserialize { get; private set; } + public bool IsIgnored { get; private set; } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs index 5c8b466a6792c0..1ceb16dc7700fa 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs @@ -175,6 +175,33 @@ public override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref U return success; } + public override bool ReadJsonAsObject(ref ReadStack state, ref Utf8JsonReader reader, out object? value) + { + bool success; + bool isNullToken = reader.TokenType == JsonTokenType.Null; + if (isNullToken && !Converter.HandleNullValue && !state.IsContinuation) + { + value = default(TTypeToConvert)!; + success = true; + } + else + { + // Optimize for internal converters by avoiding the extra call to TryRead. + if (Converter.CanUseDirectReadOrWrite) + { + value = Converter.Read(ref reader, RuntimePropertyType!, Options); + return true; + } + else + { + success = Converter.TryRead(ref reader, RuntimePropertyType!, Options, ref state, out TTypeToConvert typedValue); + value = typedValue; + } + } + + return success; + } + public override void SetValueAsObject(object obj, object? value) { Debug.Assert(HasSetter); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs index 701044f70e0ecd..fda63d5879751b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs @@ -23,35 +23,14 @@ internal static JsonPropertyInfo LookupProperty( ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state, - out bool useExtensionProperty) + out bool useExtensionProperty, + bool createExtensionProperty = true) { Debug.Assert(state.Current.JsonClassInfo.ClassType == ClassType.Object); - JsonPropertyInfo jsonPropertyInfo; + ReadOnlySpan unescapedPropertyName = GetPropertyName(ref state, ref reader, options); - ReadOnlySpan unescapedPropertyName; - ReadOnlySpan propertyName = reader.GetSpan(); - - if (reader._stringHasEscaping) - { - int idx = propertyName.IndexOf(JsonConstants.BackSlash); - Debug.Assert(idx != -1); - unescapedPropertyName = JsonReaderHelper.GetUnescapedSpan(propertyName, idx); - } - else - { - unescapedPropertyName = propertyName; - } - - if (options.ReferenceHandling.ShouldReadPreservedReferences()) - { - if (propertyName.Length > 0 && propertyName[0] == '$') - { - ThrowHelper.ThrowUnexpectedMetadataException(propertyName, ref reader, ref state); - } - } - - jsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(unescapedPropertyName, ref state.Current); + JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(unescapedPropertyName, ref state.Current); // Increment PropertyIndex so GetProperty() starts with the next property the next time this function is called. state.Current.PropertyIndex++; @@ -63,12 +42,21 @@ internal static JsonPropertyInfo LookupProperty( if (dataExtProperty != null) { state.Current.JsonPropertyNameAsString = JsonHelpers.Utf8GetString(unescapedPropertyName); - CreateDataExtensionProperty(obj, dataExtProperty); + + if (createExtensionProperty) + { + CreateDataExtensionProperty(obj, dataExtProperty); + } + jsonPropertyInfo = dataExtProperty; + useExtensionProperty = true; + } + else + { + useExtensionProperty = false; } state.Current.JsonPropertyInfo = jsonPropertyInfo; - useExtensionProperty = true; return jsonPropertyInfo; } @@ -101,7 +89,38 @@ internal static JsonPropertyInfo LookupProperty( return jsonPropertyInfo; } - private static void CreateDataExtensionProperty( + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static ReadOnlySpan GetPropertyName( + ref ReadStack state, + ref Utf8JsonReader reader, + JsonSerializerOptions options) + { + ReadOnlySpan unescapedPropertyName; + ReadOnlySpan propertyName = reader.GetSpan(); + + if (reader._stringHasEscaping) + { + int idx = propertyName.IndexOf(JsonConstants.BackSlash); + Debug.Assert(idx != -1); + unescapedPropertyName = JsonReaderHelper.GetUnescapedSpan(propertyName, idx); + } + else + { + unescapedPropertyName = propertyName; + } + + if (options.ReferenceHandling.ShouldReadPreservedReferences()) + { + if (propertyName.Length > 0 && propertyName[0] == '$') + { + ThrowHelper.ThrowUnexpectedMetadataException(propertyName, ref reader, ref state); + } + } + + return unescapedPropertyName; + } + + internal static void CreateDataExtensionProperty( object obj, JsonPropertyInfo jsonPropertyInfo) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/MemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/MemberAccessor.cs index 5a308567628952..ae87d6feffc84e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/MemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/MemberAccessor.cs @@ -11,6 +11,11 @@ internal abstract class MemberAccessor { public abstract JsonClassInfo.ConstructorDelegate? CreateConstructor(Type classType); + public abstract JsonClassInfo.ParameterizedConstructorDelegate? CreateParameterizedConstructor(ConstructorInfo constructor); + + public abstract JsonClassInfo.ParameterizedConstructorDelegate? + CreateParameterizedConstructor(ConstructorInfo constructor); + public abstract Action CreateAddMethodDelegate(); public abstract Func, TCollection> CreateImmutableEnumerableCreateRangeDelegate(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ParameterRef.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ParameterRef.cs new file mode 100644 index 00000000000000..9f2c654b5a9134 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ParameterRef.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Text.Json +{ + internal readonly struct ParameterRef + { + public ParameterRef(ulong key, JsonParameterInfo info) + { + Key = key; + Info = info; + } + + // The first 6 bytes are the first part of the name and last 2 bytes are the name's length. + public readonly ulong Key; + + public readonly JsonParameterInfo Info; + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStack.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStack.cs index fc603d77584615..3a9e0dddf145dd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStack.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStack.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Text.Json.Serialization; namespace System.Text.Json @@ -26,6 +27,9 @@ internal struct ReadStack private List _previous; + // State cache when deserializing objects with parameterized constructors. + private List? _ctorArgStateCache; + /// /// Bytes consumed in the current loop. /// @@ -100,7 +104,18 @@ public void Push() else { JsonClassInfo jsonClassInfo; - if ((Current.JsonClassInfo.ClassType & (ClassType.Object | ClassType.Value | ClassType.NewValue)) != 0) + if (Current.JsonClassInfo.ClassType == ClassType.Object) + { + if (Current.JsonPropertyInfo != null) + { + jsonClassInfo = Current.JsonPropertyInfo.RuntimeClassInfo; + } + else + { + jsonClassInfo = Current.CtorArgumentState!.JsonParameterInfo!.RuntimeClassInfo; + } + } + else if ((Current.JsonClassInfo.ClassType & (ClassType.Value | ClassType.NewValue)) != 0) { // Although ClassType.Value doesn't push, a custom custom converter may re-enter serialization. jsonClassInfo = Current.JsonPropertyInfo!.RuntimeClassInfo; @@ -138,6 +153,8 @@ public void Push() _count++; } } + + SetConstrutorArgumentState(); } public void Pop(bool success) @@ -187,6 +204,8 @@ public void Pop(bool success) { Current = _previous[--_count -1]; } + + SetConstrutorArgumentState(); } // Return a JSONPath using simple dot-notation when possible. When special characters are present, bracket-notation is used: @@ -278,8 +297,9 @@ static void AppendPropertyName(StringBuilder sb, string? propertyName) byte[]? utf8PropertyName = frame.JsonPropertyName; if (utf8PropertyName == null) { - // Attempt to get the JSON property name from the JsonPropertyInfo. - utf8PropertyName = frame.JsonPropertyInfo?.JsonPropertyName; + // Attempt to get the JSON property name from the JsonPropertyInfo or JsonParameterInfo. + utf8PropertyName = frame.JsonPropertyInfo?.JsonPropertyName ?? + frame.CtorArgumentState?.JsonParameterInfo?.JsonPropertyName; if (utf8PropertyName == null) { // Attempt to get the JSON property name set manually for dictionary @@ -296,5 +316,30 @@ static void AppendPropertyName(StringBuilder sb, string? propertyName) return propertyName; } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetConstrutorArgumentState() + { + if (Current.JsonClassInfo.ParameterCount > 0) + { + // A zero index indicates a new stack frame. + if (Current.CtorArgumentStateIndex == 0) + { + if (_ctorArgStateCache == null) + { + _ctorArgStateCache = new List(); + } + + var newState = new ArgumentState(); + _ctorArgStateCache.Add(newState); + + (Current.CtorArgumentStateIndex, Current.CtorArgumentState) = (_ctorArgStateCache.Count, newState); + } + else + { + Current.CtorArgumentState = _ctorArgStateCache![Current.CtorArgumentStateIndex - 1]; + } + } + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs index eba6e43463876a..e7d85825f15013 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs @@ -38,6 +38,17 @@ internal struct ReadStackFrame // Add method delegate for Non-generic Stack and Queue; and types that derive from them. public object? AddMethodDelegate; + // Holds relevant state when deserializing objects with parameterized constructors. + public int CtorArgumentStateIndex; + public ArgumentState? CtorArgumentState; + + public void EndConstructorParameter() + { + CtorArgumentState!.JsonParameterInfo = null; + JsonPropertyName = null; + PropertyState = StackFramePropertyState.None; + } + public void EndProperty() { JsonPropertyInfo = null!; @@ -86,6 +97,8 @@ public bool IsProcessingEnumerable() public void Reset() { AddMethodDelegate = null; + CtorArgumentStateIndex = 0; + CtorArgumentState = null; JsonClassInfo = null!; ObjectState = StackFrameObjectState.None; OriginalDepth = 0; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs index f37ceca20c7876..3e34ada077cdaf 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs @@ -5,6 +5,7 @@ #if NETFRAMEWORK || NETCOREAPP using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -55,6 +56,110 @@ internal sealed class ReflectionEmitMemberAccessor : MemberAccessor return (JsonClassInfo.ConstructorDelegate)dynamicMethod.CreateDelegate(typeof(JsonClassInfo.ConstructorDelegate)); } + public override JsonClassInfo.ParameterizedConstructorDelegate? CreateParameterizedConstructor(ConstructorInfo constructor) + { + Type type = typeof(T); + + Debug.Assert(!type.IsAbstract); + // If ctor is non-public, we've verified upstream that it has the [JsonConstructorAttribute]. + Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .Contains(constructor)); + + ParameterInfo[] parameters = constructor.GetParameters(); + int parameterCount = parameters.Length; + + if (parameterCount > JsonConstants.MaxParameterCount) + { + return null; + } + + var dynamicMethod = new DynamicMethod( + ConstructorInfo.ConstructorName, + type, + new[] { typeof(object[]) }, + typeof(ReflectionEmitMemberAccessor).Module, + skipVisibility: true); + + ILGenerator generator = dynamicMethod.GetILGenerator(); + + for (int i = 0; i < parameterCount; i++) + { + Type paramType = parameters[i].ParameterType; + + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldc_I4_S, i); + generator.Emit(OpCodes.Ldelem_Ref); + + if (paramType.IsValueType) + { + generator.Emit(OpCodes.Unbox_Any, paramType); + } + else + { + generator.Emit(OpCodes.Castclass, paramType); + }; + } + + generator.Emit(OpCodes.Newobj, constructor); + generator.Emit(OpCodes.Ret); + + return (JsonClassInfo.ParameterizedConstructorDelegate)dynamicMethod.CreateDelegate(typeof(JsonClassInfo.ParameterizedConstructorDelegate)); + } + + public override JsonClassInfo.ParameterizedConstructorDelegate? + CreateParameterizedConstructor(ConstructorInfo constructor) + { + Type type = typeof(T); + + Debug.Assert(!type.IsAbstract); + // If ctor is non-public, we've verified upstream that it has the [JsonConstructorAttribute]. + Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .Contains(constructor)); + + ParameterInfo[] parameters = constructor.GetParameters(); + int parameterCount = parameters.Length; + + Debug.Assert(parameterCount <= JsonConstants.UnboxedParameterCountThreshold); + + var dynamicMethod = new DynamicMethod( + ConstructorInfo.ConstructorName, + type, + new[] { typeof(TArg0), typeof(TArg1), typeof(TArg2), typeof(TArg3) }, + typeof(ReflectionEmitMemberAccessor).Module, + skipVisibility: true); + + ILGenerator generator = dynamicMethod.GetILGenerator(); + + for (int index = 0; index < parameterCount; index++) + { + switch (index) + { + case 0: + generator.Emit(OpCodes.Ldarg_0); + break; + case 1: + generator.Emit(OpCodes.Ldarg_1); + break; + case 2: + generator.Emit(OpCodes.Ldarg_2); + break; + case 3: + generator.Emit(OpCodes.Ldarg_3); + break; + default: + Debug.Fail("We shouldn't be here if there are more than 4 parameters."); + throw new InvalidOperationException(); + } + } + + generator.Emit(OpCodes.Newobj, constructor); + generator.Emit(OpCodes.Ret); + + return (JsonClassInfo.ParameterizedConstructorDelegate) + dynamicMethod.CreateDelegate( + typeof(JsonClassInfo.ParameterizedConstructorDelegate)); + } + public override Action CreateAddMethodDelegate() { Type collectionType = typeof(TCollection); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs index ec2bfd62b2b421..db8e8573b39353 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; +using System.Linq; using System.Reflection; namespace System.Text.Json.Serialization @@ -25,7 +27,92 @@ internal sealed class ReflectionMemberAccessor : MemberAccessor return null; } - return () => Activator.CreateInstance(type); + return () => Activator.CreateInstance(type, nonPublic: false); + } + + public override JsonClassInfo.ParameterizedConstructorDelegate? CreateParameterizedConstructor(ConstructorInfo constructor) + { + Type type = typeof(T); + + Debug.Assert(!type.IsAbstract); + // If ctor is non-public, we've verified upstream that it has the [JsonConstructorAttribute]. + Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .Contains(constructor)); + + int parameterCount = constructor.GetParameters().Length; + + if (parameterCount > JsonConstants.MaxParameterCount) + { + return null; + } + + return (arguments) => + { + // The input array was rented from the shared ArrayPool, so its size is likely to be larger than the param count. + // The emit equivalent of this method does not (need to) allocate here + transfer the objects. + object[] argsToPass = new object[parameterCount]; + + for (int i = 0; i < parameterCount; i++) + { + argsToPass[i] = arguments[i]; + } + + try + { + return (T)constructor.Invoke(argsToPass); + } + catch (TargetInvocationException e) + { + // Plumb ArgumentException through for tuples with more than 7 generic parameters, e.g. + // System.ArgumentException : The last element of an eight element tuple must be a Tuple. + // This doesn't apply to the method below as it supports a max of 4 constructor params. + throw e.InnerException ?? e; + } + }; + } + + public override JsonClassInfo.ParameterizedConstructorDelegate? + CreateParameterizedConstructor(ConstructorInfo constructor) + { + Type type = typeof(T); + + Debug.Assert(!type.IsAbstract); + // If ctor is non-public, we've verified upstream that it has the [JsonConstructorAttribute]. + Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .Contains(constructor)); + + int parameterCount = constructor.GetParameters().Length; + + Debug.Assert(parameterCount < JsonConstants.UnboxedParameterCountThreshold); + + return (arg0, arg1, arg2, arg3) => + { + object[] arguments = new object[parameterCount]; + + for (int i = 0; i < parameterCount; i++) + { + switch (i) + { + case 0: + arguments[0] = arg0!; + break; + case 1: + arguments[1] = arg1!; + break; + case 2: + arguments[2] = arg2!; + break; + case 3: + arguments[3] = arg3!; + break; + default: + Debug.Fail("We shouldn't be here if there are more than 4 parameters."); + throw new InvalidOperationException(); + } + } + + return (T)constructor.Invoke(arguments); + }; } public override Action CreateAddMethodDelegate() diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs index 20d9924951b5b7..6ff469e1616d0d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs @@ -26,6 +26,13 @@ public static void ThrowNotSupportedException_SerializationNotSupported(Type pro throw new NotSupportedException(SR.Format(SR.SerializationNotSupportedType, propertyType)); } + [DoesNotReturn] + [MethodImpl(MethodImplOptions.NoInlining)] + public static NotSupportedException ThrowNotSupportedException_ConstructorMaxOf64Parameters(ConstructorInfo constructorInfo, Type type) + { + throw new NotSupportedException(SR.Format(SR.ConstructorMaxOf64Parameters, constructorInfo, type)); + } + [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType) @@ -121,9 +128,9 @@ public static void ThrowInvalidOperationException_SerializerOptionsImmutable() [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowInvalidOperationException_SerializerPropertyNameConflict(JsonClassInfo jsonClassInfo, JsonPropertyInfo jsonPropertyInfo) + public static void ThrowInvalidOperationException_SerializerPropertyNameConflict(Type type, JsonPropertyInfo jsonPropertyInfo) { - throw new InvalidOperationException(SR.Format(SR.SerializerPropertyNameConflict, jsonClassInfo.Type, jsonPropertyInfo.PropertyInfo?.Name)); + throw new InvalidOperationException(SR.Format(SR.SerializerPropertyNameConflict, type, jsonPropertyInfo.PropertyInfo?.Name)); } [DoesNotReturn] @@ -146,6 +153,56 @@ public static void ThrowInvalidOperationException_SerializerConverterFactoryRetu throw new InvalidOperationException(SR.Format(SR.SerializerConverterFactoryReturnsNull, converterType)); } + [DoesNotReturn] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowInvalidOperationException_MultiplePropertiesBindToConstructorParameters( + Type parentType, + ParameterInfo parameterInfo, + PropertyInfo firstMatch, + PropertyInfo secondMatch, + ConstructorInfo constructorInfo) + { + throw new InvalidOperationException( + SR.Format( + SR.MultipleMembersBindWithConstructorParameter, + firstMatch.Name, + secondMatch.Name, + parentType, + parameterInfo.Name, + constructorInfo)); + } + + [DoesNotReturn] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(ConstructorInfo constructorInfo, Type parentType) + { + throw new InvalidOperationException(SR.Format(SR.ConstructorParamIncompleteBinding, constructorInfo, parentType)); + } + + [DoesNotReturn] + [MethodImpl(MethodImplOptions.NoInlining)] + public static NotSupportedException ThrowInvalidOperationException_ExtensionDataCannotBindToCtorParam( + PropertyInfo propertyInfo, + Type classType, + ConstructorInfo constructorInfo) + { + throw new InvalidOperationException(SR.Format(SR.ExtensionDataCannotBindToCtorParam, propertyInfo, classType, constructorInfo)); + } + + [DoesNotReturn] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowNotSupportedException_ObjectWithParameterizedCtorRefMetadataNotHonored( + ReadOnlySpan propertyName, + ref Utf8JsonReader reader, + ref ReadStack state) + { + state.Current.JsonPropertyName = propertyName.ToArray(); + + NotSupportedException ex = new NotSupportedException( + SR.Format(SR.ObjectWithParameterizedCtorRefMetadataNotHonored, state.Current.JsonClassInfo.Type)); + ThrowNotSupportedException(state, reader, ex); + } + [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] public static void ReThrowWithPath(in ReadStack state, JsonReaderException ex) @@ -262,9 +319,16 @@ public static void ThrowInvalidOperationException_SerializationDuplicateTypeAttr [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(JsonClassInfo jsonClassInfo, JsonPropertyInfo jsonPropertyInfo) + public static void ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(Type classType) { - throw new InvalidOperationException(SR.Format(SR.SerializationDataExtensionPropertyInvalid, jsonClassInfo.Type, jsonPropertyInfo.PropertyInfo?.Name)); + throw new InvalidOperationException(SR.Format(SR.SerializationDuplicateTypeAttribute, classType, typeof(Attribute))); + } + + [DoesNotReturn] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(Type type, JsonPropertyInfo jsonPropertyInfo) + { + throw new InvalidOperationException(SR.Format(SR.SerializationDataExtensionPropertyInvalid, type, jsonPropertyInfo.PropertyInfo?.Name)); } [DoesNotReturn] @@ -331,7 +395,7 @@ public static void ThrowNotSupportedException(in WriteStack state, NotSupportedE [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowNotSupportedException_DeserializeNoParameterlessConstructor(Type invalidType) + public static void ThrowNotSupportedException_DeserializeNoDeserializationConstructor(Type invalidType) { if (invalidType.IsInterface) { @@ -339,7 +403,7 @@ public static void ThrowNotSupportedException_DeserializeNoParameterlessConstruc } else { - throw new NotSupportedException(SR.Format(SR.DeserializeMissingParameterlessConstructor, invalidType)); + throw new NotSupportedException(SR.Format(SR.DeserializeMissingDeserializationConstructor, nameof(JsonConstructorAttribute), invalidType)); } } @@ -454,6 +518,11 @@ internal static void ThrowUnexpectedMetadataException( ref Utf8JsonReader reader, ref ReadStack state) { + if (state.Current.JsonClassInfo.PropertyInfoForClassInfo.ConverterBase.ConstructorIsParameterized) + { + ThrowNotSupportedException_ObjectWithParameterizedCtorRefMetadataNotHonored(propertyName, ref reader, ref state); + } + MetadataPropertyName name = JsonSerializer.GetMetadataPropertyName(propertyName); if (name == MetadataPropertyName.Id) { diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.AttributePresence.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.AttributePresence.cs new file mode 100644 index 00000000000000..e3b69731577da3 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.AttributePresence.cs @@ -0,0 +1,162 @@ +//Licensed to the.NET Foundation under one or more agreements. +//The.NET Foundation licenses this file to you under the MIT license. +//See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class ConstructorTests + { + [Fact] + public void NonPublicCtors_NotSupported() + { + void RunTest() + { + NotSupportedException ex = Assert.Throws(() => Serializer.Deserialize("{}")); + Assert.Contains("JsonConstructorAttribute", ex.ToString()); + } + + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + } + + [Fact] + public void SinglePublicParameterizedCtor_SingleParameterlessCtor_NoAttribute_Supported_UseParameterlessCtor() + { + var obj1 = Serializer.Deserialize(@"{""MyInt"":1,""MyString"":""1""}"); + Assert.Equal(@"{""MyInt"":0,""MyString"":null}", JsonSerializer.Serialize(obj1)); + } + + [Fact] + public void MultiplePublicParameterizedCtors_SingleParameterlessCtor_NoAttribute_Supported_UseParameterlessCtor() + { + void RunTest() + { + var obj1 = Serializer.Deserialize(@"{""MyInt"":1,""MyString"":""1""}"); + Assert.Equal(@"{""MyInt"":0,""MyString"":null}", JsonSerializer.Serialize(obj1)); + } + + RunTest(); + RunTest(); + } + + [Fact] + public void SinglePublicParameterizedCtor_NoPublicParameterlessCtor_NoAttribute_Supported() + { + void RunTest() + { + var obj1 = Serializer.Deserialize(@"{""MyInt"":1}"); + Assert.Equal(@"{""MyInt"":1}", JsonSerializer.Serialize(obj1)); + } + + RunTest(); + RunTest(); + } + + [Fact] + public void SinglePublicParameterizedCtor_NoPublicParameterlessCtor_WithAttribute_Supported() + { + void RunTest() + { + var obj1 = Serializer.Deserialize(@"{""MyInt"":1}"); + Assert.Equal(@"{""MyInt"":1}", JsonSerializer.Serialize(obj1)); + } + + RunTest(); + RunTest(); + RunTest(); + } + + [Fact] + public void Class_MultiplePublicParameterizedCtors_NoPublicParameterlessCtor_NoAttribute_NotSupported() + { + Assert.Throws(() => Serializer.Deserialize(@"{""MyInt"":1,""MyString"":""1""}")); + } + + [Fact] + public void Struct_MultiplePublicParameterizedCtors_NoPublicParameterlessCtor_NoAttribute_Supported_UseParameterlessCtor() + { + var obj = Serializer.Deserialize(@"{""myInt"":1,""myString"":""1""}"); + Assert.Equal(0, obj.MyInt); + Assert.Null(obj.MyString); + Assert.Equal(@"{""MyInt"":0,""MyString"":null}", JsonSerializer.Serialize(obj)); + } + + [Fact] + public void NoPublicParameterlessCtor_MultiplePublicParameterizedCtors_WithAttribute_Supported() + { + var obj1 = Serializer.Deserialize(@"{""MyInt"":1,""MyString"":""1""}"); + Assert.Equal(1, obj1.MyInt); + Assert.Null(obj1.MyString); + Assert.Equal(@"{""MyInt"":1,""MyString"":null}", JsonSerializer.Serialize(obj1)); + + var obj2 = Serializer.Deserialize(@"{""MyInt"":1,""MyString"":""1""}"); + Assert.Equal(1, obj2.MyInt); + Assert.Equal("1", obj2.MyString); + Assert.Equal(@"{""MyInt"":1,""MyString"":""1""}", JsonSerializer.Serialize(obj2)); + } + + [Fact] + public void PublicParameterlessCtor_MultiplePublicParameterizedCtors_WithAttribute_Supported() + { + var obj = Serializer.Deserialize(@"{""MyInt"":1,""MyString"":""1""}"); + Assert.Equal(1, obj.MyInt); + Assert.Null(obj.MyString); + Assert.Equal(@"{""MyInt"":1,""MyString"":null}", JsonSerializer.Serialize(obj)); + } + + [Fact] + public void MultipleAttributes_NotSupported() + { + void RunTest() + { + Assert.Throws(() => Serializer.Deserialize("{}")); + } + + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + RunTest(); + } + + [Fact] + public void AttributeIgnoredOnIEnumerable() + { + void RunTest() + { + Assert.Throws(() => Serializer.Deserialize("[]")); + } + + RunTest(); + RunTest(); + } + + [Fact] + public void Struct_Use_DefaultCtor_ByDefault() + { + string json = @"{""X"":1,""Y"":2}"; + + // By default, serializer uses default ctor to deserializer structs + var point1 = Serializer.Deserialize(json); + Assert.Equal(0, point1.X); + Assert.Equal(0, point1.Y); + + var point2 = Serializer.Deserialize(json); + Assert.Equal(1, point2.X); + Assert.Equal(2, point2.Y); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Cache.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Cache.cs new file mode 100644 index 00000000000000..f8797d96879646 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Cache.cs @@ -0,0 +1,162 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Reflection; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class ConstructorTests + { + [Fact, OuterLoop] + public void MultipleThreadsLooping() + { + const int Iterations = 100; + + for (int i = 0; i < Iterations; i++) + { + MultipleThreads(); + } + } + + [Fact] + public void MultipleThreads() + { + // Use local options to avoid obtaining already cached metadata from the default options. + var options = new JsonSerializerOptions(); + + // Verify the test class has >32 properties since that is a threshold for using the fallback dictionary. + Assert.True(typeof(ClassWithConstructor_SimpleAndComplexParameters).GetProperties(BindingFlags.Instance | BindingFlags.Public).Length > 32); + + void DeserializeObjectMinimal() + { + var obj = Serializer.Deserialize(@"{""MyDecimal"" : 3.3}", options); + }; + + void DeserializeObjectFlipped() + { + var obj = Serializer.Deserialize( + ClassWithConstructor_SimpleAndComplexParameters.s_json_flipped, options); + obj.Verify(); + }; + + void DeserializeObjectNormal() + { + var obj = Serializer.Deserialize( + ClassWithConstructor_SimpleAndComplexParameters.s_json, options); + obj.Verify(); + }; + + void SerializeObject() + { + var obj = ClassWithConstructor_SimpleAndComplexParameters.GetInstance(); + JsonSerializer.Serialize(obj, options); + }; + + const int ThreadCount = 8; + const int ConcurrentTestsCount = 4; + Task[] tasks = new Task[ThreadCount * ConcurrentTestsCount]; + + for (int i = 0; i < tasks.Length; i += ConcurrentTestsCount) + { + // Create race condition to populate the sorted property cache with different json ordering. + tasks[i + 0] = Task.Run(() => DeserializeObjectMinimal()); + tasks[i + 1] = Task.Run(() => DeserializeObjectFlipped()); + tasks[i + 2] = Task.Run(() => DeserializeObjectNormal()); + + // Ensure no exceptions on serialization + tasks[i + 3] = Task.Run(() => SerializeObject()); + }; + + Task.WaitAll(tasks); + } + + [Fact] + public void PropertyCacheWithMinInputsFirst() + { + // Use local options to avoid obtaining already cached metadata from the default options. + var options = new JsonSerializerOptions(); + + string json = "{}"; + Serializer.Deserialize(json, options); + + ClassWithConstructor_SimpleAndComplexParameters testObj = ClassWithConstructor_SimpleAndComplexParameters.GetInstance(); + testObj.Verify(); + + json = JsonSerializer.Serialize(testObj, options); + testObj = Serializer.Deserialize(json, options); + testObj.Verify(); + } + + [Fact] + public void PropertyCacheWithMinInputsLast() + { + // Use local options to avoid obtaining already cached metadata from the default options. + var options = new JsonSerializerOptions(); + + ClassWithConstructor_SimpleAndComplexParameters testObj = ClassWithConstructor_SimpleAndComplexParameters.GetInstance(); + testObj.Verify(); + + string json = JsonSerializer.Serialize(testObj, options); + testObj = Serializer.Deserialize(json, options); + testObj.Verify(); + + json = "{}"; + Serializer.Deserialize(json, options); + } + + // Use a common options instance to encourage additional metadata collisions across types. Also since + // this options is not the default options instance the tests will not use previously cached metadata. + private JsonSerializerOptions s_options = new JsonSerializerOptions(); + + [Fact] + public void MultipleTypes() + { + void Serialize(object[] args) + { + Type type = typeof(T); + + T localTestObj = (T)Activator.CreateInstance(type, args); + ((ITestClass)localTestObj).Initialize(); + ((ITestClass)localTestObj).Verify(); + string json = JsonSerializer.Serialize(localTestObj, s_options); + }; + + void Deserialize(string json) + { + ITestClass obj = (ITestClass)Serializer.Deserialize(json, s_options); + obj.Verify(); + }; + + void RunTest(T testObj, object[] args) + { + // Get the test json with the default options to avoid cache pollution of Deserialize() below. + ((ITestClass)testObj).Initialize(); + ((ITestClass)testObj).Verify(); + string json = JsonSerializer.Serialize(testObj); + + const int ThreadCount = 12; + const int ConcurrentTestsCount = 2; + Task[] tasks = new Task[ThreadCount * ConcurrentTestsCount]; + + for (int i = 0; i < tasks.Length; i += ConcurrentTestsCount) + { + tasks[i + 0] = Task.Run(() => Deserialize(json)); + tasks[i + 1] = Task.Run(() => Serialize(args)); + }; + + Task.WaitAll(tasks); + } + + RunTest(new Point_2D(1, 2), new object[] { 1, 2 }); + RunTest(new Point_3D(1, 2, 3), new object[] { 1, 2, 3 }); + RunTest(new Point_2D_With_ExtData(1, 2), new object[] { 1, 2 }); + + Guid id = Guid.Parse("270bb22b-4816-4bd9-9acd-8ec5b1a896d3"); + RunTest(new Parameterized_Person_Simple(id), new object[] { id }); + RunTest(new Point_MembersHave_JsonPropertyName(1, 2), new object[] { 1, 2 }); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Exceptions.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Exceptions.cs new file mode 100644 index 00000000000000..e47b1e98156cde --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Exceptions.cs @@ -0,0 +1,338 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class ConstructorTests + { + [Fact] + public void MultipleProperties_Cannot_BindTo_TheSame_ConstructorParameter() + { + InvalidOperationException ex = Assert.Throws( + () => Serializer.Deserialize("{}")); + + string exStr = ex.ToString(); + Assert.Contains("'X'", exStr); + Assert.Contains("'x'", exStr); + Assert.Contains("(Int32, Int32)", exStr); + Assert.Contains("System.Text.Json.Serialization.Tests.Point_MultipleMembers_BindTo_OneConstructorParameter", exStr); + + ex = Assert.Throws( + () => Serializer.Deserialize("{}")); + + exStr = ex.ToString(); + Assert.Contains("'X'", exStr); + Assert.Contains("'x'", exStr); + Assert.Contains("(Int32)", exStr); + Assert.Contains("System.Text.Json.Serialization.Tests.Point_MultipleMembers_BindTo_OneConstructorParameter_Variant", exStr); + } + + [Fact] + public void All_ConstructorParameters_MustBindTo_ObjectMembers() + { + InvalidOperationException ex = Assert.Throws( + () => Serializer.Deserialize("{}")); + + string exStr = ex.ToString(); + Assert.Contains("(Int32, Int32)", exStr); + Assert.Contains("System.Text.Json.Serialization.Tests.Point_Without_Members", exStr); + + ex = Assert.Throws( + () => Serializer.Deserialize("{}")); + exStr = ex.ToString(); + Assert.Contains("(Int32, Int32)", exStr); + Assert.Contains("System.Text.Json.Serialization.Tests.Point_With_MismatchedMembers", exStr); + + ex = Assert.Throws( + () => Serializer.Deserialize(@"{""MyInt"":1,""MyPoint"":{}}")); + exStr = ex.ToString(); + Assert.Contains("(Int32, Int32)", exStr); + Assert.Contains("System.Text.Json.Serialization.Tests.Point_With_MismatchedMembers", exStr); + } + + [Fact] + public void LeadingReferenceMetadataNotSupported() + { + string json = @"{""$id"":""1"",""Name"":""Jet"",""Manager"":{""$ref"":""1""}}"; + + // Metadata ignored by default. + var employee = Serializer.Deserialize(json); + + Assert.Equal("Jet", employee.Name); + Assert.Null(employee.Manager.Name); ; + Assert.Null(employee.Manager.Manager); + + // Metadata not supported with preserve ref feature on. + + var options = new JsonSerializerOptions { ReferenceHandling = ReferenceHandling.Preserve }; + + NotSupportedException ex = Assert.Throws( + () => Serializer.Deserialize(json, options)); + + string exStr = ex.ToString(); + Assert.Contains("System.Text.Json.Serialization.Tests.ConstructorTests+Employee", exStr); + Assert.Contains("$.$id", exStr); + } + + private class Employee + { + public string Name { get; } + public Employee Manager { get; set; } + + public Employee(string name) + { + Name = name; + } + } + + [Fact] + public void RandomReferenceMetadataNotSupported() + { + string json = @"{""Name"":""Jet"",""$random"":10}"; + + // Baseline, preserve ref feature off. + + var employee = JsonSerializer.Deserialize(json); + + Assert.Equal("Jet", employee.Name); + + // Metadata not supported with preserve ref feature on. + + var options = new JsonSerializerOptions { ReferenceHandling = ReferenceHandling.Preserve }; + + NotSupportedException ex = Assert.Throws(() => Serializer.Deserialize(json, options)); + string exStr = ex.ToString(); + Assert.Contains("System.Text.Json.Serialization.Tests.ConstructorTests+Employee", exStr); + Assert.Contains("$.$random", exStr); + } + + [Fact] + public void ExtensionDataProperty_CannotBindTo_CtorParam() + { + InvalidOperationException ex = Assert.Throws(() => Serializer.Deserialize("{}")); + string exStr = ex.ToString(); + Assert.Contains("System.Collections.Generic.Dictionary`2[System.String,System.Text.Json.JsonElement] ExtensionData", exStr); + Assert.Contains("System.Text.Json.Serialization.Tests.ConstructorTests+Class_ExtData_CtorParam", exStr); + Assert.Contains("(System.Collections.Generic.Dictionary`2[System.String,System.Text.Json.JsonElement])", exStr); + } + + public class Class_ExtData_CtorParam + { + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } + + public Class_ExtData_CtorParam(Dictionary extensionData) { } + } + + [Fact] + public void AnonymousObject_InvalidOperationException() + { + var obj = new { Prop = 5 }; + + InvalidOperationException ex = Assert.Throws(() => JsonSerializer.Deserialize("{}", obj.GetType())); + + // We expect property 'Prop' to bind with a ctor arg called 'prop', but the ctor arg is called 'Prop'. + string exStr = ex.ToString(); + Assert.Contains("AnonymousType", exStr); + Assert.Contains("(Int32)", exStr); + Assert.Contains("[System.Int32]", exStr); + } + + [Fact] + public void DeserializePathForObjectFails() + { + const string GoodJson = "{\"Property\u04671\":1}"; + const string GoodJsonEscaped = "{\"Property\\u04671\":1}"; + const string BadJson = "{\"Property\u04671\":bad}"; + const string BadJsonEscaped = "{\"Property\\u04671\":bad}"; + const string Expected = "$.Property\u04671"; + + ClassWithUnicodePropertyName obj; + + // Baseline. + obj = Serializer.Deserialize(GoodJson); + Assert.Equal(1, obj.Property\u04671); + + obj = Serializer.Deserialize(GoodJsonEscaped); + Assert.Equal(1, obj.Property\u04671); + + JsonException e; + + // Exception. + e = Assert.Throws(() => Serializer.Deserialize(BadJson)); + Assert.Equal(Expected, e.Path); + + e = Assert.Throws(() => Serializer.Deserialize(BadJsonEscaped)); + Assert.Equal(Expected, e.Path); + } + + private class ClassWithUnicodePropertyName + { + public int Property\u04671 { get; } // contains a trailing "1" + + public ClassWithUnicodePropertyName(int property\u04671) + { + Property\u04671 = property\u04671; + } + } + + [Fact] + public void PathForChildPropertyFails() + { + JsonException e = Assert.Throws(() => Serializer.Deserialize(@"{""Child"":{""MyInt"":bad]}")); + Assert.Equal("$.Child.MyInt", e.Path); + } + + public class RootClass + { + public ChildClass Child { get; } + + public RootClass(ChildClass child) + { + Child = child; + } + } + + public class ChildClass + { + public int MyInt { get; set; } + public int[] MyIntArray { get; set; } + public Dictionary MyDictionary { get; set; } + public ChildClass[] Children { get; set; } + } + + [Fact] + public void PathForChildListFails() + { + JsonException e = Assert.Throws(() => Serializer.Deserialize(@"{""Child"":{""MyIntArray"":[1, bad]}")); + Assert.Contains("$.Child.MyIntArray", e.Path); + } + + [Fact] + public void PathForChildDictionaryFails() + { + JsonException e = Assert.Throws(() => Serializer.Deserialize(@"{""Child"":{""MyDictionary"":{""Key"": bad]")); + Assert.Equal("$.Child.MyDictionary.Key", e.Path); + } + + [Fact] + public void PathForSpecialCharacterFails() + { + JsonException e = Assert.Throws(() => Serializer.Deserialize(@"{""Child"":{""MyDictionary"":{""Key1"":{""Children"":[{""MyDictionary"":{""K.e.y"":""")); + Assert.Equal("$.Child.MyDictionary.Key1.Children[0].MyDictionary['K.e.y']", e.Path); + } + + [Fact] + public void PathForSpecialCharacterNestedFails() + { + JsonException e = Assert.Throws(() => Serializer.Deserialize(@"{""Child"":{""Children"":[{}, {""MyDictionary"":{""K.e.y"": {""MyInt"":bad")); + Assert.Equal("$.Child.Children[1].MyDictionary['K.e.y'].MyInt", e.Path); + } + + [Fact] + public void EscapingFails() + { + JsonException e = Assert.Throws(() => Serializer.Deserialize("{\"A\u0467\":bad}")); + Assert.Equal("$.A\u0467", e.Path); + } + + public class Parameterized_ClassWithUnicodeProperty + { + public int A\u0467 { get; } + + public Parameterized_ClassWithUnicodeProperty(int a\u0467) + { + A\u0467 = a\u0467; + } + } + + [Fact] + [ActiveIssue("JsonElement needs to support Path")] + public void ExtensionPropertyRoundTripFails() + { + JsonException e = Assert.Throws(() => Serializer.Deserialize(@"{""MyNestedClass"":{""UnknownProperty"":bad}}")); + Assert.Equal("$.MyNestedClass.UnknownProperty", e.Path); + } + + private class Parameterized_ClassWithExtensionProperty + { + public SimpleTestClass MyNestedClass { get; } + public int MyInt { get; } + + [JsonExtensionData] + public IDictionary MyOverflow { get; set; } + + public Parameterized_ClassWithExtensionProperty(SimpleTestClass myNestedClass, int myInt) + { + MyNestedClass = myNestedClass; + MyInt = myInt; + } + } + + [Fact] + public void CaseInsensitiveFails() + { + var options = new JsonSerializerOptions(); + options.PropertyNameCaseInsensitive = true; + + // Baseline (no exception) + { + var obj = Serializer.Deserialize(@"{""mydecimal"":1}", options); + Assert.Equal(1, obj.MyDecimal); + } + + { + var obj = Serializer.Deserialize(@"{""MYDECIMAL"":1}", options); + Assert.Equal(1, obj.MyDecimal); + } + + JsonException e; + + e = Assert.Throws(() => Serializer.Deserialize(@"{""mydecimal"":bad}", options)); + Assert.Equal("$.mydecimal", e.Path); + + e = Assert.Throws(() => Serializer.Deserialize(@"{""MYDECIMAL"":bad}", options)); + Assert.Equal("$.MYDECIMAL", e.Path); + } + + [Fact] + public void ClassWithUnsupportedCollectionTypes() + { + Exception e; + + e = Assert.Throws(() => Serializer.Deserialize(@"{""UnsupportedArray"":[]}")); + Assert.Contains("System.Int32[,]", e.ToString()); + // The exception for element types do not contain the parent type and the property name + // since the verification occurs later and is no longer bound to the parent type. + Assert.DoesNotContain("ClassWithInvalidArray.UnsupportedArray", e.ToString()); + + e = Assert.Throws(() => Serializer.Deserialize(@"{""UnsupportedDictionary"":{}}")); + Assert.Contains("System.Int32[,]", e.ToString()); + Assert.DoesNotContain("ClassWithInvalidDictionary.UnsupportedDictionary", e.ToString()); + } + + private class ClassWithInvalidArray + { + public int[,] UnsupportedArray { get; set; } + + public ClassWithInvalidArray(int[,] unsupportedArray) + { + UnsupportedArray = unsupportedArray; + } + } + + private class ClassWithInvalidDictionary + { + public Dictionary UnsupportedDictionary { get; set; } + + public ClassWithInvalidDictionary(Dictionary unsupportedDictionary) + { + UnsupportedDictionary = unsupportedDictionary; + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.ParameterMatching.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.ParameterMatching.cs new file mode 100644 index 00000000000000..edb7090b8e08eb --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.ParameterMatching.cs @@ -0,0 +1,1002 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Specialized; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public class ConstructorTests_StringTValue : ConstructorTests + { + public ConstructorTests_StringTValue() : base(DeserializationWrapper.StringTValueSerializer) { } + } + + public class ConstructorTests_StreamTValue : ConstructorTests + { + public ConstructorTests_StreamTValue() : base(DeserializationWrapper.StreamTValueSerializer) { } + } + + public abstract partial class ConstructorTests + { + private DeserializationWrapper Serializer { get; } + + public ConstructorTests(DeserializationWrapper serializer) + { + Serializer = serializer; + } + + [Fact] + public void ReturnNullForNullObjects() + { + Assert.Null(Serializer.Deserialize("null")); + Assert.Null(Serializer.Deserialize("null")); + } + + [Fact] + public void JsonExceptionWhenAssigningNullToStruct() + { + Assert.Throws(() => Serializer.Deserialize("null")); + } + + [Fact] + public void MatchJsonPropertyToConstructorParameters() + { + Point_2D point = Serializer.Deserialize(@"{""X"":1,""Y"":2}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + + point = Serializer.Deserialize(@"{""Y"":2,""X"":1}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + } + + [Fact] + public void UseDefaultValues_When_NoJsonMatch() + { + // Using CLR value when `ParameterInfo.DefaultValue` is not set. + Point_2D point = Serializer.Deserialize(@"{""x"":1,""y"":2}"); + Assert.Equal(0, point.X); + Assert.Equal(0, point.Y); + + point = Serializer.Deserialize(@"{""y"":2,""x"":1}"); + Assert.Equal(0, point.X); + Assert.Equal(0, point.Y); + + point = Serializer.Deserialize(@"{""x"":1,""Y"":2}"); + Assert.Equal(0, point.X); + Assert.Equal(2, point.Y); + + point = Serializer.Deserialize(@"{""y"":2,""X"":1}"); + Assert.Equal(1, point.X); + Assert.Equal(0, point.Y); + + point = Serializer.Deserialize(@"{""X"":1}"); + Assert.Equal(1, point.X); + Assert.Equal(0, point.Y); + + point = Serializer.Deserialize(@"{""Y"":2}"); + Assert.Equal(0, point.X); + Assert.Equal(2, point.Y); + + point = Serializer.Deserialize(@"{""X"":1}"); + Assert.Equal(1, point.X); + Assert.Equal(0, point.Y); + + point = Serializer.Deserialize(@"{""Y"":2}"); + Assert.Equal(0, point.X); + Assert.Equal(2, point.Y); + + point = Serializer.Deserialize(@"{}"); + Assert.Equal(0, point.X); + Assert.Equal(0, point.Y); + + point = Serializer.Deserialize(@"{""a"":1,""b"":2}"); + Assert.Equal(0, point.X); + Assert.Equal(0, point.Y); + + // Using `ParameterInfo.DefaultValue` when set; using CLR value as fallback. + Point_3D point3d = Serializer.Deserialize(@"{""X"":1}"); + Assert.Equal(1, point3d.X); + Assert.Equal(0, point3d.Y); + Assert.Equal(50, point3d.Z); + + point3d = Serializer.Deserialize(@"{""y"":2}"); + Assert.Equal(0, point3d.X); + Assert.Equal(0, point3d.Y); + Assert.Equal(50, point3d.Z); + + point3d = Serializer.Deserialize(@"{""Z"":3}"); + Assert.Equal(0, point3d.X); + Assert.Equal(0, point3d.Y); + Assert.Equal(3, point3d.Z); + + point3d = Serializer.Deserialize(@"{""X"":1}"); + Assert.Equal(1, point3d.X); + Assert.Equal(0, point3d.Y); + Assert.Equal(50, point3d.Z); + + point3d = Serializer.Deserialize(@"{""Y"":2}"); + Assert.Equal(0, point3d.X); + Assert.Equal(2, point3d.Y); + Assert.Equal(50, point3d.Z); + + point3d = Serializer.Deserialize(@"{""Z"":3}"); + Assert.Equal(0, point3d.X); + Assert.Equal(0, point3d.Y); + Assert.Equal(3, point3d.Z); + + point3d = Serializer.Deserialize(@"{""x"":1,""Y"":2}"); + Assert.Equal(0, point3d.X); + Assert.Equal(2, point3d.Y); + Assert.Equal(50, point3d.Z); + + point3d = Serializer.Deserialize(@"{""Z"":3,""y"":2}"); + Assert.Equal(0, point3d.X); + Assert.Equal(0, point3d.Y); + Assert.Equal(3, point3d.Z); + + point3d = Serializer.Deserialize(@"{""x"":1,""Z"":3}"); + Assert.Equal(0, point3d.X); + Assert.Equal(0, point3d.Y); + Assert.Equal(3, point3d.Z); + + point3d = Serializer.Deserialize(@"{}"); + Assert.Equal(0, point3d.X); + Assert.Equal(0, point3d.Y); + Assert.Equal(50, point3d.Z); + + point3d = Serializer.Deserialize(@"{""a"":1,""b"":2}"); + Assert.Equal(0, point3d.X); + Assert.Equal(0, point3d.Y); + Assert.Equal(50, point3d.Z); + } + + [Fact] + public void CaseInsensitivityWorks() + { + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + + Point_2D point = Serializer.Deserialize(@"{""x"":1,""y"":2}", options); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + + point = Serializer.Deserialize(@"{""y"":2,""x"":1}", options); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + + point = Serializer.Deserialize(@"{""x"":1,""Y"":2}", options); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + + point = Serializer.Deserialize(@"{""y"":2,""X"":1}", options); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + } + + [Fact] + public void VaryingOrderingOfJson() + { + Point_3D point = Serializer.Deserialize(@"{""X"":1,""Y"":2,""Z"":3}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + Assert.Equal(3, point.Z); + + point = Serializer.Deserialize(@"{""X"":1,""Z"":3,""Y"":2}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + Assert.Equal(3, point.Z); + + point = Serializer.Deserialize(@"{""Y"":2,""Z"":3,""X"":1}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + Assert.Equal(3, point.Z); + + point = Serializer.Deserialize(@"{""Y"":2,""X"":1,""Z"":3}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + Assert.Equal(3, point.Z); + + point = Serializer.Deserialize(@"{""Z"":3,""Y"":2,""X"":1}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + Assert.Equal(3, point.Z); + + point = Serializer.Deserialize(@"{""Z"":3,""X"":1,""Y"":2}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + Assert.Equal(3, point.Z); + } + + [Fact] + public void AsListElement() + { + List list = Serializer.Deserialize>(@"[{""Y"":2,""Z"":3,""X"":1},{""Z"":10,""Y"":30,""X"":20}]"); + Assert.Equal(1, list[0].X); + Assert.Equal(2, list[0].Y); + Assert.Equal(3, list[0].Z); + Assert.Equal(20, list[1].X); + Assert.Equal(30, list[1].Y); + Assert.Equal(10, list[1].Z); + } + + [Fact] + public void AsDictionaryValue() + { + Dictionary dict = Serializer.Deserialize>(@"{""0"":{""Y"":2,""Z"":3,""X"":1},""1"":{""Z"":10,""Y"":30,""X"":20}}"); + Assert.Equal(1, dict["0"].X); + Assert.Equal(2, dict["0"].Y); + Assert.Equal(3, dict["0"].Z); + Assert.Equal(20, dict["1"].X); + Assert.Equal(30, dict["1"].Y); + Assert.Equal(10, dict["1"].Z); + } + + [Fact] + public void AsProperty_Of_ObjectWithParameterlessCtor() + { + WrapperForPoint_3D obj = Serializer.Deserialize(@"{""Point_3D"":{""Y"":2,""Z"":3,""X"":1}}"); + Point_3D point = obj.Point_3D; + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + Assert.Equal(3, point.Z); + } + + [Fact] + public void AsProperty_Of_ObjectWithParameterizedCtor() + { + ClassWrapperForPoint_3D obj = Serializer.Deserialize(@"{""Point3D"":{""Y"":2,""Z"":3,""X"":1}}"); + Point_3D point = obj.Point3D; + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + Assert.Equal(3, point.Z); + } + + [Fact] + public void At_Symbol_As_ParameterNamePrefix() + { + ClassWrapper_For_Int_String obj = Serializer.Deserialize(@"{""Int"":1,""String"":""1""}"); + Assert.Equal(1, obj.Int); + Assert.Equal("1", obj.String); + } + + [Fact] + public void At_Symbol_As_ParameterNamePrefix_UseDefaultValues() + { + ClassWrapper_For_Int_String obj = Serializer.Deserialize(@"{""@Int"":1,""@String"":""1""}"); + Assert.Equal(0, obj.Int); + Assert.Null(obj.String); + } + + [Fact] + public void PassDefaultValueToComplexStruct() + { + ClassWrapperForPoint_3D obj = Serializer.Deserialize(@"{}"); + Assert.True(obj.Point3D == default); + + ClassWrapper_For_Int_Point_3D_String obj1 = Serializer.Deserialize(@"{}"); + Assert.Equal(0, obj1.MyInt); + Assert.Equal(0, obj1.MyPoint3DStruct.X); + Assert.Equal(0, obj1.MyPoint3DStruct.Y); + Assert.Equal(0, obj1.MyPoint3DStruct.Z); + Assert.Null(obj1.MyString); + } + + [Fact] + public void Null_AsArgument_To_ParameterThat_CanBeNull() + { + ClassWrapper_For_Int_Point_3D_String obj1 = Serializer.Deserialize(@"{""MyInt"":1,""MyPoint3DStruct"":{},""MyString"":null}"); + Assert.Equal(1, obj1.MyInt); + Assert.Equal(0, obj1.MyPoint3DStruct.X); + Assert.Equal(0, obj1.MyPoint3DStruct.Y); + Assert.Equal(50, obj1.MyPoint3DStruct.Z); + Assert.Null(obj1.MyString); + } + + [Fact] + public void Null_AsArgument_To_ParameterThat_CanNotBeNull() + { + Assert.Throws(() => Serializer.Deserialize(@"{""MyInt"":null,""MyString"":""1""}")); + Assert.Throws(() => Serializer.Deserialize(@"{""MyPoint3DStruct"":null,""MyString"":""1""}")); + } + + [Fact] + public void OtherPropertiesAreSet() + { + var personClass = Serializer.Deserialize(Person_Class.s_json); + personClass.Verify(); + + var personStruct = Serializer.Deserialize(Person_Struct.s_json); + personStruct.Verify(); + } + + [Fact] + public void ExtraProperties_AreIgnored() + { + Point_2D point = Serializer.Deserialize(@"{ ""x"":1,""y"":2,""b"":3}"); + Assert.Equal(0, point.X); + Assert.Equal(0, point.Y); + } + + [Fact] + public void ExtraProperties_GoInExtensionData_IfPresent() + { + Point_2D_With_ExtData point = Serializer.Deserialize(@"{""X"":1,""y"":2,""b"":3}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.ExtensionData["y"].GetInt32()); + Assert.Equal(3, point.ExtensionData["b"].GetInt32()); + } + + [Fact] + public void PropertiesNotSet_WhenJSON_MapsToConstructorParameters() + { + var obj = Serializer.Deserialize(@"{""X"":1,""Y"":2}"); + Assert.Equal(40, obj.X); // Would be 1 if property were set directly after object construction. + Assert.Equal(60, obj.Y); // Would be 2 if property were set directly after object construction. + } + + [Fact] + public void IgnoreNullValues_DontSetNull_ToConstructorArguments_ThatCantBeNull() + { + // Default is to throw JsonException when null applied to types that can't be null. + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null,""Int"":null,""ImmutableArray"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""Int"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""ImmutableArray"":null}")); + + // Set arguments to default values when IgnoreNullValues is on. + var options = new JsonSerializerOptions { IgnoreNullValues = true }; + var obj = Serializer.Deserialize(@"{""Int"":null,""Point3DStruct"":null,""ImmutableArray"":null}", options); + Assert.Equal(0, obj.Point3DStruct.X); + Assert.Equal(0, obj.Point3DStruct.Y); + Assert.Equal(0, obj.Point3DStruct.Z); + Assert.True(obj.ImmutableArray.IsDefault); + Assert.Equal(50, obj.Int); + } + + [Fact] + public void NumerousSimpleAndComplexParameters() + { + var obj = Serializer.Deserialize(ClassWithConstructor_SimpleAndComplexParameters.s_json); + obj.Verify(); + } + + [Fact] + public void ClassWithPrimitives_Parameterless() + { + var point = new Parameterless_ClassWithPrimitives(); + + point.FirstInt = 348943; + point.SecondInt = 348943; + point.FirstString = "934sdkjfskdfssf"; + point.SecondString = "sdad9434243242"; + point.FirstDateTime = DateTime.Now; + point.SecondDateTime = DateTime.Now.AddHours(1).AddYears(1); + + point.X = 234235; + point.Y = 912874; + point.Z = 434934; + + point.ThirdInt = 348943; + point.FourthInt = 348943; + point.ThirdString = "934sdkjfskdfssf"; + point.FourthString = "sdad9434243242"; + point.ThirdDateTime = DateTime.Now; + point.FourthDateTime = DateTime.Now.AddHours(1).AddYears(1); + + string json = JsonSerializer.Serialize(point); + + var deserialized = Serializer.Deserialize(json); + Assert.Equal(point.FirstInt, deserialized.FirstInt); + Assert.Equal(point.SecondInt, deserialized.SecondInt); + Assert.Equal(point.FirstString, deserialized.FirstString); + Assert.Equal(point.SecondString, deserialized.SecondString); + Assert.Equal(point.FirstDateTime, deserialized.FirstDateTime); + Assert.Equal(point.SecondDateTime, deserialized.SecondDateTime); + + Assert.Equal(point.X, deserialized.X); + Assert.Equal(point.Y, deserialized.Y); + Assert.Equal(point.Z, deserialized.Z); + + Assert.Equal(point.ThirdInt, deserialized.ThirdInt); + Assert.Equal(point.FourthInt, deserialized.FourthInt); + Assert.Equal(point.ThirdString, deserialized.ThirdString); + Assert.Equal(point.FourthString, deserialized.FourthString); + Assert.Equal(point.ThirdDateTime, deserialized.ThirdDateTime); + Assert.Equal(point.FourthDateTime, deserialized.FourthDateTime); + } + + [Fact] + public void ClassWithPrimitives() + { + var point = new Parameterized_ClassWithPrimitives_3Args(x: 234235, y: 912874, z: 434934); + + point.FirstInt = 348943; + point.SecondInt = 348943; + point.FirstString = "934sdkjfskdfssf"; + point.SecondString = "sdad9434243242"; + point.FirstDateTime = DateTime.Now; + point.SecondDateTime = DateTime.Now.AddHours(1).AddYears(1); + + point.ThirdInt = 348943; + point.FourthInt = 348943; + point.ThirdString = "934sdkjfskdfssf"; + point.FourthString = "sdad9434243242"; + point.ThirdDateTime = DateTime.Now; + point.FourthDateTime = DateTime.Now.AddHours(1).AddYears(1); + + string json = JsonSerializer.Serialize(point); + + var deserialized = Serializer.Deserialize(json); + Assert.Equal(point.FirstInt, deserialized.FirstInt); + Assert.Equal(point.SecondInt, deserialized.SecondInt); + Assert.Equal(point.FirstString, deserialized.FirstString); + Assert.Equal(point.SecondString, deserialized.SecondString); + Assert.Equal(point.FirstDateTime, deserialized.FirstDateTime); + Assert.Equal(point.SecondDateTime, deserialized.SecondDateTime); + + Assert.Equal(point.X, deserialized.X); + Assert.Equal(point.Y, deserialized.Y); + Assert.Equal(point.Z, deserialized.Z); + + Assert.Equal(point.ThirdInt, deserialized.ThirdInt); + Assert.Equal(point.FourthInt, deserialized.FourthInt); + Assert.Equal(point.ThirdString, deserialized.ThirdString); + Assert.Equal(point.FourthString, deserialized.FourthString); + Assert.Equal(point.ThirdDateTime, deserialized.ThirdDateTime); + Assert.Equal(point.FourthDateTime, deserialized.FourthDateTime); + } + + [Fact] + public void ClassWithPrimitivesPerf() + { + var point = new Parameterized_ClassWithPrimitives_3Args(x: 234235, y: 912874, z: 434934); + + point.FirstInt = 348943; + point.SecondInt = 348943; + point.FirstString = "934sdkjfskdfssf"; + point.SecondString = "sdad9434243242"; + point.FirstDateTime = DateTime.Now; + point.SecondDateTime = DateTime.Now.AddHours(1).AddYears(1); + + point.ThirdInt = 348943; + point.FourthInt = 348943; + point.ThirdString = "934sdkjfskdfssf"; + point.FourthString = "sdad9434243242"; + point.ThirdDateTime = DateTime.Now; + point.FourthDateTime = DateTime.Now.AddHours(1).AddYears(1); + + string json = JsonSerializer.Serialize(point); + + Serializer.Deserialize(json); + Serializer.Deserialize(json); + } + + [Fact] + public void TupleDeserializationWorks() + { + var tuple = Serializer.Deserialize>(@"{""Item1"":""New York"",""Item2"":32.68}"); + Assert.Equal("New York", tuple.Item1); + Assert.Equal(32.68, tuple.Item2); + + var tupleWrapper = Serializer.Deserialize(@"{""Tuple"":{""Item1"":""New York"",""Item2"":32.68}}"); + tuple = tupleWrapper.Tuple; + Assert.Equal("New York", tuple.Item1); + Assert.Equal(32.68, tuple.Item2); + + var tupleList = Serializer.Deserialize>>(@"[{""Item1"":""New York"",""Item2"":32.68}]"); + tuple = tupleList[0]; + Assert.Equal("New York", tuple.Item1); + Assert.Equal(32.68, tuple.Item2); + } + + [Fact] + public void TupleDeserialization_MoreThanSevenItems() + { + // Seven is okay + string json = JsonSerializer.Serialize(Tuple.Create(1, 2, 3, 4, 5, 6, 7)); + var obj = Serializer.Deserialize>(json); + Assert.Equal(json, JsonSerializer.Serialize(obj)); + + // More than seven arguments needs special casing and can be revisted. + // Newtonsoft.Json fails in the same way. + json = JsonSerializer.Serialize(Tuple.Create(1, 2, 3, 4, 5, 6, 7, 8)); + Assert.Throws(() => Serializer.Deserialize>(json)); + + // Invalid JSON representing a tuple with more than seven items yields an ArgumentException from the constructor. + // System.ArgumentException : The last element of an eight element tuple must be a Tuple. + // We pass the number 8, not a new Tuple(8). + // Fixing this needs special casing. Newtonsoft behaves the same way. + string invalidJson = @"{""Item1"":1,""Item2"":2,""Item3"":3,""Item4"":4,""Item5"":5,""Item6"":6,""Item7"":7,""Item1"":8}"; + Assert.Throws(() => Serializer.Deserialize>(invalidJson)); + } + + [Fact] + public void TupleDeserialization_DefaultValuesUsed_WhenJsonMissing() + { + // Seven items; only three provided. + string input = @"{""Item2"":""2"",""Item3"":3,""Item6"":6}"; + var obj = Serializer.Deserialize>(input); + + string serialized = JsonSerializer.Serialize(obj); + Assert.Contains(@"""Item1"":0", serialized); + Assert.Contains(@"""Item2"":""2""", serialized); + Assert.Contains(@"""Item3"":3", serialized); + Assert.Contains(@"""Item4"":null", serialized); + Assert.Contains(@"""Item5"":null", serialized); + Assert.Contains(@"""Item6"":6", serialized); + Assert.Contains(@"""Item7"":{", serialized); + + serialized = JsonSerializer.Serialize(obj.Item7); + Assert.Contains(@"""X"":0", serialized); + Assert.Contains(@"""Y"":0", serialized); + Assert.Contains(@"""Z"":0", serialized); + + // Although no Json is provided for the 8th item, ArgumentException is still thrown as we use default(int) as the argument/ + // System.ArgumentException : The last element of an eight element tuple must be a Tuple. + // We pass the number 8, not a new Tuple(default(int)). + // Fixing this needs special casing. Newtonsoft behaves the same way. + Assert.Throws(() => Serializer.Deserialize>(input)); + } + + [Fact] + public void TupleDeserializationWorks_ClassWithParameterizedCtor() + { + string classJson = ClassWithConstructor_SimpleAndComplexParameters.s_json; + + StringBuilder sb = new StringBuilder(); + sb.Append("{"); + for (int i = 0; i < 6; i++) + { + sb.Append(@$"""Item{i + 1}"":{classJson},"); + } + sb.Append(@$"""Item7"":{classJson}"); + sb.Append("}"); + + string complexTupleJson = sb.ToString(); + + var complexTuple = Serializer.Deserialize>(complexTupleJson); + + complexTuple.Item1.Verify(); + complexTuple.Item2.Verify(); + complexTuple.Item3.Verify(); + complexTuple.Item4.Verify(); + complexTuple.Item5.Verify(); + complexTuple.Item6.Verify(); + complexTuple.Item7.Verify(); + } + + [Fact] + public void TupleDeserializationWorks_ClassWithParameterlessCtor() + { + string classJson = SimpleTestClass.s_json; + + StringBuilder sb = new StringBuilder(); + sb.Append("{"); + for (int i = 0; i < 6; i++) + { + sb.Append(@$"""Item{i + 1}"":{classJson},"); + } + sb.Append(@$"""Item7"":{classJson}"); + sb.Append("}"); + + string complexTupleJson = sb.ToString(); + + var complexTuple = Serializer.Deserialize>(complexTupleJson); + + complexTuple.Item1.Verify(); + complexTuple.Item2.Verify(); + complexTuple.Item3.Verify(); + complexTuple.Item4.Verify(); + complexTuple.Item5.Verify(); + complexTuple.Item6.Verify(); + complexTuple.Item7.Verify(); + } + + [Fact] + public void NoConstructorHandlingWhenObjectHasConverter() + { + // Baseline without converter + string serialized = JsonSerializer.Serialize(new Point_3D(10, 6)); + + Point_3D point = Serializer.Deserialize(serialized); + Assert.Equal(10, point.X); + Assert.Equal(6, point.Y); + Assert.Equal(50, point.Z); + + serialized = JsonSerializer.Serialize(new[] { new Point_3D(10, 6) }); + + point = Serializer.Deserialize(serialized)[0]; + Assert.Equal(10, point.X); + Assert.Equal(6, point.Y); + Assert.Equal(50, point.Z); + + serialized = JsonSerializer.Serialize(new WrapperForPoint_3D { Point_3D = new Point_3D(10, 6) }); + + point = Serializer.Deserialize(serialized).Point_3D; + Assert.Equal(10, point.X); + Assert.Equal(6, point.Y); + Assert.Equal(50, point.Z); + + // Converters for objects with parameterized ctors are honored + + var options = new JsonSerializerOptions(); + options.Converters.Add(new ConverterForPoint3D()); + + serialized = JsonSerializer.Serialize(new Point_3D(10, 6)); + + point = Serializer.Deserialize(serialized, options); + Assert.Equal(4, point.X); + Assert.Equal(4, point.Y); + Assert.Equal(4, point.Z); + + serialized = JsonSerializer.Serialize(new[] { new Point_3D(10, 6) }); + + point = Serializer.Deserialize(serialized, options)[0]; + Assert.Equal(4, point.X); + Assert.Equal(4, point.Y); + Assert.Equal(4, point.Z); + + serialized = JsonSerializer.Serialize(new WrapperForPoint_3D { Point_3D = new Point_3D(10, 6) }); + + point = Serializer.Deserialize(serialized, options).Point_3D; + Assert.Equal(4, point.X); + Assert.Equal(4, point.Y); + Assert.Equal(4, point.Z); + } + + [Fact] + public void ConstructorHandlingHonorsCustomConverters() + { + // Baseline, use internal converters for primitives + Point_2D point = Serializer.Deserialize(@"{""X"":2,""Y"":3}"); + Assert.Equal(2, point.X); + Assert.Equal(3, point.Y); + + // Honor custom converters + var options = new JsonSerializerOptions(); + options.Converters.Add(new ConverterForInt32()); + + point = Serializer.Deserialize(@"{""X"":2,""Y"":3}", options); + Assert.Equal(25, point.X); + Assert.Equal(25, point.X); + } + + [Fact] + public void CanDeserialize_ObjectWith_Ctor_With_64_Params() + { + void RunTest() + { + StringBuilder sb = new StringBuilder(); + sb.Append("{"); + for (int i = 0; i < 63; i++) + { + sb.Append($@"""Int{i}"":{i},"); + } + sb.Append($@"""Int63"":63"); + sb.Append("}"); + + string input = sb.ToString(); + + object obj = Serializer.Deserialize(input); + for (int i = 0; i < 64; i++) + { + Assert.Equal(i, (int)typeof(T).GetProperty($"Int{i}").GetValue(obj)); + } + } + + RunTest(); + RunTest(); + } + + [Fact] + public void Cannot_Deserialize_ObjectWith_Ctor_With_65_Params() + { + void RunTest() + { + Type type = typeof(T); + + StringBuilder sb = new StringBuilder(); + sb.Append("{"); + for (int i = 0; i < 64; i++) + { + sb.Append($@"""Int{i}"":{i},"); + } + sb.Append($@"""Int64"":64"); + sb.Append("}"); + + string input = sb.ToString(); + + sb = new StringBuilder(); + sb.Append("("); + for (int i = 0; i < 64; i++) + { + sb.Append("Int32, "); + } + sb.Append("Int32"); + sb.Append(")"); + + string ctorAsString = sb.ToString(); + + NotSupportedException ex = Assert.Throws(() => Serializer.Deserialize(input)); + string strEx = ex.ToString(); + Assert.Contains(ctorAsString, strEx); + Assert.Contains(type.ToString(), strEx); + + ex = Assert.Throws(() => Serializer.Deserialize("{}")); + strEx = ex.ToString(); + Assert.Contains(ctorAsString, strEx); + Assert.Contains(type.ToString(), strEx); + } + + RunTest(); + RunTest(); + } + + [Fact] + public void Deserialize_ObjectWith_Ctor_With_65_Params_IfNull() + { + Assert.Null(Serializer.Deserialize("null")); + Assert.Throws(() => Serializer.Deserialize("null")); + } + + [Fact] + public void Escaped_ParameterNames_Work() + { + Point_2D point = Serializer.Deserialize(@"{""\u0058"":1,""\u0059"":2}"); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + } + + [Fact] + public void FirstParameterWins() + { + Point_2D point = Serializer.Deserialize(@"{""X"":1,""Y"":2,""X"":4}"); + Assert.Equal(4, point.X); // Not 1. + Assert.Equal(2, point.Y); + } + + [Fact] + public void SubsequentParameter_GoesToExtensionData() + { + string json = @"{ + ""FirstName"":""Jet"", + ""Id"":""270bb22b-4816-4bd9-9acd-8ec5b1a896d3"", + ""EmailAddress"":""jetdoe@outlook.com"", + ""Id"":""0b3aa420-2e98-47f7-8a49-fea233b89416"", + ""LastName"":""Doe"", + ""Id"":""63cf821d-fd47-4782-8345-576d9228a534"" + }"; + + Parameterized_Person person = Serializer.Deserialize(json); + Assert.Equal("Jet", person.FirstName); + Assert.Equal("Doe", person.LastName); + Assert.Equal("63cf821d-fd47-4782-8345-576d9228a534", person.Id.ToString()); + Assert.Equal("jetdoe@outlook.com", person.ExtensionData["EmailAddress"].GetString()); + Assert.False(person.ExtensionData.ContainsKey("Id")); + } + + [Fact] + public void BitVector32_UsesStructDefaultCtor_MultipleParameterizedCtor() + { + string serialized = JsonSerializer.Serialize(new BitVector32(1)); + Assert.Equal(0, Serializer.Deserialize(serialized).Data); + } + + [Fact] + public void HonorExtensionDataGeneric() + { + var obj1 = Serializer.Deserialize(@"{""key"": ""value""}"); + Assert.Equal("value", obj1.ExtensionData["key"].GetString()); + + var obj2 = Serializer.Deserialize(@"{""key"": ""value""}"); + Assert.Equal("value", ((JsonElement)obj2.ExtensionData["key"]).GetString()); + + var obj3 = Serializer.Deserialize(@"{""key"": ""value""}"); + Assert.Equal("value", obj3.ExtensionData["key"].GetString()); + + var obj4 = Serializer.Deserialize(@"{""key"": ""value""}"); + Assert.Equal("value", ((JsonElement)obj4.ExtensionData["key"]).GetString()); + } + + [Fact] + public void ArgumentDeserialization_Honors_JsonPropertyName() + { + Point_MembersHave_JsonPropertyName point = new Point_MembersHave_JsonPropertyName(1, 2); + + string json = JsonSerializer.Serialize(point); + Assert.Contains(@"""XValue"":1", json); + Assert.Contains(@"""YValue"":2", json); + + point = Serializer.Deserialize(json); + point.Verify(); + } + + [Fact] + public void ArgumentDeserialization_Honors_JsonPropertyName_CaseInsensitiveWorks() + { + string json = @"{""XVALUE"":1,""yvalue"":2}"; + + // Without case insensitivity, there's no match. + Point_MembersHave_JsonPropertyName point = Serializer.Deserialize(json); + + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + point = Serializer.Deserialize(json, options); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + } + + [Fact] + public void ArgumentDeserialization_Honors_ConverterOnProperty() + { + var point = Serializer.Deserialize(Point_MembersHave_JsonConverter.s_json); + point.Verify(); + } + + [Fact] + public void ArgumentDeserialization_Honors_JsonIgnore() + { + var point = Serializer.Deserialize(Point_MembersHave_JsonIgnore.s_json); + point.Verify(); + } + + [Fact] + public void ArgumentDeserialization_UseNamingPolicy_ToMatch() + { + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = new LowerCaseNamingPolicy() + }; + + string json = JsonSerializer.Serialize(new Point_ExtendedPropNames(1, 2), options); + + // If we don't use naming policy, then we can't match serialized properties to constructor parameters on deserialization. + var point = Serializer.Deserialize(json); + Assert.Equal(0, point.XValue); + Assert.Equal(0, point.YValue); + + point = Serializer.Deserialize(json, options); + Assert.Equal(1, point.XValue); + Assert.Equal(2, point.YValue); + } + + [Fact] + public void ArgumentDeserialization_UseNamingPolicy_ToMatch_CaseInsensitiveWorks() + { + var options1 = new JsonSerializerOptions + { + PropertyNamingPolicy = new SimpleSnakeCasePolicy() + }; + + string json = @"{""x_VaLUE"":1,""Y_vALue"":2}"; + + // If we don't use case sensitivity, then we can't match serialized properties to constructor parameters on deserialization. + Point_ExtendedPropNames point = Serializer.Deserialize(json, options1); + Assert.Equal(0, point.XValue); + Assert.Equal(0, point.YValue); + + var options2 = new JsonSerializerOptions + { + PropertyNamingPolicy = new SimpleSnakeCasePolicy(), + PropertyNameCaseInsensitive = true, + }; + + point = Serializer.Deserialize(json, options2); + Assert.Equal(1, point.XValue); + Assert.Equal(2, point.YValue); + } + + [Fact] + public void ArgumentDeserialization_UseNamingPolicy_InvalidPolicyFails() + { + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = new NullNamingPolicy() + }; + + Assert.Throws(() => Serializer.Deserialize("{}", options)); + } + + [Fact] + public void ComplexJson_As_LastCtorArg() + { + Point_With_Array obj1 = Serializer.Deserialize(Point_With_Array.s_json); + ((ITestClass)obj1).Verify(); + + Point_With_Dictionary obj2 = Serializer.Deserialize(Point_With_Dictionary.s_json); + ((ITestClass)obj2).Verify(); + + Point_With_Object obj3 = Serializer.Deserialize(Point_With_Object.s_json); + ((ITestClass)obj3).Verify(); + } + + [Fact] + public void NumerousPropertiesWork() + { + StringBuilder sb = new StringBuilder(); + sb.Append("{"); + sb.Append(@"""X"":1,"); + sb.Append(@"""Y"":2,"); + + for (int i = 0; i < 65; i++) + { + sb.Append($@"""Z"":{i},"); + } + + sb.Append(@"""Z"":66"); + sb.Append("}"); + + string json = sb.ToString(); + + var point = Serializer.Deserialize(json); + Assert.Equal(1, point.X); + Assert.Equal(2, point.Y); + Assert.Equal(66, point.Z); + } + + [Fact] + public void ArgumentStateNotOverwritten() + { + ClassWithNestedClass obj = new ClassWithNestedClass(myClass: null, myPoint: default); + ClassWithNestedClass obj1 = new ClassWithNestedClass(myClass: obj, myPoint: new Point_2D_Struct_WithAttribute(1, 2)); + ClassWithNestedClass obj2 = new ClassWithNestedClass(myClass: obj1, myPoint: new Point_2D_Struct_WithAttribute(3, 4)); + + string json = JsonSerializer.Serialize(obj2); + + obj2 = Serializer.Deserialize(json); + Assert.Equal(3, obj2.MyPoint.X); + Assert.Equal(4, obj2.MyPoint.Y); + + obj1 = obj2.MyClass; + Assert.Equal(1, obj1.MyPoint.X); + Assert.Equal(2, obj1.MyPoint.Y); + + obj = obj1.MyClass; + Assert.Equal(0, obj.MyPoint.X); + Assert.Equal(0, obj.MyPoint.Y); + + Assert.Null(obj.MyClass); + } + + [Fact] + public void FourArgsWork() + { + string json = JsonSerializer.Serialize(new StructWithFourArgs(1, 2, 3, 4)); + + var obj = Serializer.Deserialize(json); + Assert.Equal(1, obj.W); + Assert.Equal(2, obj.X); + Assert.Equal(3, obj.Y); + Assert.Equal(4, obj.Z); + } + + [Fact] + public void InvalidJsonFails() + { + Assert.Throws(() => Serializer.Deserialize("{1")); + Assert.Throws(() => Serializer.Deserialize("{x")); + Assert.Throws(() => Serializer.Deserialize("{{")); + Assert.Throws(() => Serializer.Deserialize("{true")); + + // Also test deserialization of objects with parameterless ctors + Assert.Throws(() => Serializer.Deserialize("{1")); + Assert.Throws(() => Serializer.Deserialize("{x")); + Assert.Throws(() => Serializer.Deserialize("{true")); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Stream.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Stream.cs new file mode 100644 index 00000000000000..6872cd50ebb346 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Stream.cs @@ -0,0 +1,323 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class ConstructorTests + { + [Fact] + public void ReadSimpleObjectAsync() + { + async Task RunTest(byte[] testData) + { + using (MemoryStream stream = new MemoryStream(testData)) + { + JsonSerializerOptions options = new JsonSerializerOptions + { + DefaultBufferSize = 1 + }; + + var obj = await JsonSerializer.DeserializeAsync(stream, options); + ((ITestClass)obj).Verify(); + } + } + + // Array size is the count of the following tests. + Task[] tasks = new Task[14]; + + // Simple models can be deserialized. + tasks[0] = Task.Run(async () => await RunTest(Parameterized_IndexViewModel_Immutable.s_data)); + // Complex models can be deserialized. + tasks[1] = Task.Run(async () => await RunTest(ClassWithConstructor_SimpleAndComplexParameters.s_data)); + tasks[2] = Task.Run(async () => await RunTest(Parameterized_Class_With_ComplexTuple.s_data)); + // JSON that doesn't bind to ctor args are matched with properties or ignored (as appropriate). + tasks[3] = Task.Run(async () => await RunTest(Person_Class.s_data)); + tasks[4] = Task.Run(async () => await RunTest(Person_Struct.s_data)); + // JSON that doesn't bind to ctor args or properties are sent to ext data if avaiable. + tasks[5] = Task.Run(async () => await RunTest(Parameterized_Person.s_data)); + tasks[6] = Task.Run(async () => await RunTest(Parameterized_Person_ObjExtData.s_data)); + // Up to 64 ctor args are supported. + tasks[7] = Task.Run(async () => await RunTest(Class_With_Ctor_With_64_Params.Data)); + // Arg deserialization honors attributes on matching property. + tasks[8] = Task.Run(async () => await RunTest(Point_MembersHave_JsonPropertyName.s_data)); + tasks[9] = Task.Run(async () => await RunTest(Point_MembersHave_JsonConverter.s_data)); + tasks[10] = Task.Run(async () => await RunTest(Point_MembersHave_JsonIgnore.s_data)); + // Complex JSON as last argument works + tasks[11] = Task.Run(async () => await RunTest(Point_With_Array.s_data)); + tasks[12] = Task.Run(async () => await RunTest(Point_With_Dictionary.s_data)); + tasks[13] = Task.Run(async () => await RunTest(Point_With_Object.s_data)); + } + + [Fact] + public void ReadSimpleObjectWithTrailingTriviaAsync() + { + async Task RunTest(string testData) + { + byte[] data = Encoding.UTF8.GetBytes(testData + " /* Multi\r\nLine Comment */\t"); + using (MemoryStream stream = new MemoryStream(data)) + { + JsonSerializerOptions options = new JsonSerializerOptions + { + DefaultBufferSize = 1, + ReadCommentHandling = JsonCommentHandling.Skip, + }; + + var obj = await JsonSerializer.DeserializeAsync(stream, options); + ((ITestClass)obj).Verify(); + } + } + + // Array size is the count of the following tests. + Task[] tasks = new Task[14]; + + // Simple models can be deserialized. + tasks[0] = Task.Run(async () => await RunTest(Parameterized_IndexViewModel_Immutable.s_json)); + // Complex models can be deserialized. + tasks[1] = Task.Run(async () => await RunTest(ClassWithConstructor_SimpleAndComplexParameters.s_json)); + tasks[2] = Task.Run(async () => await RunTest(Parameterized_Class_With_ComplexTuple.s_json)); + // JSON that doesn't bind to ctor args are matched with properties or ignored (as appropriate). + tasks[3] = Task.Run(async () => await RunTest(Person_Class.s_json)); + tasks[4] = Task.Run(async () => await RunTest(Person_Struct.s_json)); + // JSON that doesn't bind to ctor args or properties are sent to ext data if avaiable. + tasks[5] = Task.Run(async () => await RunTest(Parameterized_Person.s_json)); + tasks[6] = Task.Run(async () => await RunTest(Parameterized_Person_ObjExtData.s_json)); + // Up to 64 ctor args are supported. + tasks[7] = Task.Run(async () => await RunTest(Encoding.UTF8.GetString(Class_With_Ctor_With_64_Params.Data))); + // Arg8deserialization honors attributes on matching property. + tasks[8] = Task.Run(async () => await RunTest(Point_MembersHave_JsonPropertyName.s_json)); + tasks[9] = Task.Run(async () => await RunTest(Point_MembersHave_JsonConverter.s_json)); + tasks[10] = Task.Run(async () => await RunTest(Point_MembersHave_JsonIgnore.s_json)); + // Complex JSON as last argument works + tasks[11] = Task.Run(async () => await RunTest(Point_With_Array.s_json)); + tasks[12] = Task.Run(async () => await RunTest(Point_With_Dictionary.s_json)); + tasks[13] = Task.Run(async () => await RunTest(Point_With_Object.s_json)); + + Task.WaitAll(tasks); + } + + [Fact] + public void Cannot_DeserializeAsync_ObjectWith_Ctor_With_65_Params() + { + async Task RunTest() + { + StringBuilder sb = new StringBuilder(); + sb.Append("{"); + for (int i = 0; i < 64; i++) + { + sb.Append($@"""Int{i}"":{i},"); + } + sb.Append($@"""Int64"":64"); + sb.Append("}"); + + string input = sb.ToString(); + + using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(input))) + { + JsonSerializerOptions options = new JsonSerializerOptions + { + DefaultBufferSize = 1 + }; + + await Assert.ThrowsAsync(async () => await JsonSerializer.DeserializeAsync(stream, options)); + } + + using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes("{}"))) + { + JsonSerializerOptions options = new JsonSerializerOptions + { + DefaultBufferSize = 1 + }; + + await Assert.ThrowsAsync(async () => await JsonSerializer.DeserializeAsync(stream, options)); + } + } + + Task[] tasks = new Task[2]; + + tasks[0] = Task.Run(async () => await RunTest()); + tasks[1] = Task.Run(async () => await RunTest()); + + Task.WaitAll(tasks); + } + + [Fact] + public async Task ExerciseStreamCodePaths() + { + static string GetPropertyName(int index) => + new string(new char[] { Convert.ToChar(index + 65), 'V', 'a', 'l', 'u', 'e' }); + + static byte[] GeneratePayload(int i, string value) + { + string whiteSpace = new string(' ', 16 ); + + StringBuilder sb; + + string prefix = ""; + + sb = new StringBuilder(); + sb.Append("{"); + + for (int j = 0; j < i; j++) + { + sb.Append(prefix); + sb.Append($@"""{GetPropertyName(j)}"":""{value}"""); + prefix = ","; + } + + sb.Append(prefix); + sb.Append($@"{whiteSpace}""{GetPropertyName(i)}"":{whiteSpace}""{value}"""); + prefix = ","; + + for (int j = 0; j < 10; j++) + { + sb.Append(prefix); + string keyPair = $@"""rand"":[""{value}""]"; + sb.Append($@"""Value{j}"":{{{keyPair},{keyPair},{keyPair}}}"); + } + + for (int j = i + 1; j < 20; j++) + { + sb.Append(prefix); + sb.Append($@"""{GetPropertyName(j)}"":""{value}"""); + } + + sb.Append("}"); + + return Encoding.UTF8.GetBytes(sb.ToString()); + } + + const string value = "ul4Oolt4VgbNm5Y1qPX911wxhyHFEQmmWBcIBR6BfUaNuIn3YOJ8vqtqz2WAh924rEILMzlh6JUhQDcmH00SI6Kv4iGTHQfGXxqWul4Oolt4VgbNm5Y1qPX911wxhyHFEQmmWBcIBR6"; + + for (int i = 0; i < 20; i++) + { + using (MemoryStream stream = new MemoryStream(GeneratePayload(i, value))) + { + JsonSerializerOptions options = new JsonSerializerOptions + { + DefaultBufferSize = 1 + }; + + ClassWithStrings obj = await JsonSerializer.DeserializeAsync(stream, options); + obj.Verify(value); + } + } + } + + public class ClassWithStrings + { + // Ctor args. + + // Ignored. + + [JsonIgnore] + public string AValue { get; } + [JsonIgnore] + public string EValue { get; } + [JsonIgnore] + public string IValue { get; } + [JsonIgnore] + public string MValue { get; } + [JsonIgnore] + public string QValue { get; } + + // Populated. + + public string CValue { get; } + public string GValue { get; } + public string KValue { get; } + public string OValue { get; } + public string SValue { get; } + + // Properties. + + // Ignored - no setter. + + public string BValue { get; } + public string FValue { get; } + public string JValue { get; } + public string NValue { get; } + public string RValue { get; } + + // Populated. + + public string DValue { get; set; } + public string HValue { get; set; } + public string LValue { get; set; } + public string PValue { get; set; } + public string TValue { get; set; } + + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } + + public ClassWithStrings( + string aValue, + string cValue, + string eValue, + string gValue, + string iValue, + string kValue, + string mValue, + string oValue, + string qValue, + string sValue) + { + AValue = aValue; + CValue = cValue; + EValue = eValue; + GValue = gValue; + IValue = iValue; + KValue = kValue; + MValue = mValue; + OValue = oValue; + QValue = qValue; + SValue = sValue; + } + + public void Verify(string expectedStr) + { + // Ctor args. + + // Ignored + Assert.Null(AValue); + Assert.Null(EValue); + Assert.Null(IValue); + Assert.Null(MValue); + Assert.Null(QValue); + + Assert.Equal(expectedStr, CValue); + Assert.Equal(expectedStr, GValue); + Assert.Equal(expectedStr, KValue); + Assert.Equal(expectedStr, OValue); + Assert.Equal(expectedStr, SValue); + + // Getter only members - skipped. + Assert.Null(BValue); + Assert.Null(FValue); + Assert.Null(JValue); + Assert.Null(NValue); + Assert.Null(RValue); + + // Members with setters + Assert.Equal(expectedStr, DValue); + Assert.Equal(expectedStr, HValue); + Assert.Equal(expectedStr, LValue); + Assert.Equal(expectedStr, PValue); + Assert.Equal(expectedStr, TValue); + + Assert.Equal(10, ExtensionData.Count); + + foreach (JsonElement value in ExtensionData.Values) + { + string keyPair = $@"""rand"":[""{expectedStr}""]"; + Assert.Equal($@"{{{keyPair},{keyPair},{keyPair}}}", value.GetRawText()); + } + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/DeserializationWrapper.cs b/src/libraries/System.Text.Json/tests/Serialization/DeserializationWrapper.cs new file mode 100644 index 00000000000000..77eae2fbf85a70 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/DeserializationWrapper.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Threading.Tasks; + +namespace System.Text.Json.Serialization.Tests +{ + /// + /// Base class for wrapping serialization calls which allows tests to run under different configurations. + /// + public abstract class DeserializationWrapper + { + private static readonly JsonSerializerOptions _optionsWithSmallBuffer = new JsonSerializerOptions { DefaultBufferSize = 1 }; + + public static DeserializationWrapper StringTValueSerializer => new StringTValueSerializerWrapper(); + public static DeserializationWrapper StreamTValueSerializer => new StreamTValueSerializerWrapper(); + + protected internal abstract T Deserialize(string json, JsonSerializerOptions options = null); + + private class StringTValueSerializerWrapper : DeserializationWrapper + { + protected internal override T Deserialize(string json, JsonSerializerOptions options = null) + { + return JsonSerializer.Deserialize(json, options); + } + } + + private class StreamTValueSerializerWrapper : DeserializationWrapper + { + protected internal override T Deserialize(string json, JsonSerializerOptions options = null) + { + if (options == null) + { + options = _optionsWithSmallBuffer; + } + + return Task.Run(async () => + { + using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) + { + return await JsonSerializer.DeserializeAsync(stream, options); + } + }).GetAwaiter().GetResult(); + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs b/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs index 7d776b93e175b3..0613262e6325da 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs @@ -2173,7 +2173,6 @@ private ClassWithPrivateParameterlessConstructor() { } [Fact] public static void DictionaryWith_ObjectWithNoParameterlessCtor_AsValue_Throws() { - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""key"":{}}")); Assert.Throws(() => JsonSerializer.Deserialize>(@"{""key"":{}}")); Assert.Throws(() => JsonSerializer.Deserialize>(@"{""key"":{}}")); } diff --git a/src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs b/src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs index 2dde90989e3c79..6787ab0b14dd77 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs @@ -217,7 +217,6 @@ public static void ReadObjectFail(string json, bool failsOnObject) [Fact] public static void ReadObjectFail_ReferenceTypeMissingPublicParameterlessConstructor() { - Assert.Throws(() => JsonSerializer.Deserialize(@"{""Name"":""Name!""}")); Assert.Throws(() => JsonSerializer.Deserialize(@"{""Name"":""Name!""}")); Assert.Throws(() => JsonSerializer.Deserialize(@"{""Name"":""Name!""}")); Assert.Throws(() => JsonSerializer.Deserialize(@"[""foo"", 1, false]")); @@ -228,10 +227,7 @@ public static void ReadObjectFail_ReferenceTypeMissingPublicParameterlessConstru private class PublicParameterizedConstructorTestClass { - public PublicParameterizedConstructorTestClass(string name) - { - Debug.Fail("The JsonSerializer should not be callin non-public ctors, by default."); - } + public PublicParameterizedConstructorTestClass(string name) { } private PublicParameterizedConstructorTestClass(int internalId) { diff --git a/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs b/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs index c1a352d3751f83..ed194538be5af6 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs @@ -74,14 +74,14 @@ public void PrimitivesAsRootObject() } [Fact] - public static void ReadPrimitivesFail() + public void ReadPrimitivesFail() { Assert.Throws(() => JsonSerializer.Deserialize(@"")); Assert.Throws(() => JsonSerializer.Deserialize(@"a")); } [Fact] - public static void ParseUntyped() + public void ParseUntyped() { object obj = JsonSerializer.Deserialize(@"""hello"""); Assert.IsType(obj); @@ -326,7 +326,7 @@ public void SimpleTestClassAsRootObject() [Fact] public void NestedObjectAsRootObject() { - static void Verify(string json) + void Verify(string json) { Assert.Contains(@"""Address"":{""City"":""MyCity""}", json); Assert.Contains(@"""List"":[""Hello"",""World""]", json); @@ -466,32 +466,32 @@ public void StaticAnalysisWithRelationship() } [Fact] - public static void PolymorphicInterface_NotSupported() + public void PolymorphicInterface_NotSupported() { Assert.Throws(() => JsonSerializer.Deserialize(@"{ ""Value"": ""A value"", ""Thing"": { ""Number"": 123 } }")); } [Fact] - public static void GenericListOfInterface_WithInvalidJson_ThrowsJsonException() + public void GenericListOfInterface_WithInvalidJson_ThrowsJsonException() { Assert.Throws(() => JsonSerializer.Deserialize("false")); Assert.Throws(() => JsonSerializer.Deserialize("{}")); } [Fact] - public static void GenericListOfInterface_WithValidJson_ThrowsNotSupportedException() + public void GenericListOfInterface_WithValidJson_ThrowsNotSupportedException() { Assert.Throws(() => JsonSerializer.Deserialize("[{}]")); } [Fact] - public static void GenericDictionaryOfInterface_WithInvalidJson_ThrowsJsonException() + public void GenericDictionaryOfInterface_WithInvalidJson_ThrowsJsonException() { Assert.Throws(() => JsonSerializer.Deserialize(@"{"""":1}")); } [Fact] - public static void GenericDictionaryOfInterface_WithValidJson_ThrowsNotSupportedException() + public void GenericDictionaryOfInterface_WithValidJson_ThrowsNotSupportedException() { Assert.Throws(() => JsonSerializer.Deserialize(@"{"""":{}}")); } diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.Constructor.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.Constructor.cs new file mode 100644 index 00000000000000..c0be977ac84a6d --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.Constructor.cs @@ -0,0 +1,2274 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public class PrivateParameterlessCtor + { + private PrivateParameterlessCtor() { } + } + + public class PrivateParameterizedCtor + { + public int X { get; } + + private PrivateParameterizedCtor(int x) { } + } + + public class PrivateParameterizedCtor_WithAttribute + { + public int X { get; } + + [JsonConstructor] + private PrivateParameterizedCtor_WithAttribute(int x) => X = x; + } + + public class InternalParameterlessCtor + { + internal InternalParameterlessCtor() { } + } + + public class InternalParameterizedCtor + { + public int X { get; } + + internal InternalParameterizedCtor(int x) { } + } + + public class InternalParameterizedCtor_WithAttribute + { + public int X { get; } + + [JsonConstructor] + internal InternalParameterizedCtor_WithAttribute(int x) => X = x; + } + + public class ProtectedParameterlessCtor + { + protected ProtectedParameterlessCtor() { } + } + + public class ProtectedParameterizedCtor + { + public int X { get; } + + protected ProtectedParameterizedCtor(int x) { } + } + + public class ProtectedParameterizedCtor_WithAttribute + { + public int X { get; } + + [JsonConstructor] + protected ProtectedParameterizedCtor_WithAttribute(int x) => X = x; + } + + public class PrivateParameterlessCtor_InternalParameterizedCtor_WithMultipleAttributes + { + [JsonConstructor] + private PrivateParameterlessCtor_InternalParameterizedCtor_WithMultipleAttributes() { } + + [JsonConstructor] + internal PrivateParameterlessCtor_InternalParameterizedCtor_WithMultipleAttributes(int value) { } + } + + public class ProtectedParameterlessCtor_PrivateParameterizedCtor_WithMultipleAttributes + { + [JsonConstructor] + protected ProtectedParameterlessCtor_PrivateParameterizedCtor_WithMultipleAttributes() { } + + [JsonConstructor] + private ProtectedParameterlessCtor_PrivateParameterizedCtor_WithMultipleAttributes(int value) { } + } + + public class PublicParameterlessCtor_PrivateParameterizedCtor_WithMultipleAttributes + { + [JsonConstructor] + public PublicParameterlessCtor_PrivateParameterizedCtor_WithMultipleAttributes() { } + + [JsonConstructor] + private PublicParameterlessCtor_PrivateParameterizedCtor_WithMultipleAttributes(int value) { } + } + + public class PublicParameterizedCtor_PublicParameterizedCtor_WithMultipleAttributes + { + [JsonConstructor] + public PublicParameterizedCtor_PublicParameterizedCtor_WithMultipleAttributes(int value) { } + + [JsonConstructor] + public PublicParameterizedCtor_PublicParameterizedCtor_WithMultipleAttributes(float value) { } + } + + public struct Struct_PublicParameterizedCtor_PrivateParameterizedCtor_WithMultipleAttributes + { + [JsonConstructor] + public Struct_PublicParameterizedCtor_PrivateParameterizedCtor_WithMultipleAttributes(float value) { } + + [JsonConstructor] + private Struct_PublicParameterizedCtor_PrivateParameterizedCtor_WithMultipleAttributes(int value) { } + } + + public struct Point_2D_Struct + { + public int X { get; } + + public int Y { get; } + + public Point_2D_Struct(int x, int y) => (X, Y) = (x, y); + } + + public struct Point_2D_Struct_WithAttribute + { + public int X { get; } + + public int Y { get; } + + [JsonConstructor] + public Point_2D_Struct_WithAttribute(int x, int y) => (X, Y) = (x, y); + } + + public struct Point_2D_Struct_WithMultipleAttributes + { + public int X { get; } + + public int Y { get; } + + [JsonConstructor] + public Point_2D_Struct_WithMultipleAttributes(int x) => (X, Y) = (x, 0); + + [JsonConstructor] + public Point_2D_Struct_WithMultipleAttributes(int x, int y) => (X, Y) = (x, y); + } + + public struct Point_2D_Struct_WithMultipleAttributes_OneNonPublic + { + public int X { get; } + + public int Y { get; } + + [JsonConstructor] + public Point_2D_Struct_WithMultipleAttributes_OneNonPublic(int x) => (X, Y) = (x, 0); + + [JsonConstructor] + private Point_2D_Struct_WithMultipleAttributes_OneNonPublic(int x, int y) => (X, Y) = (x, y); + } + + public class SinglePublicParameterizedCtor + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + public SinglePublicParameterizedCtor() { } + + public SinglePublicParameterizedCtor(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public class SingleParameterlessCtor_MultiplePublicParameterizedCtor + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + public SingleParameterlessCtor_MultiplePublicParameterizedCtor() { } + + public SingleParameterlessCtor_MultiplePublicParameterizedCtor(int myInt) + { + MyInt = myInt; + } + + public SingleParameterlessCtor_MultiplePublicParameterizedCtor(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public struct SingleParameterlessCtor_MultiplePublicParameterizedCtor_Struct + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + public SingleParameterlessCtor_MultiplePublicParameterizedCtor_Struct(int myInt) + { + MyInt = myInt; + MyString = null; + } + + public SingleParameterlessCtor_MultiplePublicParameterizedCtor_Struct(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public class PublicParameterizedCtor + { + public int MyInt { get; private set; } + + public PublicParameterizedCtor(int myInt) + { + MyInt = myInt; + } + } + + public struct Struct_PublicParameterizedConstructor + { + public int MyInt { get; } + + public Struct_PublicParameterizedConstructor(int myInt) + { + MyInt = myInt; + } + } + + public class PrivateParameterlessConstructor_PublicParameterizedCtor + { + public int MyInt { get; private set; } + + private PrivateParameterlessConstructor_PublicParameterizedCtor() { } + + public PrivateParameterlessConstructor_PublicParameterizedCtor(int myInt) + { + MyInt = myInt; + } + } + + public class PublicParameterizedCtor_WithAttribute + { + public int MyInt { get; private set; } + + [JsonConstructor] + public PublicParameterizedCtor_WithAttribute(int myInt) + { + MyInt = myInt; + } + } + + public struct Struct_PublicParameterizedConstructor_WithAttribute + { + public int MyInt { get; } + + [JsonConstructor] + public Struct_PublicParameterizedConstructor_WithAttribute(int myInt) + { + MyInt = myInt; + } + } + + public class PrivateParameterlessConstructor_PublicParameterizedCtor_WithAttribute + { + public int MyInt { get; private set; } + + private PrivateParameterlessConstructor_PublicParameterizedCtor_WithAttribute() { } + + [JsonConstructor] + public PrivateParameterlessConstructor_PublicParameterizedCtor_WithAttribute(int myInt) + { + MyInt = myInt; + } + } + + public class MultiplePublicParameterizedCtor + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + public MultiplePublicParameterizedCtor(int myInt) + { + MyInt = myInt; + } + + public MultiplePublicParameterizedCtor(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public struct MultiplePublicParameterizedCtor_Struct + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + public MultiplePublicParameterizedCtor_Struct(int myInt) + { + MyInt = myInt; + MyString = null; + } + + public MultiplePublicParameterizedCtor_Struct(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public class MultiplePublicParameterizedCtor_WithAttribute + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + [JsonConstructor] + public MultiplePublicParameterizedCtor_WithAttribute(int myInt) + { + MyInt = myInt; + } + + public MultiplePublicParameterizedCtor_WithAttribute(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public struct MultiplePublicParameterizedCtor_WithAttribute_Struct + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + public MultiplePublicParameterizedCtor_WithAttribute_Struct(int myInt) + { + MyInt = myInt; + MyString = null; + } + + [JsonConstructor] + public MultiplePublicParameterizedCtor_WithAttribute_Struct(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public class ParameterlessCtor_MultiplePublicParameterizedCtor_WithAttribute + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + public ParameterlessCtor_MultiplePublicParameterizedCtor_WithAttribute() { } + + [JsonConstructor] + public ParameterlessCtor_MultiplePublicParameterizedCtor_WithAttribute(int myInt) + { + MyInt = myInt; + } + + public ParameterlessCtor_MultiplePublicParameterizedCtor_WithAttribute(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public class MultiplePublicParameterizedCtor_WithMultipleAttributes + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + [JsonConstructor] + public MultiplePublicParameterizedCtor_WithMultipleAttributes(int myInt) + { + MyInt = myInt; + } + + [JsonConstructor] + public MultiplePublicParameterizedCtor_WithMultipleAttributes(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public class PublicParameterlessConstructor_PublicParameterizedCtor_WithMultipleAttributes + { + public int MyInt { get; private set; } + public string MyString { get; private set; } + + [JsonConstructor] + public PublicParameterlessConstructor_PublicParameterizedCtor_WithMultipleAttributes() { } + + [JsonConstructor] + public PublicParameterlessConstructor_PublicParameterizedCtor_WithMultipleAttributes(int myInt, string myString) + { + MyInt = myInt; + MyString = myString; + } + } + + public class Parameterized_StackWrapper : Stack + { + [JsonConstructor] + public Parameterized_StackWrapper(object[] elements) + { + foreach (object element in elements) + { + Push(element); + } + } + } + + public class Parameterized_WrapperForICollection : ICollection + { + private List _list = new List(); + + public Parameterized_WrapperForICollection(object[] elements) + { + _list.AddRange(elements); + } + + public int Count => ((ICollection)_list).Count; + + public bool IsSynchronized => ((ICollection)_list).IsSynchronized; + + public object SyncRoot => ((ICollection)_list).SyncRoot; + + public void CopyTo(Array array, int index) + { + ((ICollection)_list).CopyTo(array, index); + } + + public IEnumerator GetEnumerator() + { + return ((ICollection)_list).GetEnumerator(); + } + } + + public class Point_2D : ITestClass + { + public int X { get; } + + public int Y { get; } + + [JsonConstructor] + public Point_2D(int x, int y) => (X, Y) = (x, y); + + public void Initialize() { } + + public void Verify() + { + Assert.Equal(1, X); + Assert.Equal(2, Y); + } + } + + public class Point_3D : ITestClass + { + public int X { get; } + + public int Y { get; } + + public int Z { get; } + + [JsonConstructor] + public Point_3D(int x, int y, int z = 50) => (X, Y, Z) = (x, y, z); + + public void Initialize() { } + + public void Verify() + { + Assert.Equal(1, X); + Assert.Equal(2, Y); + Assert.Equal(3, Z); + } + } + + public struct Point_2D_With_ExtData : ITestClass + { + public int X { get; } + + public int Y { get; } + + [JsonConstructor] + public Point_2D_With_ExtData(int x, int y) + { + X = x; + Y = y; + ExtensionData = new Dictionary(); + } + + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } + + public void Initialize() { } + + public void Verify() + { + Assert.Equal(1, X); + Assert.Equal(2, Y); + } + } + + public struct WrapperForPoint_3D + { + public Point_3D Point_3D { get; set; } + } + + public class ClassWrapperForPoint_3D + { + public Point_3D Point3D { get; } + + public ClassWrapperForPoint_3D(Point_3D point3D) + { + Point3D = point3D; + } + } + + public class ClassWrapper_For_Int_String + { + public int Int { get; } + + public string String { get; } + + public ClassWrapper_For_Int_String(int @int, string @string) // Parameter names are "int" and "string" + { + Int = @int; + String = @string; + } + } + + public class ClassWrapper_For_Int_Point_3D_String + { + public int MyInt { get; } + + public Point_3D_Struct MyPoint3DStruct { get; } + + public string MyString { get; } + + public ClassWrapper_For_Int_Point_3D_String(Point_3D_Struct myPoint3DStruct) + { + MyInt = 0; + MyPoint3DStruct = myPoint3DStruct; + MyString = null; + } + + [JsonConstructor] + public ClassWrapper_For_Int_Point_3D_String(int myInt, Point_3D_Struct myPoint3DStruct, string myString) + { + MyInt = myInt; + MyPoint3DStruct = myPoint3DStruct; + MyString = myString; + } + } + + public struct Point_3D_Struct + { + public int X { get; } + + public int Y { get; } + + public int Z { get; } + + [JsonConstructor] + public Point_3D_Struct(int x, int y, int z = 50) => (X, Y, Z) = (x, y, z); + } + + public class Person_Class : ITestClass + { + public string FirstName { get; set; } + public string LastName { get; set; } + public string EmailAddress { get; } + public Guid Id { get; } + public int Age { get; } + + public Point_2D Point2D { get; set; } + public Point_2D ReadOnlyPoint2D { get; } + + public Point_2D_With_ExtData_Class Point2DWithExtDataClass { get; set; } + public Point_2D_With_ExtData_Class ReadOnlyPoint2DWithExtDataClass { get; } + + public Point_3D_Struct Point3DStruct { get; set; } + public Point_3D_Struct ReadOnlyPoint3DStruct { get; } + + public Point_2D_With_ExtData Point2DWithExtData { get; set; } + public Point_2D_With_ExtData ReadOnlyPoint2DWithExtData { get; } + + // Test that objects deserialized with parameterless still work fine as properties + public SinglePublicParameterizedCtor SinglePublicParameterizedCtor { get; set; } + public SinglePublicParameterizedCtor ReadOnlySinglePublicParameterizedCtor { get; } + + public Person_Class( + string emailAddress, + Guid id, + int age, + Point_2D readOnlyPoint2D, + Point_2D_With_ExtData_Class readOnlyPoint2DWithExtDataClass, + Point_3D_Struct readOnlyPoint3DStruct, + Point_2D_With_ExtData readOnlyPoint2DWithExtData, + SinglePublicParameterizedCtor readOnlySinglePublicParameterizedCtor) + { + EmailAddress = emailAddress; + Id = id; + Age = age; + ReadOnlyPoint2D = readOnlyPoint2D; + ReadOnlyPoint2DWithExtDataClass = readOnlyPoint2DWithExtDataClass; + ReadOnlyPoint3DStruct = readOnlyPoint3DStruct; + ReadOnlyPoint2DWithExtData = readOnlyPoint2DWithExtData; + ReadOnlySinglePublicParameterizedCtor = readOnlySinglePublicParameterizedCtor; + } + + public static readonly string s_json = + @"{ + ""FirstName"":""John"", + ""LastName"":""Doe"", + ""EmailAddress"":""johndoe@live.com"", + ""Id"":""f2c92fcc-459f-4287-90b6-a7cbd82aeb0e"", + ""Age"":24, + ""Point2D"":{""X"":1,""Y"":2}, + ""ReadOnlyPoint2D"":{""X"":1,""Y"":2}, + ""Point2DWithExtDataClass"":{""X"":1,""Y"":2,""b"":3}, + ""ReadOnlyPoint2DWithExtDataClass"":{""X"":1,""Y"":2,""b"":3}, + ""Point3DStruct"":{""X"":1,""Y"":2,""Z"":3}, + ""ReadOnlyPoint3DStruct"":{""X"":1,""Y"":2,""Z"":3}, + ""Point2DWithExtData"":{""X"":1,""Y"":2,""b"":3}, + ""ReadOnlyPoint2DWithExtData"":{""X"":1,""Y"":2,""b"":3} + }"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Initialize() { } + + public void Verify() + { + Assert.Equal("John", FirstName); + Assert.Equal("Doe", LastName); + Assert.Equal("johndoe@live.com", EmailAddress); + Assert.Equal("f2c92fcc-459f-4287-90b6-a7cbd82aeb0e", Id.ToString()); + Assert.Equal(24, Age); + + string serialized = JsonSerializer.Serialize(this); + Assert.Contains(@"""Point2D"":{", serialized); + Assert.Contains(@"""ReadOnlyPoint2D"":{", serialized); + Assert.Contains(@"""Point2DWithExtDataClass"":{", serialized); + Assert.Contains(@"""ReadOnlyPoint2DWithExtDataClass"":{", serialized); + Assert.Contains(@"""Point3DStruct"":{", serialized); + Assert.Contains(@"""ReadOnlyPoint3DStruct"":{", serialized); + Assert.Contains(@"""Point2DWithExtData"":{", serialized); + Assert.Contains(@"""ReadOnlyPoint2DWithExtData"":{", serialized); + + serialized = JsonSerializer.Serialize(Point2D); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + + serialized = JsonSerializer.Serialize(ReadOnlyPoint2D); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + + serialized = JsonSerializer.Serialize(Point2DWithExtDataClass); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""b"":3", serialized); + + serialized = JsonSerializer.Serialize(ReadOnlyPoint2DWithExtDataClass); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""b"":3", serialized); + + serialized = JsonSerializer.Serialize(Point3DStruct); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""Z"":3", serialized); + + serialized = JsonSerializer.Serialize(ReadOnlyPoint3DStruct); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""Z"":3", serialized); + + serialized = JsonSerializer.Serialize(Point2DWithExtData); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""b"":3", serialized); + + serialized = JsonSerializer.Serialize(ReadOnlyPoint2DWithExtData); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""b"":3", serialized); + } + } + + public struct Person_Struct : ITestClass + { + public string FirstName { get; set; } + public string LastName { get; set; } + public string EmailAddress { get; } + public Guid Id { get; } + public int Age { get; } + + public Point_2D Point2D { get; set; } + public Point_2D ReadOnlyPoint2D { get; } + + public Point_2D_With_ExtData_Class Point2DWithExtDataClass { get; set; } + public Point_2D_With_ExtData_Class ReadOnlyPoint2DWithExtDataClass { get; } + + public Point_3D_Struct Point3DStruct { get; set; } + public Point_3D_Struct ReadOnlyPoint3DStruct { get; } + + public Point_2D_With_ExtData Point2DWithExtData { get; set; } + public Point_2D_With_ExtData ReadOnlyPoint2DWithExtData { get; } + + // Test that objects deserialized with parameterless still work fine as properties + public SinglePublicParameterizedCtor SinglePublicParameterizedCtor { get; set; } + public SinglePublicParameterizedCtor ReadOnlySinglePublicParameterizedCtor { get; } + + [JsonConstructor] + public Person_Struct( + string emailAddress, + Guid id, + int age, + Point_2D readOnlyPoint2D, + Point_2D_With_ExtData_Class readOnlyPoint2DWithExtDataClass, + Point_3D_Struct readOnlyPoint3DStruct, + Point_2D_With_ExtData readOnlyPoint2DWithExtData, + SinglePublicParameterizedCtor readOnlySinglePublicParameterizedCtor) + { + // Readonly, setting in ctor. + EmailAddress = emailAddress; + Id = id; + Age = age; + ReadOnlyPoint2D = readOnlyPoint2D; + ReadOnlyPoint2DWithExtDataClass = readOnlyPoint2DWithExtDataClass; + ReadOnlyPoint3DStruct = readOnlyPoint3DStruct; + ReadOnlyPoint2DWithExtData = readOnlyPoint2DWithExtData; + ReadOnlySinglePublicParameterizedCtor = readOnlySinglePublicParameterizedCtor; + + // These properties will be set by serializer. + FirstName = null; + LastName = null; + Point2D = null; + Point2DWithExtDataClass = null; + Point3DStruct = default; + Point2DWithExtData = default; + SinglePublicParameterizedCtor = default; + } + + public static readonly string s_json = + @"{ + ""FirstName"":""John"", + ""LastName"":""Doe"", + ""EmailAddress"":""johndoe@live.com"", + ""Id"":""f2c92fcc-459f-4287-90b6-a7cbd82aeb0e"", + ""Age"":24, + ""Point2D"":{""X"":1,""Y"":2}, + ""Junk"":""Data"", + ""ReadOnlyPoint2D"":{""X"":1,""Y"":2}, + ""Point2DWithExtDataClass"":{""X"":1,""Y"":2,""b"":3}, + ""ReadOnlyPoint2DWithExtDataClass"":{""X"":1,""Y"":2,""b"":3}, + ""Point3DStruct"":{""X"":1,""Y"":2,""Z"":3}, + ""More"":""Junk"", + ""ReadOnlyPoint3DStruct"":{""X"":1,""Y"":2,""Z"":3}, + ""Point2DWithExtData"":{""X"":1,""Y"":2,""b"":3}, + ""ReadOnlyPoint2DWithExtData"":{""X"":1,""Y"":2,""b"":3} + }"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Initialize() { } + + public void Verify() + { + Assert.Equal("John", FirstName); + Assert.Equal("Doe", LastName); + Assert.Equal("johndoe@live.com", EmailAddress); + Assert.Equal("f2c92fcc-459f-4287-90b6-a7cbd82aeb0e", Id.ToString()); + Assert.Equal(24, Age); + + string serialized = JsonSerializer.Serialize(this); + Assert.Contains(@"""Point2D"":{", serialized); + Assert.Contains(@"""ReadOnlyPoint2D"":{", serialized); + Assert.Contains(@"""Point2DWithExtDataClass"":{", serialized); + Assert.Contains(@"""ReadOnlyPoint2DWithExtDataClass"":{", serialized); + Assert.Contains(@"""Point3DStruct"":{", serialized); + Assert.Contains(@"""ReadOnlyPoint3DStruct"":{", serialized); + Assert.Contains(@"""Point2DWithExtData"":{", serialized); + Assert.Contains(@"""ReadOnlyPoint2DWithExtData"":{", serialized); + + serialized = JsonSerializer.Serialize(Point2D); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + + serialized = JsonSerializer.Serialize(ReadOnlyPoint2D); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + + serialized = JsonSerializer.Serialize(Point2DWithExtDataClass); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""b"":3", serialized); + + serialized = JsonSerializer.Serialize(ReadOnlyPoint2DWithExtDataClass); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""b"":3", serialized); + + serialized = JsonSerializer.Serialize(Point3DStruct); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""Z"":3", serialized); + + serialized = JsonSerializer.Serialize(ReadOnlyPoint3DStruct); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""Z"":3", serialized); + + serialized = JsonSerializer.Serialize(Point2DWithExtData); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""b"":3", serialized); + + serialized = JsonSerializer.Serialize(ReadOnlyPoint2DWithExtData); + Assert.Contains(@"""X"":1", serialized); + Assert.Contains(@"""Y"":2", serialized); + Assert.Contains(@"""b"":3", serialized); + } + } + + + + public class Point_2D_With_ExtData_Class + { + public int X { get; } + + public int Y { get; } + + [JsonConstructor] + public Point_2D_With_ExtData_Class(int x, int y) + { + X = x; + Y = y; + } + + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } + } + + public class Point_CtorsIgnoreJson + { + public int X { get; set; } + + public int Y { get; set; } + + [JsonConstructor] + public Point_CtorsIgnoreJson(int x, int y) + { + X = 40; + Y = 60; + } + } + + public class PointPropertyNamingPolicy : JsonNamingPolicy + { + public override string ConvertName(string name) + { + if (name == "X") + { + return "A"; + } + else if (name == "Y") + { + return "B"; + } + + return name; + } + } + + public class NullArgTester + { + public Point_3D_Struct Point3DStruct { get; } + public ImmutableArray ImmutableArray { get; } + public int Int { get; } + + public NullArgTester(Point_3D_Struct point3DStruct, ImmutableArray immutableArray, int @int = 50) + { + Point3DStruct = point3DStruct; + ImmutableArray = immutableArray; + Int = @int; + } + } + + public class ClassWithConstructor_SimpleAndComplexParameters : ITestClass + { + public byte MyByte { get; } + public sbyte MySByte { get; set; } + public char MyChar { get; } + public string MyString { get; } + public decimal MyDecimal { get; } + public bool MyBooleanTrue { get; set; } + public bool MyBooleanFalse { get; } + public float MySingle { get; set; } + public double MyDouble { get; } + public DateTime MyDateTime { get; set; } + public DateTimeOffset MyDateTimeOffset { get; } + public Guid MyGuid { get; } + public Uri MyUri { get; set; } + public SampleEnum MyEnum { get; } + public SampleEnumInt64 MyInt64Enum { get; } + public SampleEnumUInt64 MyUInt64Enum { get; } + public SimpleStruct MySimpleStruct { get; } + public SimpleTestStruct MySimpleTestStruct { get; set; } + public int[][][] MyInt16ThreeDimensionArray { get; } + public List>> MyInt16ThreeDimensionList { get; } + public List MyStringList { get; } + public IEnumerable MyStringIEnumerable { get; set; } + public IList MyStringIList { get; } + public ICollection MyStringICollection { get; set; } + public IEnumerable MyStringIEnumerableT { get; } + public IReadOnlyList MyStringIReadOnlyListT { get; } + public ISet MyStringISetT { get; set; } + public KeyValuePair MyStringToStringKeyValuePair { get; } + public IDictionary MyStringToStringIDict { get; set; } + public Dictionary MyStringToStringGenericDict { get; } + public IDictionary MyStringToStringGenericIDict { get; set; } + public IImmutableDictionary MyStringToStringIImmutableDict { get; } + public ImmutableQueue MyStringImmutablQueueT { get; set; } + public ImmutableSortedSet MyStringImmutableSortedSetT { get; } + public List MyListOfNullString { get; } + + public ClassWithConstructor_SimpleAndComplexParameters( + byte myByte, + char myChar, + string myString, + decimal myDecimal, + bool myBooleanFalse, + double myDouble, + DateTimeOffset myDateTimeOffset, + Guid myGuid, + SampleEnum myEnum, + SampleEnumInt64 myInt64Enum, + SampleEnumUInt64 myUInt64Enum, + SimpleStruct mySimpleStruct, + int[][][] myInt16ThreeDimensionArray, + List>> myInt16ThreeDimensionList, + List myStringList, + IList myStringIList, + IEnumerable myStringIEnumerableT, + IReadOnlyList myStringIReadOnlyListT, + KeyValuePair myStringToStringKeyValuePair, + Dictionary myStringToStringGenericDict, + IImmutableDictionary myStringToStringIImmutableDict, + ImmutableSortedSet myStringImmutableSortedSetT, + List myListOfNullString) + { + MyByte = myByte; + MyChar = myChar; + MyString = myString; + MyDecimal = myDecimal; + MyBooleanFalse = myBooleanFalse; + MyDouble = myDouble; + MyDateTimeOffset = myDateTimeOffset; + MyGuid = myGuid; + MyEnum = myEnum; + MyInt64Enum = myInt64Enum; + MyUInt64Enum = myUInt64Enum; + MySimpleStruct = mySimpleStruct; + MyInt16ThreeDimensionArray = myInt16ThreeDimensionArray; + MyInt16ThreeDimensionList = myInt16ThreeDimensionList; + MyStringList = myStringList; + MyStringIList = myStringIList; + MyStringIEnumerableT = myStringIEnumerableT; + MyStringIReadOnlyListT = myStringIReadOnlyListT; + MyStringToStringKeyValuePair = myStringToStringKeyValuePair; + MyStringToStringGenericDict = myStringToStringGenericDict; + MyStringToStringIImmutableDict = myStringToStringIImmutableDict; + MyStringImmutableSortedSetT = myStringImmutableSortedSetT; + MyListOfNullString = myListOfNullString; + } + + public static ClassWithConstructor_SimpleAndComplexParameters GetInstance() => + JsonSerializer.Deserialize(s_json); + + public static readonly string s_json = $"{{{s_partialJson1},{s_partialJson2}}}"; + public static readonly string s_json_flipped = $"{{{s_partialJson2},{s_partialJson1}}}"; + + private const string s_partialJson1 = + @"""MyByte"" : 7," + + @"""MySByte"" : 8," + + @"""MyChar"" : ""a""," + + @"""MyString"" : ""Hello""," + + @"""MyBooleanTrue"" : true," + + @"""MyBooleanFalse"" : false," + + @"""MySingle"" : 1.1," + + @"""MyDouble"" : 2.2," + + @"""MyDecimal"" : 3.3," + + @"""MyDateTime"" : ""2019-01-30T12:01:02.0000000Z""," + + @"""MyDateTimeOffset"" : ""2019-01-30T12:01:02.0000000+01:00""," + + @"""MyGuid"" : ""1B33498A-7B7D-4DDA-9C13-F6AA4AB449A6""," + + @"""MyUri"" : ""https://github.com/dotnet/runtime""," + + @"""MyEnum"" : 2," + // int by default + @"""MyInt64Enum"" : -9223372036854775808," + + @"""MyUInt64Enum"" : 18446744073709551615," + + @"""MySimpleStruct"" : {""One"" : 11, ""Two"" : 1.9999, ""Three"" : 33}," + + @"""MySimpleTestStruct"" : {""MyInt64"" : 64, ""MyString"" :""Hello"", ""MyInt32Array"" : [32]}," + + @"""MyInt16ThreeDimensionArray"" : [[[11, 12],[13, 14]],[[21,22],[23,24]]]"; + + private const string s_partialJson2 = + @"""MyInt16ThreeDimensionList"" : [[[11, 12],[13, 14]],[[21,22],[23,24]]]," + + @"""MyStringList"" : [""Hello""]," + + @"""MyStringIEnumerable"" : [""Hello""]," + + @"""MyStringIList"" : [""Hello""]," + + @"""MyStringICollection"" : [""Hello""]," + + @"""MyStringIEnumerableT"" : [""Hello""]," + + @"""MyStringIReadOnlyListT"" : [""Hello""]," + + @"""MyStringISetT"" : [""Hello""]," + + @"""MyStringToStringKeyValuePair"" : {""Key"" : ""myKey"", ""Value"" : ""myValue""}," + + @"""MyStringToStringIDict"" : {""key"" : ""value""}," + + @"""MyStringToStringGenericDict"" : {""key"" : ""value""}," + + @"""MyStringToStringGenericIDict"" : {""key"" : ""value""}," + + @"""MyStringToStringIImmutableDict"" : {""key"" : ""value""}," + + @"""MyStringImmutablQueueT"" : [""Hello""]," + + @"""MyStringImmutableSortedSetT"" : [""Hello""]," + + @"""MyListOfNullString"" : [null]"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Initialize() { } + + public void Verify() + { + Assert.Equal((byte)7, MyByte); + Assert.Equal((sbyte)8, MySByte); + Assert.Equal('a', MyChar); + Assert.Equal("Hello", MyString); + Assert.Equal(3.3m, MyDecimal); + Assert.False(MyBooleanFalse); + Assert.True(MyBooleanTrue); + Assert.Equal(1.1f, MySingle); + Assert.Equal(2.2d, MyDouble); + Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTime); + Assert.Equal(new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)), MyDateTimeOffset); + Assert.Equal(SampleEnum.Two, MyEnum); + Assert.Equal(SampleEnumInt64.MinNegative, MyInt64Enum); + Assert.Equal(SampleEnumUInt64.Max, MyUInt64Enum); + Assert.Equal(11, MySimpleStruct.One); + Assert.Equal(1.9999, MySimpleStruct.Two); + Assert.Equal(64, MySimpleTestStruct.MyInt64); + Assert.Equal("Hello", MySimpleTestStruct.MyString); + Assert.Equal(32, MySimpleTestStruct.MyInt32Array[0]); + + Assert.Equal(11, MyInt16ThreeDimensionArray[0][0][0]); + Assert.Equal(12, MyInt16ThreeDimensionArray[0][0][1]); + Assert.Equal(13, MyInt16ThreeDimensionArray[0][1][0]); + Assert.Equal(14, MyInt16ThreeDimensionArray[0][1][1]); + Assert.Equal(21, MyInt16ThreeDimensionArray[1][0][0]); + Assert.Equal(22, MyInt16ThreeDimensionArray[1][0][1]); + Assert.Equal(23, MyInt16ThreeDimensionArray[1][1][0]); + Assert.Equal(24, MyInt16ThreeDimensionArray[1][1][1]); + + Assert.Equal(11, MyInt16ThreeDimensionList[0][0][0]); + Assert.Equal(12, MyInt16ThreeDimensionList[0][0][1]); + Assert.Equal(13, MyInt16ThreeDimensionList[0][1][0]); + Assert.Equal(14, MyInt16ThreeDimensionList[0][1][1]); + Assert.Equal(21, MyInt16ThreeDimensionList[1][0][0]); + Assert.Equal(22, MyInt16ThreeDimensionList[1][0][1]); + Assert.Equal(23, MyInt16ThreeDimensionList[1][1][0]); + Assert.Equal(24, MyInt16ThreeDimensionList[1][1][1]); + + Assert.Equal("Hello", MyStringList[0]); + + IEnumerator enumerator = MyStringIEnumerable.GetEnumerator(); + enumerator.MoveNext(); + Assert.Equal("Hello", ((JsonElement)enumerator.Current).GetString()); + + Assert.Equal("Hello", ((JsonElement)MyStringIList[0]).GetString()); + + enumerator = MyStringICollection.GetEnumerator(); + enumerator.MoveNext(); + Assert.Equal("Hello", ((JsonElement)enumerator.Current).GetString()); + + Assert.Equal("Hello", MyStringIEnumerableT.First()); + + Assert.Equal("Hello", MyStringIReadOnlyListT[0]); + Assert.Equal("Hello", MyStringISetT.First()); + + Assert.Equal("myKey", MyStringToStringKeyValuePair.Key); + Assert.Equal("myValue", MyStringToStringKeyValuePair.Value); + + enumerator = MyStringToStringIDict.GetEnumerator(); + enumerator.MoveNext(); + DictionaryEntry entry = (DictionaryEntry)enumerator.Current; + Assert.Equal("key", entry.Key); + Assert.Equal("value", ((JsonElement)entry.Value).GetString()); + + Assert.Equal("value", MyStringToStringGenericDict["key"]); + Assert.Equal("value", MyStringToStringGenericIDict["key"]); + Assert.Equal("value", MyStringToStringIImmutableDict["key"]); + + Assert.Equal("Hello", MyStringImmutablQueueT.First()); + Assert.Equal("Hello", MyStringImmutableSortedSetT.First()); + + Assert.Null(MyListOfNullString[0]); + } + } + public class Parameterless_ClassWithPrimitives + { + public int FirstInt { get; set; } + public int SecondInt { get; set; } + + public string FirstString { get; set; } + public string SecondString { get; set; } + + public DateTime FirstDateTime { get; set; } + public DateTime SecondDateTime { get; set; } + + public int X { get; set; } + public int Y { get; set; } + public int Z { get; set; } + + public int ThirdInt { get; set; } + public int FourthInt { get; set; } + + public string ThirdString { get; set; } + public string FourthString { get; set; } + + public DateTime ThirdDateTime { get; set; } + public DateTime FourthDateTime { get; set; } + } + + public class Parameterized_ClassWithPrimitives_3Args + { + public int FirstInt { get; set; } + public int SecondInt { get; set; } + + public string FirstString { get; set; } + public string SecondString { get; set; } + + public DateTime FirstDateTime { get; set; } + public DateTime SecondDateTime { get; set; } + + public int X { get; } + public int Y { get; } + public int Z { get; } + + public int ThirdInt { get; set; } + public int FourthInt { get; set; } + + public string ThirdString { get; set; } + public string FourthString { get; set; } + + public DateTime ThirdDateTime { get; set; } + public DateTime FourthDateTime { get; set; } + + + public Parameterized_ClassWithPrimitives_3Args(int x, int y, int z) => (X, Y, Z) = (x, y, z); + } + + public class TupleWrapper + { + public Tuple Tuple { get; set; } + } + + public class ConverterForPoint3D : JsonConverter + { + public override Point_3D Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(); + } + + while (reader.TokenType != JsonTokenType.EndObject) + { + reader.Read(); + } + + return new Point_3D(4, 4, 4); + } + + public override void Write(Utf8JsonWriter writer, Point_3D value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + } + public class ConverterForInt32 : JsonConverter + { + public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return 25; + } + + public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + } + + public class Class_With_Ctor_With_64_Params : ITestClass + { + public int Int0 { get; } + public int Int1 { get; } + public int Int2 { get; } + public int Int3 { get; } + public int Int4 { get; } + public int Int5 { get; } + public int Int6 { get; } + public int Int7 { get; } + public int Int8 { get; } + public int Int9 { get; } + public int Int10 { get; } + public int Int11 { get; } + public int Int12 { get; } + public int Int13 { get; } + public int Int14 { get; } + public int Int15 { get; } + public int Int16 { get; } + public int Int17 { get; } + public int Int18 { get; } + public int Int19 { get; } + public int Int20 { get; } + public int Int21 { get; } + public int Int22 { get; } + public int Int23 { get; } + public int Int24 { get; } + public int Int25 { get; } + public int Int26 { get; } + public int Int27 { get; } + public int Int28 { get; } + public int Int29 { get; } + public int Int30 { get; } + public int Int31 { get; } + public int Int32 { get; } + public int Int33 { get; } + public int Int34 { get; } + public int Int35 { get; } + public int Int36 { get; } + public int Int37 { get; } + public int Int38 { get; } + public int Int39 { get; } + public int Int40 { get; } + public int Int41 { get; } + public int Int42 { get; } + public int Int43 { get; } + public int Int44 { get; } + public int Int45 { get; } + public int Int46 { get; } + public int Int47 { get; } + public int Int48 { get; } + public int Int49 { get; } + public int Int50 { get; } + public int Int51 { get; } + public int Int52 { get; } + public int Int53 { get; } + public int Int54 { get; } + public int Int55 { get; } + public int Int56 { get; } + public int Int57 { get; } + public int Int58 { get; } + public int Int59 { get; } + public int Int60 { get; } + public int Int61 { get; } + public int Int62 { get; } + public int Int63 { get; } + + public Class_With_Ctor_With_64_Params(int int0, int int1, int int2, int int3, int int4, int int5, int int6, int int7, + int int8, int int9, int int10, int int11, int int12, int int13, int int14, int int15, + int int16, int int17, int int18, int int19, int int20, int int21, int int22, int int23, + int int24, int int25, int int26, int int27, int int28, int int29, int int30, int int31, + int int32, int int33, int int34, int int35, int int36, int int37, int int38, int int39, + int int40, int int41, int int42, int int43, int int44, int int45, int int46, int int47, + int int48, int int49, int int50, int int51, int int52, int int53, int int54, int int55, + int int56, int int57, int int58, int int59, int int60, int int61, int int62, int int63) + { + Int0 = int0; Int1 = int1; Int2 = int2; Int3 = int3; Int4 = int4; Int5 = int5; Int6 = int6; Int7 = int7; + Int8 = int8; Int9 = int9; Int10 = int10; Int11 = int11; Int12 = int12; Int13 = int13; Int14 = int14; Int15 = int15; + Int16 = int16; Int17 = int17; Int18 = int18; Int19 = int19; Int20 = int20; Int21 = int21; Int22 = int22; Int23 = int23; + Int24 = int24; Int25 = int25; Int26 = int26; Int27 = int27; Int28 = int28; Int29 = int29; Int30 = int30; Int31 = int31; + Int32 = int32; Int33 = int33; Int34 = int34; Int35 = int35; Int36 = int36; Int37 = int37; Int38 = int38; Int39 = int39; + Int40 = int40; Int41 = int41; Int42 = int42; Int43 = int43; Int44 = int44; Int45 = int45; Int46 = int46; Int47 = int47; + Int48 = int48; Int49 = int49; Int50 = int50; Int51 = int51; Int52 = int52; Int53 = int53; Int54 = int54; Int55 = int55; + Int56 = int56; Int57 = int57; Int58 = int58; Int59 = int59; Int60 = int60; Int61 = int61; Int62 = int62; Int63 = int63; + } + + public static string Json { + get + { + StringBuilder sb = new StringBuilder(); + sb.Append("{"); + for (int i = 0; i < 63; i++) + { + sb.Append($@"""Int{i}"":{i},"); + } + sb.Append($@"""Int63"":63"); + sb.Append("}"); + + return sb.ToString(); + } + } + + public static byte[] Data => Encoding.UTF8.GetBytes(Json); + + public void Initialize() { } + + public void Verify() + { + for (int i = 0; i < 64; i++) + { + Assert.Equal(i, (int)typeof(Class_With_Ctor_With_64_Params).GetProperty($"Int{i}").GetValue(this)); + } + } + } + + public struct Struct_With_Ctor_With_64_Params + { + public int Int0 { get; } + public int Int1 { get; } + public int Int2 { get; } + public int Int3 { get; } + public int Int4 { get; } + public int Int5 { get; } + public int Int6 { get; } + public int Int7 { get; } + public int Int8 { get; } + public int Int9 { get; } + public int Int10 { get; } + public int Int11 { get; } + public int Int12 { get; } + public int Int13 { get; } + public int Int14 { get; } + public int Int15 { get; } + public int Int16 { get; } + public int Int17 { get; } + public int Int18 { get; } + public int Int19 { get; } + public int Int20 { get; } + public int Int21 { get; } + public int Int22 { get; } + public int Int23 { get; } + public int Int24 { get; } + public int Int25 { get; } + public int Int26 { get; } + public int Int27 { get; } + public int Int28 { get; } + public int Int29 { get; } + public int Int30 { get; } + public int Int31 { get; } + public int Int32 { get; } + public int Int33 { get; } + public int Int34 { get; } + public int Int35 { get; } + public int Int36 { get; } + public int Int37 { get; } + public int Int38 { get; } + public int Int39 { get; } + public int Int40 { get; } + public int Int41 { get; } + public int Int42 { get; } + public int Int43 { get; } + public int Int44 { get; } + public int Int45 { get; } + public int Int46 { get; } + public int Int47 { get; } + public int Int48 { get; } + public int Int49 { get; } + public int Int50 { get; } + public int Int51 { get; } + public int Int52 { get; } + public int Int53 { get; } + public int Int54 { get; } + public int Int55 { get; } + public int Int56 { get; } + public int Int57 { get; } + public int Int58 { get; } + public int Int59 { get; } + public int Int60 { get; } + public int Int61 { get; } + public int Int62 { get; } + public int Int63 { get; } + + [JsonConstructor] + public Struct_With_Ctor_With_64_Params(int int0, int int1, int int2, int int3, int int4, int int5, int int6, int int7, + int int8, int int9, int int10, int int11, int int12, int int13, int int14, int int15, + int int16, int int17, int int18, int int19, int int20, int int21, int int22, int int23, + int int24, int int25, int int26, int int27, int int28, int int29, int int30, int int31, + int int32, int int33, int int34, int int35, int int36, int int37, int int38, int int39, + int int40, int int41, int int42, int int43, int int44, int int45, int int46, int int47, + int int48, int int49, int int50, int int51, int int52, int int53, int int54, int int55, + int int56, int int57, int int58, int int59, int int60, int int61, int int62, int int63) + { + Int0 = int0; Int1 = int1; Int2 = int2; Int3 = int3; Int4 = int4; Int5 = int5; Int6 = int6; Int7 = int7; + Int8 = int8; Int9 = int9; Int10 = int10; Int11 = int11; Int12 = int12; Int13 = int13; Int14 = int14; Int15 = int15; + Int16 = int16; Int17 = int17; Int18 = int18; Int19 = int19; Int20 = int20; Int21 = int21; Int22 = int22; Int23 = int23; + Int24 = int24; Int25 = int25; Int26 = int26; Int27 = int27; Int28 = int28; Int29 = int29; Int30 = int30; Int31 = int31; + Int32 = int32; Int33 = int33; Int34 = int34; Int35 = int35; Int36 = int36; Int37 = int37; Int38 = int38; Int39 = int39; + Int40 = int40; Int41 = int41; Int42 = int42; Int43 = int43; Int44 = int44; Int45 = int45; Int46 = int46; Int47 = int47; + Int48 = int48; Int49 = int49; Int50 = int50; Int51 = int51; Int52 = int52; Int53 = int53; Int54 = int54; Int55 = int55; + Int56 = int56; Int57 = int57; Int58 = int58; Int59 = int59; Int60 = int60; Int61 = int61; Int62 = int62; Int63 = int63; + } + } + + public class Class_With_Ctor_With_65_Params + { + public int Int0 { get; } + public int Int1 { get; } + public int Int2 { get; } + public int Int3 { get; } + public int Int4 { get; } + public int Int5 { get; } + public int Int6 { get; } + public int Int7 { get; } + public int Int8 { get; } + public int Int9 { get; } + public int Int10 { get; } + public int Int11 { get; } + public int Int12 { get; } + public int Int13 { get; } + public int Int14 { get; } + public int Int15 { get; } + public int Int16 { get; } + public int Int17 { get; } + public int Int18 { get; } + public int Int19 { get; } + public int Int20 { get; } + public int Int21 { get; } + public int Int22 { get; } + public int Int23 { get; } + public int Int24 { get; } + public int Int25 { get; } + public int Int26 { get; } + public int Int27 { get; } + public int Int28 { get; } + public int Int29 { get; } + public int Int30 { get; } + public int Int31 { get; } + public int Int32 { get; } + public int Int33 { get; } + public int Int34 { get; } + public int Int35 { get; } + public int Int36 { get; } + public int Int37 { get; } + public int Int38 { get; } + public int Int39 { get; } + public int Int40 { get; } + public int Int41 { get; } + public int Int42 { get; } + public int Int43 { get; } + public int Int44 { get; } + public int Int45 { get; } + public int Int46 { get; } + public int Int47 { get; } + public int Int48 { get; } + public int Int49 { get; } + public int Int50 { get; } + public int Int51 { get; } + public int Int52 { get; } + public int Int53 { get; } + public int Int54 { get; } + public int Int55 { get; } + public int Int56 { get; } + public int Int57 { get; } + public int Int58 { get; } + public int Int59 { get; } + public int Int60 { get; } + public int Int61 { get; } + public int Int62 { get; } + public int Int63 { get; } + public int Int64 { get; } + + public Class_With_Ctor_With_65_Params(int int0, int int1, int int2, int int3, int int4, int int5, int int6, int int7, + int int8, int int9, int int10, int int11, int int12, int int13, int int14, int int15, + int int16, int int17, int int18, int int19, int int20, int int21, int int22, int int23, + int int24, int int25, int int26, int int27, int int28, int int29, int int30, int int31, + int int32, int int33, int int34, int int35, int int36, int int37, int int38, int int39, + int int40, int int41, int int42, int int43, int int44, int int45, int int46, int int47, + int int48, int int49, int int50, int int51, int int52, int int53, int int54, int int55, + int int56, int int57, int int58, int int59, int int60, int int61, int int62, int int63, + int int64) + { + Int0 = int0; Int1 = int1; Int2 = int2; Int3 = int3; Int4 = int4; Int5 = int5; Int6 = int6; Int7 = int7; + Int8 = int8; Int9 = int9; Int10 = int10; Int11 = int11; Int12 = int12; Int13 = int13; Int14 = int14; Int15 = int15; + Int16 = int16; Int17 = int17; Int18 = int18; Int19 = int19; Int20 = int20; Int21 = int21; Int22 = int22; Int23 = int23; + Int24 = int24; Int25 = int25; Int26 = int26; Int27 = int27; Int28 = int28; Int29 = int29; Int30 = int30; Int31 = int31; + Int32 = int32; Int33 = int33; Int34 = int34; Int35 = int35; Int36 = int36; Int37 = int37; Int38 = int38; Int39 = int39; + Int40 = int40; Int41 = int41; Int42 = int42; Int43 = int43; Int44 = int44; Int45 = int45; Int46 = int46; Int47 = int47; + Int48 = int48; Int49 = int49; Int50 = int50; Int51 = int51; Int52 = int52; Int53 = int53; Int54 = int54; Int55 = int55; + Int56 = int56; Int57 = int57; Int58 = int58; Int59 = int59; Int60 = int60; Int61 = int61; Int62 = int62; Int63 = int63; + Int64 = int64; + } + } + + public struct Struct_With_Ctor_With_65_Params + { + public int Int0 { get; } + public int Int1 { get; } + public int Int2 { get; } + public int Int3 { get; } + public int Int4 { get; } + public int Int5 { get; } + public int Int6 { get; } + public int Int7 { get; } + public int Int8 { get; } + public int Int9 { get; } + public int Int10 { get; } + public int Int11 { get; } + public int Int12 { get; } + public int Int13 { get; } + public int Int14 { get; } + public int Int15 { get; } + public int Int16 { get; } + public int Int17 { get; } + public int Int18 { get; } + public int Int19 { get; } + public int Int20 { get; } + public int Int21 { get; } + public int Int22 { get; } + public int Int23 { get; } + public int Int24 { get; } + public int Int25 { get; } + public int Int26 { get; } + public int Int27 { get; } + public int Int28 { get; } + public int Int29 { get; } + public int Int30 { get; } + public int Int31 { get; } + public int Int32 { get; } + public int Int33 { get; } + public int Int34 { get; } + public int Int35 { get; } + public int Int36 { get; } + public int Int37 { get; } + public int Int38 { get; } + public int Int39 { get; } + public int Int40 { get; } + public int Int41 { get; } + public int Int42 { get; } + public int Int43 { get; } + public int Int44 { get; } + public int Int45 { get; } + public int Int46 { get; } + public int Int47 { get; } + public int Int48 { get; } + public int Int49 { get; } + public int Int50 { get; } + public int Int51 { get; } + public int Int52 { get; } + public int Int53 { get; } + public int Int54 { get; } + public int Int55 { get; } + public int Int56 { get; } + public int Int57 { get; } + public int Int58 { get; } + public int Int59 { get; } + public int Int60 { get; } + public int Int61 { get; } + public int Int62 { get; } + public int Int63 { get; } + public int Int64 { get; } + + [JsonConstructor] + public Struct_With_Ctor_With_65_Params(int int0, int int1, int int2, int int3, int int4, int int5, int int6, int int7, + int int8, int int9, int int10, int int11, int int12, int int13, int int14, int int15, + int int16, int int17, int int18, int int19, int int20, int int21, int int22, int int23, + int int24, int int25, int int26, int int27, int int28, int int29, int int30, int int31, + int int32, int int33, int int34, int int35, int int36, int int37, int int38, int int39, + int int40, int int41, int int42, int int43, int int44, int int45, int int46, int int47, + int int48, int int49, int int50, int int51, int int52, int int53, int int54, int int55, + int int56, int int57, int int58, int int59, int int60, int int61, int int62, int int63, + int int64) + { + Int0 = int0; Int1 = int1; Int2 = int2; Int3 = int3; Int4 = int4; Int5 = int5; Int6 = int6; Int7 = int7; + Int8 = int8; Int9 = int9; Int10 = int10; Int11 = int11; Int12 = int12; Int13 = int13; Int14 = int14; Int15 = int15; + Int16 = int16; Int17 = int17; Int18 = int18; Int19 = int19; Int20 = int20; Int21 = int21; Int22 = int22; Int23 = int23; + Int24 = int24; Int25 = int25; Int26 = int26; Int27 = int27; Int28 = int28; Int29 = int29; Int30 = int30; Int31 = int31; + Int32 = int32; Int33 = int33; Int34 = int34; Int35 = int35; Int36 = int36; Int37 = int37; Int38 = int38; Int39 = int39; + Int40 = int40; Int41 = int41; Int42 = int42; Int43 = int43; Int44 = int44; Int45 = int45; Int46 = int46; Int47 = int47; + Int48 = int48; Int49 = int49; Int50 = int50; Int51 = int51; Int52 = int52; Int53 = int53; Int54 = int54; Int55 = int55; + Int56 = int56; Int57 = int57; Int58 = int58; Int59 = int59; Int60 = int60; Int61 = int61; Int62 = int62; Int63 = int63; + Int64 = int64; + } + } + + public class Parameterized_Person : ITestClass + { + public string FirstName { get; set; } + + public string LastName { get; set; } + + public Guid Id { get; } + + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } + + public Parameterized_Person(Guid id) => Id = id; + + public static readonly string s_json = @"{ + ""FirstName"":""Jet"", + ""Id"":""270bb22b-4816-4bd9-9acd-8ec5b1a896d3"", + ""EmailAddress"":""jetdoe@outlook.com"", + ""Id"":""0b3aa420-2e98-47f7-8a49-fea233b89416"", + ""LastName"":""Doe"", + ""Id"":""63cf821d-fd47-4782-8345-576d9228a534"" + }"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Initialize() { } + + public void Verify() + { + Assert.Equal("Jet", FirstName); + Assert.Equal("Doe", LastName); + Assert.Equal("63cf821d-fd47-4782-8345-576d9228a534", Id.ToString()); + Assert.Equal("jetdoe@outlook.com", ExtensionData["EmailAddress"].GetString()); + Assert.False(ExtensionData.ContainsKey("Id")); + } + } + + public class Parameterized_Person_ObjExtData : ITestClass + { + public string FirstName { get; set; } + + public string LastName { get; set; } + + public Guid Id { get; } + + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } + + public Parameterized_Person_ObjExtData(Guid id) => Id = id; + + public static readonly string s_json = @"{ + ""FirstName"":""Jet"", + ""Id"":""270bb22b-4816-4bd9-9acd-8ec5b1a896d3"", + ""EmailAddress"":""jetdoe@outlook.com"", + ""Id"":""0b3aa420-2e98-47f7-8a49-fea233b89416"", + ""LastName"":""Doe"", + ""Id"":""63cf821d-fd47-4782-8345-576d9228a534"" + }"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Initialize() { } + + public void Verify() + { + Assert.Equal("Jet", FirstName); + Assert.Equal("Doe", LastName); + Assert.Equal("63cf821d-fd47-4782-8345-576d9228a534", Id.ToString()); + Assert.Equal("jetdoe@outlook.com", ((JsonElement)ExtensionData["EmailAddress"]).GetString()); + Assert.False(ExtensionData.ContainsKey("Id")); + } + } + + public class Parameterized_Person_Simple : ITestClass + { + public string FirstName { get; set; } + + public string LastName { get; set; } + + public Guid Id { get; } + + public Parameterized_Person_Simple(Guid id) => Id = id; + + public static readonly string s_json = @"{ + ""FirstName"":""Jet"", + ""Id"":""270bb22b-4816-4bd9-9acd-8ec5b1a896d3"", + ""LastName"":""Doe"" + }"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Initialize() + { + FirstName = "Jet"; + LastName = "Doe"; + } + + public void Verify() + { + Assert.Equal("Jet", FirstName); + Assert.Equal("Doe", LastName); + Assert.Equal("270bb22b-4816-4bd9-9acd-8ec5b1a896d3", Id.ToString()); + } + } + + public class SimpleClassWithParameterizedCtor_GenericDictionary_JsonElementExt + { + public int X { get; } + + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } + + [JsonConstructor] + public SimpleClassWithParameterizedCtor_GenericDictionary_JsonElementExt(int x) { } + } + + public class SimpleClassWithParameterizedCtor_GenericDictionary_ObjectExt + { + public int X { get; } + + [JsonExtensionData] + public Dictionary ExtensionData { get; set; } + + [JsonConstructor] + public SimpleClassWithParameterizedCtor_GenericDictionary_ObjectExt(int x) { } + } + + public class SimpleClassWithParameterizedCtor_Derived_GenericIDictionary_JsonElementExt + { + public int X { get; } + + [JsonExtensionData] + public GenericIDictionaryWrapper ExtensionData { get; set; } + + [JsonConstructor] + public SimpleClassWithParameterizedCtor_Derived_GenericIDictionary_JsonElementExt(int x) { } + } + + public class SimpleClassWithParameterizedCtor_Derived_GenericIDictionary_ObjectExt + { + public int X { get; } + + [JsonExtensionData] + public GenericIDictionaryWrapper ExtensionData { get; set; } + + [JsonConstructor] + public SimpleClassWithParameterizedCtor_Derived_GenericIDictionary_ObjectExt(int x) { } + } + + public class Parameterized_IndexViewModel_Immutable : ITestClass + { + public List ActiveOrUpcomingEvents { get; } + public CampaignSummaryViewModel FeaturedCampaign { get; } + public bool IsNewAccount { get; } + public bool HasFeaturedCampaign => FeaturedCampaign != null; + + public Parameterized_IndexViewModel_Immutable( + List activeOrUpcomingEvents, + CampaignSummaryViewModel featuredCampaign, + bool isNewAccount) + { + ActiveOrUpcomingEvents = activeOrUpcomingEvents; + FeaturedCampaign = featuredCampaign; + IsNewAccount = isNewAccount; + } + + public static readonly string s_json = + @"{ + ""ActiveOrUpcomingEvents"": [ + { + ""Id"": 10, + ""ImageUrl"": ""https://www.dotnetfoundation.org/theme/img/carousel/foundation-diagram-content.png"", + ""Name"": ""Just a name"", + ""CampaignName"": ""The very new campaing"", + ""CampaignManagedOrganizerName"": ""Name FamiltyName"", + ""Description"": ""The .NET Foundation works with Microsoft and the broader industry to increase the exposure of open source projects in the .NET community and the .NET Foundation. The .NET Foundation provides access to these resources to projects and looks to promote the activities of our communities."", + ""StartDate"": ""2019-01-30T12:01:02+00:00"", + ""EndDate"": ""2019-01-30T12:01:02+00:00"" + } + ], + ""FeaturedCampaign"": { + ""Id"": 234235, + ""Title"": ""Promoting Open Source"", + ""Description"": ""Very nice campaing"", + ""ImageUrl"": ""https://www.dotnetfoundation.org/theme/img/carousel/foundation-diagram-content.png"", + ""OrganizationName"": ""The Company XYZ"", + ""Headline"": ""The Headline"" + }, + ""IsNewAccount"": false, + ""HasFeaturedCampaign"": true + }"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Initialize() { } + + public void Verify() + { + Assert.False(IsNewAccount); + + ActiveOrUpcomingEvent @event = ActiveOrUpcomingEvents.First(); + Assert.Equal(10, @event.Id); + Assert.Equal("Name FamiltyName", @event.CampaignManagedOrganizerName); + Assert.Equal("The very new campaing", @event.CampaignName); + Assert.Equal("The .NET Foundation works with Microsoft and the broader industry to increase the exposure of open source projects in the .NET community and the .NET Foundation. The .NET Foundation provides access to these resources to projects and looks to promote the activities of our communities.", @event.Description); + Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), @event.EndDate); + Assert.Equal("Just a name", @event.Name); + Assert.Equal("https://www.dotnetfoundation.org/theme/img/carousel/foundation-diagram-content.png", @event.ImageUrl); + Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), @event.StartDate); + + Assert.Equal("Very nice campaing", FeaturedCampaign.Description); + Assert.Equal("The Headline", FeaturedCampaign.Headline); + Assert.Equal(234235, FeaturedCampaign.Id); + Assert.Equal("The Company XYZ", FeaturedCampaign.OrganizationName); + Assert.Equal("https://www.dotnetfoundation.org/theme/img/carousel/foundation-diagram-content.png", FeaturedCampaign.ImageUrl); + Assert.Equal("Promoting Open Source", FeaturedCampaign.Title); + } + } + + public class ActiveOrUpcomingEvent + { + public int Id { get; set; } + public string ImageUrl { get; set; } + public string Name { get; set; } + public string CampaignName { get; set; } + public string CampaignManagedOrganizerName { get; set; } + public string Description { get; set; } + public DateTimeOffset StartDate { get; set; } + public DateTimeOffset EndDate { get; set; } + } + + public class CampaignSummaryViewModel + { + public int Id { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string ImageUrl { get; set; } + public string OrganizationName { get; set; } + public string Headline { get; set; } + } + + public class Parameterized_Class_With_ComplexTuple : ITestClass + { + public Tuple< + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters> MyTuple { get; } + + public Parameterized_Class_With_ComplexTuple( + Tuple< + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters, + ClassWithConstructor_SimpleAndComplexParameters> myTuple) => MyTuple = myTuple; + + private static readonly string s_inner_json = @" + { + ""MyByte"": 7, + ""MyChar"": ""a"", + ""MyString"": ""Hello"", + ""MyDecimal"": 3.3, + ""MyBooleanFalse"": false, + ""MyDouble"": 2.2, + ""MyDateTimeOffset"": ""2019-01-30T12:01:02+01:00"", + ""MyGuid"": ""1b33498a-7b7d-4dda-9c13-f6aa4ab449a6"", + ""MyEnum"": 2, + ""MyInt64Enum"": -9223372036854775808, + ""MyUInt64Enum"": 18446744073709551615, + ""MySimpleStruct"": { ""One"": 11, ""Two"": 1.9999 }, + ""MyInt16ThreeDimensionArray"": [ [ [ 11, 12 ], [ 13, 14 ] ], [ [ 21, 22 ], [ 23, 24 ] ] ], + ""MyInt16ThreeDimensionList"": [ [ [ 11, 12 ], [ 13, 14 ] ], [ [ 21, 22 ], [ 23, 24 ] ] ], + ""MyStringList"": [ ""Hello"" ], + ""MyStringIList"": [ ""Hello"" ], + ""MyStringIEnumerableT"": [ ""Hello"" ], + ""MyStringIReadOnlyListT"": [ ""Hello"" ], + ""MyStringToStringKeyValuePair"": { ""Key"": ""myKey"", ""Value"": ""myValue"" }, + ""MyStringToStringGenericDict"": { ""key"": ""value"" }, + ""MyStringToStringIImmutableDict"": { ""key"": ""value"" }, + ""MyStringImmutableSortedSetT"": [ ""Hello"" ], + ""MyListOfNullString"": [ null ], + ""MySByte"": 8, + ""MyBooleanTrue"": true, + ""MySingle"": 1.1, + ""MyDateTime"": ""2019-01-30T12:01:02Z"", + ""MyUri"": ""https://github.com/dotnet/runtime"", + ""MySimpleTestStruct"": { + ""MyInt16"": 0, + ""MyInt32"": 0, + ""MyInt64"": 64, + ""MyUInt16"": 0, + ""MyUInt32"": 0, + ""MyUInt64"": 0, + ""MyByte"": 0, + ""MySByte"": 0, + ""MyChar"": ""\u0000"", + ""MyString"": ""Hello"", + ""MyDecimal"": 0, + ""MyBooleanTrue"": false, + ""MyBooleanFalse"": false, + ""MySingle"": 0, + ""MyDouble"": 0, + ""MyDateTime"": ""0001-01-01T00:00:00"", + ""MyDateTimeOffset"": ""0001-01-01T00:00:00+00:00"", + ""MyEnum"": 0, + ""MyInt64Enum"": 0, + ""MyUInt64Enum"": 0, + ""MySimpleStruct"": { + ""One"": 0, + ""Two"": 0 + }, + ""MyInt32Array"": [ 32 ] + }, + ""MyStringIEnumerable"": [ ""Hello"" ], + ""MyStringICollection"": [ ""Hello"" ], + ""MyStringISetT"": [ ""Hello"" ], + ""MyStringToStringIDict"": { ""key"": ""value"" }, + ""MyStringToStringGenericIDict"": { ""key"": ""value"" }, + ""MyStringImmutablQueueT"": [ ""Hello"" ] + }"; + + public static readonly string s_json = + $@"{{ + ""MyTuple"": {{ + ""Item1"":{s_inner_json}, + ""Item2"":{s_inner_json}, + ""Item3"":{s_inner_json}, + ""Item4"":{s_inner_json}, + ""Item5"":{s_inner_json}, + ""Item6"":{s_inner_json}, + ""Item7"":{s_inner_json} + }} + }}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Initialize() { } + + public void Verify() + { + MyTuple.Item1.Verify(); + MyTuple.Item2.Verify(); + MyTuple.Item3.Verify(); + MyTuple.Item4.Verify(); + MyTuple.Item5.Verify(); + MyTuple.Item6.Verify(); + MyTuple.Item7.Verify(); + } + } + + public class Point_MembersHave_JsonPropertyName : ITestClass + { + [JsonPropertyName("XValue")] + public int X { get; } + + [JsonPropertyName("YValue")] + public int Y { get; } + + public Point_MembersHave_JsonPropertyName(int x, int y) => (X, Y) = (x, y); + + public void Initialize() { } + + public static readonly string s_json = @"{""XValue"":1,""YValue"":2}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Verify() + { + Assert.Equal(1, X); + Assert.Equal(2, Y); + } + } + + public class Point_MembersHave_JsonConverter : ITestClass + { + [JsonConverter(typeof(ConverterForInt32))] + public int X { get; } + + [JsonConverter(typeof(ConverterForInt32))] + public int Y { get; } + + public Point_MembersHave_JsonConverter(int x, int y) => (X, Y) = (x, y); + + public void Initialize() { } + + public static readonly string s_json = @"{""X"":1,""Y"":2}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Verify() + { + Assert.Equal(25, X); + Assert.Equal(25, Y); + } + } + + public class Point_MembersHave_JsonIgnore : ITestClass + { + [JsonIgnore] + public int X { get; } + + [JsonIgnore] + public int Y { get; } + + public Point_MembersHave_JsonIgnore(int x, int y = 5) => (X, Y) = (x, y); + + public void Initialize() { } + + public static readonly string s_json = @"{""X"":1,""Y"":2}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Verify() + { + Assert.Equal(0, X); + Assert.Equal(0, Y); // We don't set parameter default value here. + } + } + + public class Point_MultipleMembers_BindTo_OneConstructorParameter + { + public int X { get; } + + public int x { get; } + + public Point_MultipleMembers_BindTo_OneConstructorParameter(int X, int x) { } + } + + public class Point_MultipleMembers_BindTo_OneConstructorParameter_Variant + { + public int X { get; } + + public int x { get; } + + public Point_MultipleMembers_BindTo_OneConstructorParameter_Variant(int x) { } + } + + public class Point_Without_Members + { + public Point_Without_Members(int x, int y) { } + } + + public class Point_With_MismatchedMembers + { + public int X { get; } + public float Y { get; } + + public Point_With_MismatchedMembers(int x, int y) { } + } + + public class WrapperFor_Point_With_MismatchedMembers + { + public int MyInt { get; set; } + public Point_With_MismatchedMembers MyPoint { get; set; } + } + + + public class Point_ExtendedPropNames + { + public int XValue { get; } + public int YValue { get; } + + public Point_ExtendedPropNames(int xValue, int yValue) + { + XValue = xValue; + YValue = yValue; + } + } + + public class LowerCaseNamingPolicy : JsonNamingPolicy + { + public override string ConvertName(string name) + { + return name.ToLowerInvariant(); + } + } + + public class SimpleSnakeCasePolicy : JsonNamingPolicy + { + public override string ConvertName(string name) + { + return string.Concat(name.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString())).ToLower(); + } + } + + public class Point_With_Array : ITestClass + { + public int X { get; } + public int Y { get; } + + public int[] Arr { get; } + + public static readonly string s_json = @"{""X"":1,""Y"":2,""Arr"":[1,2]}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public Point_With_Array(int x, int y, int[] arr) + { + X = x; + Y = y; + Arr = arr; + } + + public void Initialize() { } + + public void Verify() + { + Assert.Equal(1, X); + Assert.Equal(2, Y); + Assert.Equal(1, Arr[0]); + Assert.Equal(2, Arr[1]); + } + } + + public class Point_With_Dictionary : ITestClass + { + public int X { get; } + public int Y { get; } + + public Dictionary Dict { get; } + + public static readonly string s_json = @"{""X"":1,""Y"":2,""Dict"":{""1"":1,""2"":2}}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public Point_With_Dictionary(int x, int y, Dictionary dict) + { + X = x; + Y = y; + Dict = dict; + } + + public void Initialize() { } + + public void Verify() + { + Assert.Equal(1, X); + Assert.Equal(2, Y); + Assert.Equal(1, Dict["1"]); + Assert.Equal(2, Dict["2"]); + } + } + + public class Point_With_Object : ITestClass + { + public int X { get; } + public int Y { get; } + + public Point_With_Array Obj { get; } + + public static readonly string s_json = @$"{{""X"":1,""Y"":2,""Obj"":{Point_With_Array.s_json}}}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public Point_With_Object(int x, int y, Point_With_Array obj) + { + X = x; + Y = y; + Obj = obj; + } + + public void Initialize() { } + + public void Verify() + { + Assert.Equal(1, X); + Assert.Equal(2, Y); + Obj.Verify(); + } + } + + public struct Point_With_Property + { + public int X { get; } + public int Y { get; } + public int Z { get; set; } + + [JsonConstructor] + public Point_With_Property(int x, int y) + { + X = x; + Y = y; + Z = 0; + } + } + + public class MyEventsListerViewModel + { + public List CurrentEvents { get; set; } = new List(); + public List FutureEvents { get; set; } = new List(); + public List PastEvents { get; set; } = new List(); + + public static MyEventsListerViewModel Instance + = new MyEventsListerViewModel + { + CurrentEvents = Enumerable.Repeat(MyEventsListerItem.Instance, 3).ToList(), + FutureEvents = Enumerable.Repeat(MyEventsListerItem.Instance, 9).ToList(), + PastEvents = Enumerable.Repeat(MyEventsListerItem.Instance, 60).ToList() // usually there is a lot of historical data + }; + } + + public class MyEventsListerItem + { + public int EventId { get; set; } + public string EventName { get; set; } + public DateTimeOffset StartDate { get; set; } + public DateTimeOffset EndDate { get; set; } + public string TimeZone { get; set; } + public string Campaign { get; set; } + public string Organization { get; set; } + public int VolunteerCount { get; set; } + + public List Tasks { get; set; } = new List(); + + public static MyEventsListerItem Instance + = new MyEventsListerItem + { + Campaign = "A very nice campaing", + EndDate = DateTime.UtcNow.AddDays(7), + EventId = 321, + EventName = "wonderful name", + Organization = "Local Animal Shelter", + StartDate = DateTime.UtcNow.AddDays(-7), + TimeZone = TimeZoneInfo.Utc.DisplayName, + VolunteerCount = 15, + Tasks = Enumerable.Repeat( + new MyEventsListerItemTask + { + StartDate = DateTime.UtcNow, + EndDate = DateTime.UtcNow.AddDays(1), + Name = "A very nice task to have" + }, 4).ToList() + }; + } + + public class MyEventsListerItemTask + { + public string Name { get; set; } + public DateTimeOffset? StartDate { get; set; } + public DateTimeOffset? EndDate { get; set; } + + public string FormattedDate + { + get + { + if (!StartDate.HasValue || !EndDate.HasValue) + { + return null; + } + + var startDateString = string.Format("{0:g}", StartDate.Value); + var endDateString = string.Format("{0:g}", EndDate.Value); + + return string.Format($"From {startDateString} to {endDateString}"); + } + } + } + + public class ClassWithNestedClass + { + public ClassWithNestedClass MyClass { get; } + + public Point_2D_Struct_WithAttribute MyPoint { get; } + + public ClassWithNestedClass(ClassWithNestedClass myClass, Point_2D_Struct_WithAttribute myPoint) + { + MyClass = myClass; + MyPoint = myPoint; + } + } + + public struct StructWithFourArgs + { + public int W { get; } + public int X { get; } + public int Y { get; } + public int Z { get; } + + [JsonConstructor] + public StructWithFourArgs(int w, int x, int y, int z) => (W, X, Y, Z) = (w, x, y, z); + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj index 36926ba492a798..66d388ad5c5c91 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) $(DefineConstants);BUILDING_INBOX_LIBRARY @@ -36,6 +36,11 @@ + + + + + @@ -59,6 +64,7 @@ + @@ -89,6 +95,7 @@ + diff --git a/src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.cs b/src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.cs index 3fee5804f832b7..b4ffb878d26302 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.cs @@ -18,7 +18,7 @@ public ActionBlock(System.Func action, Syst public void Complete() { } public bool Post(TInput item) { throw null; } void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { } - System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock source, bool consumeToAccept) { throw null; } + System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock? source, bool consumeToAccept) { throw null; } public override string ToString() { throw null; } } public sealed partial class BatchBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock, System.Threading.Tasks.Dataflow.ISourceBlock, System.Threading.Tasks.Dataflow.ITargetBlock @@ -31,14 +31,15 @@ public BatchBlock(int batchSize, System.Threading.Tasks.Dataflow.GroupingDataflo public void Complete() { } public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; } void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { } + [return: System.Diagnostics.CodeAnalysis.MaybeNull] T[] System.Threading.Tasks.Dataflow.ISourceBlock.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target, out bool messageConsumed) { throw null; } void System.Threading.Tasks.Dataflow.ISourceBlock.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { throw null; } - System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock source, bool consumeToAccept) { throw null; } + System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock? source, bool consumeToAccept) { throw null; } public override string ToString() { throw null; } public void TriggerBatch() { } - public bool TryReceive(System.Predicate filter, out T[] item) { throw null; } - public bool TryReceiveAll(out System.Collections.Generic.IList items) { throw null; } + public bool TryReceive(System.Predicate? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out T[]? item) { throw null; } + public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList? items) { throw null; } } public sealed partial class BatchedJoinBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock, System.Collections.Generic.IList>>, System.Threading.Tasks.Dataflow.ISourceBlock, System.Collections.Generic.IList>> { @@ -56,8 +57,8 @@ void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception excep void System.Threading.Tasks.Dataflow.ISourceBlock,System.Collections.Generic.IList>>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock, System.Collections.Generic.IList>> target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock,System.Collections.Generic.IList>>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock, System.Collections.Generic.IList>> target) { throw null; } public override string ToString() { throw null; } - public bool TryReceive(System.Predicate, System.Collections.Generic.IList>> filter, out System.Tuple, System.Collections.Generic.IList> item) { throw null; } - public bool TryReceiveAll(out System.Collections.Generic.IList, System.Collections.Generic.IList>> items) { throw null; } + public bool TryReceive(System.Predicate, System.Collections.Generic.IList>>? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Tuple, System.Collections.Generic.IList>? item) { throw null; } + public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList, System.Collections.Generic.IList>>? items) { throw null; } } public sealed partial class BatchedJoinBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock, System.Collections.Generic.IList, System.Collections.Generic.IList>>, System.Threading.Tasks.Dataflow.ISourceBlock, System.Collections.Generic.IList, System.Collections.Generic.IList>> { @@ -76,24 +77,25 @@ void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception excep void System.Threading.Tasks.Dataflow.ISourceBlock,System.Collections.Generic.IList,System.Collections.Generic.IList>>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock, System.Collections.Generic.IList, System.Collections.Generic.IList>> target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock,System.Collections.Generic.IList,System.Collections.Generic.IList>>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock, System.Collections.Generic.IList, System.Collections.Generic.IList>> target) { throw null; } public override string ToString() { throw null; } - public bool TryReceive(System.Predicate, System.Collections.Generic.IList, System.Collections.Generic.IList>> filter, out System.Tuple, System.Collections.Generic.IList, System.Collections.Generic.IList> item) { throw null; } - public bool TryReceiveAll(out System.Collections.Generic.IList, System.Collections.Generic.IList, System.Collections.Generic.IList>> items) { throw null; } + public bool TryReceive(System.Predicate, System.Collections.Generic.IList, System.Collections.Generic.IList>>? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Tuple, System.Collections.Generic.IList, System.Collections.Generic.IList>? item) { throw null; } + public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList, System.Collections.Generic.IList, System.Collections.Generic.IList>>? items) { throw null; } } public sealed partial class BroadcastBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock, System.Threading.Tasks.Dataflow.ISourceBlock, System.Threading.Tasks.Dataflow.ITargetBlock { - public BroadcastBlock(System.Func cloningFunction) { } - public BroadcastBlock(System.Func cloningFunction, System.Threading.Tasks.Dataflow.DataflowBlockOptions dataflowBlockOptions) { } + public BroadcastBlock(System.Func? cloningFunction) { } + public BroadcastBlock(System.Func? cloningFunction, System.Threading.Tasks.Dataflow.DataflowBlockOptions dataflowBlockOptions) { } public System.Threading.Tasks.Task Completion { get { throw null; } } public void Complete() { } public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; } void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { } - bool System.Threading.Tasks.Dataflow.IReceivableSourceBlock.TryReceiveAll(out System.Collections.Generic.IList items) { throw null; } + bool System.Threading.Tasks.Dataflow.IReceivableSourceBlock.TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList? items) { throw null; } + [return: System.Diagnostics.CodeAnalysis.MaybeNull] T System.Threading.Tasks.Dataflow.ISourceBlock.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target, out bool messageConsumed) { throw null; } void System.Threading.Tasks.Dataflow.ISourceBlock.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { throw null; } - System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock source, bool consumeToAccept) { throw null; } + System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock? source, bool consumeToAccept) { throw null; } public override string ToString() { throw null; } - public bool TryReceive(System.Predicate filter, out T item) { throw null; } + public bool TryReceive(System.Predicate? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out T item) { throw null; } } public sealed partial class BufferBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock, System.Threading.Tasks.Dataflow.ISourceBlock, System.Threading.Tasks.Dataflow.ITargetBlock { @@ -104,13 +106,14 @@ public BufferBlock(System.Threading.Tasks.Dataflow.DataflowBlockOptions dataflow public void Complete() { } public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; } void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { } + [return: System.Diagnostics.CodeAnalysis.MaybeNull] T System.Threading.Tasks.Dataflow.ISourceBlock.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target, out bool messageConsumed) { throw null; } void System.Threading.Tasks.Dataflow.ISourceBlock.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { throw null; } - System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock source, bool consumeToAccept) { throw null; } + System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock? source, bool consumeToAccept) { throw null; } public override string ToString() { throw null; } - public bool TryReceive(System.Predicate filter, out T item) { throw null; } - public bool TryReceiveAll(out System.Collections.Generic.IList items) { throw null; } + public bool TryReceive(System.Predicate? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out T item) { throw null; } + public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList? items) { throw null; } } public static partial class DataflowBlock { @@ -138,7 +141,7 @@ public static partial class DataflowBlock public static TOutput Receive(this System.Threading.Tasks.Dataflow.ISourceBlock source, System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) { throw null; } public static System.Threading.Tasks.Task SendAsync(this System.Threading.Tasks.Dataflow.ITargetBlock target, TInput item) { throw null; } public static System.Threading.Tasks.Task SendAsync(this System.Threading.Tasks.Dataflow.ITargetBlock target, TInput item, System.Threading.CancellationToken cancellationToken) { throw null; } - public static bool TryReceive(this System.Threading.Tasks.Dataflow.IReceivableSourceBlock source, out TOutput item) { throw null; } + public static bool TryReceive(this System.Threading.Tasks.Dataflow.IReceivableSourceBlock source, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out TOutput item) { throw null; } } public partial class DataflowBlockOptions { @@ -164,7 +167,7 @@ public DataflowLinkOptions() { } public DataflowMessageHeader(long id) { throw null; } public long Id { get { throw null; } } public bool IsValid { get { throw null; } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public bool Equals(System.Threading.Tasks.Dataflow.DataflowMessageHeader other) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(System.Threading.Tasks.Dataflow.DataflowMessageHeader left, System.Threading.Tasks.Dataflow.DataflowMessageHeader right) { throw null; } @@ -201,11 +204,12 @@ public partial interface IPropagatorBlock : System.Threa } public partial interface IReceivableSourceBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.ISourceBlock { - bool TryReceive(System.Predicate filter, out TOutput item); - bool TryReceiveAll(out System.Collections.Generic.IList items); + bool TryReceive(System.Predicate? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out TOutput item); + bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList? items); } public partial interface ISourceBlock : System.Threading.Tasks.Dataflow.IDataflowBlock { + [return: System.Diagnostics.CodeAnalysis.MaybeNull] TOutput ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target, out bool messageConsumed); System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions); void ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target); @@ -213,7 +217,7 @@ public partial interface ISourceBlock : System.Threading.Tasks.Data } public partial interface ITargetBlock : System.Threading.Tasks.Dataflow.IDataflowBlock { - System.Threading.Tasks.Dataflow.DataflowMessageStatus OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock source, bool consumeToAccept); + System.Threading.Tasks.Dataflow.DataflowMessageStatus OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock? source, bool consumeToAccept); } public sealed partial class JoinBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock>, System.Threading.Tasks.Dataflow.ISourceBlock> { @@ -226,12 +230,12 @@ public JoinBlock(System.Threading.Tasks.Dataflow.GroupingDataflowBlockOptions da public void Complete() { } public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; } void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { } - System.Tuple System.Threading.Tasks.Dataflow.ISourceBlock>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock> target, out bool messageConsumed) { throw null; } + System.Tuple? System.Threading.Tasks.Dataflow.ISourceBlock>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock> target, out bool messageConsumed) { throw null; } void System.Threading.Tasks.Dataflow.ISourceBlock>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock> target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock> target) { throw null; } public override string ToString() { throw null; } - public bool TryReceive(System.Predicate> filter, out System.Tuple item) { throw null; } - public bool TryReceiveAll(out System.Collections.Generic.IList> items) { throw null; } + public bool TryReceive(System.Predicate>? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Tuple? item) { throw null; } + public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList>? items) { throw null; } } public sealed partial class JoinBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock>, System.Threading.Tasks.Dataflow.ISourceBlock> { @@ -245,12 +249,12 @@ public JoinBlock(System.Threading.Tasks.Dataflow.GroupingDataflowBlockOptions da public void Complete() { } public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; } void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { } - System.Tuple System.Threading.Tasks.Dataflow.ISourceBlock>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock> target, out bool messageConsumed) { throw null; } + System.Tuple? System.Threading.Tasks.Dataflow.ISourceBlock>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock> target, out bool messageConsumed) { throw null; } void System.Threading.Tasks.Dataflow.ISourceBlock>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock> target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock> target) { throw null; } public override string ToString() { throw null; } - public bool TryReceive(System.Predicate> filter, out System.Tuple item) { throw null; } - public bool TryReceiveAll(out System.Collections.Generic.IList> items) { throw null; } + public bool TryReceive(System.Predicate>? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Tuple? item) { throw null; } + public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList>? items) { throw null; } } public sealed partial class TransformBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock, System.Threading.Tasks.Dataflow.ISourceBlock, System.Threading.Tasks.Dataflow.ITargetBlock { @@ -264,13 +268,14 @@ public TransformBlock(System.Func transform, System.Threading.T public void Complete() { } public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; } void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { } + [return: System.Diagnostics.CodeAnalysis.MaybeNull] TOutput System.Threading.Tasks.Dataflow.ISourceBlock.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target, out bool messageConsumed) { throw null; } void System.Threading.Tasks.Dataflow.ISourceBlock.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { throw null; } - System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock source, bool consumeToAccept) { throw null; } + System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock? source, bool consumeToAccept) { throw null; } public override string ToString() { throw null; } - public bool TryReceive(System.Predicate filter, out TOutput item) { throw null; } - public bool TryReceiveAll(out System.Collections.Generic.IList items) { throw null; } + public bool TryReceive(System.Predicate? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out TOutput item) { throw null; } + public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList? items) { throw null; } } public sealed partial class TransformManyBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock, System.Threading.Tasks.Dataflow.ISourceBlock, System.Threading.Tasks.Dataflow.ITargetBlock { @@ -284,28 +289,30 @@ public TransformManyBlock(System.Func target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; } void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { } + [return: System.Diagnostics.CodeAnalysis.MaybeNull] TOutput System.Threading.Tasks.Dataflow.ISourceBlock.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target, out bool messageConsumed) { throw null; } void System.Threading.Tasks.Dataflow.ISourceBlock.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { throw null; } - System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock source, bool consumeToAccept) { throw null; } + System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock? source, bool consumeToAccept) { throw null; } public override string ToString() { throw null; } - public bool TryReceive(System.Predicate filter, out TOutput item) { throw null; } - public bool TryReceiveAll(out System.Collections.Generic.IList items) { throw null; } + public bool TryReceive(System.Predicate? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out TOutput item) { throw null; } + public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList? items) { throw null; } } public sealed partial class WriteOnceBlock : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock, System.Threading.Tasks.Dataflow.ISourceBlock, System.Threading.Tasks.Dataflow.ITargetBlock { - public WriteOnceBlock(System.Func cloningFunction) { } - public WriteOnceBlock(System.Func cloningFunction, System.Threading.Tasks.Dataflow.DataflowBlockOptions dataflowBlockOptions) { } + public WriteOnceBlock(System.Func? cloningFunction) { } + public WriteOnceBlock(System.Func? cloningFunction, System.Threading.Tasks.Dataflow.DataflowBlockOptions dataflowBlockOptions) { } public System.Threading.Tasks.Task Completion { get { throw null; } } public void Complete() { } public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; } void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { } - bool System.Threading.Tasks.Dataflow.IReceivableSourceBlock.TryReceiveAll(out System.Collections.Generic.IList items) { throw null; } + bool System.Threading.Tasks.Dataflow.IReceivableSourceBlock.TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList? items) { throw null; } + [return: System.Diagnostics.CodeAnalysis.MaybeNull] T System.Threading.Tasks.Dataflow.ISourceBlock.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target, out bool messageConsumed) { throw null; } void System.Threading.Tasks.Dataflow.ISourceBlock.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { } bool System.Threading.Tasks.Dataflow.ISourceBlock.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock target) { throw null; } - System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock source, bool consumeToAccept) { throw null; } + System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock? source, bool consumeToAccept) { throw null; } public override string ToString() { throw null; } - public bool TryReceive(System.Predicate filter, out T item) { throw null; } + public bool TryReceive(System.Predicate? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out T item) { throw null; } } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.csproj b/src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.csproj index 9a09a9416b4e77..915b6a275eae36 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.csproj +++ b/src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.csproj @@ -1,6 +1,7 @@ netstandard2.0;netstandard1.0;netstandard1.1 + enable diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs index 73dd608d85cf70..1753d40bd71da4 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs @@ -133,7 +133,9 @@ private bool RunPredicate(T item) } /// +#pragma warning disable 8617 DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) +#pragma warning restore 8617 { // Validate arguments. Some targets may have a null source, but FilteredLinkPropagator // is an internal target that should only ever have source non-null. @@ -153,6 +155,7 @@ DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader message } /// + [return: MaybeNull] T ISourceBlock.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { // This message should have only made it to the target if it passes the filter, so we shouldn't need to check again. @@ -442,7 +445,7 @@ private void CompleteAsAccepted(bool runAsync) { RunCompletionAction(state => { - try { ((SendAsyncSource)state).TrySetResult(true); } + try { ((SendAsyncSource)state!).TrySetResult(true); } catch (ObjectDisposedException) { } }, this, runAsync); } @@ -455,7 +458,7 @@ private void CompleteAsDeclined(bool runAsync) { // The try/catch for ObjectDisposedException handles the case where the // user disposes of the returned task before we're done with it. - try { ((SendAsyncSource)state).TrySetResult(false); } + try { ((SendAsyncSource)state!).TrySetResult(false); } catch (ObjectDisposedException) { } }, this, runAsync); } @@ -467,7 +470,7 @@ private void CompleteAsFaulted(Exception exception, bool runAsync) { RunCompletionAction(state => { - var tuple = (Tuple, Exception>)state; + var tuple = (Tuple, Exception>)state!; try { tuple.Item1.TrySetException(tuple.Item2); } catch (ObjectDisposedException) { } }, Tuple.Create, Exception>(this, exception), runAsync); @@ -479,7 +482,7 @@ private void CompleteAsCanceled(bool runAsync) { RunCompletionAction(state => { - try { ((SendAsyncSource)state).TrySetCanceled(); } + try { ((SendAsyncSource)state!).TrySetCanceled(); } catch (ObjectDisposedException) { } }, this, runAsync); } @@ -493,7 +496,7 @@ private void CompleteAsCanceled(bool runAsync) /// the target is calling to ConsumeMessage. We don't want to block the target indefinitely /// with any synchronous continuations off of the returned send async task. /// - private void RunCompletionAction(Action completionAction, object completionActionState, bool runAsync) + private void RunCompletionAction(Action completionAction, object completionActionState, bool runAsync) { Debug.Assert(completionAction != null, "Completion action to run is required."); @@ -527,21 +530,21 @@ private void RunCompletionAction(Action completionAction, object complet private void OfferToTargetAsync() { System.Threading.Tasks.Task.Factory.StartNew( - state => ((SendAsyncSource)state).OfferToTarget(), this, + state => ((SendAsyncSource)state!).OfferToTarget(), this, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); } /// Cached delegate used to cancel a send in response to a cancellation request. - private static readonly Action _cancellationCallback = CancellationHandler; + private static readonly Action _cancellationCallback = CancellationHandler; /// Attempts to cancel the source passed as state in response to a cancellation request. /// /// A weak reference to the SendAsyncSource. A weak reference is used to prevent the source /// from being rooted in a long-lived token. /// - private static void CancellationHandler(object state) + private static void CancellationHandler(object? state) { - SendAsyncSource source = Common.UnwrapWeakReference>(state); + SendAsyncSource? source = Common.UnwrapWeakReference>(state!); if (source != null) { Debug.Assert(source._cancellationState != CANCELLATION_STATE_NONE, @@ -619,6 +622,7 @@ internal void OfferToTarget() } /// Called by the target to consume the buffered message. + [return: MaybeNull] TOutput ISourceBlock.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { // Validate arguments @@ -770,7 +774,7 @@ public DebugView(SendAsyncSource source) /// This method does not wait until the source has an item to provide. /// It will return whether or not an element was available. /// - public static bool TryReceive(this IReceivableSourceBlock source, out TOutput item) + public static bool TryReceive(this IReceivableSourceBlock source, [MaybeNullWhen(false)] out TOutput item) { if (source == null) throw new ArgumentNullException(nameof(source)); @@ -1034,7 +1038,7 @@ private enum ReceiveCoreByLinkingCleanupReason } /// Cancels a CancellationTokenSource passed as the object state argument. - private static readonly Action _cancelCts = state => ((CancellationTokenSource)state).Cancel(); + private static readonly Action _cancelCts = state => ((CancellationTokenSource)state!).Cancel(); /// Receives an item from the source by linking a temporary target from it. /// Specifies the type of data contained in the source. @@ -1113,20 +1117,21 @@ private sealed class ReceiveTarget : TaskCompletionSource, ITargetBlock /// The C# compiler will not cache this delegate by default due to it being a generic method on a non-generic class. internal static readonly TimerCallback CachedLinkingTimerCallback = state => { - var receiveTarget = (ReceiveTarget)state; + var receiveTarget = (ReceiveTarget)state!; receiveTarget.TryCleanupAndComplete(ReceiveCoreByLinkingCleanupReason.Timer); }; /// Cached delegate used in ReceiveCoreByLinking on the cancellation token. Passed the ReceiveTarget as the state argument. /// The C# compiler will not cache this delegate by default due to it being a generic method on a non-generic class. - internal static readonly Action CachedLinkingCancellationCallback = state => + internal static readonly Action CachedLinkingCancellationCallback = state => { - var receiveTarget = (ReceiveTarget)state; + var receiveTarget = (ReceiveTarget)state!; receiveTarget.TryCleanupAndComplete(ReceiveCoreByLinkingCleanupReason.Cancellation); }; /// The received value if we accepted a value from the source. - private T _receivedValue; + [AllowNull, MaybeNull] + private T _receivedValue = default!; /// The cancellation token source representing both external and internal cancellation. internal readonly CancellationTokenSource _cts = new CancellationTokenSource(); @@ -1137,11 +1142,11 @@ private sealed class ReceiveTarget : TaskCompletionSource, ITargetBlock /// The registration on the external token that cancels the internal token. internal CancellationTokenRegistration _regFromExternalCancellationToken; /// The timer that fires when the timeout has been exceeded. - internal Timer _timer; + internal Timer? _timer; /// The unlinker from removing this target from the source from which we're receiving. - internal IDisposable _unlink; + internal IDisposable? _unlink; /// The received exception if an error occurred. - internal Exception _receivedException; + internal Exception? _receivedException; /// Gets the sync obj used to synchronize all activity on this target. internal object IncomingLock { get { return _cts; } } @@ -1150,7 +1155,7 @@ private sealed class ReceiveTarget : TaskCompletionSource, ITargetBlock internal ReceiveTarget() { } /// Offers a message to be used to complete the TaskCompletionSource. - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { // Validate arguments if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); @@ -1172,7 +1177,7 @@ DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader message { // Accept the message if possible and complete this task with the message's value. bool consumed = true; - T acceptedValue = consumeToAccept ? source.ConsumeMessage(messageHeader, this, out consumed) : messageValue; + T acceptedValue = consumeToAccept ? source!.ConsumeMessage(messageHeader, this, out consumed) : messageValue; if (consumed) { status = DataflowMessageStatus.Accepted; @@ -1238,10 +1243,10 @@ private void CleanupAndComplete(ReceiveCoreByLinkingCleanupReason reason) // completed, this is unnecessary, as the source should have already // emptied out its target registry, or at least be in the process of doing so. // We are racing with the linking code - only one can dispose of the unlinker. - IDisposable unlink = _unlink; + IDisposable? unlink = _unlink; if (reason != ReceiveCoreByLinkingCleanupReason.SourceCompletion && unlink != null) { - IDisposable disposableUnlink = Interlocked.CompareExchange(ref _unlink, null, unlink); + IDisposable? disposableUnlink = Interlocked.CompareExchange(ref _unlink, null, unlink); if (disposableUnlink != null) { // If an error occurs, fault the target and override the reason to @@ -1297,8 +1302,8 @@ private void CleanupAndComplete(ReceiveCoreByLinkingCleanupReason reason) System.Threading.Tasks.Task.Factory.StartNew(state => { // Complete with the received value - var target = (ReceiveTarget)state; - try { target.TrySetResult(target._receivedValue); } + var target = (ReceiveTarget)state!; + try { target.TrySetResult(target._receivedValue!); } catch (ObjectDisposedException) { /* benign race if returned task is already disposed */ } }, this, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); break; @@ -1308,7 +1313,7 @@ private void CleanupAndComplete(ReceiveCoreByLinkingCleanupReason reason) System.Threading.Tasks.Task.Factory.StartNew(state => { // Complete as canceled - var target = (ReceiveTarget)state; + var target = (ReceiveTarget)state!; try { target.TrySetCanceled(); } catch (ObjectDisposedException) { /* benign race if returned task is already disposed */ } }, this, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); @@ -1329,7 +1334,7 @@ private void CleanupAndComplete(ReceiveCoreByLinkingCleanupReason reason) System.Threading.Tasks.Task.Factory.StartNew(state => { // Complete with the received exception - var target = (ReceiveTarget)state; + var target = (ReceiveTarget)state!; try { target.TrySetException(target._receivedException ?? new InvalidOperationException(SR.InvalidOperation_ErrorDuringCleanup)); } catch (ObjectDisposedException) { /* benign race if returned task is already disposed */ } }, this, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); @@ -1482,7 +1487,7 @@ private sealed class OutputAvailableAsyncTarget : TaskCompletionSource, /// Cached continuation delegate that unregisters from cancellation and /// marshals the antecedent's result to the return value. /// - internal static readonly Func, object, bool> s_handleCompletion = (antecedent, state) => + internal static readonly Func, object?, bool> s_handleCompletion = (antecedent, state) => { var target = state as OutputAvailableAsyncTarget; Debug.Assert(target != null, "Expected non-null target"); @@ -1494,11 +1499,11 @@ private sealed class OutputAvailableAsyncTarget : TaskCompletionSource, /// Cached delegate that cancels the target and unlinks the target from the source. /// Expects an OutputAvailableAsyncTarget as the state argument. /// - internal static readonly Action s_cancelAndUnlink = CancelAndUnlink; + internal static readonly Action s_cancelAndUnlink = CancelAndUnlink; /// Cancels the target and unlinks the target from the source. /// An OutputAvailableAsyncTarget. - private static void CancelAndUnlink(object state) + private static void CancelAndUnlink(object? state) { var target = state as OutputAvailableAsyncTarget; Debug.Assert(target != null, "Expected a non-null target"); @@ -1508,7 +1513,7 @@ private static void CancelAndUnlink(object state) // Take advantage of this task and unlink from there to avoid doing the interlocked operation synchronously. System.Threading.Tasks.Task.Factory.StartNew(tgt => { - var thisTarget = (OutputAvailableAsyncTarget)tgt; + var thisTarget = (OutputAvailableAsyncTarget)tgt!; thisTarget.TrySetCanceled(); thisTarget.AttemptThreadSafeUnlink(); }, @@ -1519,7 +1524,7 @@ private static void CancelAndUnlink(object state) internal void AttemptThreadSafeUnlink() { // A race is possible. Therefore use an interlocked operation. - IDisposable cachedUnlinker = _unlinker; + IDisposable? cachedUnlinker = _unlinker; if (cachedUnlinker != null && Interlocked.CompareExchange(ref _unlinker, null, cachedUnlinker) == cachedUnlinker) { cachedUnlinker.Dispose(); @@ -1527,12 +1532,12 @@ internal void AttemptThreadSafeUnlink() } /// The IDisposable used to unlink this target from its source. - internal IDisposable _unlinker; + internal IDisposable? _unlinker; /// The registration used to unregister this target from the cancellation token. internal CancellationTokenRegistration _ctr; /// Completes the task when offered a message (but doesn't consume the message). - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); if (source == null) throw new ArgumentNullException(nameof(source)); @@ -1625,7 +1630,7 @@ void IDataflowBlock.Fault(Exception exception) _target.Fault(exception); } /// - public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock source, bool consumeToAccept) + public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock? source, bool consumeToAccept) { return _target.OfferMessage(messageHeader, messageValue, source, consumeToAccept); } @@ -1640,7 +1645,7 @@ public IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions link } /// - public bool TryReceive(Predicate filter, out TOutput item) + public bool TryReceive(Predicate? filter, [MaybeNullWhen(false)] out TOutput item) { var receivableSource = _source as IReceivableSourceBlock; if (receivableSource != null) return receivableSource.TryReceive(filter, out item); @@ -1650,7 +1655,7 @@ public bool TryReceive(Predicate filter, out TOutput item) } /// - public bool TryReceiveAll(out IList items) + public bool TryReceiveAll([NotNullWhen(true)] out IList? items) { var receivableSource = _source as IReceivableSourceBlock; if (receivableSource != null) return receivableSource.TryReceiveAll(out items); @@ -1660,6 +1665,7 @@ public bool TryReceiveAll(out IList items) } /// + [return: MaybeNull] public TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { return _source.ConsumeMessage(messageHeader, target, out messageConsumed); @@ -1905,7 +1911,7 @@ public static Task Choose( private static Task ChooseCore( ISourceBlock source1, Action action1, ISourceBlock source2, Action action2, - ISourceBlock source3, Action action3, + ISourceBlock? source3, Action? action3, DataflowBlockOptions dataflowBlockOptions) { Debug.Assert(source1 != null && action1 != null, "The first source and action should not be null."); @@ -1919,13 +1925,13 @@ private static Task ChooseCore( return Common.CreateTaskFromCancellation(dataflowBlockOptions.CancellationToken); // Fast path: if any of the sources already has data available that can be received immediately. - Task resultTask; + Task? resultTask; try { TaskScheduler scheduler = dataflowBlockOptions.TaskScheduler; if (TryChooseFromSource(source1, action1, 0, scheduler, out resultTask) || TryChooseFromSource(source2, action2, 1, scheduler, out resultTask) || - (hasThirdSource && TryChooseFromSource(source3, action3, 2, scheduler, out resultTask))) + (hasThirdSource && TryChooseFromSource(source3!, action3!, 2, scheduler, out resultTask))) { return resultTask; } @@ -1952,7 +1958,7 @@ private static Task ChooseCore( /// true if this try attempt satisfies the choose operation; otherwise, false. private static bool TryChooseFromSource( ISourceBlock source, Action action, int branchId, TaskScheduler scheduler, - out Task task) + [NotNullWhen(true)] out Task? task) { // Validate arguments Debug.Assert(source != null, "Expected a non-null source"); @@ -1990,7 +1996,7 @@ private static bool TryChooseFromSource( private static Task ChooseCoreByLinking( ISourceBlock source1, Action action1, ISourceBlock source2, Action action2, - ISourceBlock source3, Action action3, + ISourceBlock? source3, Action? action3, DataflowBlockOptions dataflowBlockOptions) { Debug.Assert(source1 != null && action1 != null, "The first source and action should not be null."); @@ -2015,7 +2021,7 @@ private static Task ChooseCoreByLinking( branchTasks[1] = CreateChooseBranch(boxedCompleted, cts, scheduler, 1, source2, action2); if (hasThirdSource) { - branchTasks[2] = CreateChooseBranch(boxedCompleted, cts, scheduler, 2, source3, action3); + branchTasks[2] = CreateChooseBranch(boxedCompleted, cts, scheduler, 2, source3!, action3!); } // Asynchronously wait for all branches to complete, then complete @@ -2029,14 +2035,14 @@ private static Task ChooseCoreByLinking( // of whether a branch completed successfully. Others may have been // canceled (or run but found they were not needed), and those // we just ignore. - List exceptions = null; + List? exceptions = null; int successfulBranchId = -1; foreach (Task task in tasks) { switch (task.Status) { case TaskStatus.Faulted: - Common.AddException(ref exceptions, task.Exception, unwrapInnerExceptions: true); + Common.AddException(ref exceptions, task.Exception!, unwrapInnerExceptions: true); break; case TaskStatus.RanToCompletion: int resultBranchId = task.Result; @@ -2150,9 +2156,9 @@ private sealed class ChooseTarget : TaskCompletionSource, ITargetBlock, /// Delegate used to invoke the action for a branch when that branch is activated /// on the fast path. /// - internal static readonly Func s_processBranchFunction = state => + internal static readonly Func s_processBranchFunction = state => { - Tuple, T, int> actionResultBranch = (Tuple, T, int>)state; + Tuple, T, int> actionResultBranch = (Tuple, T, int>)state!; actionResultBranch.Item1(actionResultBranch.Item2); return actionResultBranch.Item3; }; @@ -2176,13 +2182,13 @@ internal ChooseTarget(StrongBox completed, CancellationToken cancellationT Common.WireCancellationToComplete(cancellationToken, base.Task, state => { - var thisChooseTarget = (ChooseTarget)state; + var thisChooseTarget = (ChooseTarget)state!; lock (thisChooseTarget._completed) thisChooseTarget.TrySetCanceled(); }, this); } /// Called when this choice branch is being offered a message. - public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { // Validate arguments if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); @@ -2197,12 +2203,12 @@ public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T if (consumeToAccept) { bool consumed; - messageValue = source.ConsumeMessage(messageHeader, this, out consumed); + messageValue = source!.ConsumeMessage(messageHeader, this, out consumed); if (!consumed) return DataflowMessageStatus.NotAvailable; } // Store the result and signal our success - TrySetResult(messageValue); + TrySetResult(messageValue!); _completed.Value = Task; return DataflowMessageStatus.Accepted; } @@ -2295,9 +2301,9 @@ internal SourceObservable(ISourceBlock source) /// Gets any exceptions from the source block. /// The aggregate exception of all errors, or null if everything completed successfully. - private AggregateException GetCompletionError() + private AggregateException? GetCompletionError() { - Task sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(_source); + Task? sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(_source); return sourceCompletionTask != null && sourceCompletionTask.IsFaulted ? sourceCompletionTask.Exception : null; } @@ -2311,10 +2317,10 @@ IDisposable IObservable.Subscribe(IObserver observer) if (observer == null) throw new ArgumentNullException(nameof(observer)); Common.ContractAssertMonitorStatus(_SubscriptionLock, held: false); - Task sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(_source); + Task? sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(_source); // Synchronize all observers for this source. - Exception error = null; + Exception? error = null; lock (_SubscriptionLock) { // Fast path for if everything is already done. We need to ensure that both @@ -2338,7 +2344,7 @@ IDisposable IObservable.Subscribe(IObserver observer) if (_observersState.Unlinker == null) { _observersState.Observers = ImmutableArray>.Empty; - return null; + return Disposables.Nop; } } @@ -2452,12 +2458,12 @@ private sealed class ObserversState /// internal ImmutableArray> Observers = ImmutableArray>.Empty; /// Used to unlink the source from this target when the last observer is unsubscribed. - internal IDisposable Unlinker; + internal IDisposable? Unlinker; /// /// Temporary list to keep track of SendAsync tasks to TargetObservers with back pressure. /// This field gets instantiated on demand. It gets populated and cleared within an offering cycle. /// - private List> _tempSendAsyncTaskList; + private List>? _tempSendAsyncTaskList; /// Initializes the target instance. /// The owning observable. @@ -2472,22 +2478,22 @@ internal ObserversState(SourceObservable observable) // If the target block fails due to an unexpected exception (e.g. it calls back to the source and the source throws an error), // we fault currently registered observers and reset the observable. Target.Completion.ContinueWith( - (t, state) => ((ObserversState)state).NotifyObserversOfCompletion(t.Exception), this, + (t, state) => ((ObserversState)state!).NotifyObserversOfCompletion(t.Exception!), this, CancellationToken.None, Common.GetContinuationOptions(TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously), TaskScheduler.Default); // When the source completes, complete the target. Then when the target completes, // send completion messages to any observers still registered. - Task sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(Observable._source); + Task? sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(Observable._source); if (sourceCompletionTask != null) { sourceCompletionTask.ContinueWith((_1, state1) => { - var ti = (ObserversState)state1; + var ti = (ObserversState)state1!; ti.Target.Complete(); ti.Target.Completion.ContinueWith( - (_2, state2) => ((ObserversState)state2).NotifyObserversOfCompletion(), state1, + (_2, state2) => ((ObserversState)state2!).NotifyObserversOfCompletion(), state1, CancellationToken.None, Common.GetContinuationOptions(TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.ExecuteSynchronously), TaskScheduler.Default); @@ -2558,7 +2564,7 @@ private Task ProcessItemAsync(TOutput item) /// Non-null when an unexpected exception occurs during processing. Faults /// all subscribed observers and resets the observable back to its original condition. /// - private void NotifyObserversOfCompletion(Exception targetException = null) + private void NotifyObserversOfCompletion(Exception? targetException = null) { Debug.Assert(Target.Completion.IsCompleted, "The target must have already completed in order to notify of completion."); Common.ContractAssertMonitorStatus(Observable._SubscriptionLock, held: false); @@ -2579,7 +2585,7 @@ private void NotifyObserversOfCompletion(Exception targetException = null) if (currentObservers.Count > 0) { // Determine if we should fault or complete the observers - Exception error = targetException ?? Observable.GetCompletionError(); + Exception? error = targetException ?? Observable.GetCompletionError(); try { // Do it. @@ -2696,10 +2702,10 @@ public static ITargetBlock NullTarget() /// The type of the messages this block can accept. private class NullTargetBlock : ITargetBlock { - private Task _completion; + private Task? _completion; /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock? source, bool consumeToAccept) { if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowMessageHeader.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowMessageHeader.cs index fcf8b45ede9141..25cd92fd12be17 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowMessageHeader.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowMessageHeader.cs @@ -57,7 +57,7 @@ public bool Equals(DataflowMessageHeader other) /// Checks boxed instances for equality by ID. /// A boxed instance. /// True if the instances are equal. False otherwise. - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is DataflowMessageHeader && this == (DataflowMessageHeader)obj; } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/IReceivableSourceBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/IReceivableSourceBlock.cs index 3bb2f54c3b79da..9dc8439c215def 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/IReceivableSourceBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/IReceivableSourceBlock.cs @@ -12,6 +12,7 @@ // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace System.Threading.Tasks.Dataflow { @@ -22,11 +23,11 @@ public interface IReceivableSourceBlock : ISourceBlock // IMPLEMENT IMPLICITLY /// - bool TryReceive(Predicate filter, out TOutput item); + bool TryReceive(Predicate? filter, [MaybeNullWhen(false)] out TOutput item); // IMPLEMENT IMPLICITLY IF BLOCK SUPPORTS RECEIVING MORE THAN ONE ITEM, OTHERWISE EXPLICITLY /// - bool TryReceiveAll(out IList items); + bool TryReceiveAll([NotNullWhen(true)] out IList? items); } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/ISourceBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/ISourceBlock.cs index 8b5406674d11ae..8b2f9bc8aff1e0 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/ISourceBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/ISourceBlock.cs @@ -28,6 +28,7 @@ public interface ISourceBlock : IDataflowBlock // IMPLEMENT EXPLICITLY /// + [return: MaybeNull] TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed); /// diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/ITargetBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/ITargetBlock.cs index 1728d5873f5598..67eed5c0aaaa9c 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/ITargetBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/ITargetBlock.cs @@ -20,6 +20,6 @@ public interface ITargetBlock : IDataflowBlock // IMPLEMENT EXPLICITLY /// - DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock source, bool consumeToAccept); + DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock? source, bool consumeToAccept); } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/ActionBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/ActionBlock.cs index f6875321a68dd0..e81e34ca57bc1c 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/ActionBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/ActionBlock.cs @@ -26,9 +26,9 @@ namespace System.Threading.Tasks.Dataflow public sealed class ActionBlock : ITargetBlock, IDebuggerDisplay { /// The core implementation of this message block when in default mode. - private readonly TargetCore _defaultTarget; + private readonly TargetCore? _defaultTarget; /// The core implementation of this message block when in SPSC mode. - private readonly SpscTargetCore _spscTarget; + private readonly SpscTargetCore? _spscTarget; /// Initializes the with the specified . /// The action to invoke with each data element received. @@ -113,7 +113,7 @@ private ActionBlock(Delegate action, ExecutionDataflowBlockOptions dataflowBlock // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore)state).Complete(exception: null, dropPendingMessages: true), _defaultTarget); + dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore)state!).Complete(exception: null, dropPendingMessages: true), _defaultTarget); } #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; @@ -131,6 +131,7 @@ private ActionBlock(Delegate action, ExecutionDataflowBlockOptions dataflowBlock /// The message to be processed. private void ProcessMessage(Action action, KeyValuePair messageWithId) { + Debug.Assert(_defaultTarget != null); try { action(messageWithId.Key); @@ -154,10 +155,11 @@ private void ProcessMessage(Action action, KeyValuePair me private void ProcessMessageWithTask(Func action, KeyValuePair messageWithId) { Debug.Assert(action != null, "action needed for processing"); + Debug.Assert(_defaultTarget != null); // Run the action to get the task that represents the operation's completion - Task task = null; - Exception caughtException = null; + Task? task = null; + Exception? caughtException = null; try { task = action(messageWithId.Key); @@ -188,7 +190,7 @@ private void ProcessMessageWithTask(Func action, KeyValuePair { - ((ActionBlock)state).AsyncCompleteProcessMessageWithTask(completed); + ((ActionBlock)state!).AsyncCompleteProcessMessageWithTask(completed); }, this, CancellationToken.None, Common.GetContinuationOptions(TaskContinuationOptions.ExecuteSynchronously), TaskScheduler.Default); } } @@ -199,6 +201,7 @@ private void AsyncCompleteProcessMessageWithTask(Task completed) { Debug.Assert(completed != null, "Need completed task for processing"); Debug.Assert(completed.IsCompleted, "The task to be processed must be completed by now."); + Debug.Assert(_defaultTarget != null); // If the task faulted, store its errors. We must add the exception before declining // and signaling completion, as the exception is part of the operation, and the completion conditions @@ -224,6 +227,7 @@ public void Complete() } else { + Debug.Assert(_spscTarget != null); _spscTarget.Complete(exception: null); } } @@ -239,6 +243,7 @@ void IDataflowBlock.Fault(Exception exception) } else { + Debug.Assert(_spscTarget != null); _spscTarget.Complete(exception); } } @@ -246,7 +251,7 @@ void IDataflowBlock.Fault(Exception exception) /// public Task Completion { - get { return _defaultTarget != null ? _defaultTarget.Completion : _spscTarget.Completion; } + get { return _defaultTarget != null ? _defaultTarget.Completion : _spscTarget!.Completion; } } /// Posts an item to the . @@ -273,33 +278,33 @@ public bool Post(TInput item) return _defaultTarget != null ? _defaultTarget.OfferMessage(Common.SingleMessageHeader, item, null, false) == DataflowMessageStatus.Accepted : - _spscTarget.Post(item); + _spscTarget!.Post(item); } /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock? source, bool consumeToAccept) { return _defaultTarget != null ? _defaultTarget.OfferMessage(messageHeader, messageValue, source, consumeToAccept) : - _spscTarget.OfferMessage(messageHeader, messageValue, source, consumeToAccept); + _spscTarget!.OfferMessage(messageHeader, messageValue, source, consumeToAccept); } /// public int InputCount { - get { return _defaultTarget != null ? _defaultTarget.InputCount : _spscTarget.InputCount; } + get { return _defaultTarget != null ? _defaultTarget.InputCount : _spscTarget!.InputCount; } } /// Gets the number of messages waiting to be processed. This must only be used from the debugger. private int InputCountForDebugger { - get { return _defaultTarget != null ? _defaultTarget.GetDebuggingInformation().InputCount : _spscTarget.InputCount; } + get { return _defaultTarget != null ? _defaultTarget.GetDebuggingInformation().InputCount : _spscTarget!.InputCount; } } /// public override string ToString() { - return Common.GetNameForDebugger(this, _defaultTarget != null ? _defaultTarget.DataflowBlockOptions : _spscTarget.DataflowBlockOptions); + return Common.GetNameForDebugger(this, _defaultTarget != null ? _defaultTarget.DataflowBlockOptions : _spscTarget!.DataflowBlockOptions); } /// The data to display in the debugger display attribute. @@ -308,7 +313,7 @@ private object DebuggerDisplayContent get { return string.Format("{0}, InputCount={1}", - Common.GetNameForDebugger(this, _defaultTarget != null ? _defaultTarget.DataflowBlockOptions : _spscTarget.DataflowBlockOptions), + Common.GetNameForDebugger(this, _defaultTarget != null ? _defaultTarget.DataflowBlockOptions : _spscTarget!.DataflowBlockOptions), InputCountForDebugger); } } @@ -321,9 +326,9 @@ private sealed class DebugView /// The action block being viewed. private readonly ActionBlock _actionBlock; /// The action block's default target being viewed. - private readonly TargetCore.DebuggingInformation _defaultDebugInfo; + private readonly TargetCore.DebuggingInformation? _defaultDebugInfo; /// The action block's SPSC target being viewed. - private readonly SpscTargetCore.DebuggingInformation _spscDebugInfo; + private readonly SpscTargetCore.DebuggingInformation? _spscDebugInfo; /// Initializes the debug view. /// The target being debugged. @@ -333,21 +338,21 @@ public DebugView(ActionBlock actionBlock) _actionBlock = actionBlock; if (_actionBlock._defaultTarget != null) { - _defaultDebugInfo = actionBlock._defaultTarget.GetDebuggingInformation(); + _defaultDebugInfo = actionBlock._defaultTarget!.GetDebuggingInformation(); } else { - _spscDebugInfo = actionBlock._spscTarget.GetDebuggingInformation(); + _spscDebugInfo = actionBlock._spscTarget!.GetDebuggingInformation(); } } /// Gets the messages waiting to be processed. public IEnumerable InputQueue { - get { return _defaultDebugInfo != null ? _defaultDebugInfo.InputQueue : _spscDebugInfo.InputQueue; } + get { return _defaultDebugInfo != null ? _defaultDebugInfo.InputQueue : _spscDebugInfo!.InputQueue; } } /// Gets any postponed messages. - public QueuedMap, DataflowMessageHeader> PostponedMessages + public QueuedMap, DataflowMessageHeader>? PostponedMessages { get { return _defaultDebugInfo != null ? _defaultDebugInfo.PostponedMessages : null; } } @@ -355,23 +360,23 @@ public QueuedMap, DataflowMessageHeader> PostponedMessages /// Gets the number of outstanding input operations. public int CurrentDegreeOfParallelism { - get { return _defaultDebugInfo != null ? _defaultDebugInfo.CurrentDegreeOfParallelism : _spscDebugInfo.CurrentDegreeOfParallelism; } + get { return _defaultDebugInfo != null ? _defaultDebugInfo.CurrentDegreeOfParallelism : _spscDebugInfo!.CurrentDegreeOfParallelism; } } /// Gets the ExecutionDataflowBlockOptions used to configure this block. public ExecutionDataflowBlockOptions DataflowBlockOptions { - get { return _defaultDebugInfo != null ? _defaultDebugInfo.DataflowBlockOptions : _spscDebugInfo.DataflowBlockOptions; } + get { return _defaultDebugInfo != null ? _defaultDebugInfo.DataflowBlockOptions : _spscDebugInfo!.DataflowBlockOptions; } } /// Gets whether the block is declining further messages. public bool IsDecliningPermanently { - get { return _defaultDebugInfo != null ? _defaultDebugInfo.IsDecliningPermanently : _spscDebugInfo.IsDecliningPermanently; } + get { return _defaultDebugInfo != null ? _defaultDebugInfo.IsDecliningPermanently : _spscDebugInfo!.IsDecliningPermanently; } } /// Gets whether the block is completed. public bool IsCompleted { - get { return _defaultDebugInfo != null ? _defaultDebugInfo.IsCompleted : _spscDebugInfo.IsCompleted; } + get { return _defaultDebugInfo != null ? _defaultDebugInfo.IsCompleted : _spscDebugInfo!.IsCompleted; } } /// Gets the block's Id. public int Id { get { return Common.GetBlockId(_actionBlock); } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchBlock.cs index 8c18c716e48355..48976abd85f41d 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchBlock.cs @@ -55,8 +55,8 @@ public BatchBlock(int batchSize, GroupingDataflowBlockOptions dataflowBlockOptio dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone(); // Initialize bounding actions - Action, int> onItemsRemoved = null; - Func, T[], IList, int> itemCountingFunc = null; + Action, int>? onItemsRemoved = null; + Func, T[], IList?, int>? itemCountingFunc = null; if (dataflowBlockOptions.BoundedCapacity > 0) { onItemsRemoved = (owningSource, count) => ((BatchBlock)owningSource)._target.OnItemsRemoved(count); @@ -81,14 +81,14 @@ public BatchBlock(int batchSize, GroupingDataflowBlockOptions dataflowBlockOptio // to handle multiple completion requests and to carry over only one. _source.Completion.ContinueWith((completed, state) => { - var thisBlock = ((BatchBlock)state) as IDataflowBlock; + var thisBlock = ((BatchBlock)state!) as IDataflowBlock; Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion."); - thisBlock.Fault(completed.Exception); + thisBlock.Fault(completed.Exception!); }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchBlockTargetCore)state).Complete(exception: null, dropPendingMessages: true, releaseReservedMessages: false), _target); + dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchBlockTargetCore)state!).Complete(exception: null, dropPendingMessages: true, releaseReservedMessages: false), _target); #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; if (etwLog.IsEnabled()) @@ -127,13 +127,15 @@ public IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions linkOpti } /// - public bool TryReceive(Predicate filter, out T[] item) +#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470 + public bool TryReceive(Predicate? filter, [NotNullWhen(true)] out T[]? item) +#pragma warning restore CS8614 { return _source.TryReceive(filter, out item); } /// - public bool TryReceiveAll(out IList items) { return _source.TryReceiveAll(out items); } + public bool TryReceiveAll([NotNullWhen(true)] out IList? items) { return _source.TryReceiveAll(out items); } /// public int OutputCount { get { return _source.OutputCount; } } @@ -149,12 +151,13 @@ public bool TryReceive(Predicate filter, out T[] item) public int BatchSize { get { return _target.BatchSize; } } /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { return _target.OfferMessage(messageHeader, messageValue, source, consumeToAccept); } /// + [return: MaybeNull] T[] ISourceBlock.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { return _source.ConsumeMessage(messageHeader, target, out messageConsumed); @@ -220,9 +223,9 @@ public DebugView(BatchBlock batchBlock) public long BatchesCompleted { get { return _targetDebuggingInformation.NumberOfBatchesCompleted; } } /// Gets the task being used for input processing. - public Task TaskForInputProcessing { get { return _targetDebuggingInformation.TaskForInputProcessing; } } + public Task? TaskForInputProcessing { get { return _targetDebuggingInformation.TaskForInputProcessing; } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } /// Gets the DataflowBlockOptions used to configure this block. public GroupingDataflowBlockOptions DataflowBlockOptions { get { return _targetDebuggingInformation.DataflowBlockOptions; } } @@ -236,11 +239,11 @@ public DebugView(BatchBlock batchBlock) public int Id { get { return Common.GetBlockId(_batchBlock); } } /// Gets the messages postponed by this batch. - public QueuedMap, DataflowMessageHeader> PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } } + public QueuedMap, DataflowMessageHeader>? PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } } /// Gets the set of all targets linked from this block. public TargetRegistry LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } } /// Gets the set of all targets linked from this block. - public ITargetBlock NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } + public ITargetBlock? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } } /// Provides the core target implementation for a Batch. @@ -260,9 +263,9 @@ private sealed class BatchBlockTargetCore /// The batch size. private readonly int _batchSize; /// State used when in non-greedy mode. - private readonly NonGreedyState _nonGreedyState; + private readonly NonGreedyState? _nonGreedyState; /// Bounding state for when the block is executing in bounded mode. - private readonly BoundingState _boundingState; + private readonly BoundingState? _boundingState; /// The options associated with this block. private readonly GroupingDataflowBlockOptions _dataflowBlockOptions; /// The action invoked with a completed batch. @@ -288,7 +291,7 @@ private sealed class NonGreedyState /// This value may be read not under a lock, but it must only be written to protected by the IncomingLock. internal bool AcceptFewerThanBatchSize; /// The task used to process messages. - internal Task TaskForInputProcessing; + internal Task? TaskForInputProcessing; /// Initializes the NonGreedyState. /// The batch size used by the BatchBlock. @@ -356,7 +359,7 @@ internal void TriggerBatch() } /// - internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { // Validate arguments if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); @@ -380,7 +383,7 @@ internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, if (_dataflowBlockOptions.Greedy && (_boundingState == null || - (_boundingState.CountIsLessThanBound && _nonGreedyState.PostponedMessages.Count == 0 && _nonGreedyState.TaskForInputProcessing == null))) + (_boundingState.CountIsLessThanBound && _nonGreedyState!.PostponedMessages.Count == 0 && _nonGreedyState.TaskForInputProcessing == null))) { // Consume the message from the source if necessary if (consumeToAccept) @@ -393,7 +396,7 @@ internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, } // Once consumed, enqueue it. - _messages.Enqueue(messageValue); + _messages.Enqueue(messageValue!); if (_boundingState != null) _boundingState.CurrentCount += 1; // track this new item against our bound // Now start declining if the number of batches we've already made plus @@ -432,7 +435,7 @@ internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, /// In general, it is not safe to pass releaseReservedMessages:true, because releasing of reserved messages /// is done without taking a lock. We pass releaseReservedMessages:true only when an exception has been /// caught inside the message processing loop which is a single instance at any given moment. - internal void Complete(Exception exception, bool dropPendingMessages, bool releaseReservedMessages, bool revertProcessingState = false) + internal void Complete(Exception? exception, bool dropPendingMessages, bool releaseReservedMessages, bool revertProcessingState = false) { // Ensure that no new messages may be added lock (IncomingLock) @@ -531,10 +534,10 @@ private void CompleteBlockIfPossible() // completion task continuations in that case, do it in a separate task. Task.Factory.StartNew(thisTargetCore => { - var targetCore = (BatchBlockTargetCore)thisTargetCore; + var targetCore = (BatchBlockTargetCore)thisTargetCore!; // Release any postponed messages - List exceptions = null; + List? exceptions = null; if (targetCore._nonGreedyState != null) { // Note: No locks should be held at this point @@ -637,7 +640,7 @@ private void ProcessAsyncIfNecessary_Slow(bool isReplacementReplica) // Create task and store into _taskForInputProcessing prior to scheduling the task // so that _taskForInputProcessing will be visibly set in the task loop. - _nonGreedyState.TaskForInputProcessing = new Task(thisBatchTarget => ((BatchBlockTargetCore)thisBatchTarget).ProcessMessagesLoopCore(), this, + _nonGreedyState!.TaskForInputProcessing = new Task(thisBatchTarget => ((BatchBlockTargetCore)thisBatchTarget!).ProcessMessagesLoopCore(), this, Common.GetCreationOptionsForTask(isReplacementReplica)); #if FEATURE_TRACING @@ -651,11 +654,11 @@ private void ProcessAsyncIfNecessary_Slow(bool isReplacementReplica) #endif // Start the task handling scheduling exceptions - Exception exception = Common.StartTaskSafe(_nonGreedyState.TaskForInputProcessing, _dataflowBlockOptions.TaskScheduler); + Exception? exception = Common.StartTaskSafe(_nonGreedyState.TaskForInputProcessing, _dataflowBlockOptions.TaskScheduler); if (exception != null) { // Get out from under currently held locks. Complete re-acquires the locks it needs. - Task.Factory.StartNew(exc => Complete(exception: (Exception)exc, dropPendingMessages: true, releaseReservedMessages: true, revertProcessingState: true), + Task.Factory.StartNew(exc => Complete(exception: (Exception)exc!, dropPendingMessages: true, releaseReservedMessages: true, revertProcessingState: true), exception, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); } } @@ -793,7 +796,7 @@ private void RetrievePostponedItemsNonGreedy(bool allowFewerThanBatchSize) KeyValuePair, DataflowMessageHeader> sourceAndMessage = postponedTemp[i]; if (sourceAndMessage.Key.ReserveMessage(sourceAndMessage.Value, _owningBatch)) { - var reservedMessage = new KeyValuePair(sourceAndMessage.Value, default(T)); + var reservedMessage = new KeyValuePair(sourceAndMessage.Value, default(T)!); var reservedSourceAndMessage = new KeyValuePair, KeyValuePair>(sourceAndMessage.Key, reservedMessage); reserved.Add(reservedSourceAndMessage); } @@ -811,7 +814,7 @@ private void RetrievePostponedItemsNonGreedy(bool allowFewerThanBatchSize) } // Release the lock. We must not hold it while calling Reserve/Consume/Release. if (sourceAndMessage.Key.ReserveMessage(sourceAndMessage.Value, _owningBatch)) { - var reservedMessage = new KeyValuePair(sourceAndMessage.Value, default(T)); + var reservedMessage = new KeyValuePair(sourceAndMessage.Value, default(T)!); var reservedSourceAndMessage = new KeyValuePair, KeyValuePair>(sourceAndMessage.Key, reservedMessage); reserved.Add(reservedSourceAndMessage); } @@ -908,7 +911,7 @@ private void RetrievePostponedItemsGreedyBounded(bool allowFewerThanBatchSize) for (int i = 0; i < poppedInitially; i++) { KeyValuePair, DataflowMessageHeader> sourceAndMessage = postponedTemp[i]; - var reservedMessage = new KeyValuePair(sourceAndMessage.Value, default(T)); + var reservedMessage = new KeyValuePair(sourceAndMessage.Value, default(T)!); var reservedSourceAndMessage = new KeyValuePair, KeyValuePair>(sourceAndMessage.Key, reservedMessage); reserved.Add(reservedSourceAndMessage); } @@ -924,7 +927,7 @@ private void RetrievePostponedItemsGreedyBounded(bool allowFewerThanBatchSize) if (!postponed.TryPop(out sourceAndMessage)) break; } // Release the lock. We must not hold it while calling Reserve/Consume/Release. - var reservedMessage = new KeyValuePair(sourceAndMessage.Value, default(T)); + var reservedMessage = new KeyValuePair(sourceAndMessage.Value, default(T)!); var reservedSourceAndMessage = new KeyValuePair, KeyValuePair>(sourceAndMessage.Key, reservedMessage); reserved.Add(reservedSourceAndMessage); } @@ -1007,7 +1010,7 @@ private void ConsumeReservedMessagesNonGreedy() throw new InvalidOperationException(SR.InvalidOperation_FailedToConsumeReservedMessage); } - var consumedMessage = new KeyValuePair(sourceAndMessage.Value.Key, consumedValue); + var consumedMessage = new KeyValuePair(sourceAndMessage.Value.Key, consumedValue!); var consumedSourceAndMessage = new KeyValuePair, KeyValuePair>(sourceAndMessage.Key, consumedMessage); reserved[i] = consumedSourceAndMessage; } @@ -1052,7 +1055,7 @@ private void ConsumeReservedMessagesGreedyBounded() T consumedValue = sourceAndMessage.Key.ConsumeMessage(sourceAndMessage.Value.Key, _owningBatch, out consumed); if (consumed) { - var consumedMessage = new KeyValuePair(sourceAndMessage.Value.Key, consumedValue); + var consumedMessage = new KeyValuePair(sourceAndMessage.Value.Key, consumedValue!); var consumedSourceAndMessage = new KeyValuePair, KeyValuePair>(sourceAndMessage.Key, consumedMessage); reserved[i] = consumedSourceAndMessage; @@ -1087,7 +1090,7 @@ internal void ReleaseReservedMessages(bool throwOnFirstException) Debug.Assert(_nonGreedyState != null, "Non-greedy state is required for non-greedy mode."); Debug.Assert(_nonGreedyState.ReservedSourcesTemp != null, "Should have been initialized"); - List exceptions = null; + List? exceptions = null; List, KeyValuePair>> reserved = _nonGreedyState.ReservedSourcesTemp; for (int i = 0; i < reserved.Count; i++) @@ -1139,7 +1142,7 @@ internal void OnItemsRemoved(int numItemsRemoved) /// Counts the input items in a single output item or in a list of output items. /// A single output item. Only considered if multipleOutputItems == null. /// A list of output items. May be null. - internal static int CountItems(T[] singleOutputItem, IList multipleOutputItems) + internal static int CountItems(T[] singleOutputItem, IList? multipleOutputItems) { // If multipleOutputItems == null, then singleOutputItem is the subject of counting if (multipleOutputItems == null) return singleOutputItem.Length; @@ -1181,9 +1184,9 @@ internal sealed class DebuggingInformation /// Gets the messages waiting to be processed. public IEnumerable InputQueue { get { return _target._messages.ToList(); } } /// Gets the task being used for input processing. - public Task TaskForInputProcessing { get { return _target._nonGreedyState != null ? _target._nonGreedyState.TaskForInputProcessing : null; } } + public Task? TaskForInputProcessing { get { return _target._nonGreedyState != null ? _target._nonGreedyState.TaskForInputProcessing : null; } } /// Gets the collection of postponed messages. - public QueuedMap, DataflowMessageHeader> PostponedMessages { get { return _target._nonGreedyState != null ? _target._nonGreedyState.PostponedMessages : null; } } + public QueuedMap, DataflowMessageHeader>? PostponedMessages { get { return _target._nonGreedyState != null ? _target._nonGreedyState.PostponedMessages : null; } } /// Gets whether the block is declining further messages. public bool IsDecliningPermanently { get { return _target._decliningPermanently; } } /// Gets the DataflowBlockOptions used to configure this block. diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchedJoinBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchedJoinBlock.cs index 4b961f52e90623..4e4f576fad7b3f 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchedJoinBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchedJoinBlock.cs @@ -99,14 +99,14 @@ public BatchedJoinBlock(int batchSize, GroupingDataflowBlockOptions dataflowBloc // to handle multiple completion requests and to carry over only one. _source.Completion.ContinueWith((completed, state) => { - var thisBlock = ((BatchedJoinBlock)state) as IDataflowBlock; + var thisBlock = ((BatchedJoinBlock)state!) as IDataflowBlock; Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion."); - thisBlock.Fault(completed.Exception); + thisBlock.Fault(completed.Exception!); }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchedJoinBlock)state).CompleteEachTarget(), this); + dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchedJoinBlock)state!).CompleteEachTarget(), this); #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; if (etwLog.IsEnabled()) @@ -132,13 +132,15 @@ public IDisposable LinkTo(ITargetBlock, IList>> target, Data } /// - public bool TryReceive(Predicate, IList>> filter, out Tuple, IList> item) +#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470 + public bool TryReceive(Predicate, IList>>? filter, [NotNullWhen(true)] out Tuple, IList>? item) +#pragma warning restore CS8614 { return _source.TryReceive(filter, out item); } /// - public bool TryReceiveAll(out IList, IList>> items) { return _source.TryReceiveAll(out items); } + public bool TryReceiveAll([NotNullWhen(true)] out IList, IList>>? items) { return _source.TryReceiveAll(out items); } /// public int OutputCount { get { return _source.OutputCount; } } @@ -173,6 +175,7 @@ void IDataflowBlock.Fault(Exception exception) } /// + [return: MaybeNull] Tuple, IList> ISourceBlock, IList>>.ConsumeMessage( DataflowMessageHeader messageHeader, ITargetBlock, IList>> target, out bool messageConsumed) { @@ -254,7 +257,7 @@ public DebugView(BatchedJoinBlock batchedJoinBlock) public ITargetBlock Target2 { get { return _batchedJoinBlock._target2; } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } /// Gets the DataflowBlockOptions used to configure this block. public GroupingDataflowBlockOptions DataflowBlockOptions { get { return (GroupingDataflowBlockOptions)_sourceDebuggingInformation.DataflowBlockOptions; } } @@ -266,7 +269,7 @@ public DebugView(BatchedJoinBlock batchedJoinBlock) /// Gets the set of all targets linked from this block. public TargetRegistry, IList>> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } } /// Gets the target that holds a reservation on the next message, if any. - public ITargetBlock, IList>> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } + public ITargetBlock, IList>>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } } } @@ -357,14 +360,14 @@ public BatchedJoinBlock(int batchSize, GroupingDataflowBlockOptions dataflowBloc // to handle multiple completion requests and to carry over only one. _source.Completion.ContinueWith((completed, state) => { - var thisBlock = ((BatchedJoinBlock)state) as IDataflowBlock; + var thisBlock = ((BatchedJoinBlock)state!) as IDataflowBlock; Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion."); - thisBlock.Fault(completed.Exception); + thisBlock.Fault(completed.Exception!); }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchedJoinBlock)state).CompleteEachTarget(), this); + dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchedJoinBlock)state!).CompleteEachTarget(), this); #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; if (etwLog.IsEnabled()) @@ -393,13 +396,15 @@ public IDisposable LinkTo(ITargetBlock, IList, IList>> t } /// - public bool TryReceive(Predicate, IList, IList>> filter, out Tuple, IList, IList> item) +#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470 + public bool TryReceive(Predicate, IList, IList>>? filter, [NotNullWhen(true)] out Tuple, IList, IList>? item) +#pragma warning restore CS8614 { return _source.TryReceive(filter, out item); } /// - public bool TryReceiveAll(out IList, IList, IList>> items) { return _source.TryReceiveAll(out items); } + public bool TryReceiveAll([NotNullWhen(true)] out IList, IList, IList>>? items) { return _source.TryReceiveAll(out items); } /// public int OutputCount { get { return _source.OutputCount; } } @@ -436,6 +441,7 @@ void IDataflowBlock.Fault(Exception exception) } /// + [return: MaybeNull] Tuple, IList, IList> ISourceBlock, IList, IList>>.ConsumeMessage( DataflowMessageHeader messageHeader, ITargetBlock, IList, IList>> target, out bool messageConsumed) { @@ -520,7 +526,7 @@ public DebugView(BatchedJoinBlock batchedJoinBlock) public ITargetBlock Target3 { get { return _batchedJoinBlock._target3; } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } /// Gets the DataflowBlockOptions used to configure this block. public GroupingDataflowBlockOptions DataflowBlockOptions { get { return (GroupingDataflowBlockOptions)_sourceDebuggingInformation.DataflowBlockOptions; } } @@ -532,7 +538,7 @@ public DebugView(BatchedJoinBlock batchedJoinBlock) /// Gets the set of all targets linked from this block. public TargetRegistry, IList, IList>> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } } /// Gets the target that holds a reservation on the next message, if any. - public ITargetBlock, IList, IList>> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } + public ITargetBlock, IList, IList>>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } } } } @@ -580,7 +586,7 @@ internal IList GetAndEmptyMessages() } /// - public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { // Validate arguments if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); @@ -602,7 +608,7 @@ public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue = source.ConsumeMessage(messageHeader, this, out consumed); if (!consumed) return DataflowMessageStatus.NotAvailable; } - _messages.Add(messageValue); + _messages.Add(messageValue!); // If this message makes a batch, notify the shared resources that a batch has been completed if (--_sharedResources._remainingItemsInBatch == 0) _sharedResources._batchSizeReachedAction(); diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BroadcastBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BroadcastBlock.cs index ab471333b62b5a..103a124a53653c 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BroadcastBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BroadcastBlock.cs @@ -39,7 +39,7 @@ public sealed class BroadcastBlock : IPropagatorBlock, IReceivableSourc /// The source side. private readonly BroadcastingSourceCore _source; /// Bounding state for when the block is executing in bounded mode. - private readonly BoundingStateWithPostponedAndTask _boundingState; + private readonly BoundingStateWithPostponedAndTask? _boundingState; /// Whether all future messages should be declined. private bool _decliningPermanently; /// A task has reserved the right to run the completion routine. @@ -52,7 +52,7 @@ public sealed class BroadcastBlock : IPropagatorBlock, IReceivableSourc /// The function to use to clone the data when offered to other blocks. /// This may be null to indicate that no cloning need be performed. /// - public BroadcastBlock(Func cloningFunction) : + public BroadcastBlock(Func? cloningFunction) : this(cloningFunction, DataflowBlockOptions.Default) { } @@ -63,7 +63,7 @@ public BroadcastBlock(Func cloningFunction) : /// /// The options with which to configure this . /// The is null (Nothing in Visual Basic). - public BroadcastBlock(Func cloningFunction, DataflowBlockOptions dataflowBlockOptions) + public BroadcastBlock(Func? cloningFunction, DataflowBlockOptions dataflowBlockOptions) { // Validate arguments if (dataflowBlockOptions == null) throw new ArgumentNullException(nameof(dataflowBlockOptions)); @@ -72,7 +72,7 @@ public BroadcastBlock(Func cloningFunction, DataflowBlockOptions dataflowB dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone(); // Initialize bounding state if necessary - Action onItemsRemoved = null; + Action? onItemsRemoved = null; if (dataflowBlockOptions.BoundedCapacity > 0) { Debug.Assert(dataflowBlockOptions.BoundedCapacity > 0, "Positive bounding count expected; should have been verified by options ctor"); @@ -89,14 +89,14 @@ public BroadcastBlock(Func cloningFunction, DataflowBlockOptions dataflowB // to handle multiple completion requests and to carry over only one. _source.Completion.ContinueWith((completed, state) => { - var thisBlock = ((BroadcastBlock)state) as IDataflowBlock; + var thisBlock = ((BroadcastBlock)state!) as IDataflowBlock; Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion."); - thisBlock.Fault(completed.Exception); + thisBlock.Fault(completed.Exception!); }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BroadcastBlock)state).Complete(), this); + dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BroadcastBlock)state!).Complete(), this); #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; if (etwLog.IsEnabled()) @@ -120,7 +120,7 @@ void IDataflowBlock.Fault(Exception exception) CompleteCore(exception, storeExceptionEvenIfAlreadyCompleting: false); } - internal void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyCompleting, bool revertProcessingState = false) + internal void CompleteCore(Exception? exception, bool storeExceptionEvenIfAlreadyCompleting, bool revertProcessingState = false) { Debug.Assert(storeExceptionEvenIfAlreadyCompleting || !revertProcessingState, "Indicating dirty processing state may only come with storeExceptionEvenIfAlreadyCompleting==true."); @@ -152,16 +152,16 @@ internal void CompleteCore(Exception exception, bool storeExceptionEvenIfAlready public IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions linkOptions) { return _source.LinkTo(target, linkOptions); } /// - public bool TryReceive(Predicate filter, out T item) { return _source.TryReceive(filter, out item); } + public bool TryReceive(Predicate? filter, [MaybeNullWhen(false)] out T item) { return _source.TryReceive(filter, out item); } /// - bool IReceivableSourceBlock.TryReceiveAll(out IList items) { return _source.TryReceiveAll(out items); } + bool IReceivableSourceBlock.TryReceiveAll([NotNullWhen(true)] out IList? items) { return _source.TryReceiveAll(out items); } /// public Task Completion { get { return _source.Completion; } } /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { // Validate arguments if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); @@ -197,7 +197,7 @@ DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader message } // Once consumed, pass it to the delegate - _source.AddMessage(messageValue); + _source.AddMessage(messageValue!); if (_boundingState != null) _boundingState.CurrentCount += 1; // track this new item against our bound return DataflowMessageStatus.Accepted; } @@ -255,7 +255,7 @@ internal void ConsumeAsyncIfNecessary(bool isReplacementReplica = false) // Create task and store into _taskForInputProcessing prior to scheduling the task // so that _taskForInputProcessing will be visibly set in the task loop. _boundingState.TaskForInputProcessing = - new Task(state => ((BroadcastBlock)state).ConsumeMessagesLoopCore(), this, + new Task(state => ((BroadcastBlock)state!).ConsumeMessagesLoopCore(), this, Common.GetCreationOptionsForTask(isReplacementReplica)); #if FEATURE_TRACING @@ -269,11 +269,11 @@ internal void ConsumeAsyncIfNecessary(bool isReplacementReplica = false) #endif // Start the task handling scheduling exceptions - Exception exception = Common.StartTaskSafe(_boundingState.TaskForInputProcessing, _source.DataflowBlockOptions.TaskScheduler); + Exception? exception = Common.StartTaskSafe(_boundingState.TaskForInputProcessing, _source.DataflowBlockOptions.TaskScheduler); if (exception != null) { // Get out from under currently held locks. Complete re-acquires the locks it needs. - Task.Factory.StartNew(exc => CompleteCore(exception: (Exception)exc, storeExceptionEvenIfAlreadyCompleting: true, revertProcessingState: true), + Task.Factory.StartNew(exc => CompleteCore(exception: (Exception)exc!, storeExceptionEvenIfAlreadyCompleting: true, revertProcessingState: true), exception, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); } } @@ -356,7 +356,7 @@ private bool ConsumeAndStoreOneMessageIfAvailable() T consumedValue = sourceAndMessage.Key.ConsumeMessage(sourceAndMessage.Value, this, out consumed); if (consumed) { - _source.AddMessage(consumedValue); + _source.AddMessage(consumedValue!); return true; } } @@ -387,10 +387,10 @@ private void CompleteTargetIfPossible() { Task.Factory.StartNew(state => { - var thisBroadcastBlock = (BroadcastBlock)state; + var thisBroadcastBlock = (BroadcastBlock)state!; // Release any postponed messages - List exceptions = null; + List? exceptions = null; if (thisBroadcastBlock._boundingState != null) { // Note: No locks should be held at this point @@ -418,6 +418,7 @@ private void CompleteTargetIfPossible() } /// + [return: MaybeNull] T ISourceBlock.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { return _source.ConsumeMessage(messageHeader, target, out messageConsumed); @@ -482,7 +483,7 @@ public DebugView(BroadcastBlock broadcastBlock) public T Value { get { return _broadcastBlock.ValueForDebugger; } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } /// Gets the DataflowBlockOptions used to configure this block. public DataflowBlockOptions DataflowBlockOptions { get { return _sourceDebuggingInformation.DataflowBlockOptions; } } @@ -496,7 +497,7 @@ public DebugView(BroadcastBlock broadcastBlock) /// Gets the set of all targets linked from this block. public TargetRegistry LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } } /// Gets the set of all targets linked from this block. - public ITargetBlock NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } + public ITargetBlock? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } } /// Provides a core implementation for blocks that implement . @@ -514,7 +515,7 @@ private sealed class BroadcastingSourceCore /// An action to be invoked on the owner block when an item is removed. /// This may be null if the owner block doesn't need to be notified. /// - private readonly Action _itemsRemovedAction; + private readonly Action? _itemsRemovedAction; /// Gets the object to use as the outgoing lock. private object OutgoingLock { get { return _completionTask; } } @@ -526,22 +527,23 @@ private sealed class BroadcastingSourceCore /// The options used to configure this block's execution. private readonly DataflowBlockOptions _dataflowBlockOptions; /// The cloning function to use. - private readonly Func _cloningFunction; + private readonly Func? _cloningFunction; /// An indicator whether _currentMessage has a value. private bool _currentMessageIsValid; /// The message currently being broadcast. - private TOutput _currentMessage; + [AllowNull, MaybeNull] + private TOutput _currentMessage = default; /// The target that the next message is reserved for, or null if nothing is reserved. - private ITargetBlock _nextMessageReservedFor; + private ITargetBlock? _nextMessageReservedFor; /// Whether this block should again attempt to offer messages to targets. private bool _enableOffering; /// Whether all future messages should be declined. private bool _decliningPermanently; /// The task used to process the output and offer it to targets. - private Task _taskForOutputProcessing; + private Task? _taskForOutputProcessing; /// Exceptions that may have occurred and gone unhandled during processing. - private List _exceptions; + private List? _exceptions; /// Counter for message IDs unique within this source block. private long _nextMessageId = 1; // We are going to use this value before incrementing. /// Whether someone has reserved the right to call CompleteBlockOncePossible. @@ -554,9 +556,9 @@ private sealed class BroadcastingSourceCore /// Action to invoke when an item is removed. internal BroadcastingSourceCore( BroadcastBlock owningSource, - Func cloningFunction, + Func? cloningFunction, DataflowBlockOptions dataflowBlockOptions, - Action itemsRemovedAction) + Action? itemsRemovedAction) { Debug.Assert(owningSource != null, "Must be associated with a broadcast block."); Debug.Assert(dataflowBlockOptions != null, "Options are required to configure this block."); @@ -572,7 +574,7 @@ internal BroadcastingSourceCore( } /// - internal bool TryReceive(Predicate filter, out TOutput item) + internal bool TryReceive(Predicate? filter, [MaybeNullWhen(false)] out TOutput item) { // Take the lock only long enough to get the message, // synchronizing with other activities on the block. @@ -591,9 +593,9 @@ internal bool TryReceive(Predicate filter, out TOutput item) // Clone and hand back a message if we have one and if it passes the filter. // (A null filter means all messages pass.) - if (isValid && (filter == null || filter(message))) + if (isValid && (filter == null || filter(message!))) { - item = CloneItem(message); + item = CloneItem(message!); return true; } else @@ -604,7 +606,7 @@ internal bool TryReceive(Predicate filter, out TOutput item) } /// - internal bool TryReceiveAll(out IList items) + internal bool TryReceiveAll([NotNullWhen(true)] out IList? items) { // Try to receive the one item this block may have. // If we can, give back an array of one item. Otherwise, give back null. @@ -653,7 +655,7 @@ internal void Complete() // and take the necessary locks in a situation where we're sure it won't cause a problem. Task.Factory.StartNew(state => { - var thisSourceCore = (BroadcastingSourceCore)state; + var thisSourceCore = (BroadcastingSourceCore)state!; lock (thisSourceCore.OutgoingLock) { lock (thisSourceCore.ValueLock) @@ -698,7 +700,7 @@ private void OfferCurrentMessageToNewTarget(ITargetBlock target) // Offer it to the target. // We must not increment the message ID here. We only do that when we populate _currentMessage, i.e. when we dequeue. bool useCloning = _cloningFunction != null; - DataflowMessageStatus result = target.OfferMessage(new DataflowMessageHeader(_nextMessageId), currentMessage, _owningSource, consumeToAccept: useCloning); + DataflowMessageStatus result = target.OfferMessage(new DataflowMessageHeader(_nextMessageId), currentMessage!, _owningSource, consumeToAccept: useCloning); // If accepted and the target was linked as "unlinkAfterOne", remove it if (result == DataflowMessageStatus.Accepted) @@ -770,14 +772,14 @@ private bool OfferToTargets() if (_itemsRemovedAction != null) _itemsRemovedAction(numDequeuedMessages); // Offer it to each target, unless a soleTarget was provided, which case just offer it to that one. - TargetRegistry.LinkedTargetInfo cur = _targetRegistry.FirstTargetNode; + TargetRegistry.LinkedTargetInfo? cur = _targetRegistry.FirstTargetNode; while (cur != null) { // Note that during OfferMessage, a target may call ConsumeMessage, which may unlink the target // if the target is registered as "once". Doing so will remove the target from the targets list. // As such, we avoid using an enumerator over _targetRegistry and instead walk from back to front, // so that if an element is removed, it won't affect the rest of our walk. - TargetRegistry.LinkedTargetInfo next = cur.Next; + TargetRegistry.LinkedTargetInfo? next = cur.Next; ITargetBlock target = cur.Target; OfferMessageToTarget(header, message, target); cur = next; @@ -842,7 +844,7 @@ private void OfferAsyncIfNecessary(bool isReplacementReplica = false) { // Create task and store into _taskForOutputProcessing prior to scheduling the task // so that _taskForOutputProcessing will be visibly set in the task loop. - _taskForOutputProcessing = new Task(thisSourceCore => ((BroadcastingSourceCore)thisSourceCore).OfferMessagesLoopCore(), this, + _taskForOutputProcessing = new Task(thisSourceCore => ((BroadcastingSourceCore)thisSourceCore!).OfferMessagesLoopCore(), this, Common.GetCreationOptionsForTask(isReplacementReplica)); #if FEATURE_TRACING @@ -855,7 +857,7 @@ private void OfferAsyncIfNecessary(bool isReplacementReplica = false) #endif // Start the task handling scheduling exceptions - Exception exception = Common.StartTaskSafe(_taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler); + Exception? exception = Common.StartTaskSafe(_taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler); if (exception != null) { // First, log the exception while the processing state is dirty which is preventing the block from completing. @@ -869,7 +871,7 @@ private void OfferAsyncIfNecessary(bool isReplacementReplica = false) // Re-take the locks on a separate thread. Task.Factory.StartNew(state => { - var thisSourceCore = (BroadcastingSourceCore)state; + var thisSourceCore = (BroadcastingSourceCore)state!; lock (thisSourceCore.OutgoingLock) { lock (thisSourceCore.ValueLock) @@ -959,7 +961,7 @@ private void CompleteBlockIfPossible_Slow() _completionReserved = true; // Run asynchronously to get out of the currently held locks - Task.Factory.StartNew(thisSourceCore => ((BroadcastingSourceCore)thisSourceCore).CompleteBlockOncePossible(), + Task.Factory.StartNew(thisSourceCore => ((BroadcastingSourceCore)thisSourceCore!).CompleteBlockOncePossible(), this, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); } @@ -969,8 +971,8 @@ private void CompleteBlockIfPossible_Slow() /// private void CompleteBlockOncePossible() { - TargetRegistry.LinkedTargetInfo linkedTargets; - List exceptions; + TargetRegistry.LinkedTargetInfo? linkedTargets; + List? exceptions; // Clear out the target registry and buffers to help avoid memory leaks. // We do not clear _currentMessage, which should remain as that message forever. @@ -1048,6 +1050,7 @@ internal IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions li } /// + [return: MaybeNull] internal TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { // Validate arguments @@ -1084,7 +1087,7 @@ internal TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBloc } messageConsumed = true; - return CloneItem(valueToClone); + return CloneItem(valueToClone!); } /// @@ -1145,7 +1148,7 @@ internal void ReleaseReservation(DataflowMessageHeader messageHeader, ITargetBlo // do this if _messages.Count == 0, as if it's > 0 the message will get overwritten // as part of the asynchronous offering, but for consistency we should always reoffer // the current message. - OfferMessageToTarget(messageHeader, messageToReoffer, target); + OfferMessageToTarget(messageHeader, messageToReoffer!, target); } } @@ -1223,11 +1226,11 @@ internal sealed class DebuggingInformation /// Gets whether the source contains a current message. public bool HasValue { get { return _source._currentMessageIsValid; } } /// Gets the value of the source's current message. - public TOutput Value { get { return _source._currentMessage; } } + public TOutput Value { get { return _source._currentMessage!; } } /// Gets the messages available for receiving. public IEnumerable InputQueue { get { return _source._messages.ToList(); } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _source._taskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _source._taskForOutputProcessing; } } /// Gets the DataflowBlockOptions used to configure this block. public DataflowBlockOptions DataflowBlockOptions { get { return _source._dataflowBlockOptions; } } @@ -1237,7 +1240,7 @@ internal sealed class DebuggingInformation /// Gets the set of all targets linked from this block. public TargetRegistry LinkedTargets { get { return _source._targetRegistry; } } /// Gets the target that holds a reservation on the next message, if any. - public ITargetBlock NextMessageReservedFor { get { return _source._nextMessageReservedFor; } } + public ITargetBlock? NextMessageReservedFor { get { return _source._nextMessageReservedFor; } } } } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BufferBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BufferBlock.cs index d9dce57b4d9b49..806ee1561ae0db 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BufferBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BufferBlock.cs @@ -28,7 +28,7 @@ public sealed class BufferBlock : IPropagatorBlock, IReceivableSourceBl /// The core logic for the buffer block. private readonly SourceCore _source; /// The bounding state for when in bounding mode; null if not bounding. - private readonly BoundingStateWithPostponedAndTask _boundingState; + private readonly BoundingStateWithPostponedAndTask? _boundingState; /// Whether all future messages should be declined on the target. private bool _targetDecliningPermanently; /// A task has reserved the right to run the target's completion routine. @@ -52,7 +52,7 @@ public BufferBlock(DataflowBlockOptions dataflowBlockOptions) dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone(); // Initialize bounding state if necessary - Action, int> onItemsRemoved = null; + Action, int>? onItemsRemoved = null; if (dataflowBlockOptions.BoundedCapacity > 0) { onItemsRemoved = (owningSource, count) => ((BufferBlock)owningSource).OnItemsRemoved(count); @@ -70,14 +70,14 @@ public BufferBlock(DataflowBlockOptions dataflowBlockOptions) // to handle multiple completion requests and to carry over only one. _source.Completion.ContinueWith((completed, state) => { - var thisBlock = ((BufferBlock)state) as IDataflowBlock; + var thisBlock = ((BufferBlock)state!) as IDataflowBlock; Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion."); - thisBlock.Fault(completed.Exception); + thisBlock.Fault(completed.Exception!); }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, _source.Completion, owningSource => ((BufferBlock)owningSource).Complete(), this); + dataflowBlockOptions.CancellationToken, _source.Completion, owningSource => ((BufferBlock)owningSource!).Complete(), this); #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; if (etwLog.IsEnabled()) @@ -88,7 +88,7 @@ public BufferBlock(DataflowBlockOptions dataflowBlockOptions) } /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { // Validate arguments if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); @@ -124,7 +124,7 @@ DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader message } // Once consumed, pass it to the source - _source.AddMessage(messageValue); + _source.AddMessage(messageValue!); if (_boundingState != null) _boundingState.CurrentCount++; return DataflowMessageStatus.Accepted; @@ -154,7 +154,7 @@ void IDataflowBlock.Fault(Exception exception) CompleteCore(exception, storeExceptionEvenIfAlreadyCompleting: false); } - private void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyCompleting, bool revertProcessingState = false) + private void CompleteCore(Exception? exception, bool storeExceptionEvenIfAlreadyCompleting, bool revertProcessingState = false) { Debug.Assert(storeExceptionEvenIfAlreadyCompleting || !revertProcessingState, "Indicating dirty processing state may only come with storeExceptionEvenIfAlreadyCompleting==true."); @@ -186,10 +186,10 @@ private void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyC public IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions linkOptions) { return _source.LinkTo(target, linkOptions); } /// - public bool TryReceive(Predicate filter, out T item) { return _source.TryReceive(filter, out item); } + public bool TryReceive(Predicate? filter, [MaybeNullWhen(false)] out T item) { return _source.TryReceive(filter, out item); } /// - public bool TryReceiveAll(out IList items) { return _source.TryReceiveAll(out items); } + public bool TryReceiveAll([NotNullWhen(true)] out IList? items) { return _source.TryReceiveAll(out items); } /// Gets the number of items currently stored in the buffer. public int Count { get { return _source.OutputCount; } } @@ -198,6 +198,7 @@ private void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyC public Task Completion { get { return _source.Completion; } } /// + [return: MaybeNull] T ISourceBlock.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { return _source.ConsumeMessage(messageHeader, target, out messageConsumed); @@ -255,7 +256,7 @@ internal void ConsumeAsyncIfNecessary(bool isReplacementReplica = false) // Create task and store into _taskForInputProcessing prior to scheduling the task // so that _taskForInputProcessing will be visibly set in the task loop. _boundingState.TaskForInputProcessing = - new Task(state => ((BufferBlock)state).ConsumeMessagesLoopCore(), this, + new Task(state => ((BufferBlock)state!).ConsumeMessagesLoopCore(), this, Common.GetCreationOptionsForTask(isReplacementReplica)); #if FEATURE_TRACING @@ -269,11 +270,11 @@ internal void ConsumeAsyncIfNecessary(bool isReplacementReplica = false) #endif // Start the task handling scheduling exceptions - Exception exception = Common.StartTaskSafe(_boundingState.TaskForInputProcessing, _source.DataflowBlockOptions.TaskScheduler); + Exception? exception = Common.StartTaskSafe(_boundingState.TaskForInputProcessing, _source.DataflowBlockOptions.TaskScheduler); if (exception != null) { // Get out from under currently held locks. CompleteCore re-acquires the locks it needs. - Task.Factory.StartNew(exc => CompleteCore(exception: (Exception)exc, storeExceptionEvenIfAlreadyCompleting: true, revertProcessingState: true), + Task.Factory.StartNew(exc => CompleteCore(exception: (Exception)exc!, storeExceptionEvenIfAlreadyCompleting: true, revertProcessingState: true), exception, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); } } @@ -358,7 +359,7 @@ private bool ConsumeAndStoreOneMessageIfAvailable() T consumedValue = sourceAndMessage.Key.ConsumeMessage(sourceAndMessage.Value, this, out consumed); if (consumed) { - _source.AddMessage(consumedValue); + _source.AddMessage(consumedValue!); return true; } } @@ -389,10 +390,10 @@ private void CompleteTargetIfPossible() { Task.Factory.StartNew(state => { - var thisBufferBlock = (BufferBlock)state; + var thisBufferBlock = (BufferBlock)state!; // Release any postponed messages - List exceptions = null; + List? exceptions = null; if (thisBufferBlock._boundingState != null) { // Note: No locks should be held at this point @@ -456,7 +457,7 @@ public DebugView(BufferBlock bufferBlock) } /// Gets the collection of postponed message headers. - public QueuedMap, DataflowMessageHeader> PostponedMessages + public QueuedMap, DataflowMessageHeader>? PostponedMessages { get { return _bufferBlock._boundingState != null ? _bufferBlock._boundingState.PostponedMessages : null; } } @@ -464,9 +465,9 @@ public QueuedMap, DataflowMessageHeader> PostponedMessages public IEnumerable Queue { get { return _sourceDebuggingInformation.OutputQueue; } } /// The task used to process messages. - public Task TaskForInputProcessing { get { return _bufferBlock._boundingState != null ? _bufferBlock._boundingState.TaskForInputProcessing : null; } } + public Task? TaskForInputProcessing { get { return _bufferBlock._boundingState != null ? _bufferBlock._boundingState.TaskForInputProcessing : null; } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } /// Gets the DataflowBlockOptions used to configure this block. public DataflowBlockOptions DataflowBlockOptions { get { return _sourceDebuggingInformation.DataflowBlockOptions; } } @@ -481,7 +482,7 @@ public QueuedMap, DataflowMessageHeader> PostponedMessages /// Gets the set of all targets linked from this block. public TargetRegistry LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } } /// Gets the set of all targets linked from this block. - public ITargetBlock NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } + public ITargetBlock? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } } } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/JoinBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/JoinBlock.cs index b5d405247ed6e1..9d8b1ad79d64c5 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/JoinBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/JoinBlock.cs @@ -57,7 +57,7 @@ public JoinBlock(GroupingDataflowBlockOptions dataflowBlockOptions) dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone(); // Initialize bounding state if necessary - Action>, int> onItemsRemoved = null; + Action>, int>? onItemsRemoved = null; if (dataflowBlockOptions.BoundedCapacity > 0) onItemsRemoved = (owningSource, count) => ((JoinBlock)owningSource)._sharedResources.OnItemsRemoved(count); // Configure the source @@ -93,14 +93,14 @@ public JoinBlock(GroupingDataflowBlockOptions dataflowBlockOptions) // to handle multiple completion requests and to carry over only one. _source.Completion.ContinueWith((completed, state) => { - var thisBlock = ((JoinBlock)state) as IDataflowBlock; + var thisBlock = ((JoinBlock)state!) as IDataflowBlock; Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion."); - thisBlock.Fault(completed.Exception); + thisBlock.Fault(completed.Exception!); }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, _source.Completion, state => ((JoinBlock)state)._sharedResources.CompleteEachTarget(), this); + dataflowBlockOptions.CancellationToken, _source.Completion, state => ((JoinBlock)state!)._sharedResources.CompleteEachTarget(), this); #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; if (etwLog.IsEnabled()) @@ -117,13 +117,15 @@ public IDisposable LinkTo(ITargetBlock> target, DataflowLinkOption } /// - public bool TryReceive(Predicate> filter, out Tuple item) +#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470 + public bool TryReceive(Predicate>? filter, [NotNullWhen(true)] out Tuple? item) +#pragma warning restore CS8614 { return _source.TryReceive(filter, out item); } /// - public bool TryReceiveAll(out IList> items) { return _source.TryReceiveAll(out items); } + public bool TryReceiveAll([NotNullWhen(true)] out IList>? items) { return _source.TryReceiveAll(out items); } /// public int OutputCount { get { return _source.OutputCount; } } @@ -164,7 +166,9 @@ void IDataflowBlock.Fault(Exception exception) public ITargetBlock Target2 { get { return _target2; } } /// - Tuple ISourceBlock>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock> target, out bool messageConsumed) +#pragma warning disable CS8616 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470 + Tuple? ISourceBlock>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock> target, out bool messageConsumed) +#pragma warning restore CS8616 { return _source.ConsumeMessage(messageHeader, target, out messageConsumed); } @@ -223,9 +227,9 @@ public DebugView(JoinBlock joinBlock) public long JoinsCreated { get { return _joinBlock._sharedResources._joinsCreated; } } /// Gets the task being used for input processing. - public Task TaskForInputProcessing { get { return _joinBlock._sharedResources._taskForInputProcessing; } } + public Task? TaskForInputProcessing { get { return _joinBlock._sharedResources._taskForInputProcessing; } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } /// Gets the GroupingDataflowBlockOptions used to configure this block. public GroupingDataflowBlockOptions DataflowBlockOptions { get { return (GroupingDataflowBlockOptions)_sourceDebuggingInformation.DataflowBlockOptions; } } @@ -244,7 +248,7 @@ public DebugView(JoinBlock joinBlock) /// Gets the set of all targets linked from this block. public TargetRegistry> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } } /// Gets the set of all targets linked from this block. - public ITargetBlock> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } + public ITargetBlock>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } } } @@ -287,7 +291,7 @@ public JoinBlock(GroupingDataflowBlockOptions dataflowBlockOptions) dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone(); // Initialize bounding state if necessary - Action>, int> onItemsRemoved = null; + Action>, int>? onItemsRemoved = null; if (dataflowBlockOptions.BoundedCapacity > 0) onItemsRemoved = (owningSource, count) => ((JoinBlock)owningSource)._sharedResources.OnItemsRemoved(count); // Configure the source @@ -321,14 +325,14 @@ public JoinBlock(GroupingDataflowBlockOptions dataflowBlockOptions) // to handle multiple completion requests and to carry over only one. _source.Completion.ContinueWith((completed, state) => { - var thisBlock = ((JoinBlock)state) as IDataflowBlock; + var thisBlock = ((JoinBlock)state!) as IDataflowBlock; Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion."); - thisBlock.Fault(completed.Exception); + thisBlock.Fault(completed.Exception!); }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, _source.Completion, state => ((JoinBlock)state)._sharedResources.CompleteEachTarget(), this); + dataflowBlockOptions.CancellationToken, _source.Completion, state => ((JoinBlock)state!)._sharedResources.CompleteEachTarget(), this); #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; if (etwLog.IsEnabled()) @@ -345,13 +349,15 @@ public IDisposable LinkTo(ITargetBlock> target, DataflowLinkOp } /// - public bool TryReceive(Predicate> filter, out Tuple item) +#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470 + public bool TryReceive(Predicate>? filter, [NotNullWhen(true)] out Tuple? item) +#pragma warning restore CS8614 { return _source.TryReceive(filter, out item); } /// - public bool TryReceiveAll(out IList> items) { return _source.TryReceiveAll(out items); } + public bool TryReceiveAll([NotNullWhen(true)] out IList>? items) { return _source.TryReceiveAll(out items); } /// public int OutputCount { get { return _source.OutputCount; } } @@ -397,7 +403,9 @@ void IDataflowBlock.Fault(Exception exception) public ITargetBlock Target3 { get { return _target3; } } /// - Tuple ISourceBlock>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock> target, out bool messageConsumed) +#pragma warning disable CS8616 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470 + Tuple? ISourceBlock>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock> target, out bool messageConsumed) +#pragma warning restore CS8616 { return _source.ConsumeMessage(messageHeader, target, out messageConsumed); } @@ -456,9 +464,9 @@ public DebugView(JoinBlock joinBlock) public long JoinsCreated { get { return _joinBlock._sharedResources._joinsCreated; } } /// Gets the task being used for input processing. - public Task TaskForInputProcessing { get { return _joinBlock._sharedResources._taskForInputProcessing; } } + public Task? TaskForInputProcessing { get { return _joinBlock._sharedResources._taskForInputProcessing; } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } /// Gets the GroupingDataflowBlockOptions used to configure this block. public GroupingDataflowBlockOptions DataflowBlockOptions { get { return (GroupingDataflowBlockOptions)_sourceDebuggingInformation.DataflowBlockOptions; } } @@ -479,7 +487,7 @@ public DebugView(JoinBlock joinBlock) /// Gets the set of all targets linked from this block. public TargetRegistry> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } } /// Gets the set of all targets linked from this block. - public ITargetBlock> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } + public ITargetBlock>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } } } } @@ -497,9 +505,9 @@ internal sealed class JoinBlockTarget : JoinBlockTargetBase, ITargetBlock, /// A task representing the completion of the block. private readonly TaskCompletionSource _completionTask = new TaskCompletionSource(); /// Input messages for the next batch. - private readonly Queue _messages; + private readonly Queue? _messages; /// State used when in non-greedy mode. - private readonly NonGreedyState _nonGreedy; + private readonly NonGreedyState? _nonGreedy; /// Whether this target is declining future messages. private bool _decliningPermanently; @@ -540,9 +548,9 @@ internal T GetOneMessage() } else { - Debug.Assert(_nonGreedy.ConsumedMessage.Key, "A message must have been consumed by this point."); + Debug.Assert(_nonGreedy!.ConsumedMessage.Key, "A message must have been consumed by this point."); T value = _nonGreedy.ConsumedMessage.Value; - _nonGreedy.ConsumedMessage = new KeyValuePair(false, default(T)); + _nonGreedy.ConsumedMessage = new KeyValuePair(false, default(T)!); return value; } } @@ -570,7 +578,7 @@ internal override bool HasAtLeastOneMessageAvailable } else { - return _nonGreedy.ConsumedMessage.Key; + return _nonGreedy!.ConsumedMessage.Key; } } } @@ -591,7 +599,7 @@ internal override int NumberOfMessagesAvailableOrPostponed get { Common.ContractAssertMonitorStatus(_sharedResources.IncomingLock, held: true); - return !_sharedResources._dataflowBlockOptions.Greedy ? _nonGreedy.PostponedMessages.Count : _messages.Count; + return !_sharedResources._dataflowBlockOptions.Greedy ? _nonGreedy!.PostponedMessages.Count : _messages!.Count; } } @@ -604,7 +612,7 @@ internal override bool HasTheHighestNumberOfMessagesAvailable Common.ContractAssertMonitorStatus(_sharedResources.IncomingLock, held: true); // Note: If there is a tie, we must return true - int count = _messages.Count; + int count = _messages!.Count; foreach (JoinBlockTargetBase target in _sharedResources._targets) if (target != this && target.NumberOfMessagesAvailableOrPostponed > count) return false; // Strictly bigger! @@ -628,7 +636,7 @@ internal override bool ReserveOneMessage() // While we are holding the lock, try to pop a postponed message. // If there are no postponed messages, we can't do anything. - if (!_nonGreedy.PostponedMessages.TryPop(out next)) return false; + if (!_nonGreedy!.PostponedMessages.TryPop(out next)) return false; } // We'll bail out of this loop either when we have reserved a message (true) @@ -658,7 +666,7 @@ internal override bool ConsumeReservedMessage() { Common.ContractAssertMonitorStatus(_sharedResources.IncomingLock, held: false); Debug.Assert(!_sharedResources._dataflowBlockOptions.Greedy, "This is only used in non-greedy mode"); - Debug.Assert(_nonGreedy.ReservedMessage.Key != null, "This target must have a reserved message"); + Debug.Assert(_nonGreedy!.ReservedMessage.Key != null, "This target must have a reserved message"); bool consumed; T consumedValue = _nonGreedy.ReservedMessage.Key.ConsumeMessage(_nonGreedy.ReservedMessage.Value, this, out consumed); @@ -685,7 +693,7 @@ internal override bool ConsumeReservedMessage() { // Now that we've consumed it, store its data. Debug.Assert(!_nonGreedy.ConsumedMessage.Key, "There must be no other consumed message"); - _nonGreedy.ConsumedMessage = new KeyValuePair(true, consumedValue); + _nonGreedy.ConsumedMessage = new KeyValuePair(true, consumedValue!); // We don't account bounding per target in non-greedy mode. We do it once per batch (in the loop). CompleteIfLastJoinIsFeasible(); @@ -716,7 +724,7 @@ internal override bool ConsumeOnePostponedMessage() hasTheHighestNumberOfMessagesAvailable = HasTheHighestNumberOfMessagesAvailable; bool boundingCapacityAvailable = _sharedResources._boundingState.CountIsLessThanBound || !hasTheHighestNumberOfMessagesAvailable; if (_decliningPermanently || _sharedResources._decliningPermanently || - !boundingCapacityAvailable || !_nonGreedy.PostponedMessages.TryPop(out next)) + !boundingCapacityAvailable || !_nonGreedy!.PostponedMessages.TryPop(out next)) return false; } @@ -729,7 +737,7 @@ internal override bool ConsumeOnePostponedMessage() { // The ranking in highest number of available messages cannot have changed because this task is causing OfferMessage to postpone if (hasTheHighestNumberOfMessagesAvailable) _sharedResources._boundingState.CurrentCount += 1; // track this new item against our bound - _messages.Enqueue(consumedValue); + _messages!.Enqueue(consumedValue!); CompleteIfLastJoinIsFeasible(); return true; @@ -746,8 +754,8 @@ private void CompleteIfLastJoinIsFeasible() { Common.ContractAssertMonitorStatus(_sharedResources.IncomingLock, held: true); int messageCount = _sharedResources._dataflowBlockOptions.Greedy ? - _messages.Count : - _nonGreedy.ConsumedMessage.Key ? 1 : 0; + _messages!.Count : + _nonGreedy!.ConsumedMessage.Key ? 1 : 0; if ((_sharedResources._joinsCreated + messageCount) >= _sharedResources._dataflowBlockOptions.ActualMaxNumberOfGroups) { _decliningPermanently = true; @@ -806,7 +814,7 @@ internal override void CompleteOncePossible() } // Release any postponed messages - List exceptions = null; + List? exceptions = null; if (_nonGreedy != null) { // Note: No locks should be held at this point @@ -830,7 +838,7 @@ internal override void CompleteOncePossible() } /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { // Validate arguments if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); @@ -855,7 +863,7 @@ DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader message (_sharedResources._boundingState == null || ((_sharedResources._boundingState.CountIsLessThanBound || !HasTheHighestNumberOfMessagesAvailable) && - _nonGreedy.PostponedMessages.Count == 0 && _sharedResources._taskForInputProcessing == null))) + _nonGreedy!.PostponedMessages.Count == 0 && _sharedResources._taskForInputProcessing == null))) { if (consumeToAccept) { @@ -866,7 +874,7 @@ DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader message if (!consumed) return DataflowMessageStatus.NotAvailable; } if (_sharedResources._boundingState != null && HasTheHighestNumberOfMessagesAvailable) _sharedResources._boundingState.CurrentCount += 1; // track this new item against our bound - _messages.Enqueue(messageValue); + _messages!.Enqueue(messageValue!); CompleteIfLastJoinIsFeasible(); // Since we're in greedy mode, we can skip asynchronous processing and @@ -899,7 +907,7 @@ DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader message /// In general, it is not safe to pass releaseReservedMessages:true, because releasing of reserved messages /// is done without taking a lock. We pass releaseReservedMessages:true only when an exception has been /// caught inside the message processing loop which is a single instance at any given moment. - internal override void CompleteCore(Exception exception, bool dropPendingMessages, bool releaseReservedMessages) + internal override void CompleteCore(Exception? exception, bool dropPendingMessages, bool releaseReservedMessages) { bool greedy = _sharedResources._dataflowBlockOptions.Greedy; lock (_sharedResources.IncomingLock) @@ -954,7 +962,7 @@ void IDataflowBlock.Fault(Exception exception) internal Task CompletionTaskInternal { get { return _completionTask.Task; } } /// Gets the number of messages waiting to be processed. This must only be used from the debugger as it avoids taking necessary locks. - private int InputCountForDebugger { get { return _messages != null ? _messages.Count : _nonGreedy.ConsumedMessage.Key ? 1 : 0; } } + private int InputCountForDebugger { get { return _messages != null ? _messages.Count : _nonGreedy!.ConsumedMessage.Key ? 1 : 0; } } /// The data to display in the debugger display attribute. private object DebuggerDisplayContent @@ -986,7 +994,7 @@ public DebugView(JoinBlockTarget joinBlockTarget) } /// Gets the messages waiting to be processed. - public IEnumerable InputQueue { get { return _joinBlockTarget._messages; } } + public IEnumerable? InputQueue { get { return _joinBlockTarget._messages; } } /// Gets whether the block is declining further messages. public bool IsDecliningPermanently { get { return _joinBlockTarget._decliningPermanently || _joinBlockTarget._sharedResources._decliningPermanently; } } } @@ -1023,7 +1031,7 @@ internal abstract class JoinBlockTargetBase /// Access point to the corresponding API method. public void Complete() { CompleteCore(exception: null, dropPendingMessages: false, releaseReservedMessages: false); } /// Internal implementation of the corresponding API method. - internal abstract void CompleteCore(Exception exception, bool dropPendingMessages, bool releaseReservedMessages); + internal abstract void CompleteCore(Exception? exception, bool dropPendingMessages, bool releaseReservedMessages); /// Completes the target. internal abstract void CompleteOncePossible(); } @@ -1075,11 +1083,11 @@ internal JoinBlockTargetSharedResources( /// The options for the join. internal readonly GroupingDataflowBlockOptions _dataflowBlockOptions; /// Bounding state for when the block is executing in bounded mode. - internal readonly BoundingState _boundingState; + internal readonly BoundingState? _boundingState; /// Whether all targets should decline all further messages. internal bool _decliningPermanently; /// The task used to process messages. - internal Task _taskForInputProcessing; + internal Task? _taskForInputProcessing; /// Whether any exceptions have been generated and stored into the source core. internal bool _hasExceptions; /// The number of joins this block has created. @@ -1286,7 +1294,7 @@ private void ProcessAsyncIfNecessary_Slow(bool isReplacementReplica) // Create task and store into _taskForInputProcessing prior to scheduling the task // so that _taskForInputProcessing will be visibly set in the task loop. - _taskForInputProcessing = new Task(thisSharedResources => ((JoinBlockTargetSharedResources)thisSharedResources).ProcessMessagesLoopCore(), this, + _taskForInputProcessing = new Task(thisSharedResources => ((JoinBlockTargetSharedResources)thisSharedResources!).ProcessMessagesLoopCore(), this, Common.GetCreationOptionsForTask(isReplacementReplica)); #if FEATURE_TRACING @@ -1300,7 +1308,7 @@ private void ProcessAsyncIfNecessary_Slow(bool isReplacementReplica) #endif // Start the task handling scheduling exceptions - Exception exception = Common.StartTaskSafe(_taskForInputProcessing, _dataflowBlockOptions.TaskScheduler); + Exception? exception = Common.StartTaskSafe(_taskForInputProcessing, _dataflowBlockOptions.TaskScheduler); if (exception != null) { // All of the following actions must be performed under the lock. @@ -1354,7 +1362,7 @@ internal void CompleteBlockIfPossible() // Complete each target asynchronously so as not to invoke synchronous continuations under a lock Task.Factory.StartNew(state => { - var sharedResources = (JoinBlockTargetSharedResources)state; + var sharedResources = (JoinBlockTargetSharedResources)state!; foreach (JoinBlockTargetBase target in sharedResources._targets) target.CompleteOncePossible(); }, this, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformBlock.cs index 1dacf7e0d9ad72..c79e9db5552710 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformBlock.cs @@ -28,7 +28,7 @@ public sealed class TransformBlock : IPropagatorBlockThe target side. private readonly TargetCore _target; /// Buffer used to reorder outputs that may have completed out-of-order between the target half and the source half. - private readonly ReorderingBuffer _reorderingBuffer; + private readonly ReorderingBuffer? _reorderingBuffer; /// The source side. private readonly SourceCore _source; @@ -89,7 +89,7 @@ public TransformBlock(Func> transform, ExecutionDataflowBl /// The options with which to configure this . /// The and are both null (Nothing in Visual Basic). /// The is null (Nothing in Visual Basic). - private TransformBlock(Func transformSync, Func> transformAsync, ExecutionDataflowBlockOptions dataflowBlockOptions) + private TransformBlock(Func? transformSync, Func>? transformAsync, ExecutionDataflowBlockOptions dataflowBlockOptions) { if (transformSync == null && transformAsync == null) throw new ArgumentNullException("transform"); if (dataflowBlockOptions == null) throw new ArgumentNullException(nameof(dataflowBlockOptions)); @@ -100,7 +100,7 @@ private TransformBlock(Func transformSync, Func, int> onItemsRemoved = null; + Action, int>? onItemsRemoved = null; if (dataflowBlockOptions.BoundedCapacity > 0) onItemsRemoved = (owningSource, count) => ((TransformBlock)owningSource)._target.ChangeBoundingCount(-count); @@ -138,8 +138,8 @@ private TransformBlock(Func transformSync, Func { - var sourceCore = (SourceCore)state; - if (completed.IsFaulted) sourceCore.AddAndUnwrapAggregateException(completed.Exception); + var sourceCore = (SourceCore)state!; + if (completed.IsFaulted) sourceCore.AddAndUnwrapAggregateException(completed.Exception!); sourceCore.Complete(); }, _source, CancellationToken.None, Common.GetContinuationOptions(), TaskScheduler.Default); @@ -149,14 +149,14 @@ private TransformBlock(Func transformSync, Func { - var thisBlock = ((TransformBlock)state) as IDataflowBlock; + var thisBlock = ((TransformBlock)state!) as IDataflowBlock; Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion."); - thisBlock.Fault(completed.Exception); + thisBlock.Fault(completed.Exception!); }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore)state).Complete(exception: null, dropPendingMessages: true), _target); + dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore)state!).Complete(exception: null, dropPendingMessages: true), _target); #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; if (etwLog.IsEnabled()) @@ -203,18 +203,18 @@ private void ProcessMessage(Func transform, KeyValuePair> transform, KeyVa Debug.Assert(transform != null, "Function to invoke is required."); // Run the transform function to get the task that represents the operation's completion - Task task = null; - Exception caughtException = null; + Task? task = null; + Exception? caughtException = null; try { task = transform(messageWithId.Key); @@ -257,7 +257,7 @@ private void ProcessMessageWithTask(Func> transform, KeyVa // Otherwise, join with the asynchronous operation when it completes. task.ContinueWith((completed, state) => { - var tuple = (Tuple, KeyValuePair>)state; + var tuple = (Tuple, KeyValuePair>)state!; tuple.Item1.AsyncCompleteProcessMessageWithTask(completed, tuple.Item2); }, Tuple.Create(this, messageWithId), CancellationToken.None, Common.GetContinuationOptions(TaskContinuationOptions.ExecuteSynchronously), TaskScheduler.Default); @@ -285,7 +285,7 @@ private void AsyncCompleteProcessMessageWithTask(Task completed, KeyVal case TaskStatus.Faulted: // We must add the exception before declining and signaling completion, as the exception // is part of the operation, and the completion conditions depend on this. - AggregateException aggregate = completed.Exception; + AggregateException aggregate = completed.Exception!; Common.StoreDataflowMessageValueIntoExceptionData(aggregate, messageWithId.Key, targetInnerExceptions: true); _target.Complete(aggregate, dropPendingMessages: true, storeExceptionEvenIfAlreadyCompleting: true, unwrapInnerExceptions: true); break; @@ -307,13 +307,13 @@ private void AsyncCompleteProcessMessageWithTask(Task completed, KeyVal { if (_target.DataflowBlockOptions.MaxDegreeOfParallelism == 1) { - _source.AddMessage(outputItem); + _source.AddMessage(outputItem!); } else { lock (ParallelSourceLock) { - _source.AddMessage(outputItem); + _source.AddMessage(outputItem!); } } } @@ -321,7 +321,7 @@ private void AsyncCompleteProcessMessageWithTask(Task completed, KeyVal // Otherwise, there's a reordering buffer, so add to it instead. // Even if something goes wrong, we need to update the // reordering buffer, so it knows that an item isn't missing. - else _reorderingBuffer.AddItem(messageWithId.Value, outputItem, itemIsValid: gotOutputItem); + else _reorderingBuffer.AddItem(messageWithId.Value, outputItem!, itemIsValid: gotOutputItem); // Let the target know that one of the asynchronous operations it launched has completed. _target.SignalOneAsyncMessageCompleted(); @@ -345,13 +345,13 @@ public IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions link } /// - public bool TryReceive(Predicate filter, out TOutput item) + public bool TryReceive(Predicate? filter, [MaybeNullWhen(false)] out TOutput item) { return _source.TryReceive(filter, out item); } /// - public bool TryReceiveAll(out IList items) { return _source.TryReceiveAll(out items); } + public bool TryReceiveAll([NotNullWhen(true)] out IList? items) { return _source.TryReceiveAll(out items); } /// public Task Completion { get { return _source.Completion; } } @@ -363,12 +363,13 @@ public bool TryReceive(Predicate filter, out TOutput item) public int OutputCount { get { return _source.OutputCount; } } /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock? source, bool consumeToAccept) { return _target.OfferMessage(messageHeader, messageValue, source, consumeToAccept); } /// + [return: MaybeNull] TOutput ISourceBlock.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { return _source.ConsumeMessage(messageHeader, target, out messageConsumed); @@ -431,14 +432,14 @@ public DebugView(TransformBlock transformBlock) /// Gets the messages waiting to be processed. public IEnumerable InputQueue { get { return _targetDebuggingInformation.InputQueue; } } /// Gets any postponed messages. - public QueuedMap, DataflowMessageHeader> PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } } + public QueuedMap, DataflowMessageHeader>? PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } } /// Gets the messages waiting to be received. public IEnumerable OutputQueue { get { return _sourceDebuggingInformation.OutputQueue; } } /// Gets the number of outstanding input operations. public int CurrentDegreeOfParallelism { get { return _targetDebuggingInformation.CurrentDegreeOfParallelism; } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } /// Gets the DataflowBlockOptions used to configure this block. public ExecutionDataflowBlockOptions DataflowBlockOptions { get { return _targetDebuggingInformation.DataflowBlockOptions; } } @@ -452,7 +453,7 @@ public DebugView(TransformBlock transformBlock) /// Gets the set of all targets linked from this block. public TargetRegistry LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } } /// Gets the target that holds a reservation on the next message, if any. - public ITargetBlock NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } + public ITargetBlock? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } } } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformManyBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformManyBlock.cs index 612ac2dfd81675..ef4b5dfa5d624b 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformManyBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformManyBlock.cs @@ -33,7 +33,7 @@ public sealed class TransformManyBlock : IPropagatorBlock - private readonly ReorderingBuffer> _reorderingBuffer; + private readonly ReorderingBuffer>? _reorderingBuffer; /// The source side. private readonly SourceCore _source; @@ -97,7 +97,7 @@ public TransformManyBlock(Func>> transform, Ex /// The options with which to configure this . /// The and are both null (Nothing in Visual Basic). /// The is null (Nothing in Visual Basic). - private TransformManyBlock(Func> transformSync, Func>> transformAsync, ExecutionDataflowBlockOptions dataflowBlockOptions) + private TransformManyBlock(Func>? transformSync, Func>>? transformAsync, ExecutionDataflowBlockOptions dataflowBlockOptions) { // Validate arguments. It's ok for the filterFunction to be null, but not the other parameters. if (transformSync == null && transformAsync == null) throw new ArgumentNullException("transform"); @@ -109,7 +109,7 @@ private TransformManyBlock(Func> transformSync, Fun dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone(); // Initialize onItemsRemoved delegate if necessary - Action, int> onItemsRemoved = null; + Action, int>? onItemsRemoved = null; if (dataflowBlockOptions.BoundedCapacity > 0) onItemsRemoved = (owningSource, count) => ((TransformManyBlock)owningSource)._target.ChangeBoundingCount(-count); @@ -155,8 +155,8 @@ private TransformManyBlock(Func> transformSync, Fun // we know for certain that no more messages will need to be sent to the source. _target.Completion.ContinueWith((completed, state) => { - var sourceCore = (SourceCore)state; - if (completed.IsFaulted) sourceCore.AddAndUnwrapAggregateException(completed.Exception); + var sourceCore = (SourceCore)state!; + if (completed.IsFaulted) sourceCore.AddAndUnwrapAggregateException(completed.Exception!); sourceCore.Complete(); }, _source, CancellationToken.None, Common.GetContinuationOptions(), TaskScheduler.Default); @@ -166,14 +166,14 @@ private TransformManyBlock(Func> transformSync, Fun // to handle multiple completion requests and to carry over only one. _source.Completion.ContinueWith((completed, state) => { - var thisBlock = ((TransformManyBlock)state) as IDataflowBlock; + var thisBlock = ((TransformManyBlock)state!) as IDataflowBlock; Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion."); - thisBlock.Fault(completed.Exception); + thisBlock.Fault(completed.Exception!); }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore)state).Complete(exception: null, dropPendingMessages: true), _target); + dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore)state!).Complete(exception: null, dropPendingMessages: true), _target); #if FEATURE_TRACING DataflowEtwProvider etwLog = DataflowEtwProvider.Log; if (etwLog.IsEnabled()) @@ -219,8 +219,8 @@ private void ProcessMessageWithTask(Func>> fun Debug.Assert(function != null, "Function to invoke is required."); // Run the transform function to get the resulting task - Task> task = null; - Exception caughtException = null; + Task>? task = null; + Exception? caughtException = null; try { task = function(messageWithId.Key); @@ -263,7 +263,7 @@ private void ProcessMessageWithTask(Func>> fun // scheduler as we'll be running user code through enumerating the returned enumerable. task.ContinueWith((completed, state) => { - var tuple = (Tuple, KeyValuePair>)state; + var tuple = (Tuple, KeyValuePair>)state!; tuple.Item1.AsyncCompleteProcessMessageWithTask(completed, tuple.Item2); }, Tuple.Create(this, messageWithId), CancellationToken.None, @@ -307,7 +307,7 @@ private void AsyncCompleteProcessMessageWithTask( case TaskStatus.Faulted: // We must add the exception before declining and signaling completion, as the exception // is part of the operation, and the completion conditions depend on this. - AggregateException aggregate = completed.Exception; + AggregateException aggregate = completed.Exception!; Common.StoreDataflowMessageValueIntoExceptionData(aggregate, messageWithId.Key, targetInnerExceptions: true); _target.Complete(aggregate, dropPendingMessages: true, storeExceptionEvenIfAlreadyCompleting: true, unwrapInnerExceptions: true); goto case TaskStatus.Canceled; @@ -331,7 +331,7 @@ private void AsyncCompleteProcessMessageWithTask( /// The message with id. /// The output items to be persisted. private void StoreOutputItems( - KeyValuePair messageWithId, IEnumerable outputItems) + KeyValuePair messageWithId, IEnumerable? outputItems) { // If there's a reordering buffer, pass the data along to it. // The reordering buffer will handle all details, including bounding. @@ -369,7 +369,7 @@ private void StoreOutputItems( /// Stores the next item using the reordering buffer. /// The ID of the item. /// The completed item. - private void StoreOutputItemsReordered(long id, IEnumerable item) + private void StoreOutputItemsReordered(long id, IEnumerable? item) { Debug.Assert(_reorderingBuffer != null, "Expected a reordering buffer"); Debug.Assert(id != Common.INVALID_REORDERING_ID, "This ID should never have been handed out."); @@ -381,7 +381,7 @@ private void StoreOutputItemsReordered(long id, IEnumerable item) // Handle invalid items (null enumerables) by delegating to the base if (item == null) { - _reorderingBuffer.AddItem(id, null, false); + _reorderingBuffer.AddItem(id, null!, false); if (isBounded) target.ChangeBoundingCount(count: -1); return; } @@ -390,7 +390,7 @@ private void StoreOutputItemsReordered(long id, IEnumerable item) // This avoids the cost of updating it once per output item (since each update requires synchronization). // Even if we're not bounding, we still want to determine whether the item is trusted so that we // can immediately dump it out once we take the lock if we're the next item. - IList itemAsTrustedList = item as TOutput[]; + IList? itemAsTrustedList = item as TOutput[]; if (itemAsTrustedList == null) itemAsTrustedList = item as List; if (itemAsTrustedList != null && isBounded) { @@ -407,7 +407,7 @@ private void StoreOutputItemsReordered(long id, IEnumerable item) // By this point, either we're not the next item, in which case we need to make a copy of the // data and store it, or we are the next item and can store it immediately but we need to enumerate // the items and store them individually because we don't want to enumerate while holding a lock. - List itemCopy = null; + List? itemCopy = null; try { // If this is the next item, we can output it now. @@ -581,10 +581,10 @@ void IDataflowBlock.Fault(Exception exception) public IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions linkOptions) { return _source.LinkTo(target, linkOptions); } /// - public bool TryReceive(Predicate filter, out TOutput item) { return _source.TryReceive(filter, out item); } + public bool TryReceive(Predicate? filter, [MaybeNullWhen(false)] out TOutput item) { return _source.TryReceive(filter, out item); } /// - public bool TryReceiveAll(out IList items) { return _source.TryReceiveAll(out items); } + public bool TryReceiveAll([NotNullWhen(true)] out IList? items) { return _source.TryReceiveAll(out items); } /// public Task Completion { get { return _source.Completion; } } @@ -596,12 +596,13 @@ void IDataflowBlock.Fault(Exception exception) public int OutputCount { get { return _source.OutputCount; } } /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock? source, bool consumeToAccept) { return _target.OfferMessage(messageHeader, messageValue, source, consumeToAccept); } /// + [return: MaybeNull] TOutput ISourceBlock.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { return _source.ConsumeMessage(messageHeader, target, out messageConsumed); @@ -664,14 +665,14 @@ public DebugView(TransformManyBlock transformManyBlock) /// Gets the messages waiting to be processed. public IEnumerable InputQueue { get { return _targetDebuggingInformation.InputQueue; } } /// Gets any postponed messages. - public QueuedMap, DataflowMessageHeader> PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } } + public QueuedMap, DataflowMessageHeader>? PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } } /// Gets the messages waiting to be received. public IEnumerable OutputQueue { get { return _sourceDebuggingInformation.OutputQueue; } } /// Gets the number of input operations currently in flight. public int CurrentDegreeOfParallelism { get { return _targetDebuggingInformation.CurrentDegreeOfParallelism; } } /// Gets the task being used for output processing. - public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } + public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } } /// Gets the DataflowBlockOptions used to configure this block. public ExecutionDataflowBlockOptions DataflowBlockOptions { get { return _targetDebuggingInformation.DataflowBlockOptions; } } @@ -685,7 +686,7 @@ public DebugView(TransformManyBlock transformManyBlock) /// Gets the set of all targets linked from this block. public TargetRegistry LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } } /// Gets the set of all targets linked from this block. - public ITargetBlock NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } + public ITargetBlock? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } } } } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/WriteOnceBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/WriteOnceBlock.cs index 8a0b29da851d83..b588a7d1c7fe5f 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/WriteOnceBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/WriteOnceBlock.cs @@ -28,11 +28,11 @@ public sealed class WriteOnceBlock : IPropagatorBlock, IReceivableSourc /// A registry used to store all linked targets and information about them. private readonly TargetRegistry _targetRegistry; /// The cloning function. - private readonly Func _cloningFunction; + private readonly Func? _cloningFunction; /// The options used to configure this block's execution. private readonly DataflowBlockOptions _dataflowBlockOptions; /// Lazily initialized task completion source that produces the actual completion task when needed. - private TaskCompletionSource _lazyCompletionTaskSource; + private TaskCompletionSource? _lazyCompletionTaskSource; /// Whether all future messages should be declined. private bool _decliningPermanently; /// Whether block completion is disallowed. @@ -40,7 +40,8 @@ public sealed class WriteOnceBlock : IPropagatorBlock, IReceivableSourc /// The header of the singly-assigned value. private DataflowMessageHeader _header; /// The singly-assigned value. - private T _value; + [AllowNull, MaybeNull] + private T _value = default; /// Gets the object used as the value lock. private object ValueLock { get { return _targetRegistry; } } @@ -50,7 +51,7 @@ public sealed class WriteOnceBlock : IPropagatorBlock, IReceivableSourc /// The function to use to clone the data when offered to other blocks. /// This may be null to indicate that no cloning need be performed. /// - public WriteOnceBlock(Func cloningFunction) : + public WriteOnceBlock(Func? cloningFunction) : this(cloningFunction, DataflowBlockOptions.Default) { } @@ -61,7 +62,7 @@ public WriteOnceBlock(Func cloningFunction) : /// /// The options with which to configure this . /// The is null (Nothing in Visual Basic). - public WriteOnceBlock(Func cloningFunction, DataflowBlockOptions dataflowBlockOptions) + public WriteOnceBlock(Func? cloningFunction, DataflowBlockOptions dataflowBlockOptions) { // Validate arguments if (dataflowBlockOptions == null) throw new ArgumentNullException(nameof(dataflowBlockOptions)); @@ -94,7 +95,7 @@ public WriteOnceBlock(Func cloningFunction, DataflowBlockOptions dataflowB { // Handle async cancellation requests by declining on the target Common.WireCancellationToComplete( - dataflowBlockOptions.CancellationToken, _lazyCompletionTaskSource.Task, state => ((WriteOnceBlock)state).Complete(), this); + dataflowBlockOptions.CancellationToken, _lazyCompletionTaskSource.Task, state => ((WriteOnceBlock)state!).Complete(), this); } } #if FEATURE_TRACING @@ -110,7 +111,7 @@ public WriteOnceBlock(Func cloningFunction, DataflowBlockOptions dataflowB /// /// This must only be called once all of the completion conditions are met. /// - private void CompleteBlockAsync(IList exceptions) + private void CompleteBlockAsync(IList? exceptions) { Debug.Assert(_decliningPermanently, "We may get here only after we have started to decline permanently."); Debug.Assert(_completionReserved, "We may get here only after we have reserved completion."); @@ -121,7 +122,7 @@ private void CompleteBlockAsync(IList exceptions) if (exceptions == null) { // Offer the message to any linked targets and complete the block asynchronously to avoid blocking the caller - var taskForOutputProcessing = new Task(state => ((WriteOnceBlock)state).OfferToTargetsAndCompleteBlock(), this, + var taskForOutputProcessing = new Task(state => ((WriteOnceBlock)state!).OfferToTargetsAndCompleteBlock(), this, Common.GetCreationOptionsForTask()); #if FEATURE_TRACING @@ -134,7 +135,7 @@ private void CompleteBlockAsync(IList exceptions) #endif // Start the task handling scheduling exceptions - Exception exception = Common.StartTaskSafe(taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler); + Exception? exception = Common.StartTaskSafe(taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler); if (exception != null) CompleteCore(exception, storeExceptionEvenIfAlreadyCompleting: true); } else @@ -142,7 +143,7 @@ private void CompleteBlockAsync(IList exceptions) // Complete the block asynchronously to avoid blocking the caller Task.Factory.StartNew(state => { - Tuple, IList> blockAndList = (Tuple, IList>)state; + Tuple, IList> blockAndList = (Tuple, IList>)state!; blockAndList.Item1.CompleteBlock(blockAndList.Item2); }, Tuple.Create(this, exceptions), CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); @@ -159,7 +160,7 @@ private void OfferToTargetsAndCompleteBlock() // could be faulty and throw an exception. OfferToTargets creates a // list of all such exceptions and returns it. // If _value is null, OfferToTargets does nothing. - List exceptions = OfferToTargets(); + List? exceptions = OfferToTargets(); CompleteBlock(exceptions); } @@ -167,7 +168,7 @@ private void OfferToTargetsAndCompleteBlock() /// /// This is called only once. /// - private void CompleteBlock(IList exceptions) + private void CompleteBlock(IList? exceptions) { // Do not invoke the CompletionTaskSource property if there is a chance that _lazyCompletionTaskSource // has not been initialized yet and we may have to complete normally, because that would defeat the @@ -176,7 +177,7 @@ private void CompleteBlock(IList exceptions) Debug.Assert(_lazyCompletionTaskSource == null || !_lazyCompletionTaskSource.Task.IsCompleted, "The task completion source must not be completed. This must be the only thread that ever completes the block."); // Save the linked list of targets so that it could be traversed later to propagate completion - TargetRegistry.LinkedTargetInfo linkedTargets = _targetRegistry.ClearEntryPoints(); + TargetRegistry.LinkedTargetInfo? linkedTargets = _targetRegistry.ClearEntryPoints(); // Complete the block's completion task if (exceptions != null && exceptions.Count > 0) @@ -224,7 +225,7 @@ public void Complete() CompleteCore(exception: null, storeExceptionEvenIfAlreadyCompleting: false); } - private void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyCompleting) + private void CompleteCore(Exception? exception, bool storeExceptionEvenIfAlreadyCompleting) { Debug.Assert(exception != null || !storeExceptionEvenIfAlreadyCompleting, "When storeExceptionEvenIfAlreadyCompleting is set to true, an exception must be provided."); @@ -249,7 +250,7 @@ private void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyC // there's nothing more this block needs to do... complete it if we just reserved completion. if (thisThreadReservedCompletion) { - List exceptions = null; + List? exceptions = null; if (exception != null) { exceptions = new List(); @@ -261,7 +262,7 @@ private void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyC } /// - public bool TryReceive(Predicate filter, out T item) + public bool TryReceive(Predicate? filter, [MaybeNullWhen(false)] out T item) { // No need to take the outgoing lock, as we don't need to synchronize with other // targets, and _value only ever goes from null to non-null, not the other way around. @@ -269,9 +270,9 @@ public bool TryReceive(Predicate filter, out T item) // If we have a value, give it up. All receives on a successfully // completed WriteOnceBlock will return true, as long as the message // passes the filter (all messages pass a null filter). - if (_header.IsValid && (filter == null || filter(_value))) + if (_header.IsValid && (filter == null || filter(_value!))) { - item = CloneItem(_value); + item = CloneItem(_value!); return true; } // Otherwise, nothing to receive @@ -283,7 +284,7 @@ public bool TryReceive(Predicate filter, out T item) } /// - bool IReceivableSourceBlock.TryReceiveAll(out IList items) + bool IReceivableSourceBlock.TryReceiveAll([NotNullWhen(true)] out IList? items) { // Try to receive the one item this block may have. // If we can, give back an array of one item. Otherwise, @@ -327,7 +328,7 @@ public IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions linkOption if (hasValue) { bool useCloning = _cloningFunction != null; - target.OfferMessage(_header, _value, this, consumeToAccept: useCloning); + target.OfferMessage(_header, _value!, this, consumeToAccept: useCloning); } // If completion propagation has been requested, do it safely. @@ -341,7 +342,7 @@ public IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions linkOption public Task Completion { get { return CompletionTaskSource.Task; } } /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { // Validate arguments if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); @@ -358,7 +359,7 @@ DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader message if (consumeToAccept) { bool consumed; - messageValue = source.ConsumeMessage(messageHeader, this, out consumed); + messageValue = source!.ConsumeMessage(messageHeader, this, out consumed); if (!consumed) return DataflowMessageStatus.NotAvailable; } @@ -392,12 +393,12 @@ T ISourceBlock.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlo if (_header.Id == messageHeader.Id) { messageConsumed = true; - return CloneItem(_value); + return CloneItem(_value!); } else { messageConsumed = false; - return default(T); + return default(T)!; } } @@ -433,7 +434,7 @@ void ISourceBlock.ReleaseReservation(DataflowMessageHeader messageHeader, ITa // or not, nor do we care about any exceptions which may emerge (they should just propagate). Debug.Assert(_header.IsValid, "A valid header is required."); bool useCloning = _cloningFunction != null; - target.OfferMessage(_header, _value, this, consumeToAccept: useCloning); + target.OfferMessage(_header, _value!, this, consumeToAccept: useCloning); } /// Clones the item. @@ -447,20 +448,20 @@ private T CloneItem(T item) } /// Offers the WriteOnceBlock's message to all targets. - private List OfferToTargets() + private List? OfferToTargets() { Common.ContractAssertMonitorStatus(ValueLock, held: false); // If there is a message, offer it to everyone. Return values // don't matter, because we only get one message and then complete, // and everyone who wants a copy can get a copy. - List exceptions = null; + List? exceptions = null; if (HasValue) { - TargetRegistry.LinkedTargetInfo cur = _targetRegistry.FirstTargetNode; + TargetRegistry.LinkedTargetInfo? cur = _targetRegistry.FirstTargetNode; while (cur != null) { - TargetRegistry.LinkedTargetInfo next = cur.Next; + TargetRegistry.LinkedTargetInfo? next = cur.Next; ITargetBlock target = cur.Target; try { @@ -469,14 +470,14 @@ private List OfferToTargets() // the cloning function once we know they want the data. If there is no cloning // function, there's no reason for them to call back here. bool useCloning = _cloningFunction != null; - target.OfferMessage(_header, _value, this, consumeToAccept: useCloning); + target.OfferMessage(_header, _value!, this, consumeToAccept: useCloning); } catch (Exception exc) { // Track any erroneous exceptions that may occur // and return them to the caller so that they may // be logged in the completion task. - Common.StoreDataflowMessageValueIntoExceptionData(exc, _value); + Common.StoreDataflowMessageValueIntoExceptionData(exc, _value!); Common.AddException(ref exceptions, exc); } cur = next; @@ -506,6 +507,7 @@ private TaskCompletionSource CompletionTaskSource /// Gets whether the block is storing a value. private bool HasValue { get { return _header.IsValid; } } /// Gets the value being stored by the block. + [MaybeNull] private T Value { get { return _header.IsValid ? _value : default(T); } } /// @@ -545,6 +547,7 @@ public DebugView(WriteOnceBlock writeOnceBlock) /// Gets whether the WriteOnceBlock has a value. public bool HasValue { get { return _writeOnceBlock.HasValue; } } /// Gets the WriteOnceBlock's value if it has one, or default(T) if it doesn't. + [MaybeNull] public T Value { get { return _writeOnceBlock.Value; } } /// Gets the DataflowBlockOptions used to configure this block. diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ActionOnDispose.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ActionOnDispose.cs index bb87f432aef4c8..a3d004797d115b 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ActionOnDispose.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ActionOnDispose.cs @@ -66,7 +66,7 @@ private sealed class Disposable : IDisposable /// Second state argument. private readonly T2 _arg2; /// The action to run when disposed. Null if disposed. - private Action _action; + private Action? _action; /// Initializes the ActionOnDispose. /// The action to run when disposed. @@ -86,7 +86,7 @@ internal Disposable(Action action, T1 arg1, T2 arg2) /// Invoke the action. void IDisposable.Dispose() { - Action toRun = _action; + Action? toRun = _action; if (toRun != null && Interlocked.CompareExchange(ref _action, null, toRun) == toRun) { @@ -106,7 +106,7 @@ private sealed class Disposable : IDisposable /// Third state argument. private readonly T3 _arg3; /// The action to run when disposed. Null if disposed. - private Action _action; + private Action? _action; /// Initializes the ActionOnDispose. /// The action to run when disposed. @@ -128,7 +128,7 @@ internal Disposable(Action action, T1 arg1, T2 arg2, T3 arg3) /// Invoke the action. void IDisposable.Dispose() { - Action toRun = _action; + Action? toRun = _action; if (toRun != null && Interlocked.CompareExchange(ref _action, null, toRun) == toRun) { diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Common.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Common.cs index b915ca1bd2621b..61bd0e86a748c0 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Common.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Common.cs @@ -71,7 +71,7 @@ internal static void ContractAssertMonitorStatus(object syncObj, bool held) /// Output state for the predicate in order to avoid closure allocations. /// True if the predicate was evaluated and it returned true. False otherwise. internal static bool TryKeepAliveUntil(KeepAlivePredicate predicate, - TStateIn stateIn, out TStateOut stateOut) + TStateIn stateIn, [MaybeNullWhen(false)] out TStateOut stateOut) { Debug.Assert(predicate != null, "Non-null predicate to execute is required."); const int ITERATION_LIMIT = 16; @@ -94,12 +94,12 @@ internal static bool TryKeepAliveUntil(KeepAlivePredicateThe type of the data to be unwrapped. /// The weak reference. /// The T instance. + [return: MaybeNull] internal static T UnwrapWeakReference(object state) where T : class { var wr = state as WeakReference; Debug.Assert(wr != null, "Expected a WeakReference as the state argument"); - T item; - return wr.TryGetTarget(out item) ? item : null; + return wr.TryGetTarget(out T? item) ? item : null; } /// Gets an ID for the dataflow block. @@ -109,7 +109,7 @@ internal static int GetBlockId(IDataflowBlock block) { Debug.Assert(block != null, "Block required to extract an Id."); const int NOTASKID = 0; // tasks don't have 0 as ids - Task t = Common.GetPotentiallyNotSupportedCompletionTask(block); + Task? t = Common.GetPotentiallyNotSupportedCompletionTask(block); return t != null ? t.Id : NOTASKID; } @@ -121,7 +121,7 @@ internal static int GetBlockId(IDataflowBlock block) /// The name of the object. /// This is used from DebuggerDisplay attributes. internal static string GetNameForDebugger( - IDataflowBlock block, DataflowBlockOptions options = null) + IDataflowBlock block, DataflowBlockOptions? options = null) { Debug.Assert(block != null, "Should only be used with valid objects being displayed in the debugger."); Debug.Assert(options == null || options.NameFormat != null, "If options are provided, NameFormat must be valid."); @@ -179,7 +179,7 @@ internal static bool IsCooperativeCancellation(Exception exception) /// An action that will decline permanently on the state passed to it. /// The block on which to decline permanently. internal static void WireCancellationToComplete( - CancellationToken cancellationToken, Task completionTask, Action completeAction, object completeState) + CancellationToken cancellationToken, Task completionTask, Action completeAction, object completeState) { Debug.Assert(completionTask != null, "A task to wire up for completion is needed."); Debug.Assert(completeAction != null, "An action to invoke upon cancellation is required."); @@ -196,7 +196,7 @@ internal static void WireCancellationToComplete( else if (cancellationToken.CanBeCanceled) { CancellationTokenRegistration reg = cancellationToken.Register(completeAction, completeState); - completionTask.ContinueWith((completed, state) => ((CancellationTokenRegistration)state).Dispose(), + completionTask.ContinueWith((completed, state) => ((CancellationTokenRegistration)state!).Dispose(), reg, cancellationToken, Common.GetContinuationOptions(), TaskScheduler.Default); } } @@ -225,7 +225,7 @@ internal static void StoreDataflowMessageValueIntoExceptionData(Exception exc Debug.Assert(exc != null, "The exception into which data should be stored must be provided."); // Get the string value to store - string strValue = messageValue as string; + string? strValue = messageValue as string; if (strValue == null && messageValue != null) { try @@ -295,7 +295,7 @@ private static void StoreStringIntoExceptionData(Exception exception, string key internal static void ThrowAsync(Exception error) { ExceptionDispatchInfo edi = ExceptionDispatchInfo.Capture(error); - ThreadPool.QueueUserWorkItem(state => { ((ExceptionDispatchInfo)state).Throw(); }, edi); + ThreadPool.QueueUserWorkItem(state => { ((ExceptionDispatchInfo)state!).Throw(); }, edi); } /// Adds the exception to the list, first initializing the list if the list is null. @@ -303,25 +303,25 @@ internal static void ThrowAsync(Exception error) /// The exception to add or whose inner exception(s) should be added. /// Unwrap and add the inner exception(s) rather than the specified exception directly. /// This method is not thread-safe, in that it manipulates without any synchronization. - internal static void AddException(ref List list, Exception exception, bool unwrapInnerExceptions = false) + internal static void AddException([NotNull] ref List? list, Exception exception, bool unwrapInnerExceptions = false) { Debug.Assert(exception != null, "An exception to add is required."); Debug.Assert(!unwrapInnerExceptions || exception.InnerException != null, "If unwrapping is requested, an inner exception is required."); // Make sure the list of exceptions is initialized (lazily). - if (list == null) list = new List(); + list ??= new List(); if (unwrapInnerExceptions) { - AggregateException aggregate = exception as AggregateException; + AggregateException? aggregate = exception as AggregateException; if (aggregate != null) { list.AddRange(aggregate.InnerExceptions); } else { - list.Add(exception.InnerException); + list.Add(exception.InnerException!); } } else list.Add(exception); @@ -346,7 +346,7 @@ private static Task CreateCachedBooleanTask(bool value) private static TaskCompletionSource CreateCachedTaskCompletionSource() { var tcs = new TaskCompletionSource(); - tcs.SetResult(default(T)); + tcs.SetResult(default(T)!); return tcs; } @@ -376,7 +376,7 @@ internal static Task CreateTaskFromCancellation(CancellationTo /// Gets the completion task of a block, and protects against common cases of the completion task not being implemented or supported. /// The block. /// The completion task, or null if the block's completion task is not implemented or supported. - internal static Task GetPotentiallyNotSupportedCompletionTask(IDataflowBlock block) + internal static Task? GetPotentiallyNotSupportedCompletionTask(IDataflowBlock block) { Debug.Assert(block != null, "We need a block from which to retrieve a cancellation task."); try @@ -444,7 +444,7 @@ internal static TaskCreationOptions GetCreationOptionsForTask(bool isReplacement /// Task to be started. /// TaskScheduler to schedule the task on. /// null on success, an exception reference on scheduling error. In the latter case, the task reference is nulled out. - internal static Exception StartTaskSafe(Task task, TaskScheduler scheduler) + internal static Exception? StartTaskSafe(Task task, TaskScheduler scheduler) { Debug.Assert(task != null, "Task to start is required."); Debug.Assert(scheduler != null, "Scheduler on which to start the task is required."); @@ -462,12 +462,12 @@ internal static Exception StartTaskSafe(Task task, TaskScheduler scheduler) /// Task to be started. /// TaskScheduler to schedule the task on. /// null on success, an exception reference on scheduling error. In the latter case, the task reference is nulled out. - private static Exception StartTaskSafeCore(Task task, TaskScheduler scheduler) + private static Exception? StartTaskSafeCore(Task task, TaskScheduler scheduler) { Debug.Assert(task != null, "Task to start is needed."); Debug.Assert(scheduler != null, "Scheduler on which to start the task is required."); - Exception schedulingException = null; + Exception? schedulingException = null; try { @@ -479,7 +479,7 @@ private static Exception StartTaskSafeCore(Task task, TaskScheduler scheduler) Debug.Assert(task.IsFaulted, "The task should have been faulted if it failed to start."); // Observe the task's exception - AggregateException ignoredTaskException = task.Exception; + _ = task.Exception; schedulingException = caughtException; } @@ -491,7 +491,7 @@ private static Exception StartTaskSafeCore(Task task, TaskScheduler scheduler) /// No locks should be held at this time. Unfortunately we cannot assert that. internal static void ReleaseAllPostponedMessages(ITargetBlock target, QueuedMap, DataflowMessageHeader> postponedMessages, - ref List exceptions) + ref List? exceptions) { Debug.Assert(target != null, "There must be a subject target."); Debug.Assert(postponedMessages != null, "The stacked map of postponed messages must exist."); @@ -538,13 +538,13 @@ internal static void ReleaseAllPostponedMessages(ITargetBlock target, /// The task whose completion is to be propagated. It must be completed. /// The block where completion is propagated. /// Handler for exceptions from the target. May be null which would propagate the exception to the caller. - internal static void PropagateCompletion(Task sourceCompletionTask, IDataflowBlock target, Action exceptionHandler) + internal static void PropagateCompletion(Task sourceCompletionTask, IDataflowBlock target, Action? exceptionHandler) { Debug.Assert(sourceCompletionTask != null, "sourceCompletionTask may not be null."); Debug.Assert(target != null, "The target where completion is to be propagated may not be null."); Debug.Assert(sourceCompletionTask.IsCompleted, "sourceCompletionTask must be completed in order to propagate its completion."); - AggregateException exception = sourceCompletionTask.IsFaulted ? sourceCompletionTask.Exception : null; + AggregateException? exception = sourceCompletionTask.IsFaulted ? sourceCompletionTask.Exception : null; try { @@ -565,7 +565,7 @@ private static void PropagateCompletionAsContinuation(Task sourceCompletionTask, { Debug.Assert(sourceCompletionTask != null, "sourceCompletionTask may not be null."); Debug.Assert(target != null, "The target where completion is to be propagated may not be null."); - sourceCompletionTask.ContinueWith((task, state) => Common.PropagateCompletion(task, (IDataflowBlock)state, AsyncExceptionHandler), + sourceCompletionTask.ContinueWith((task, state) => Common.PropagateCompletion(task, (IDataflowBlock)state!, AsyncExceptionHandler), target, CancellationToken.None, Common.GetContinuationOptions(), TaskScheduler.Default); } @@ -588,7 +588,7 @@ internal static void PropagateCompletionOnceCompleted(Task sourceCompletionTask, private static class CachedGenericDelegates { /// A function that returns the default value of T. - internal static readonly Func DefaultTResultFunc = () => default(T); + internal static readonly Func DefaultTResultFunc = () => default(T)!; /// /// A function to use as the body of ActionOnDispose in CreateUnlinkerShim. /// Passed a tuple of the sync obj, the target registry, and the target block as the state parameter. @@ -667,7 +667,7 @@ internal BoundingStateWithPostponed(int boundedCapacity) : base(boundedCapacity) internal class BoundingStateWithPostponedAndTask : BoundingStateWithPostponed { /// The task used to process messages. - internal Task TaskForInputProcessing; + internal Task? TaskForInputProcessing; /// Initializes the BoundingState. /// The positive bounded capacity. diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ConcurrentQueue.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ConcurrentQueue.cs index b4058ec8b84302..db5af01adc1c1f 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ConcurrentQueue.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ConcurrentQueue.cs @@ -11,6 +11,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable disable // old copy used only for netstandard1.0 build using System; using System.Collections; using System.Collections.Generic; diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/IProducerConsumerCollection.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/IProducerConsumerCollection.cs index 171f14129e88d2..1177af8f0af869 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/IProducerConsumerCollection.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/IProducerConsumerCollection.cs @@ -11,6 +11,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable disable // copy used only for netstandard1.0 build using System.Collections; using System.Collections.Generic; using System.Diagnostics; diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ProducerConsumerQueues.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ProducerConsumerQueues.cs index 3897cc399ecb10..70c72e4f4f4325 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ProducerConsumerQueues.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ProducerConsumerQueues.cs @@ -31,6 +31,7 @@ #endif using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Internal; @@ -49,7 +50,7 @@ internal interface IProducerConsumerQueue : IEnumerable /// The dequeued item. /// true if an item could be dequeued; otherwise, false. /// This method is meant to be thread-safe subject to the particular nature of the implementation. - bool TryDequeue(out T result); + bool TryDequeue([MaybeNullWhen(false)] out T result); /// Gets whether the collection is currently empty. /// This method may or may not be thread-safe. @@ -210,7 +211,7 @@ private void EnqueueSlow(T item, ref Segment segment) /// Attempts to dequeue an item from the queue. /// The dequeued item. /// true if an item could be dequeued; otherwise, false. - public bool TryDequeue(out T result) + public bool TryDequeue([MaybeNullWhen(false)] out T result) { Segment segment = _head; T[] array = segment._array; @@ -220,7 +221,7 @@ public bool TryDequeue(out T result) if (first != segment._state._lastCopy) { result = array[first]; - array[first] = default(T); // Clear the slot to release the element + array[first] = default(T)!; // Clear the slot to release the element segment._state._first = (first + 1) & (array.Length - 1); return true; } @@ -233,7 +234,7 @@ public bool TryDequeue(out T result) /// The segment from which the item was dequeued. /// The dequeued item. /// true if an item could be dequeued; otherwise, false. - private bool TryDequeueSlow(ref Segment segment, ref T[] array, out T result) + private bool TryDequeueSlow(ref Segment segment, ref T[] array, [MaybeNullWhen(false)] out T result) { Debug.Assert(segment != null, "Expected a non-null segment."); Debug.Assert(array != null, "Expected a non-null item array."); @@ -260,7 +261,7 @@ private bool TryDequeueSlow(ref Segment segment, ref T[] array, out T result) } result = array[first]; - array[first] = default(T); // Clear the slot to release the element + array[first] = default(T)!; // Clear the slot to release the element segment._state._first = (first + 1) & (segment._array.Length - 1); segment._state._lastCopy = segment._state._last; // Refresh _lastCopy to ensure that _first has not passed _lastCopy @@ -291,7 +292,7 @@ public bool TryPeek(out T result) /// The segment from which the item is peeked. /// The peeked item. /// true if an item could be peeked; otherwise, false. - private bool TryPeekSlow(ref Segment segment, ref T[] array, out T result) + private bool TryPeekSlow(ref Segment segment, ref T[] array, [MaybeNullWhen(false)] out T result) { Debug.Assert(segment != null, "Expected a non-null segment."); Debug.Assert(array != null, "Expected a non-null item array."); @@ -325,7 +326,7 @@ private bool TryPeekSlow(ref Segment segment, ref T[] array, out T result) /// The predicate that must return true for the item to be dequeued. If null, all items implicitly return true. /// The dequeued item. /// true if an item could be dequeued; otherwise, false. - public bool TryDequeueIf(Predicate predicate, out T result) + public bool TryDequeueIf(Predicate? predicate, [MaybeNullWhen(false)] out T result) { Segment segment = _head; T[] array = segment._array; @@ -337,7 +338,7 @@ public bool TryDequeueIf(Predicate predicate, out T result) result = array[first]; if (predicate == null || predicate(result)) { - array[first] = default(T); // Clear the slot to release the element + array[first] = default(T)!; // Clear the slot to release the element segment._state._first = (first + 1) & (array.Length - 1); return true; } @@ -357,7 +358,7 @@ public bool TryDequeueIf(Predicate predicate, out T result) /// The segment from which the item was dequeued. /// The dequeued item. /// true if an item could be dequeued; otherwise, false. - private bool TryDequeueIfSlow(Predicate predicate, ref Segment segment, ref T[] array, out T result) + private bool TryDequeueIfSlow(Predicate? predicate, ref Segment segment, ref T[] array, [MaybeNullWhen(false)] out T result) { Debug.Assert(segment != null, "Expected a non-null segment."); Debug.Assert(array != null, "Expected a non-null item array."); @@ -386,7 +387,7 @@ private bool TryDequeueIfSlow(Predicate predicate, ref Segment segment, ref T result = array[first]; if (predicate == null || predicate(result)) { - array[first] = default(T); // Clear the slot to release the element + array[first] = default(T)!; // Clear the slot to release the element segment._state._first = (first + 1) & (segment._array.Length - 1); segment._state._lastCopy = segment._state._last; // Refresh _lastCopy to ensure that _first has not passed _lastCopy return true; @@ -422,7 +423,7 @@ public bool IsEmpty /// WARNING: This should only be used for debugging purposes. It is not safe to be used concurrently. public IEnumerator GetEnumerator() { - for (Segment segment = _head; segment != null; segment = segment._next) + for (Segment? segment = _head; segment != null; segment = segment._next) { for (int pt = segment._state._first; pt != segment._state._last; @@ -443,7 +444,7 @@ public int Count get { int count = 0; - for (Segment segment = _head; segment != null; segment = segment._next) + for (Segment? segment = _head; segment != null; segment = segment._next) { int arraySize = segment._array.Length; int first, last; @@ -475,7 +476,7 @@ int IProducerConsumerQueue.GetCountSafe(object syncObj) private sealed class Segment { /// The next segment in the linked list of segments. - internal Segment _next; + internal Segment? _next; /// The data stored in this segment. internal readonly T[] _array; /// Details about the segment. diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/QueuedMap.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/QueuedMap.cs index ed4ef24a60c710..bcd745f8523d23 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/QueuedMap.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/QueuedMap.cs @@ -15,6 +15,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Threading.Tasks.Dataflow.Internal { @@ -28,7 +29,7 @@ namespace System.Threading.Tasks.Dataflow.Internal /// This type is not thread-safe. [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(EnumerableDebugView<,>))] - internal sealed class QueuedMap + internal sealed class QueuedMap where TKey: notnull { /// /// A queue structure that uses an array-based list to store its items @@ -108,7 +109,7 @@ internal int Enqueue(T item) /// Tries to dequeue an item. /// The item that is dequeued. - internal bool TryDequeue(out T item) + internal bool TryDequeue([MaybeNullWhen(false)] out T item) { // If the queue is empty, just initialize the output item and return false if (_headIndex == TERMINATOR_INDEX) @@ -124,7 +125,7 @@ internal bool TryDequeue(out T item) // Move the popped slot to the head of the free list int newHeadIndex = _storage[_headIndex].Key; - _storage[_headIndex] = new KeyValuePair(_freeIndex, default(T)); + _storage[_headIndex] = new KeyValuePair(_freeIndex, default(T)!); _freeIndex = _headIndex; _headIndex = newHeadIndex; if (_headIndex == TERMINATOR_INDEX) _tailIndex = TERMINATOR_INDEX; diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ReorderingBuffer.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ReorderingBuffer.cs index 15fc700c4c4e32..7181bf800c8573 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ReorderingBuffer.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ReorderingBuffer.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace System.Threading.Tasks.Dataflow.Internal @@ -66,7 +67,7 @@ internal ReorderingBuffer(object owningSource, Action outputAct /// The ID of the item. /// The completed item. /// Specifies whether the item is valid (true) or just a placeholder (false). - internal void AddItem(long id, TOutput item, bool itemIsValid) + internal void AddItem(long id, [AllowNull] TOutput item, bool itemIsValid) { Debug.Assert(id != Common.INVALID_REORDERING_ID, "This ID should never have been handed out."); Common.ContractAssertMonitorStatus(ValueLock, held: false); @@ -84,7 +85,7 @@ internal void AddItem(long id, TOutput item, bool itemIsValid) else { Debug.Assert((ulong)id > (ulong)_nextReorderedIdToOutput, "Duplicate id."); - _reorderingBuffer.Add(id, new KeyValuePair(itemIsValid, item)); + _reorderingBuffer.Add(id, new KeyValuePair(itemIsValid, item!)); } } } @@ -104,7 +105,7 @@ internal void AddItem(long id, TOutput item, bool itemIsValid) /// true if the item was not added but is next in line. /// false if the item was not added and is not next in line. /// - internal bool? AddItemIfNextAndTrusted(long id, TOutput item, bool isTrusted) + internal bool? AddItemIfNextAndTrusted(long id, [AllowNull] TOutput item, bool isTrusted) { Debug.Assert(id != Common.INVALID_REORDERING_ID, "This ID should never have been handed out."); Common.ContractAssertMonitorStatus(ValueLock, held: false); @@ -132,20 +133,20 @@ internal void AddItem(long id, TOutput item, bool itemIsValid) /// The id of the message to be ignored. public void IgnoreItem(long id) { - AddItem(id, default(TOutput), itemIsValid: false); + AddItem(id, default(TOutput)!, itemIsValid: false); } /// Outputs the item. The item must have already been confirmed to have the next ID. /// The item to output. /// Whether the item is valid. - private void OutputNextItem(TOutput theNextItem, bool itemIsValid) + private void OutputNextItem([AllowNull] TOutput theNextItem, bool itemIsValid) { Common.ContractAssertMonitorStatus(ValueLock, held: true); // Note that we're now looking for a different item, and pass this one through. // Then release any items which may be pending. _nextReorderedIdToOutput++; - if (itemIsValid) _outputAction(_owningSource, theNextItem); + if (itemIsValid) _outputAction(_owningSource, theNextItem!); // Try to get the next available item from the buffer and output it. Continue to do so // until we run out of items in the reordering buffer or don't yet have the next ID buffered. diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SourceCore.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SourceCore.cs index 57f701ad30869e..0b5899a6ad786a 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SourceCore.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SourceCore.cs @@ -70,18 +70,18 @@ internal sealed class SourceCore /// An action to be invoked on the owner block when an item is removed. /// This may be null if the owner block doesn't need to be notified. /// - private readonly Action, int> _itemsRemovedAction; + private readonly Action, int>? _itemsRemovedAction; /// Item counting function - private readonly Func, TOutput, IList, int> _itemCountingFunc; + private readonly Func, TOutput, IList?, int>? _itemCountingFunc; // *** These fields are mutated during execution. /// The task used to process the output and offer it to targets. - private Task _taskForOutputProcessing; // protected by ValueLock + private Task? _taskForOutputProcessing; // protected by ValueLock /// Counter for message IDs unique within this source block. private PaddedInt64 _nextMessageId = new PaddedInt64 { Value = 1 }; // We are going to use this value before incrementing. Protected by ValueLock. /// The target that the next message is reserved for, or null if nothing is reserved. - private ITargetBlock _nextMessageReservedFor; // protected by OutgoingLock + private ITargetBlock? _nextMessageReservedFor; // protected by OutgoingLock /// Whether all future messages should be declined. private bool _decliningPermanently; // Protected by ValueLock /// Whether this block should again attempt to offer messages to targets. @@ -89,7 +89,7 @@ internal sealed class SourceCore /// Whether someone has reserved the right to call CompleteBlockOncePossible. private bool _completionReserved; // Protected by OutgoingLock /// Exceptions that may have occurred and gone unhandled during processing. - private List _exceptions; // Protected by ValueLock, sometimes read with volatile reads + private List? _exceptions; // Protected by ValueLock, sometimes read with volatile reads /// Initializes the source core. /// The source utilizing this core. @@ -103,8 +103,8 @@ internal sealed class SourceCore internal SourceCore( ISourceBlock owningSource, DataflowBlockOptions dataflowBlockOptions, Action> completeAction, - Action, int> itemsRemovedAction = null, - Func, TOutput, IList, int> itemCountingFunc = null) + Action, int>? itemsRemovedAction = null, + Func, TOutput, IList?, int>? itemCountingFunc = null) { Debug.Assert(owningSource != null, "Core must be associated with a source."); Debug.Assert(dataflowBlockOptions != null, "Options must be provided to configure the core."); @@ -156,6 +156,7 @@ internal IDisposable LinkTo(ITargetBlock target, DataflowLinkOptions li } /// + [return: MaybeNull] internal TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { // Validate arguments @@ -274,7 +275,7 @@ internal void ReleaseReservation(DataflowMessageHeader messageHeader, ITargetBlo internal Task Completion { get { return _completionTask.Task; } } /// - internal bool TryReceive(Predicate filter, out TOutput item) + internal bool TryReceive(Predicate? filter, [MaybeNullWhen(false)] out TOutput item) { item = default(TOutput); bool itemReceived = false; @@ -313,7 +314,7 @@ internal bool TryReceive(Predicate filter, out TOutput item) // Notify the owner block that our count has decreased if (_itemsRemovedAction != null) { - int count = _itemCountingFunc != null ? _itemCountingFunc(_owningSource, item, null) : 1; + int count = _itemCountingFunc != null ? _itemCountingFunc(_owningSource, item!, null) : 1; _itemsRemovedAction(_owningSource, count); } } @@ -321,7 +322,7 @@ internal bool TryReceive(Predicate filter, out TOutput item) } /// - internal bool TryReceiveAll(out IList items) + internal bool TryReceiveAll([NotNullWhen(true)] out IList? items) { items = null; int countReceived = 0; @@ -360,10 +361,12 @@ internal bool TryReceiveAll(out IList items) // Notify the owner block that our count has decreased if (_itemsRemovedAction != null) { - int count = _itemCountingFunc != null ? _itemCountingFunc(_owningSource, default(TOutput), items) : countReceived; + int count = _itemCountingFunc != null ? _itemCountingFunc(_owningSource, default(TOutput)!, items) : countReceived; _itemsRemovedAction(_owningSource, count); } +#pragma warning disable CS8762 // Parameter may not have a null value when exiting in some condition. return true; +#pragma warning restore CS8762 } else return false; } @@ -423,7 +426,7 @@ internal void AddMessages(IEnumerable items) } else { - TOutput[] itemsAsArray = items as TOutput[]; + TOutput[]? itemsAsArray = items as TOutput[]; if (itemsAsArray != null) { for (int i = 0; i < itemsAsArray.Length; i++) @@ -511,7 +514,7 @@ internal void Complete() // and take the necessary locks in a situation where we're sure it won't cause a problem. Task.Factory.StartNew(state => { - var thisSourceCore = (SourceCore)state; + var thisSourceCore = (SourceCore)state!; lock (thisSourceCore.OutgoingLock) { lock (thisSourceCore.ValueLock) @@ -531,7 +534,7 @@ internal void Complete() /// The newly linked target, if OfferToTargets is being called to synchronously /// propagate to a target during a LinkTo operation. /// - private bool OfferToTargets(ITargetBlock linkToTarget = null) + private bool OfferToTargets(ITargetBlock? linkToTarget = null) { Common.ContractAssertMonitorStatus(OutgoingLock, held: true); Common.ContractAssertMonitorStatus(ValueLock, held: false); @@ -585,10 +588,10 @@ private bool OfferToTargets(ITargetBlock linkToTarget = null) // separately from cur.Next, in case cur.Next changes by cur being removed from the list. // No other node in the list should change, as we're protected by OutgoingLock. - TargetRegistry.LinkedTargetInfo cur = _targetRegistry.FirstTargetNode; + TargetRegistry.LinkedTargetInfo? cur = _targetRegistry.FirstTargetNode; while (cur != null) { - TargetRegistry.LinkedTargetInfo next = cur.Next; + TargetRegistry.LinkedTargetInfo? next = cur.Next; if (OfferMessageToTarget(header, message, cur.Target, out messageWasAccepted)) break; cur = next; } @@ -749,7 +752,7 @@ private void OfferAsyncIfNecessary_Slow(bool isReplacementReplica, bool outgoing { // Create task and store into _taskForOutputProcessing prior to scheduling the task // so that _taskForOutputProcessing will be visibly set in the task loop. - _taskForOutputProcessing = new Task(thisSourceCore => ((SourceCore)thisSourceCore).OfferMessagesLoopCore(), this, + _taskForOutputProcessing = new Task(thisSourceCore => ((SourceCore)thisSourceCore!).OfferMessagesLoopCore(), this, Common.GetCreationOptionsForTask(isReplacementReplica)); #if FEATURE_TRACING @@ -762,7 +765,7 @@ private void OfferAsyncIfNecessary_Slow(bool isReplacementReplica, bool outgoing #endif // Start the task handling scheduling exceptions - Exception exception = Common.StartTaskSafe(_taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler); + Exception? exception = Common.StartTaskSafe(_taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler); if (exception != null) { // First, log the exception while the processing state is dirty which is preventing the block from completing. @@ -776,7 +779,7 @@ private void OfferAsyncIfNecessary_Slow(bool isReplacementReplica, bool outgoing // Re-take the locks on a separate thread. Task.Factory.StartNew(state => { - var thisSourceCore = (SourceCore)state; + var thisSourceCore = (SourceCore)state!; lock (thisSourceCore.OutgoingLock) { lock (thisSourceCore.ValueLock) @@ -917,7 +920,7 @@ private void CompleteBlockIfPossible_Slow() // Get out from under currently held locks. This is to avoid // invoking synchronous continuations off of _completionTask.Task // while holding a lock. - Task.Factory.StartNew(state => ((SourceCore)state).CompleteBlockOncePossible(), + Task.Factory.StartNew(state => ((SourceCore)state!).CompleteBlockOncePossible(), this, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); } } @@ -928,8 +931,8 @@ private void CompleteBlockIfPossible_Slow() /// private void CompleteBlockOncePossible() { - TargetRegistry.LinkedTargetInfo linkedTargets; - List exceptions; + TargetRegistry.LinkedTargetInfo? linkedTargets; + List? exceptions; // Avoid completing while the code that caused this completion to occur is still holding a lock. // Clear out the target registry and buffers to help avoid memory leaks. @@ -1006,7 +1009,7 @@ internal sealed class DebuggingInformation /// Gets the messages available for receiving. internal IEnumerable OutputQueue { get { return _source._messages.ToList(); } } /// Gets the task being used for output processing. - internal Task TaskForOutputProcessing { get { return _source._taskForOutputProcessing; } } + internal Task? TaskForOutputProcessing { get { return _source._taskForOutputProcessing; } } /// Gets the DataflowBlockOptions used to configure this block. internal DataflowBlockOptions DataflowBlockOptions { get { return _source._dataflowBlockOptions; } } @@ -1017,7 +1020,7 @@ internal sealed class DebuggingInformation /// Gets the set of all targets linked from this block. internal TargetRegistry LinkedTargets { get { return _source._targetRegistry; } } /// Gets the target that holds a reservation on the next message, if any. - internal ITargetBlock NextMessageReservedFor { get { return _source._nextMessageReservedFor; } } + internal ITargetBlock? NextMessageReservedFor { get { return _source._nextMessageReservedFor; } } } } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SpscTargetCore.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SpscTargetCore.cs index f742443ece9a37..07187ac4db4e7a 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SpscTargetCore.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SpscTargetCore.cs @@ -53,7 +53,7 @@ internal sealed class SpscTargetCore private readonly Action _action; /// Exceptions that may have occurred and gone unhandled during processing. This field is lazily initialized. - private volatile List _exceptions; + private volatile List? _exceptions; /// Whether to stop accepting new messages. private volatile bool _decliningPermanently; /// A task has reserved the right to run the completion routine. @@ -63,9 +63,9 @@ internal sealed class SpscTargetCore /// and it should not be set to null once the block completes, as doing so would allow for races where the producer /// gets another consumer task queued even though the block has completed. /// - private volatile Task _activeConsumer; + private volatile Task? _activeConsumer; /// A task representing the completion of the block. This field is lazily initialized. - private TaskCompletionSource _completionTask; + private TaskCompletionSource? _completionTask; /// Initialize the SPSC target core. /// The owning target block. @@ -108,7 +108,7 @@ internal bool Post(TInput messageValue) } /// - internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock source, bool consumeToAccept) + internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock? source, bool consumeToAccept) { // If we're not required to go back to the source to consume the offered message, try fast path. return !consumeToAccept && Post(messageValue) ? @@ -122,7 +122,7 @@ internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, /// The source offering the message. This may be null. /// true if we need to call back to the source to consume the message; otherwise, false if we can simply accept it directly. /// The status of the message. - private DataflowMessageStatus OfferMessage_Slow(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock source, bool consumeToAccept) + private DataflowMessageStatus OfferMessage_Slow(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock? source, bool consumeToAccept) { // If we're declining permanently, let the caller know. if (_decliningPermanently) @@ -146,7 +146,7 @@ private DataflowMessageStatus OfferMessage_Slow(DataflowMessageHeader messageHea } // See the "fast path" comments in Post - _messages.Enqueue(messageValue); + _messages.Enqueue(messageValue!); Interlocked.MemoryBarrier(); // ensure the read of _activeConsumer doesn't move up before the writes in Enqueue if (_activeConsumer == null) { @@ -164,7 +164,7 @@ private void ScheduleConsumerIfNecessary(bool isReplica) { // Create a new consumption task and try to set it as current as long as there's still no other task var newConsumer = new Task( - state => ((SpscTargetCore)state).ProcessMessagesLoopCore(), + state => ((SpscTargetCore)state!).ProcessMessagesLoopCore(), this, CancellationToken.None, Common.GetCreationOptionsForTask(isReplica)); if (Interlocked.CompareExchange(ref _activeConsumer, newConsumer, null) == null) { @@ -225,7 +225,7 @@ private void ProcessMessagesLoopCore() if (!Common.IsCooperativeCancellation(exc)) { _decliningPermanently = true; // stop accepting from producers - Common.StoreDataflowMessageValueIntoExceptionData(exc, nextMessage, false); + Common.StoreDataflowMessageValueIntoExceptionData(exc, nextMessage!, false); StoreException(exc); } } @@ -254,7 +254,7 @@ private void ProcessMessagesLoopCore() else { // Mark that we're exiting. - Task previousConsumer = Interlocked.Exchange(ref _activeConsumer, null); + Task? previousConsumer = Interlocked.Exchange(ref _activeConsumer, null); Debug.Assert(previousConsumer != null && previousConsumer.Id == Task.CurrentId, "The running task should have been denoted as the active task."); @@ -285,7 +285,7 @@ private void ProcessMessagesLoopCore() /// completing, all invocations after the first are ignored. /// /// The exception to be stored. - internal void Complete(Exception exception) + internal void Complete(Exception? exception) { // If we're not yet declining permanently... if (!_decliningPermanently) diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetCore.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetCore.cs index f3aa761e2b9924..58a8ada376dad0 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetCore.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetCore.cs @@ -71,9 +71,9 @@ internal sealed class TargetCore /// Whether the block relies on the delegate to signal when an async operation has completed. private readonly TargetCoreOptions _targetCoreOptions; /// Bounding state for when the block is executing in bounded mode. - private readonly BoundingStateWithPostponed _boundingState; + private readonly BoundingStateWithPostponed? _boundingState; /// The reordering buffer used by the owner. May be null. - private readonly IReorderingBuffer _reorderingBuffer; + private readonly IReorderingBuffer? _reorderingBuffer; /// Gets the object used as the incoming lock. private object IncomingLock { get { return _messages; } } @@ -81,7 +81,7 @@ internal sealed class TargetCore // *** These fields are mutated during execution. /// Exceptions that may have occurred and gone unhandled during processing. - private List _exceptions; + private List? _exceptions; /// Whether to stop accepting new messages. private bool _decliningPermanently; /// The number of operations (including service tasks) currently running asynchronously. @@ -106,7 +106,7 @@ internal sealed class TargetCore internal TargetCore( ITargetBlock owningTarget, Action> callAction, - IReorderingBuffer reorderingBuffer, + IReorderingBuffer? reorderingBuffer, ExecutionDataflowBlockOptions dataflowBlockOptions, TargetCoreOptions targetCoreOptions) { @@ -137,7 +137,7 @@ internal TargetCore( /// If true, an exception will be stored after _decliningPermanently has been set to true. /// If true, exception will be treated as an AggregateException. /// Indicates whether the processing state is dirty and has to be reverted. - internal void Complete(Exception exception, bool dropPendingMessages, bool storeExceptionEvenIfAlreadyCompleting = false, + internal void Complete(Exception? exception, bool dropPendingMessages, bool storeExceptionEvenIfAlreadyCompleting = false, bool unwrapInnerExceptions = false, bool revertProcessingState = false) { Debug.Assert(storeExceptionEvenIfAlreadyCompleting || !revertProcessingState, @@ -178,7 +178,7 @@ internal void Complete(Exception exception, bool dropPendingMessages, bool store } /// - internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock source, bool consumeToAccept) + internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock? source, bool consumeToAccept) { // Validate arguments if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader)); @@ -217,7 +217,7 @@ internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, long messageId = _nextAvailableInputMessageId.Value++; Debug.Assert(messageId != Common.INVALID_REORDERING_ID, "The assigned message ID is invalid."); if (_boundingState != null) _boundingState.CurrentCount += 1; // track this new item against our bound - _messages.Enqueue(new KeyValuePair(messageValue, messageId)); + _messages.Enqueue(new KeyValuePair(messageValue!, messageId)); ProcessAsyncIfNecessary(); return DataflowMessageStatus.Accepted; } @@ -369,7 +369,7 @@ private void ProcessAsyncIfNecessary_Slow(bool repeat) _numberOfOutstandingOperations++; if (UsesAsyncCompletion) _numberOfOutstandingServiceTasks++; - var taskForInputProcessing = new Task(thisTargetCore => ((TargetCore)thisTargetCore).ProcessMessagesLoopCore(), this, + var taskForInputProcessing = new Task(thisTargetCore => ((TargetCore)thisTargetCore!).ProcessMessagesLoopCore(), this, Common.GetCreationOptionsForTask(repeat)); #if FEATURE_TRACING @@ -383,11 +383,11 @@ private void ProcessAsyncIfNecessary_Slow(bool repeat) #endif // Start the task handling scheduling exceptions - Exception exception = Common.StartTaskSafe(taskForInputProcessing, _dataflowBlockOptions.TaskScheduler); + Exception? exception = Common.StartTaskSafe(taskForInputProcessing, _dataflowBlockOptions.TaskScheduler); if (exception != null) { // Get out from under currently held locks. Complete re-acquires the locks it needs. - Task.Factory.StartNew(exc => Complete(exception: (Exception)exc, dropPendingMessages: true, storeExceptionEvenIfAlreadyCompleting: true, + Task.Factory.StartNew(exc => Complete(exception: (Exception)exc!, dropPendingMessages: true, storeExceptionEvenIfAlreadyCompleting: true, unwrapInnerExceptions: false, revertProcessingState: true), exception, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); } @@ -424,7 +424,7 @@ private void ProcessMessagesLoopCore() lock (IncomingLock) { Debug.Assert( - _boundingState.OutstandingTransfers > 0 + _boundingState!.OutstandingTransfers > 0 && _boundingState.OutstandingTransfers <= _dataflowBlockOptions.ActualMaxDegreeOfParallelism, "Expected TryConsumePostponedMessage to have incremented the count and for the count to not exceed the DOP."); _boundingState.OutstandingTransfers--; // was incremented in TryConsumePostponedMessage @@ -638,7 +638,7 @@ private bool TryConsumePostponedMessage( // We can consume a message to process if there's one to process and also if // if we have logical room within our bound for the message. - if (!_boundingState.CountIsLessThanBound || !_boundingState.PostponedMessages.TryPop(out element)) + if (!_boundingState!.CountIsLessThanBound || !_boundingState.PostponedMessages.TryPop(out element)) { if (countIncrementedExpectingToGetItem) { @@ -665,7 +665,7 @@ private bool TryConsumePostponedMessage( TInput consumedValue = element.Key.ConsumeMessage(element.Value, _owningTarget, out consumed); if (consumed) { - result = new KeyValuePair(consumedValue, messageId); + result = new KeyValuePair(consumedValue!, messageId); return true; } else @@ -734,7 +734,7 @@ private void CompleteBlockIfPossible_Slow() // Get out from under currently held locks. This is to avoid // invoking synchronous continuations off of _completionSource.Task // while holding a lock. - Task.Factory.StartNew(state => ((TargetCore)state).CompleteBlockOncePossible(), + Task.Factory.StartNew(state => ((TargetCore)state!).CompleteBlockOncePossible(), this, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default); } } @@ -770,7 +770,7 @@ private void CompleteBlockOncePossible() // It's ok to read _exceptions' content here, because // at this point no more exceptions can be generated and thus no one will // be writing to it. - _completionSource.TrySetException(Volatile.Read(ref _exceptions)); + _completionSource.TrySetException(Volatile.Read(ref _exceptions!)); } // If we completed with cancellation, finish in a canceled state else if (_dataflowBlockOptions.CancellationToken.IsCancellationRequested) @@ -851,7 +851,7 @@ internal sealed class DebuggingInformation internal IEnumerable InputQueue { get { return _target._messages.Select(kvp => kvp.Key).ToList(); } } /// Gets any postponed messages. - internal QueuedMap, DataflowMessageHeader> PostponedMessages + internal QueuedMap, DataflowMessageHeader>? PostponedMessages { get { return _target._boundingState != null ? _target._boundingState.PostponedMessages : null; } } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetRegistry.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetRegistry.cs index c75a644c54ce65..954d1836d2d3e2 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetRegistry.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetRegistry.cs @@ -52,9 +52,9 @@ internal LinkedTargetInfo(ITargetBlock target, DataflowLinkOptions linkOption /// gets decremented after each successful propagation. internal int RemainingMessages; /// The previous node in the list. - internal LinkedTargetInfo Previous; + internal LinkedTargetInfo? Previous; /// The next node in the list. - internal LinkedTargetInfo Next; + internal LinkedTargetInfo? Next; } /// A reference to the owning source block. @@ -62,9 +62,9 @@ internal LinkedTargetInfo(ITargetBlock target, DataflowLinkOptions linkOption /// A mapping of targets to information about them. private readonly Dictionary, LinkedTargetInfo> _targetInformation; /// The first node of an ordered list of targets. Messages should be offered to targets starting from First and following Next. - private LinkedTargetInfo _firstTarget; + private LinkedTargetInfo? _firstTarget; /// The last node of the ordered list of targets. This field is used purely as a perf optimization to avoid traversing the list for each Add. - private LinkedTargetInfo _lastTarget; + private LinkedTargetInfo? _lastTarget; /// Number of links with positive RemainingMessages counters. /// This is an optimization that allows us to skip dictionary lookup when this counter is 0. private int _linksWithRemainingMessages; @@ -86,7 +86,7 @@ internal void Add(ref ITargetBlock target, DataflowLinkOptions linkOptions) Debug.Assert(target != null, "The target that is supposed to be linked must not be null."); Debug.Assert(linkOptions != null, "The link options must not be null."); - LinkedTargetInfo targetInfo; + LinkedTargetInfo? targetInfo; // If the target already exists in the registry, replace it with a new NopLinkPropagator to maintain uniqueness if (_targetInformation.TryGetValue(target, out targetInfo)) target = new NopLinkPropagator(_owningSource, target); @@ -147,7 +147,7 @@ private void Remove_Slow(ITargetBlock target, bool onlyIfReachedMaxMessages) Debug.Assert(!onlyIfReachedMaxMessages || _linksWithRemainingMessages > 0, "We shouldn't have ended on the slow path."); // If the target is registered... - LinkedTargetInfo node; + LinkedTargetInfo? node; if (_targetInformation.TryGetValue(target, out node)) { Debug.Assert(node != null, "The LinkedTargetInfo node referenced in the Dictionary must be non-null."); @@ -180,10 +180,10 @@ private void Remove_Slow(ITargetBlock target, bool onlyIfReachedMaxMessages) } /// Clears the target registry entry points while allowing subsequent traversals of the linked list. - internal LinkedTargetInfo ClearEntryPoints() + internal LinkedTargetInfo? ClearEntryPoints() { // Save _firstTarget so we can return it - LinkedTargetInfo firstTarget = _firstTarget; + LinkedTargetInfo? firstTarget = _firstTarget; // Clear out the entry points _firstTarget = _lastTarget = null; @@ -196,7 +196,7 @@ internal LinkedTargetInfo ClearEntryPoints() /// Propagated completion to the targets of the given linked list. /// The head of a saved linked list. - internal void PropagateCompletion(LinkedTargetInfo firstTarget) + internal void PropagateCompletion(LinkedTargetInfo? firstTarget) { Debug.Assert(_owningSource.Completion.IsCompleted, "The owning source must have completed before propagating completion."); @@ -204,14 +204,14 @@ internal void PropagateCompletion(LinkedTargetInfo firstTarget) Task owningSourceCompletion = _owningSource.Completion; // Propagate completion to those targets that have requested it - for (LinkedTargetInfo node = firstTarget; node != null; node = node.Next) + for (LinkedTargetInfo? node = firstTarget; node != null; node = node.Next) { if (node.PropagateCompletion) Common.PropagateCompletion(owningSourceCompletion, node.Target, Common.AsyncExceptionHandler); } } /// Gets the first node of the ordered target list. - internal LinkedTargetInfo FirstTargetNode { get { return _firstTarget; } } + internal LinkedTargetInfo? FirstTargetNode { get { return _firstTarget; } } /// Adds a LinkedTargetInfo node to the doubly-linked list. /// The node to be added. @@ -257,8 +257,8 @@ internal void RemoveFromList(LinkedTargetInfo node) Debug.Assert(node != null, "Node to remove is required."); Debug.Assert(_firstTarget != null && _lastTarget != null, "Both first and last node must be non-null before RemoveFromList."); - LinkedTargetInfo previous = node.Previous; - LinkedTargetInfo next = node.Next; + LinkedTargetInfo? previous = node.Previous; + LinkedTargetInfo? next = node.Next; // Remove the node by linking the adjacent nodes if (node.Previous != null) @@ -290,7 +290,7 @@ private ITargetBlock[] TargetsForDebugger { var targets = new ITargetBlock[Count]; int i = 0; - for (LinkedTargetInfo node = _firstTarget; node != null; node = node.Next) + for (LinkedTargetInfo? node = _firstTarget; node != null; node = node.Next) { targets[i++] = node.Target; } @@ -325,13 +325,14 @@ internal NopLinkPropagator(ISourceBlock owningSource, ITargetBlock target) } /// - DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock source, bool consumeToAccept) + DataflowMessageStatus ITargetBlock.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock? source, bool consumeToAccept) { Debug.Assert(source == _owningSource, "Only valid to be used with the source for which it was created."); return _target.OfferMessage(messageHeader, messageValue, this, consumeToAccept); } /// + [return: MaybeNull] T ISourceBlock.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock target, out bool messageConsumed) { return _owningSource.ConsumeMessage(messageHeader, this, out messageConsumed); diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Threading.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Threading.cs index 2d2a99ff32d7c6..b34c41a76d5019 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Threading.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Threading.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable disable // used only for netstandard1.0 build using System; using System.Collections.Generic; using System.Diagnostics; diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj b/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj index c4319ee2d4672e..9e20116e0ba468 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj @@ -1,10 +1,11 @@ - + $(DefineConstants);FEATURE_TRACING $(DefineConstants);USE_INTERNAL_CONCURRENT_COLLECTIONS $(DefineConstants);USE_INTERNAL_THREADING netstandard1.1;portable-net45+win8+wpa81 netstandard2.0;netstandard1.0;netstandard1.1 + enable diff --git a/src/libraries/System.Threading.Tasks.Dataflow/tests/Dataflow/DataflowBlockExtensionTests.cs b/src/libraries/System.Threading.Tasks.Dataflow/tests/Dataflow/DataflowBlockExtensionTests.cs index 2db6048042e17f..d022a31de866d3 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/tests/Dataflow/DataflowBlockExtensionTests.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/tests/Dataflow/DataflowBlockExtensionTests.cs @@ -306,10 +306,10 @@ public void TestAsObservableAndAsObserver_LinkAndUnlink() } // Validate sane behavior with a bad LinkTo - Assert.Null( - new DelegatePropagator { - LinkToDelegate = (_,__) => null - }.AsObservable().Subscribe(DataflowBlock.NullTarget().AsObserver())); + new DelegatePropagator + { + LinkToDelegate = (_, __) => null + }.AsObservable().Subscribe(DataflowBlock.NullTarget().AsObserver()).Dispose(); } [Fact] diff --git a/src/libraries/pkg/baseline/packageIndex.json b/src/libraries/pkg/baseline/packageIndex.json index 5eebf5e6b2e8d5..8ea122447fc6d3 100644 --- a/src/libraries/pkg/baseline/packageIndex.json +++ b/src/libraries/pkg/baseline/packageIndex.json @@ -145,6 +145,274 @@ "5.0.0.0": "5.0.0" } }, + "Microsoft.Extensions.Caching.Abstractions": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.1.2", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Configuration": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.1.10", + "2.2.0", + "2.2.4", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Configuration.CommandLine": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Configuration.EnvironmentVariables": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.2.0", + "2.2.4", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Configuration.FileExtensions": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Configuration.Ini": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "2.0.0", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "2.0.0", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, "Microsoft.Extensions.FileProviders.Abstractions": { "StableVersions": [ "1.0.0", @@ -239,6 +507,125 @@ "5.0.0.0": "5.0.0" } }, + "Microsoft.Extensions.Hosting.Abstractions": { + "StableVersions": [ + "2.0.0", + "2.0.1", + "2.0.2", + "2.0.3", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Options": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Options.ConfigurationExtensions": { + "StableVersions": [ + "1.0.0", + "1.0.1", + "1.0.2", + "1.1.0", + "1.1.1", + "1.1.2", + "2.0.0", + "2.0.1", + "2.0.2", + "2.1.0", + "2.1.1", + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, + "Microsoft.Extensions.Options.DataAnnotations": { + "StableVersions": [ + "2.2.0", + "3.0.0", + "3.0.1", + "3.0.2", + "3.0.3", + "3.1.0", + "3.1.1", + "3.1.2" + ], + "InboxOn": {}, + "AssemblyVersionInPackageVersion": { + "5.0.0.0": "5.0.0" + } + }, "Microsoft.Extensions.Primitives": { "StableVersions": [ "1.0.0", diff --git a/src/libraries/pkg/descriptions.json b/src/libraries/pkg/descriptions.json index cd991471690984..45937674b626f1 100644 --- a/src/libraries/pkg/descriptions.json +++ b/src/libraries/pkg/descriptions.json @@ -14,13 +14,26 @@ "Description": "Provides a portable version of the Microsoft.Cci library", "CommonTypes": [] }, + { + "Name": "Microsoft.Extensions.Caching.Abstractions", + "Description": "Caching abstractions for in-memory cache and distributed cache.", + "CommonTypes": [ + "Microsoft.Extensions.Caching.Distributed.IDistributedCache", + "Microsoft.Extensions.Caching.Memory.IMemoryCache" + ] + }, + { + "Name": "Microsoft.Extensions.Caching.Memory", + "Description": "In-memory cache implementation of Microsoft.Extensions.Caching.Memory.IMemoryCache.", + "CommonTypes": [] + }, { "Name": "Microsoft.Extensions.Configuration", "Description": "Implementation of key-value pair based configuration for Microsoft.Extensions.Configuration. Includes the memory configuration provider.", "CommonTypes": [] }, { - "Name": "Microsoft.Extensions.Configuration.Abstraction", + "Name": "Microsoft.Extensions.Configuration.Abstractions", "Description": "Abstractions of key-value pair based configuration.", "CommonTypes": [ "Microsoft.Extensions.Configuration.IConfiguration", @@ -31,7 +44,7 @@ ] }, { - "Name": "Microsoft.Extensions.Configuration.Bindar", + "Name": "Microsoft.Extensions.Configuration.Binder", "Description": "Functionality to bind an object to data in configuration providers for Microsoft.Extensions.Configuration.", "CommonTypes": [] }, @@ -116,6 +129,13 @@ "Description": ".NET Core hosting and startup abstractions for applications.", "CommonTypes": [] }, + { + "Name": "Microsoft.Extensions.Http", + "Description": "The HttpClient factory is a pattern for configuring and retrieving named HttpClients in a composable way. The HttpClient factory provides extensibility to plug in DelegatingHandlers that address cross-cutting concerns such as service location, load balancing, and reliability. The default HttpClient factory provides built-in diagnostics and logging and manages the lifetimes of connections in a performant way.", + "CommonTypes": [ + "System.Net.Http.IHttpClientFactory" + ] + }, { "Name": "Microsoft.Extensions.Logging", "Description": "Logging infrastructure default implementation for Microsoft.Extensions.Logging.", diff --git a/src/libraries/restore/netstandard/netstandard.depproj b/src/libraries/restore/netstandard/netstandard.depproj index 6ecf6cb0ee7866..756d35dd515247 100644 --- a/src/libraries/restore/netstandard/netstandard.depproj +++ b/src/libraries/restore/netstandard/netstandard.depproj @@ -69,6 +69,9 @@ 4.7.0 + + 4.7.0 + diff --git a/src/mono/Directory.Build.props b/src/mono/Directory.Build.props index 9a4e3aef542033..bfb1333563d147 100644 --- a/src/mono/Directory.Build.props +++ b/src/mono/Directory.Build.props @@ -29,8 +29,6 @@ false $(PackageVersion) - - preview8 diff --git a/src/mono/configure.ac b/src/mono/configure.ac index e684552200a849..fd2d543b424dd3 100644 --- a/src/mono/configure.ac +++ b/src/mono/configure.ac @@ -2372,14 +2372,6 @@ if test x$host_win32 = xno; then dnl ***************************** AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket") - case "$host" in - *-*-*freebsd*) - dnl ***************************** - dnl *** Checks for libinotify *** - dnl ***************************** - AC_CHECK_LIB(inotify, inotify_init, LIBS="$LIBS -linotify") - esac - dnl ***************************** dnl *** Checks for IPPROTO_IP *** dnl ***************************** @@ -3648,6 +3640,35 @@ if test x$host_win32 = xno; then AC_MSG_RESULT(no) ]) + case "$host" in + *-*-*freebsd*) + dnl ***************************** + dnl *** Checks for libinotify *** + dnl ***************************** + AC_CHECK_LIB(inotify, inotify_init, LIBS="$LIBS -linotify") + if test "x$ac_cv_lib_inotify_inotify_init" = "xyes" ; then + AC_DEFINE(HAVE_LIBINOTIFY, 1, [FreeBSD libinotify kqueue shim]) + dnl Needs to be done this way to avoid collision with various + dnl ports including glib and llvm* + METADATA_CFLAGS="-I/usr/local/include" + AC_SUBST(METADATA_CFLAGS) + fi + dnl Workaround due to inotify_rm_watch check failing without -I + AC_MSG_CHECKING(for inotify_rm_watch with unsigned wd in libinotify) + AC_TRY_LINK([ + #include + ], [ + intptr_t fd; + uint32_t wd; + int result = inotify_rm_watch(fd, wd); + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(INOTIFY_RM_WATCH_WD_UNSIGNED, 1, [inotify_rm_watch with unsigned wd]) + ], [ + AC_MSG_RESULT(no) + ]) + esac + CFLAGS="$ORIG_CFLAGS" AC_MSG_CHECKING(for shm_open that works well enough with mmap) @@ -6565,7 +6586,7 @@ elif case $host_os in freebsd*) true;; *) false;; esac; then MONO_NATIVE_CXX=$CXX MONO_NATIVE_CPPFLAGS=$CPPFLAGS MONO_NATIVE_CXXFLAGS=$CXXFLAGS - MONO_NATIVE_CFLAGS=$CFLAGS + MONO_NATIVE_CFLAGS="$CFLAGS -I/usr/local/include" MONO_NATIVE_LDFLAGS=$LDFLAGS mono_native=yes diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 3b187a17337266..d52d8dc3e4e7ad 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -370,6 +370,7 @@ <_MonoBuildParams Include="/p:MONO_BUILD_DIR_PREFIX=""$(MonoObjDir)""" /> <_MonoBuildParams Include="/p:MONO_ENABLE_NETCORE=true" /> + <_MonoBuildParams Condition="'$(Configuration)' == 'Debug'" Include="/p:MONO_USE_STATIC_C_RUNTIME=true" /> <_MonoBuildParams Include="/p:CL_MPCount=$([System.Environment]::ProcessorCount)" /> <_MonoBuildParams Include="/v:minimal" /> <_MonoBuildParams Condition="$(MonoEnableLLVM) == true" Include="/p:MONO_ENABLE_LLVM=true" /> @@ -577,7 +578,7 @@ - + diff --git a/src/mono/mono/metadata/Makefile.am b/src/mono/mono/metadata/Makefile.am index dc9cf2a4d257ba..f8bb45da5d0a10 100644 --- a/src/mono/mono/metadata/Makefile.am +++ b/src/mono/mono/metadata/Makefile.am @@ -107,7 +107,7 @@ noinst_LTLIBRARIES = libmonoruntime-config.la $(support_libraries) $(boehm_libra lib_LTLIBRARIES = $(icall_table_libraries) $(ilgen_libraries) -AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/mono $(LIBGC_CPPFLAGS) $(GLIB_CFLAGS) $(SHARED_CFLAGS) +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/mono $(LIBGC_CPPFLAGS) $(GLIB_CFLAGS) $(SHARED_CFLAGS) $(METADATA_CFLAGS) # # Make sure any prefix changes are updated in the binaries too. diff --git a/src/mono/mono/metadata/icall-signatures.h b/src/mono/mono/metadata/icall-signatures.h index 876c427c314fae..40d2f9b8392376 100644 --- a/src/mono/mono/metadata/icall-signatures.h +++ b/src/mono/mono/metadata/icall-signatures.h @@ -199,6 +199,7 @@ ICALL_SIG (3, (object, object, ptr)) \ ICALL_SIG (3, (object, ptr, int)) \ ICALL_SIG (3, (object, ptr, int32)) \ ICALL_SIG (3, (object, ptr, ptr)) \ +ICALL_SIG (3, (object, ptr, sizet)) \ ICALL_SIG (3, (ptr, int32, ptrref)) \ ICALL_SIG (3, (ptr, object, ptr)) \ ICALL_SIG (3, (ptr, ptr, int)) \ @@ -229,6 +230,8 @@ ICALL_SIG (4, (object, ptr, int, int)) \ ICALL_SIG (4, (object, ptr, int, int32)) \ ICALL_SIG (4, (object, ptr, int, ptr)) \ ICALL_SIG (4, (object, ptr, ptr, int32)) \ +ICALL_SIG (4, (object, ptr, sizet, ptr)) \ +ICALL_SIG (4, (object, ptr, sizet, int32)) \ ICALL_SIG (4, (ptr, object, int32, int32)) \ ICALL_SIG (4, (ptr, object, ptr, ptr)) \ ICALL_SIG (4, (ptr, ptr, int, ptr)) \ diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 86ce68c89dee70..1a198289b95a7e 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -8422,7 +8422,7 @@ typedef struct _EventPipeEventInstanceData { gconstpointer ves_icall_System_Diagnostics_Tracing_EventPipeInternal_CreateProvider (MonoStringHandle provider_name, MonoDelegateHandle callback_func, MonoError *error) { - return EVENT_PIPE_DUMMY_PROVIDER_ID; + return GUINT_TO_POINTER (EVENT_PIPE_DUMMY_PROVIDER_ID); } intptr_t @@ -9509,7 +9509,6 @@ mono_lookup_icall_symbol (MonoMethod *m) // Storage for these enums is pointer-sized as it gets replaced with MonoType*. // // mono_create_icall_signatures depends on this order. Handle with care. -// It is alphabetical. typedef enum ICallSigType { ICALL_SIG_TYPE_bool = 0x00, ICALL_SIG_TYPE_boolean = ICALL_SIG_TYPE_bool, @@ -9517,12 +9516,12 @@ typedef enum ICallSigType { ICALL_SIG_TYPE_float = 0x02, ICALL_SIG_TYPE_int = 0x03, ICALL_SIG_TYPE_int16 = 0x04, - ICALL_SIG_TYPE_int32 = 0x05, - ICALL_SIG_TYPE_int8 = 0x06, - ICALL_SIG_TYPE_long = 0x07, - ICALL_SIG_TYPE_obj = 0x08, + ICALL_SIG_TYPE_int32 = ICALL_SIG_TYPE_int, + ICALL_SIG_TYPE_int8 = 0x05, + ICALL_SIG_TYPE_long = 0x06, + ICALL_SIG_TYPE_obj = 0x07, ICALL_SIG_TYPE_object = ICALL_SIG_TYPE_obj, - ICALL_SIG_TYPE_ptr = ICALL_SIG_TYPE_int, + ICALL_SIG_TYPE_ptr = 0x08, ICALL_SIG_TYPE_ptrref = 0x09, ICALL_SIG_TYPE_string = 0x0A, ICALL_SIG_TYPE_uint16 = 0x0B, @@ -9530,6 +9529,7 @@ typedef enum ICallSigType { ICALL_SIG_TYPE_uint8 = 0x0D, ICALL_SIG_TYPE_ulong = 0x0E, ICALL_SIG_TYPE_void = 0x0F, + ICALL_SIG_TYPE_sizet = 0x10 } ICallSigType; #define ICALL_SIG_TYPES_1(a) ICALL_SIG_TYPE_ ## a, @@ -9592,12 +9592,12 @@ mono_create_icall_signatures (void) m_class_get_byval_arg (mono_defaults.boolean_class), // ICALL_SIG_TYPE_bool m_class_get_byval_arg (mono_defaults.double_class), // ICALL_SIG_TYPE_double m_class_get_byval_arg (mono_defaults.single_class), // ICALL_SIG_TYPE_float - m_class_get_byval_arg (mono_defaults.int_class), // ICALL_SIG_TYPE_int + m_class_get_byval_arg (mono_defaults.int32_class), // ICALL_SIG_TYPE_int m_class_get_byval_arg (mono_defaults.int16_class), // ICALL_SIG_TYPE_int16 - m_class_get_byval_arg (mono_defaults.int32_class), // ICALL_SIG_TYPE_int32 m_class_get_byval_arg (mono_defaults.sbyte_class), // ICALL_SIG_TYPE_int8 m_class_get_byval_arg (mono_defaults.int64_class), // ICALL_SIG_TYPE_long m_class_get_byval_arg (mono_defaults.object_class), // ICALL_SIG_TYPE_obj + m_class_get_byval_arg (mono_defaults.int_class), // ICALL_SIG_TYPE_ptr mono_class_get_byref_type (mono_defaults.int_class), // ICALL_SIG_TYPE_ptrref m_class_get_byval_arg (mono_defaults.string_class), // ICALL_SIG_TYPE_string m_class_get_byval_arg (mono_defaults.uint16_class), // ICALL_SIG_TYPE_uint16 @@ -9605,6 +9605,7 @@ mono_create_icall_signatures (void) m_class_get_byval_arg (mono_defaults.byte_class), // ICALL_SIG_TYPE_uint8 m_class_get_byval_arg (mono_defaults.uint64_class), // ICALL_SIG_TYPE_ulong m_class_get_byval_arg (mono_defaults.void_class), // ICALL_SIG_TYPE_void + m_class_get_byval_arg (mono_defaults.int_class), // ICALL_SIG_TYPE_sizet }; MonoMethodSignature_a *sig = (MonoMethodSignature*)&mono_icall_signatures; diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index 5fbaeaf50d4a99..8d28bb63c07259 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -6607,13 +6607,12 @@ mono_string_empty_handle (MonoDomain *domain) MonoString * mono_string_new_utf16 (MonoDomain *domain, const mono_unichar2 *text, gint32 len) { - MONO_REQ_GC_UNSAFE_MODE; - - ERROR_DECL (error); MonoString *res = NULL; + MONO_ENTER_GC_UNSAFE; + ERROR_DECL (error); res = mono_string_new_utf16_checked (domain, text, len, error); mono_error_cleanup (error); - + MONO_EXIT_GC_UNSAFE; return res; } @@ -6710,10 +6709,12 @@ mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len MonoString * mono_string_new_size (MonoDomain *domain, gint32 len) { + MonoString *str; + MONO_ENTER_GC_UNSAFE; ERROR_DECL (error); - MonoString *str = mono_string_new_size_checked (domain, len, error); + str = mono_string_new_size_checked (domain, len, error); mono_error_cleanup (error); - + MONO_EXIT_GC_UNSAFE; return str; } @@ -7546,9 +7547,12 @@ mono_string_intern (MonoString *str_raw) MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx) { + MonoString *result; + MONO_ENTER_GC_UNSAFE; ERROR_DECL (error); - MonoString *result = mono_ldstr_checked (domain, image, idx, error); + result = mono_ldstr_checked (domain, image, idx, error); mono_error_cleanup (error); + MONO_EXIT_GC_UNSAFE; return result; } diff --git a/src/mono/mono/metadata/sgen-mono.c b/src/mono/mono/metadata/sgen-mono.c index ab104aafe799c2..37e4f456bc8c7f 100644 --- a/src/mono/mono/metadata/sgen-mono.c +++ b/src/mono/mono/metadata/sgen-mono.c @@ -2970,9 +2970,9 @@ sgen_client_init (void) void mono_gc_init_icalls (void) { - mono_register_jit_icall (mono_gc_alloc_obj, mono_icall_sig_object_ptr_int, FALSE); - mono_register_jit_icall (mono_gc_alloc_vector, mono_icall_sig_object_ptr_int_int, FALSE); - mono_register_jit_icall (mono_gc_alloc_string, mono_icall_sig_object_ptr_int_int32, FALSE); + mono_register_jit_icall (mono_gc_alloc_obj, mono_icall_sig_object_ptr_sizet, FALSE); + mono_register_jit_icall (mono_gc_alloc_vector, mono_icall_sig_object_ptr_sizet_ptr, FALSE); + mono_register_jit_icall (mono_gc_alloc_string, mono_icall_sig_object_ptr_sizet_int32, FALSE); mono_register_jit_icall (mono_profiler_raise_gc_allocation, mono_icall_sig_void_object, FALSE); } diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index f244d26fcf1b79..f28e0bdc8e9e22 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -6523,6 +6523,9 @@ summarizer_state_term (SummarizerGlobalState *state, gchar **out, gchar *mem, si mono_get_eh_callbacks ()->mono_summarize_managed_stack (threads [i]); } + /* The value of the breadcrumb should match the "StackHash" value written by `mono_merp_write_fingerprint_payload` */ + mono_create_crash_hash_breadcrumb (controlling); + MonoStateWriter writer; memset (&writer, 0, sizeof (writer)); diff --git a/src/mono/mono/mini/Makefile.am.in b/src/mono/mono/mini/Makefile.am.in index 025f100f015f7f..567313b6c7f4a7 100755 --- a/src/mono/mono/mini/Makefile.am.in +++ b/src/mono/mono/mini/Makefile.am.in @@ -921,11 +921,7 @@ gctest: mono gc-test.exe MONO_DEBUG_OPTIONS=clear-nursery-at-gc $(MINI_RUNTIME) --regression gc-test.exe LLVM_AOT_RUNTIME_OPTS=$(if $(LLVM),--llvm,) -if AMD64 -LLVM_AOT_COMPILER_OPTS=$(if $(LLVM),llvmllc=-mattr=+sse3,) -else -LLVM_AOT_COMPILER_OPTS= -endif +LLVM_AOT_COMPILER_OPTS=mcpu=native GSHAREDVT_RUNTIME_OPTS=$(if $(GSHAREDVT),-O=gsharedvt,) aotcheck: mono $(regtests) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index f92545f50222f5..215dd5db108c14 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -12921,10 +12921,6 @@ acfg_create (MonoAssembly *ass, guint32 jit_opts) acfg->globals = g_ptr_array_new (); acfg->image = image; acfg->jit_opts = jit_opts; - /* TODO: Write out set of SIMD instructions used, rather than just those available */ -#ifndef MONO_CROSS_COMPILE - acfg->simd_opts = mono_arch_cpu_enumerate_simd_versions (); -#endif acfg->mempool = mono_mempool_new (); acfg->extra_methods = g_ptr_array_new (); acfg->unwind_info_offsets = g_hash_table_new (NULL, NULL); diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index b8c755543ea1ac..c603e03dae7a9f 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -1916,11 +1916,6 @@ check_usable (MonoAssembly *assembly, MonoAotFileInfo *info, guint8 *blob, char usable = FALSE; } - if (!mono_aot_only && (info->simd_opts & ~mono_arch_cpu_enumerate_simd_versions ())) { - msg = g_strdup ("compiled with unsupported SIMD extensions"); - usable = FALSE; - } - if (info->gc_name_index != -1) { char *gc_name = (char*)&blob [info->gc_name_index]; const char *current_gc_name = mono_gc_get_gc_name (); diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 47b6b31fa5b538..0a0671df6b6a13 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -7252,6 +7252,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) ignore_case = decode_byte (p, &p, end); if (!mono_reflection_parse_type_checked (name, &info, error)) { + buffer_add_string (buf, mono_error_get_message (error)); mono_error_cleanup (error); g_free (name); mono_reflection_free_type_info (&info); @@ -7740,6 +7741,8 @@ assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf) case CMD_ASSEMBLY_GET_TYPE: { ERROR_DECL (error); char *s = decode_string (p, &p, end); + char* original_s = g_strdup_printf ("\"%s\"", s); + gboolean ignorecase = decode_byte (p, &p, end); MonoTypeNameParse info; MonoType *t; @@ -7755,20 +7758,33 @@ assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf) mono_error_cleanup (error); t = NULL; } else { - if (info.assembly.name) - NOT_IMPLEMENTED; + if (info.assembly.name) { + mono_reflection_free_type_info (&info); + g_free (s); + mono_domain_set_fast (d, TRUE); + char* error_msg = g_strdup_printf ("Unexpected assembly-qualified type %s was provided", original_s); + buffer_add_string (buf, error_msg); + g_free (error_msg); + g_free (original_s); + return ERR_INVALID_ARGUMENT; + } t = mono_reflection_get_type_checked (alc, ass->image, ass->image, &info, ignorecase, TRUE, &type_resolve, error); if (!is_ok (error)) { mono_error_cleanup (error); /* FIXME don't swallow the error */ mono_reflection_free_type_info (&info); g_free (s); + mono_domain_set_fast (d, TRUE); + char* error_msg = g_strdup_printf ("Invalid type name %s", original_s); + buffer_add_string (buf, error_msg); + g_free (error_msg); + g_free (original_s); return ERR_INVALID_ARGUMENT; } } buffer_add_typeid (buf, domain, t ? mono_class_from_mono_type_internal (t) : NULL); mono_reflection_free_type_info (&info); g_free (s); - + g_free (original_s); mono_domain_set_fast (d, TRUE); break; @@ -7825,6 +7841,7 @@ assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf) error_init (error); MonoClass* mono_class = mono_class_get_checked (ass->image, token, error); if (!is_ok (error)) { + buffer_add_string (buf, mono_error_get_message (error)); mono_error_cleanup (error); return ERR_INVALID_ARGUMENT; } @@ -7841,6 +7858,7 @@ assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf) error_init (error); MonoMethod* mono_method = mono_get_method_checked (ass->image, token, NULL, NULL, error); if (!is_ok (error)) { + buffer_add_string (buf, mono_error_get_message (error)); mono_error_cleanup (error); return ERR_INVALID_ARGUMENT; } @@ -8693,6 +8711,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g header = mono_method_get_header_checked (method, error); if (!header) { + buffer_add_string (buf, mono_error_get_message (error)); mono_error_cleanup (error); /* FIXME don't swallow the error */ return ERR_INVALID_ARGUMENT; } @@ -9524,7 +9543,7 @@ string_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (!is_ok (error)) { if (s) g_free (s); - + buffer_add_string (buf, mono_error_get_message (error)); return ERR_INVALID_ARGUMENT; } buffer_add_string (buf, s); diff --git a/src/mono/mono/mini/driver.c b/src/mono/mono/mini/driver.c index c32e9f4e144a59..8925f6bf92a6e6 100644 --- a/src/mono/mono/mini/driver.c +++ b/src/mono/mono/mini/driver.c @@ -2168,7 +2168,7 @@ mono_main (int argc, char* argv[]) char *build = mono_get_runtime_build_info (); char *gc_descr; - g_print ("Mono JIT compiler version %s\nCopyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com\n", build); + g_print ("Mono JIT compiler version %s\nCopyright (C) Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com\n", build); g_free (build); char *info = mono_get_version_info (); g_print (info); diff --git a/src/mono/mono/mini/exceptions-amd64.c b/src/mono/mono/mini/exceptions-amd64.c index cd0397ef39ed24..617257cf9c11f3 100644 --- a/src/mono/mono/mini/exceptions-amd64.c +++ b/src/mono/mono/mini/exceptions-amd64.c @@ -1407,7 +1407,7 @@ mono_arch_unwindinfo_insert_range_in_table (const gpointer code_block, gsize blo AcquireSRWLockExclusive (&g_dynamic_function_table_lock); init_table_no_lock (); new_entry = find_range_in_table_no_lock (code_block, block_size); - if (new_entry == NULL) { + if (new_entry == NULL && block_size != 0) { // Allocate new entry. new_entry = g_new0 (DynamicFunctionTableEntry, 1); if (new_entry != NULL) { diff --git a/src/mono/mono/mini/interp/interp-internals.h b/src/mono/mono/mini/interp/interp-internals.h index 010074f36a9080..95c60bd5a88f14 100644 --- a/src/mono/mono/mini/interp/interp-internals.h +++ b/src/mono/mono/mini/interp/interp-internals.h @@ -19,8 +19,7 @@ #define MINT_TYPE_R4 6 #define MINT_TYPE_R8 7 #define MINT_TYPE_O 8 -#define MINT_TYPE_P 9 -#define MINT_TYPE_VT 10 +#define MINT_TYPE_VT 9 #define INLINED_METHOD_FLAG 0xffff #define TRACING_FLAG 0x1 @@ -43,9 +42,11 @@ enum { #if SIZEOF_VOID_P == 4 typedef guint32 mono_u; typedef gint32 mono_i; +#define MINT_TYPE_I MINT_TYPE_I4 #elif SIZEOF_VOID_P == 8 typedef guint64 mono_u; typedef gint64 mono_i; +#define MINT_TYPE_I MINT_TYPE_I8 #endif @@ -279,7 +280,7 @@ mint_type(MonoType *type_) { MonoType *type = mini_native_type_replace_type (type_); if (type->byref) - return MINT_TYPE_P; + return MINT_TYPE_I; enum_type: switch (type->type) { case MONO_TYPE_I1: @@ -297,13 +298,8 @@ mint_type(MonoType *type_) return MINT_TYPE_I4; case MONO_TYPE_I: case MONO_TYPE_U: -#if SIZEOF_VOID_P == 4 - return MINT_TYPE_I4; -#else - return MINT_TYPE_I8; -#endif case MONO_TYPE_PTR: - return MINT_TYPE_P; + return MINT_TYPE_I; case MONO_TYPE_R4: return MINT_TYPE_R4; case MONO_TYPE_I8: diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 3a9bd3e2aed0cf..c61cf8ccf4ab6d 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -3595,7 +3595,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs THROW_EX (ex, ip); EXCEPTION_CHECKPOINT; } - ip += 2; const gboolean realloc_frame = new_method->alloca_size > frame->imethod->alloca_size; frame->imethod = new_method; /* @@ -5022,11 +5021,13 @@ call:; MINT_IN_CASE(MINT_NEWOBJ_VT_FAST) MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) { + guint16 imethod_index = ip [1]; + gboolean is_inlined = imethod_index == INLINED_METHOD_FLAG; - frame->ip = ip; - cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; guint16 const param_count = ip [2]; + frame->ip = ip; + // Make room for extra parameter and result. if (param_count) { sp -= param_count; @@ -5049,6 +5050,14 @@ call:; memset (sp, 0, sizeof (*sp)); sp [1].data.p = &sp [0].data; // valuetype_this == result } + + if (is_inlined) { + if (vtst) + vt_sp += ALIGN_TO (ip [-1], MINT_VT_ALIGNMENT); + sp += param_count + 2; + MINT_IN_BREAK; + } + cmethod = (InterpMethod*)frame->imethod->data_items [imethod_index]; } // call_newobj captures the pattern where the return value is placed // on the stack before the call, instead of the call forming it. @@ -5323,7 +5332,6 @@ call:; MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK; @@ -5371,7 +5379,6 @@ call:; MINT_IN_CASE(MINT_LDARGFLD_R4) LDARGFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDARGFLD_R8) LDARGFLD(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDARGFLD_O) LDARGFLD(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARGFLD_P) LDARGFLD(p, gpointer); MINT_IN_BREAK; #define LDLOCFLD(datamem, fieldtype) do { \ MonoObject *o = *(MonoObject**)(locals + ip [1]); \ @@ -5389,7 +5396,6 @@ call:; MINT_IN_CASE(MINT_LDLOCFLD_R4) LDLOCFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDLOCFLD_R8) LDLOCFLD(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDLOCFLD_O) LDLOCFLD(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOCFLD_P) LDLOCFLD(p, gpointer); MINT_IN_BREAK; #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \ MonoObject* const o = sp [-2].data.o; \ @@ -5412,7 +5418,6 @@ call:; MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STFLD_O) { MonoObject* const o = sp [-2].data.o; NULL_CHECK (o); @@ -5483,7 +5488,6 @@ call:; MINT_IN_CASE(MINT_STARGFLD_I8) STARGFLD(l, gint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_STARGFLD_R4) STARGFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_STARGFLD_R8) STARGFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARGFLD_P) STARGFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STARGFLD_O) { MonoObject *o = frame->stack_args [ip [1]].data.o; NULL_CHECK (o); @@ -5508,7 +5512,6 @@ call:; MINT_IN_CASE(MINT_STLOCFLD_I8) STLOCFLD(l, gint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_STLOCFLD_R4) STLOCFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_STLOCFLD_R8) STLOCFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOCFLD_P) STLOCFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STLOCFLD_O) { MonoObject *o = *(MonoObject**)(locals + ip [1]); NULL_CHECK (o); @@ -5553,7 +5556,6 @@ call:; MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDSFLD_VT) { MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; @@ -5586,7 +5588,6 @@ call:; MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDSSFLD) { guint32 offset = READ32(ip + 2); @@ -5625,7 +5626,6 @@ call:; MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STSFLD_VT) { @@ -5658,7 +5658,6 @@ call:; MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STSSFLD) { @@ -6700,7 +6699,6 @@ call:; MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDARG_P0) LDARGn(p, gpointer, 0); MINT_IN_BREAK; @@ -6728,7 +6726,6 @@ call:; MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STARG_VT) { int const i32 = READ32 (ip + 2); @@ -6830,7 +6827,6 @@ call:; MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDLOC_VT) { sp->data.p = vt_sp; @@ -6861,7 +6857,6 @@ call:; MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK; #define STLOC_NP(datamem, argtype) \ * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \ diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 3074dea68c8b54..ed7f2a66fd14fb 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -55,7 +55,6 @@ OPDEF(MINT_LDARG_I8, "ldarg.i8", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDARG_R4, "ldarg.r4", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDARG_R8, "ldarg.r8", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDARG_O, "ldarg.o", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDARG_P, "ldarg.p", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDARG_P0, "ldarg.p0", 1, Pop0, Push1, MintOpNoArgs) OPDEF(MINT_LDARG_VT, "ldarg.vt", 4, Pop0, Push1, MintOpShortAndInt) @@ -68,7 +67,6 @@ OPDEF(MINT_STARG_I8, "starg.i8", 2, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STARG_R4, "starg.r4", 2, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STARG_R8, "starg.r8", 2, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STARG_O, "starg.o", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STARG_P, "starg.p", 2, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STARG_VT, "starg.vt", 4, Pop1, Push0, MintOpShortAndInt) OPDEF(MINT_LDARGA, "ldarga", 2, Pop0, Push1, MintOpUShortInt) @@ -83,7 +81,6 @@ OPDEF(MINT_LDFLD_I8, "ldfld.i8", 2, Pop1, Push1, MintOpUShortInt) OPDEF(MINT_LDFLD_R4, "ldfld.r4", 2, Pop1, Push1, MintOpUShortInt) OPDEF(MINT_LDFLD_R8, "ldfld.r8", 2, Pop1, Push1, MintOpUShortInt) OPDEF(MINT_LDFLD_O, "ldfld.o", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_P, "ldfld.p", 2, Pop1, Push1, MintOpUShortInt) OPDEF(MINT_LDFLD_VT, "ldfld.vt", 4, Pop1, Push1, MintOpShortAndInt) OPDEF(MINT_LDFLD_I8_UNALIGNED, "ldfld.i8.unaligned", 2, Pop1, Push1, MintOpUShortInt) OPDEF(MINT_LDFLD_R8_UNALIGNED, "ldfld.r8.unaligned", 2, Pop1, Push1, MintOpUShortInt) @@ -103,7 +100,6 @@ OPDEF(MINT_LDARGFLD_I8, "ldargfld.i8", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDARGFLD_R4, "ldargfld.r4", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDARGFLD_R8, "ldargfld.r8", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDARGFLD_O, "ldargfld.o", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDARGFLD_P, "ldargfld.p", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDLOCFLD_I1, "ldlocfld.i1", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDLOCFLD_U1, "ldlocfld.u1", 3, Pop0, Push1, MintOpTwoShorts) @@ -114,7 +110,6 @@ OPDEF(MINT_LDLOCFLD_I8, "ldlocfld.i8", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDLOCFLD_R4, "ldlocfld.r4", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDLOCFLD_R8, "ldlocfld.r8", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDLOCFLD_O, "ldlocfld.o", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDLOCFLD_P, "ldlocfld.p", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_STFLD_I1, "stfld.i1", 2, Pop2, Push0, MintOpUShortInt) OPDEF(MINT_STFLD_U1, "stfld.u1", 2, Pop2, Push0, MintOpUShortInt) @@ -125,7 +120,6 @@ OPDEF(MINT_STFLD_I8, "stfld.i8", 2, Pop2, Push0, MintOpUShortInt) OPDEF(MINT_STFLD_R4, "stfld.r4", 2, Pop2, Push0, MintOpUShortInt) OPDEF(MINT_STFLD_R8, "stfld.r8", 2, Pop2, Push0, MintOpUShortInt) OPDEF(MINT_STFLD_O, "stfld.o", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_P, "stfld.p", 2, Pop2, Push0, MintOpUShortInt) OPDEF(MINT_STFLD_VT, "stfld.vt", 3, Pop2, Push0, MintOpTwoShorts) OPDEF(MINT_STFLD_I8_UNALIGNED, "stfld.i8.unaligned", 2, Pop2, Push0, MintOpUShortInt) OPDEF(MINT_STFLD_R8_UNALIGNED, "stfld.r8.unaligned", 2, Pop2, Push0, MintOpUShortInt) @@ -142,7 +136,6 @@ OPDEF(MINT_STARGFLD_I8, "stargfld.i8", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STARGFLD_R4, "stargfld.r4", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STARGFLD_R8, "stargfld.r8", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STARGFLD_O, "stargfld.o", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STARGFLD_P, "stargfld.p", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STLOCFLD_I1, "stlocfld.i1", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STLOCFLD_U1, "stlocfld.u1", 3, Pop1, Push0, MintOpTwoShorts) @@ -153,7 +146,6 @@ OPDEF(MINT_STLOCFLD_I8, "stlocfld.i8", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STLOCFLD_R4, "stlocfld.r4", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STLOCFLD_R8, "stlocfld.r8", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_STLOCFLD_O, "stlocfld.o", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STLOCFLD_P, "stlocfld.p", 3, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_LDTSFLD_I1, "ldtsfld.i1", 3, Pop0, Push1, MintOpInt) OPDEF(MINT_LDTSFLD_U1, "ldtsfld.u1", 3, Pop0, Push1, MintOpInt) @@ -164,7 +156,6 @@ OPDEF(MINT_LDTSFLD_I8, "ldtsfld.i8", 3, Pop0, Push1, MintOpInt) OPDEF(MINT_LDTSFLD_R4, "ldtsfld.r4", 3, Pop0, Push1, MintOpInt) OPDEF(MINT_LDTSFLD_R8, "ldtsfld.r8", 3, Pop0, Push1, MintOpInt) OPDEF(MINT_LDTSFLD_O, "ldtsfld.o", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDTSFLD_P, "ldtsfld.p", 3, Pop0, Push1, MintOpInt) OPDEF(MINT_LDSSFLD, "ldssfld", 4, Pop0, Push1, MintOpFieldToken) OPDEF(MINT_LDSSFLD_VT, "ldssfld.vt", 5, Pop0, Push1, MintOpInt) @@ -177,7 +168,6 @@ OPDEF(MINT_LDSFLD_I8, "ldsfld.i8", 3, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDSFLD_R4, "ldsfld.r4", 3, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDSFLD_R8, "ldsfld.r8", 3, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDSFLD_O, "ldsfld.o", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_P, "ldsfld.p", 3, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDSFLD_VT, "ldsfld.vt", 5, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_STTSFLD_I1, "sttsfld.i1", 3, Pop1, Push0, MintOpInt) @@ -189,7 +179,6 @@ OPDEF(MINT_STTSFLD_I8, "sttsfld.i8", 3, Pop1, Push0, MintOpInt) OPDEF(MINT_STTSFLD_R4, "sttsfld.r4", 3, Pop1, Push0, MintOpInt) OPDEF(MINT_STTSFLD_R8, "sttsfld.r8", 3, Pop1, Push0, MintOpInt) OPDEF(MINT_STTSFLD_O, "sttsfld.o", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STTSFLD_P, "sttsfld.p", 3, Pop1, Push0, MintOpInt) OPDEF(MINT_STSSFLD, "stssfld", 4, Pop1, Push0, MintOpFieldToken) OPDEF(MINT_STSSFLD_VT, "stssfld.vt", 5, Pop1, Push0, MintOpInt) OPDEF(MINT_STSFLD_I1, "stsfld.i1", 3, Pop1, Push0, MintOpUShortInt) @@ -201,7 +190,6 @@ OPDEF(MINT_STSFLD_I8, "stsfld.i8", 3, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STSFLD_R4, "stsfld.r4", 3, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STSFLD_R8, "stsfld.r8", 3, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STSFLD_O, "stsfld.o", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_P, "stsfld.p", 3, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STSFLD_VT, "stsfld.vt", 5, Pop1, Push0, MintOpTwoShorts) OPDEF(MINT_LDSFLDA, "ldsflda", 3, Pop0, Push1, MintOpTwoShorts) OPDEF(MINT_LDSSFLDA, "ldssflda", 3, Pop0, Push1, MintOpInt) @@ -215,7 +203,6 @@ OPDEF(MINT_LDLOC_I8, "ldloc.i8", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDLOC_R4, "ldloc.r4", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDLOC_R8, "ldloc.r8", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDLOC_O, "ldloc.o", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_P, "ldloc.p", 2, Pop0, Push1, MintOpUShortInt) OPDEF(MINT_LDLOC_VT, "ldloc.vt", 4, Pop0, Push1, MintOpShortAndInt) OPDEF(MINT_STLOC_I1, "stloc.i1", 2, Pop1, Push0, MintOpUShortInt) @@ -227,7 +214,6 @@ OPDEF(MINT_STLOC_I8, "stloc.i8", 2, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STLOC_R4, "stloc.r4", 2, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STLOC_R8, "stloc.r8", 2, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STLOC_O, "stloc.o", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_P, "stloc.p", 2, Pop1, Push0, MintOpUShortInt) OPDEF(MINT_STLOC_VT, "stloc.vt", 4, Pop1, Push0, MintOpShortAndInt) OPDEF(MINT_STLOC_NP_I4, "stloc.np.i4", 2, Pop0, Push0, MintOpUShortInt) @@ -693,11 +679,11 @@ OPDEF(MINT_CONV_OVF_U8_R4, "conv.ovf.u8.r4", 1, Pop1, Push1, MintOpNoArgs) OPDEF(MINT_CONV_OVF_U8_R8, "conv.ovf.u8.r8", 1, Pop1, Push1, MintOpNoArgs) OPDEF(MINT_CEQ0_I4, "ceq0.i4", 1, Pop1, Push1, MintOpNoArgs) -/* unops end */ OPDEF(MINT_CONV_I4_I8_SP, "conv.i4.i8.sp", 1, Pop2, Push2, MintOpNoArgs) /* special for narrowing sp[-2] on 64 bits */ OPDEF(MINT_CONV_I8_I4_SP, "conv.i8.i4.sp", 1, Pop2, Push2, MintOpNoArgs) /* special for widening sp[-2] on 64 bits */ OPDEF(MINT_CONV_R8_R4_SP, "conv.r8.r4.sp", 1, Pop2, Push2, MintOpNoArgs) +/* unops end */ OPDEF(MINT_CKFINITE, "ckfinite", 1, Pop1, Push1, MintOpNoArgs) OPDEF(MINT_MKREFANY, "mkrefany", 2, Pop1, Push1, MintOpClassToken) diff --git a/src/mono/mono/mini/interp/mintops.h b/src/mono/mono/mini/interp/mintops.h index 41647338c09dfc..d2c0efe1066221 100644 --- a/src/mono/mono/mini/interp/mintops.h +++ b/src/mono/mono/mini/interp/mintops.h @@ -65,10 +65,10 @@ typedef enum { #define MINT_IS_PATCHABLE_CALL(op) ((op) >= MINT_CALL && (op) <= MINT_VCALL) #define MINT_IS_NEWOBJ(op) ((op) >= MINT_NEWOBJ && (op) <= MINT_NEWOBJ_MAGIC) #define MINT_IS_LDC_I4(op) ((op) >= MINT_LDC_I4_M1 && (op) <= MINT_LDC_I4) -#define MINT_IS_UNOP(op) ((op) >= MINT_ADD1_I4 && (op) <= MINT_CEQ0_I4) +#define MINT_IS_UNOP(op) ((op) >= MINT_ADD1_I4 && (op) <= MINT_CONV_R8_R4_SP) #define MINT_IS_BINOP(op) ((op) >= MINT_ADD_I4 && (op) <= MINT_CLT_UN_R8) -#define MINT_IS_LDLOCFLD(op) ((op) >= MINT_LDLOCFLD_I1 && (op) <= MINT_LDLOCFLD_P) -#define MINT_IS_STLOCFLD(op) ((op) >= MINT_STLOCFLD_I1 && (op) <= MINT_STLOCFLD_P) +#define MINT_IS_LDLOCFLD(op) ((op) >= MINT_LDLOCFLD_I1 && (op) <= MINT_LDLOCFLD_O) +#define MINT_IS_STLOCFLD(op) ((op) >= MINT_STLOCFLD_I1 && (op) <= MINT_STLOCFLD_O) #define MINT_IS_LOCUNOP(op) ((op) >= MINT_LOCADD1_I4 && (op) <= MINT_LOCSUB1_I8) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index de77ee4ae2f95e..ed641f4f615245 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -176,7 +176,6 @@ static int stack_type [] = { STACK_TYPE_R4, /*R4*/ STACK_TYPE_R8, /*R8*/ STACK_TYPE_O, /*O*/ - STACK_TYPE_MP, /*P*/ STACK_TYPE_VT }; @@ -594,7 +593,7 @@ load_arg(TransformData *td, int n) size = mono_class_value_size (klass, NULL); if (hasthis && n == 0) { - mt = MINT_TYPE_P; + mt = MINT_TYPE_I; interp_add_ins (td, MINT_LDARG_P0); klass = NULL; } else { @@ -604,8 +603,10 @@ load_arg(TransformData *td, int n) WRITE32_INS (td->last_ins, 1, &size); } } else { - if ((hasthis || mt == MINT_TYPE_P) && n == 0) { - mt = MINT_TYPE_P; + if ((hasthis || mt == MINT_TYPE_I) && n == 0) { + // Special case loading of the first ptr sized argument + if (mt != MINT_TYPE_O) + mt = MINT_TYPE_I; interp_add_ins (td, MINT_LDARG_P0); } else { interp_add_ins (td, MINT_LDARG_I1 + (mt - MINT_TYPE_I1)); @@ -1176,224 +1177,231 @@ interp_emit_ldelema (TransformData *td, MonoClass *array_class, MonoClass *check SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP); } -/* Return TRUE if call transformation is finished */ static gboolean -interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClass *constrained_class, MonoMethodSignature *csignature, gboolean readonly, int *op) +interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_method, MonoMethodSignature *csignature, int type_index) { + MonoClass *magic_class = target_method->klass; const char *tm = target_method->name; int i; - int type_index = mono_class_get_magic_index (target_method->klass); - gboolean in_corlib = m_class_get_image (target_method->klass) == mono_defaults.corlib; - const char *klass_name_space = m_class_get_name_space (target_method->klass); - const char *klass_name = m_class_get_name (target_method->klass); - - if (target_method->klass == mono_defaults.string_class) { - if (tm [0] == 'g') { - if (strcmp (tm, "get_Chars") == 0) - *op = MINT_GETCHR; - else if (strcmp (tm, "get_Length") == 0) - *op = MINT_STRLEN; - } - } else if (type_index >= 0) { - MonoClass *magic_class = target_method->klass; - const int mt = mint_type (m_class_get_byval_arg (magic_class)); - if (!strcmp (".ctor", tm)) { - MonoType *arg = csignature->params [0]; - /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */ - int arg_size = mini_magic_type_size (NULL, arg); + const int mt = mint_type (m_class_get_byval_arg (magic_class)); + if (!strcmp (".ctor", tm)) { + MonoType *arg = csignature->params [0]; + /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */ + int arg_size = mini_magic_type_size (NULL, arg); - if (arg_size > SIZEOF_VOID_P) { // 8 -> 4 - switch (type_index) { - case 0: case 1: - interp_add_ins (td, MINT_CONV_I4_I8); - break; - case 2: - interp_add_ins (td, MINT_CONV_R4_R8); - break; - } + if (arg_size > SIZEOF_VOID_P) { // 8 -> 4 + switch (type_index) { + case 0: case 1: + interp_add_ins (td, MINT_CONV_I4_I8); + break; + case 2: + interp_add_ins (td, MINT_CONV_R4_R8); + break; } + } - if (arg_size < SIZEOF_VOID_P) { // 4 -> 8 - switch (type_index) { - case 0: - interp_add_ins (td, MINT_CONV_I8_I4); - break; - case 1: - interp_add_ins (td, MINT_CONV_I8_U4); - break; - case 2: - interp_add_ins (td, MINT_CONV_R8_R4); - break; - } + if (arg_size < SIZEOF_VOID_P) { // 4 -> 8 + switch (type_index) { + case 0: + interp_add_ins (td, MINT_CONV_I8_I4); + break; + case 1: + interp_add_ins (td, MINT_CONV_I8_U4); + break; + case 2: + interp_add_ins (td, MINT_CONV_R8_R4); + break; } + } - switch (type_index) { - case 0: case 1: + switch (type_index) { + case 0: case 1: #if SIZEOF_VOID_P == 4 - interp_add_ins (td, MINT_STIND_I4); + interp_add_ins (td, MINT_STIND_I4); #else - interp_add_ins (td, MINT_STIND_I8); + interp_add_ins (td, MINT_STIND_I8); #endif - break; - case 2: + break; + case 2: #if SIZEOF_VOID_P == 4 - interp_add_ins (td, MINT_STIND_R4); + interp_add_ins (td, MINT_STIND_R4); #else - interp_add_ins (td, MINT_STIND_R8); + interp_add_ins (td, MINT_STIND_R8); #endif - break; + break; + } + + td->sp -= 2; + td->ip += 5; + return TRUE; + } else if (!strcmp ("op_Implicit", tm ) || !strcmp ("op_Explicit", tm)) { + MonoType *src = csignature->params [0]; + MonoType *dst = csignature->ret; + MonoClass *src_klass = mono_class_from_mono_type_internal (src); + int src_size = mini_magic_type_size (NULL, src); + int dst_size = mini_magic_type_size (NULL, dst); + + gboolean store_value_as_local = FALSE; + + switch (type_index) { + case 0: case 1: + if (!mini_magic_is_int_type (src) || !mini_magic_is_int_type (dst)) { + if (mini_magic_is_int_type (src)) + store_value_as_local = TRUE; + else if (mono_class_is_magic_float (src_klass)) + store_value_as_local = TRUE; + else + return FALSE; + } + break; + case 2: + if (!mini_magic_is_float_type (src) || !mini_magic_is_float_type (dst)) { + if (mini_magic_is_float_type (src)) + store_value_as_local = TRUE; + else if (mono_class_is_magic_int (src_klass)) + store_value_as_local = TRUE; + else + return FALSE; } + break; + } - td->sp -= 2; - td->ip += 5; - return TRUE; - } else if (!strcmp ("op_Implicit", tm ) || !strcmp ("op_Explicit", tm)) { - MonoType *src = csignature->params [0]; - MonoType *dst = csignature->ret; - MonoClass *src_klass = mono_class_from_mono_type_internal (src); - int src_size = mini_magic_type_size (NULL, src); - int dst_size = mini_magic_type_size (NULL, dst); + if (store_value_as_local) { + emit_store_value_as_local (td, src); - gboolean store_value_as_local = FALSE; + /* emit call to managed conversion method */ + return FALSE; + } + if (src_size > dst_size) { // 8 -> 4 switch (type_index) { case 0: case 1: - if (!mini_magic_is_int_type (src) || !mini_magic_is_int_type (dst)) { - if (mini_magic_is_int_type (src)) - store_value_as_local = TRUE; - else if (mono_class_is_magic_float (src_klass)) - store_value_as_local = TRUE; - else - return FALSE; - } + interp_add_ins (td, MINT_CONV_I4_I8); break; case 2: - if (!mini_magic_is_float_type (src) || !mini_magic_is_float_type (dst)) { - if (mini_magic_is_float_type (src)) - store_value_as_local = TRUE; - else if (mono_class_is_magic_int (src_klass)) - store_value_as_local = TRUE; - else - return FALSE; - } + interp_add_ins (td, MINT_CONV_R4_R8); break; } + } - if (store_value_as_local) { - emit_store_value_as_local (td, src); - - /* emit call to managed conversion method */ - return FALSE; - } - - if (src_size > dst_size) { // 8 -> 4 - switch (type_index) { - case 0: case 1: - interp_add_ins (td, MINT_CONV_I4_I8); - break; - case 2: - interp_add_ins (td, MINT_CONV_R4_R8); - break; - } - } - - if (src_size < dst_size) { // 4 -> 8 - switch (type_index) { - case 0: - interp_add_ins (td, MINT_CONV_I8_I4); - break; - case 1: - interp_add_ins (td, MINT_CONV_I8_U4); - break; - case 2: - interp_add_ins (td, MINT_CONV_R8_R4); - break; - } + if (src_size < dst_size) { // 4 -> 8 + switch (type_index) { + case 0: + interp_add_ins (td, MINT_CONV_I8_I4); + break; + case 1: + interp_add_ins (td, MINT_CONV_I8_U4); + break; + case 2: + interp_add_ins (td, MINT_CONV_R8_R4); + break; } + } - SET_TYPE (td->sp - 1, stack_type [mint_type (dst)], mono_class_from_mono_type_internal (dst)); - td->ip += 5; - return TRUE; - } else if (!strcmp ("op_Increment", tm)) { - g_assert (type_index != 2); // no nfloat + SET_TYPE (td->sp - 1, stack_type [mint_type (dst)], mono_class_from_mono_type_internal (dst)); + td->ip += 5; + return TRUE; + } else if (!strcmp ("op_Increment", tm)) { + g_assert (type_index != 2); // no nfloat #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_ADD1_I8); + interp_add_ins (td, MINT_ADD1_I8); #else - interp_add_ins (td, MINT_ADD1_I4); + interp_add_ins (td, MINT_ADD1_I4); #endif - SET_TYPE (td->sp - 1, stack_type [mt], magic_class); - td->ip += 5; - return TRUE; - } else if (!strcmp ("op_Decrement", tm)) { - g_assert (type_index != 2); // no nfloat + SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->ip += 5; + return TRUE; + } else if (!strcmp ("op_Decrement", tm)) { + g_assert (type_index != 2); // no nfloat #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_SUB1_I8); + interp_add_ins (td, MINT_SUB1_I8); #else - interp_add_ins (td, MINT_SUB1_I4); + interp_add_ins (td, MINT_SUB1_I4); #endif + SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->ip += 5; + return TRUE; + } else if (!strcmp ("CompareTo", tm) || !strcmp ("Equals", tm)) { + MonoType *arg = csignature->params [0]; + + /* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed + * pointer instead of value */ + if (arg->type == MONO_TYPE_VALUETYPE) + emit_store_value_as_local (td, arg); + + /* emit call to managed conversion method */ + return FALSE; + } else if (!strcmp (".cctor", tm)) { + /* white list */ + return FALSE; + } else if (!strcmp ("Parse", tm)) { + /* white list */ + return FALSE; + } else if (!strcmp ("ToString", tm)) { + /* white list */ + return FALSE; + } else if (!strcmp ("GetHashCode", tm)) { + /* white list */ + return FALSE; + } else if (!strcmp ("IsNaN", tm) || !strcmp ("IsInfinity", tm) || !strcmp ("IsNegativeInfinity", tm) || !strcmp ("IsPositiveInfinity", tm)) { + g_assert (type_index == 2); // nfloat only + /* white list */ + return FALSE; + } + + for (i = 0; i < sizeof (int_unnop) / sizeof (MagicIntrinsic); ++i) { + if (!strcmp (int_unnop [i].op_name, tm)) { + interp_add_ins (td, int_unnop [i].insn [type_index]); SET_TYPE (td->sp - 1, stack_type [mt], magic_class); td->ip += 5; return TRUE; - } else if (!strcmp ("CompareTo", tm) || !strcmp ("Equals", tm)) { - MonoType *arg = csignature->params [0]; - - /* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed - * pointer instead of value */ - if (arg->type == MONO_TYPE_VALUETYPE) - emit_store_value_as_local (td, arg); - - /* emit call to managed conversion method */ - return FALSE; - } else if (!strcmp (".cctor", tm)) { - /* white list */ - return FALSE; - } else if (!strcmp ("Parse", tm)) { - /* white list */ - return FALSE; - } else if (!strcmp ("ToString", tm)) { - /* white list */ - return FALSE; - } else if (!strcmp ("GetHashCode", tm)) { - /* white list */ - return FALSE; - } else if (!strcmp ("IsNaN", tm) || !strcmp ("IsInfinity", tm) || !strcmp ("IsNegativeInfinity", tm) || !strcmp ("IsPositiveInfinity", tm)) { - g_assert (type_index == 2); // nfloat only - /* white list */ - return FALSE; } + } - for (i = 0; i < sizeof (int_unnop) / sizeof (MagicIntrinsic); ++i) { - if (!strcmp (int_unnop [i].op_name, tm)) { - interp_add_ins (td, int_unnop [i].insn [type_index]); - SET_TYPE (td->sp - 1, stack_type [mt], magic_class); - td->ip += 5; - return TRUE; - } + for (i = 0; i < sizeof (int_binop) / sizeof (MagicIntrinsic); ++i) { + if (!strcmp (int_binop [i].op_name, tm)) { + interp_add_ins (td, int_binop [i].insn [type_index]); + td->sp -= 1; + SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->ip += 5; + return TRUE; } + } - for (i = 0; i < sizeof (int_binop) / sizeof (MagicIntrinsic); ++i) { - if (!strcmp (int_binop [i].op_name, tm)) { - interp_add_ins (td, int_binop [i].insn [type_index]); - td->sp -= 1; - SET_TYPE (td->sp - 1, stack_type [mt], magic_class); - td->ip += 5; - return TRUE; - } + for (i = 0; i < sizeof (int_cmpop) / sizeof (MagicIntrinsic); ++i) { + if (!strcmp (int_cmpop [i].op_name, tm)) { + MonoClass *k = mono_defaults.boolean_class; + interp_add_ins (td, int_cmpop [i].insn [type_index]); + td->sp -= 1; + SET_TYPE (td->sp - 1, stack_type [mint_type (m_class_get_byval_arg (k))], k); + td->ip += 5; + return TRUE; } + } - for (i = 0; i < sizeof (int_cmpop) / sizeof (MagicIntrinsic); ++i) { - if (!strcmp (int_cmpop [i].op_name, tm)) { - MonoClass *k = mono_defaults.boolean_class; - interp_add_ins (td, int_cmpop [i].insn [type_index]); - td->sp -= 1; - SET_TYPE (td->sp - 1, stack_type [mint_type (m_class_get_byval_arg (k))], k); - td->ip += 5; - return TRUE; - } - } + g_error ("TODO: interp_transform_call %s:%s", m_class_get_name (target_method->klass), tm); +} + +/* Return TRUE if call transformation is finished */ +static gboolean +interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClass *constrained_class, MonoMethodSignature *csignature, gboolean readonly, int *op) +{ + const char *tm = target_method->name; + int type_index = mono_class_get_magic_index (target_method->klass); + gboolean in_corlib = m_class_get_image (target_method->klass) == mono_defaults.corlib; + const char *klass_name_space = m_class_get_name_space (target_method->klass); + const char *klass_name = m_class_get_name (target_method->klass); - g_error ("TODO: interp_transform_call %s:%s", m_class_get_name (target_method->klass), tm); + if (target_method->klass == mono_defaults.string_class) { + if (tm [0] == 'g') { + if (strcmp (tm, "get_Chars") == 0) + *op = MINT_GETCHR; + else if (strcmp (tm, "get_Length") == 0) + *op = MINT_STRLEN; + } + } else if (type_index >= 0) { + return interp_handle_magic_type_intrinsics (td, target_method, csignature, type_index); } else if (mono_class_is_subclass_of_internal (target_method->klass, mono_defaults.array_class, FALSE)) { if (!strcmp (tm, "get_Rank")) { *op = MINT_ARRAY_RANK; @@ -2249,7 +2257,8 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target * to it is identical to the internal pointer that is passed on the stack * when using the value type, not needing any dereferencing. */ - g_assert ((td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP); + int this_type = (td->sp - csignature->param_count - 1)->type; + g_assert (this_type == STACK_TYPE_I || this_type == STACK_TYPE_MP); if (mint_type (m_class_get_byval_arg (constrained_class)) != MINT_TYPE_VT) { /* Always load the entire stackval, to handle also the case where the enum has long storage */ interp_add_ins (td, MINT_LDIND_I8); @@ -2265,7 +2274,8 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target * but that type doesn't override the method we're * calling, so we need to box `this'. */ - g_assert ((td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP); + int this_type = (td->sp - csignature->param_count - 1)->type; + g_assert (this_type == STACK_TYPE_I || this_type == STACK_TYPE_MP); if (mint_type (m_class_get_byval_arg (constrained_class)) != MINT_TYPE_VT) { /* managed pointer on the stack, we need to deref that puppy */ /* Always load the entire stackval, to handle also the case where the enum has long storage */ @@ -3089,11 +3099,7 @@ interp_emit_ldsflda (TransformData *td, MonoClassField *field, MonoError *error) static gboolean interp_emit_load_const (TransformData *td, gpointer field_addr, int mt) { - if ((mt >= MINT_TYPE_I1 && mt <= MINT_TYPE_I4) -#if SIZEOF_VOID_P == 4 - || mt == MINT_TYPE_P -#endif - ) { + if ((mt >= MINT_TYPE_I1 && mt <= MINT_TYPE_I4)) { gint32 val; switch (mt) { case MINT_TYPE_I1: @@ -3112,11 +3118,7 @@ interp_emit_load_const (TransformData *td, gpointer field_addr, int mt) val = *(gint32*)field_addr; } interp_get_ldc_i4_from_const (td, NULL, val); - } else if (mt == MINT_TYPE_I8 -#if SIZEOF_VOID_P == 8 - || mt == MINT_TYPE_P -#endif - ) { + } else if (mt == MINT_TYPE_I8) { gint64 val = *(gint64*)field_addr; interp_add_ins (td, MINT_LDC_I8); WRITE64_INS (td->last_ins, 0, &val); @@ -3219,6 +3221,18 @@ interp_emit_sfld_access (TransformData *td, MonoClassField *field, MonoClass *fi } } +static gboolean +signature_has_vt_params (MonoMethodSignature *csignature) +{ + int i; + for (i = 0; i < csignature->param_count; ++i) { + int mt = mint_type (csignature->params [i]); + if (mt == MINT_TYPE_VT) + return TRUE; + } + return FALSE; +} + static gboolean generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoGenericContext *generic_context, MonoError *error) { @@ -3395,9 +3409,13 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (signature->hasthis) { /* * If this is value type, it is passed by address and not by value. - * FIXME We should use MINT_TYPE_P instead of MINT_TYPE_O + * Valuetype this local gets integer type MINT_TYPE_I. */ - MonoType *type = mono_get_object_type (); + MonoType *type; + if (m_class_is_valuetype (method->klass)) + type = mono_get_int_type (); + else + type = mono_get_object_type (); local = create_interp_local (td, type); arg_locals [0] = local; store_local (td, local); @@ -4546,6 +4564,17 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); goto_if_nok (error, exit); + PUSH_TYPE (td, stack_type [mint_type (m_class_get_byval_arg (klass))], klass); + } else if (klass == mono_defaults.int_class && csignature->param_count == 1) { + td->sp--; +#if SIZEOF_VOID_P == 8 + if (td->sp [0].type == STACK_TYPE_I4) + interp_add_ins (td, MINT_CONV_I8_I4); +#else + if (td->sp [0].type == STACK_TYPE_I8) + interp_add_ins (td, MINT_CONV_OVF_I4_I8); +#endif + PUSH_TYPE (td, stack_type [mint_type (m_class_get_byval_arg (klass))], klass); } else { if (m_class_get_parent (klass) == mono_defaults.array_class) { @@ -4563,53 +4592,59 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, !mono_class_is_marshalbyref (klass) && !mono_class_has_finalizer (klass) && !m_class_has_weak_fields (klass)) { - if (!m_class_is_valuetype (klass)) { - InterpInst *newobj_fast = interp_add_ins (td, MINT_NEWOBJ_FAST); - - newobj_fast->data [1] = csignature->param_count; - + gboolean is_vt = m_class_is_valuetype (klass); + int mt = mint_type (m_class_get_byval_arg (klass)); + gboolean is_vtst = is_vt ? mt == MINT_TYPE_VT : FALSE; + int vtsize = mono_class_value_size (klass, NULL); + InterpInst *newobj_fast; + + if (is_vt) { + newobj_fast = interp_add_ins (td, is_vtst ? MINT_NEWOBJ_VTST_FAST : MINT_NEWOBJ_VT_FAST); + if (is_vtst) + newobj_fast->data [2] = vtsize; + } else { MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error); goto_if_nok (error, exit); + newobj_fast = interp_add_ins (td, MINT_NEWOBJ_FAST); newobj_fast->data [2] = get_data_item_index (td, vtable); - - move_stack (td, (td->sp - td->stack) - csignature->param_count, 2); - - StackInfo *tmp_sp = td->sp - csignature->param_count - 2; - SET_TYPE (tmp_sp, STACK_TYPE_O, klass); + } + newobj_fast->data [1] = csignature->param_count; + + move_stack (td, (td->sp - td->stack) - csignature->param_count, 2); + StackInfo *tmp_sp = td->sp - csignature->param_count - 2; + SET_TYPE (tmp_sp, stack_type [mt], klass); + // for MINT_TYPE_VT, we will push a value type on vtstack + if (is_vtst) + PUSH_VT (td, vtsize); + // In vt case we pass indirect pointer as this + if (is_vt) + SET_SIMPLE_TYPE (tmp_sp + 1, STACK_TYPE_I); + else SET_TYPE (tmp_sp + 1, STACK_TYPE_O, klass); - if ((mono_interp_opt & INTERP_OPT_INLINE) && interp_method_check_inlining (td, m)) { - MonoMethodHeader *mheader = interp_method_get_header (m, error); - goto_if_nok (error, exit); + // We don't support inlining ctors of MINT_TYPE_VT which also receive a MINT_TYPE_VT + // as an argument. The reason is that we would need to push this on the vtstack before + // the argument, which is very awkward for uncommon scenario. + if ((mono_interp_opt & INTERP_OPT_INLINE) && interp_method_check_inlining (td, m) && + (!is_vtst || !signature_has_vt_params (csignature))) { + MonoMethodHeader *mheader = interp_method_get_header (m, error); + goto_if_nok (error, exit); - if (interp_inline_method (td, m, mheader, error)) { - newobj_fast->data [0] = INLINED_METHOD_FLAG; - break; - } + if (interp_inline_method (td, m, mheader, error)) { + newobj_fast->data [0] = INLINED_METHOD_FLAG; + break; } - // If inlining failed, restore the stack. - // At runtime, interp.c newobj_fast uses an extra stack element - // after the parameters to store `o` across the non-recursive call - // where GC will see it. - // move_stack with the last parameter negative does not reduce max_stack. - move_stack (td, (td->sp - td->stack) - csignature->param_count, -2); - // Set the method to be executed as part of newobj instruction - newobj_fast->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); - } else { - // Runtime (interp_exec_method_full in interp.c) inserts - // extra stack to hold this and return value, before call. - simulate_runtime_stack_increase (td, 2); - - const gboolean vt = mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT; - - interp_add_ins (td, vt ? MINT_NEWOBJ_VTST_FAST : MINT_NEWOBJ_VT_FAST); - - td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); - td->last_ins->data [1] = csignature->param_count; - - if (vt) - td->last_ins->data [2] = mono_class_value_size (klass, NULL); } + // If inlining failed, restore the stack. + // At runtime, interp.c newobj_fast uses an extra stack element + // after the parameters to store `o` across the non-recursive call + // where GC will see it. + // move_stack with the last parameter negative does not reduce max_stack. + if (is_vtst) + POP_VT (td, vtsize); + move_stack (td, (td->sp - td->stack) - csignature->param_count, -2); + // Set the method to be executed as part of newobj instruction + newobj_fast->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); } else { // Runtime (interp_exec_method_full in interp.c) inserts // extra stack to hold this and return value, before call. @@ -4790,7 +4825,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if ((td->sp - 1)->type == STACK_TYPE_O) { interp_add_ins (td, MINT_LDFLDA); } else { - g_assert ((td->sp -1)->type == STACK_TYPE_MP); + int sp_type = (td->sp - 1)->type; + g_assert (sp_type == STACK_TYPE_MP || sp_type == STACK_TYPE_I); interp_add_ins (td, MINT_LDFLDA_UNSAFE); } td->last_ins->data [0] = m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset; @@ -6387,6 +6423,8 @@ get_inst_stack_usage (TransformData *td, InterpInst *ins, int *pop, int *push) *push = imethod->rtype->type != MONO_TYPE_VOID; break; } + case MINT_NEWOBJ_VT_FAST: + case MINT_NEWOBJ_VTST_FAST: case MINT_NEWOBJ_FAST: { int param_count = ins->data [1]; gboolean is_inlined = ins->data [0] == INLINED_METHOD_FLAG; @@ -6402,8 +6440,6 @@ get_inst_stack_usage (TransformData *td, InterpInst *ins, int *pop, int *push) break; } case MINT_NEWOBJ_ARRAY: - case MINT_NEWOBJ_VT_FAST: - case MINT_NEWOBJ_VTST_FAST: *pop = ins->data [1]; *push = 1; break; @@ -6618,7 +6654,6 @@ get_movloc_for_type (int mt) case MINT_TYPE_R8: return MINT_MOVLOC_8; case MINT_TYPE_O: - case MINT_TYPE_P: #if SIZEOF_VOID_P == 8 return MINT_MOVLOC_8; #else @@ -6736,41 +6771,57 @@ static InterpInst* interp_fold_unop (TransformData *td, StackContentInfo *sp, InterpInst *ins) { StackValue result; - // Decrement sp so it's easier to access top of the stack - sp--; - if (sp->val.type != STACK_VALUE_I4 && sp->val.type != STACK_VALUE_I8) - goto cfold_failed; - // Top of the stack is a constant - switch (ins->opcode) { - INTERP_FOLD_UNOP (MINT_ADD1_I4, STACK_VALUE_I4, i, 1+); - INTERP_FOLD_UNOP (MINT_ADD1_I8, STACK_VALUE_I8, l, 1+); - INTERP_FOLD_UNOP (MINT_SUB1_I4, STACK_VALUE_I4, i, -1+); - INTERP_FOLD_UNOP (MINT_SUB1_I8, STACK_VALUE_I8, l, -1+); - INTERP_FOLD_UNOP (MINT_NEG_I4, STACK_VALUE_I4, i, -); - INTERP_FOLD_UNOP (MINT_NEG_I8, STACK_VALUE_I8, l, -); - INTERP_FOLD_UNOP (MINT_NOT_I4, STACK_VALUE_I4, i, ~); - INTERP_FOLD_UNOP (MINT_NOT_I8, STACK_VALUE_I8, l, ~); - INTERP_FOLD_UNOP (MINT_CEQ0_I4, STACK_VALUE_I4, i, 0 ==); - - INTERP_FOLD_CONV (MINT_CONV_I1_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint8); - INTERP_FOLD_CONV (MINT_CONV_I1_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint8); - INTERP_FOLD_CONV (MINT_CONV_U1_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, guint8); - INTERP_FOLD_CONV (MINT_CONV_U1_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, guint8); - - INTERP_FOLD_CONV (MINT_CONV_I2_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint16); - INTERP_FOLD_CONV (MINT_CONV_I2_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint16); - INTERP_FOLD_CONV (MINT_CONV_U2_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, guint16); - INTERP_FOLD_CONV (MINT_CONV_U2_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, guint16); - - INTERP_FOLD_CONV (MINT_CONV_I4_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32); - INTERP_FOLD_CONV (MINT_CONV_U4_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32); - - INTERP_FOLD_CONV (MINT_CONV_I8_I4, STACK_VALUE_I8, l, STACK_VALUE_I4, i, gint32); - INTERP_FOLD_CONV (MINT_CONV_I8_U4, STACK_VALUE_I8, l, STACK_VALUE_I4, i, guint32); + if (ins->opcode >= MINT_CONV_I4_I8_SP && + ins->opcode <= MINT_CONV_R8_R4_SP) { + // Decrement sp so it's easier to access top of the stack + sp -= 2; + if (sp->val.type != STACK_VALUE_I4 && sp->val.type != STACK_VALUE_I8) + goto cfold_failed; - default: + switch (ins->opcode) { + INTERP_FOLD_CONV (MINT_CONV_I4_I8_SP, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32); + INTERP_FOLD_CONV (MINT_CONV_I8_I4_SP, STACK_VALUE_I8, l, STACK_VALUE_I4, i, gint64); + default: + goto cfold_failed; + } + } else { + // Decrement sp so it's easier to access top of the stack + sp--; + if (sp->val.type != STACK_VALUE_I4 && sp->val.type != STACK_VALUE_I8) goto cfold_failed; + + // Top of the stack is a constant + switch (ins->opcode) { + INTERP_FOLD_UNOP (MINT_ADD1_I4, STACK_VALUE_I4, i, 1+); + INTERP_FOLD_UNOP (MINT_ADD1_I8, STACK_VALUE_I8, l, 1+); + INTERP_FOLD_UNOP (MINT_SUB1_I4, STACK_VALUE_I4, i, -1+); + INTERP_FOLD_UNOP (MINT_SUB1_I8, STACK_VALUE_I8, l, -1+); + INTERP_FOLD_UNOP (MINT_NEG_I4, STACK_VALUE_I4, i, -); + INTERP_FOLD_UNOP (MINT_NEG_I8, STACK_VALUE_I8, l, -); + INTERP_FOLD_UNOP (MINT_NOT_I4, STACK_VALUE_I4, i, ~); + INTERP_FOLD_UNOP (MINT_NOT_I8, STACK_VALUE_I8, l, ~); + INTERP_FOLD_UNOP (MINT_CEQ0_I4, STACK_VALUE_I4, i, 0 ==); + + INTERP_FOLD_CONV (MINT_CONV_I1_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint8); + INTERP_FOLD_CONV (MINT_CONV_I1_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint8); + INTERP_FOLD_CONV (MINT_CONV_U1_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, guint8); + INTERP_FOLD_CONV (MINT_CONV_U1_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, guint8); + + INTERP_FOLD_CONV (MINT_CONV_I2_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint16); + INTERP_FOLD_CONV (MINT_CONV_I2_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint16); + INTERP_FOLD_CONV (MINT_CONV_U2_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, guint16); + INTERP_FOLD_CONV (MINT_CONV_U2_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, guint16); + + INTERP_FOLD_CONV (MINT_CONV_I4_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32); + INTERP_FOLD_CONV (MINT_CONV_U4_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32); + + INTERP_FOLD_CONV (MINT_CONV_I8_I4, STACK_VALUE_I8, l, STACK_VALUE_I4, i, gint32); + INTERP_FOLD_CONV (MINT_CONV_I8_U4, STACK_VALUE_I8, l, STACK_VALUE_I4, i, guint32); + + default: + goto cfold_failed; + } } // We were able to compute the result of the ins instruction. We store the @@ -6778,19 +6829,19 @@ interp_fold_unop (TransformData *td, StackContentInfo *sp, InterpInst *ins) // instructions that are part of this unary operation with a single LDC. mono_interp_stats.constant_folds++; if (sp->ins != NULL) { - interp_clear_ins (td, sp->ins); - mono_interp_stats.killed_instructions++; + // The instruction that pushed the top of stack can be replaced with the new constant result if (result.type == STACK_VALUE_I4) - ins = interp_get_ldc_i4_from_const (td, ins, result.i); + sp->ins = interp_get_ldc_i4_from_const (td, sp->ins, result.i); else if (result.type == STACK_VALUE_I8) - ins = interp_inst_replace_with_i8_const (td, ins, result.l); + sp->ins = interp_inst_replace_with_i8_const (td, sp->ins, result.l); else g_assert_not_reached (); if (td->verbose_level) { g_print ("Fold unop :\n\t"); - dump_interp_inst_newline (ins); + dump_interp_inst_newline (sp->ins); } - sp->ins = ins; + mono_interp_stats.killed_instructions++; + interp_clear_ins (td, ins); } sp->val = result; return ins; @@ -7010,7 +7061,7 @@ interp_cprop (TransformData *td) replace_op = MINT_STLOC_NP_R4; else if (mt == MINT_TYPE_R8) replace_op = MINT_STLOC_NP_R8; - else if (mt == MINT_TYPE_O || mt == MINT_TYPE_P) + else if (mt == MINT_TYPE_O) replace_op = MINT_STLOC_NP_O; if (replace_op) { int stored_local = prev_ins->data [0]; @@ -7223,7 +7274,7 @@ interp_cprop (TransformData *td) // value of the stack, so it is not considered for further optimizations. sp->val.type = STACK_VALUE_NONE; } - } else if (ins->opcode == MINT_NEWOBJ_FAST && ins->data [0] == INLINED_METHOD_FLAG) { + } else if ((ins->opcode >= MINT_NEWOBJ_FAST && ins->opcode <= MINT_NEWOBJ_VTST_FAST) && ins->data [0] == INLINED_METHOD_FLAG) { int param_count = ins->data [1]; // memmove the stack values while clearing ins, to prevent instruction removal for (int i = 1; i <= param_count; i++) { @@ -7248,7 +7299,7 @@ interp_cprop (TransformData *td) } else if (MINT_IS_BINOP (ins->opcode)) { ins = interp_fold_binop (td, sp, ins); sp--; - } else if (ins->opcode >= MINT_STFLD_I1 && ins->opcode <= MINT_STFLD_P && (mono_interp_opt & INTERP_OPT_SUPER_INSTRUCTIONS)) { + } else if (ins->opcode >= MINT_STFLD_I1 && ins->opcode <= MINT_STFLD_O && (mono_interp_opt & INTERP_OPT_SUPER_INSTRUCTIONS)) { StackContentInfo *src = &sp [-2]; if (src->ins) { if (src->val.type == STACK_VALUE_LOCAL) { @@ -7329,7 +7380,7 @@ interp_super_instructions (TransformData *td) prev2_ins = NULL; prev1_ins = NULL; } - if (ins->opcode >= MINT_LDFLD_I1 && ins->opcode <= MINT_LDFLD_P && prev1_ins) { + if (ins->opcode >= MINT_LDFLD_I1 && ins->opcode <= MINT_LDFLD_O && prev1_ins) { if (prev1_ins->opcode == MINT_LDLOC_O) { int loc_index = prev1_ins->data [0]; int fld_offset = ins->data [0]; diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index aa593298d3ac4b..38b7150b77d7cd 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -1927,10 +1927,10 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } #ifdef ENABLE_NETCORE - // Return false for IsSupported for all types in System.Runtime.Intrinsics.X86 - // as we don't support them now + // Return false for IsSupported for all types in System.Runtime.Intrinsics.* + // if it's not handled in mono_emit_simd_intrinsics if (in_corlib && - !strcmp ("System.Runtime.Intrinsics.X86", cmethod_klass_name_space) && + !strncmp ("System.Runtime.Intrinsics", cmethod_klass_name_space, 25) && !strcmp (cmethod->name, "get_IsSupported")) { EMIT_NEW_ICONST (cfg, ins, 0); ins->type = STACK_I4; diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 5de18f7e27d5d4..4ea484f39dd98a 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -1467,45 +1467,28 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) return opts; } -/* - * This function test for all SSE functions supported. - * - * Returns a bitmask corresponding to all supported versions. - * - */ -guint32 -mono_arch_cpu_enumerate_simd_versions (void) +MonoCPUFeatures +mono_arch_get_cpu_features (void) { - guint32 sse_opts = 0; + guint64 features = MONO_CPU_INITED; if (mono_hwcap_x86_has_sse1) - sse_opts |= SIMD_VERSION_SSE1; + features |= MONO_CPU_X86_SSE; if (mono_hwcap_x86_has_sse2) - sse_opts |= SIMD_VERSION_SSE2; + features |= MONO_CPU_X86_SSE2; if (mono_hwcap_x86_has_sse3) - sse_opts |= SIMD_VERSION_SSE3; + features |= MONO_CPU_X86_SSE3; if (mono_hwcap_x86_has_ssse3) - sse_opts |= SIMD_VERSION_SSSE3; + features |= MONO_CPU_X86_SSSE3; if (mono_hwcap_x86_has_sse41) - sse_opts |= SIMD_VERSION_SSE41; + features |= MONO_CPU_X86_SSE41; if (mono_hwcap_x86_has_sse42) - sse_opts |= SIMD_VERSION_SSE42; - - if (mono_hwcap_x86_has_sse4a) - sse_opts |= SIMD_VERSION_SSE4a; - - return sse_opts; -} - -MonoCPUFeatures -mono_arch_get_cpu_features (void) -{ - guint64 features = MONO_CPU_INITED; + features |= MONO_CPU_X86_SSE42; if (mono_hwcap_x86_has_popcnt) features |= MONO_CPU_X86_POPCNT; @@ -5840,7 +5823,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if ((d == 0.0) && (mono_signbit (d) == 0)) { amd64_sse_xorpd_reg_reg (code, ins->dreg, ins->dreg); - } else if (cfg->compile_aot && (cfg->flags & JIT_FLAG_CODE_EXEC_ONLY)) { + } else if (cfg->compile_aot && cfg->code_exec_only) { mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8_GOT, ins->inst_p0); amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, sizeof(gpointer)); amd64_sse_movsd_reg_membase (code, ins->dreg, AMD64_R11, 0); @@ -5859,7 +5842,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) else amd64_sse_xorpd_reg_reg (code, ins->dreg, ins->dreg); } else { - if (cfg->compile_aot && (cfg->flags & JIT_FLAG_CODE_EXEC_ONLY)) { + if (cfg->compile_aot && cfg->code_exec_only) { mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4_GOT, ins->inst_p0); amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, sizeof(gpointer)); amd64_sse_movss_reg_membase (code, ins->dreg, AMD64_R11, 0); @@ -6065,19 +6048,33 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) static double r8_0 = -0.0; g_assert (ins->sreg1 == ins->dreg); - - mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, &r8_0); - amd64_sse_xorpd_reg_membase (code, ins->dreg, AMD64_RIP, 0); + + if (cfg->compile_aot && cfg->code_exec_only) { + mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8_GOT, &r8_0); + amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, sizeof (target_mgreg_t)); + amd64_sse_movsd_reg_membase (code, MONO_ARCH_FP_SCRATCH_REG, AMD64_R11, 0); + amd64_sse_xorpd_reg_reg (code, ins->dreg, MONO_ARCH_FP_SCRATCH_REG); + } else { + mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, &r8_0); + amd64_sse_xorpd_reg_membase (code, ins->dreg, AMD64_RIP, 0); + } break; } case OP_ABS: { static guint64 d = 0x7fffffffffffffffUL; g_assert (ins->sreg1 == ins->dreg); - - mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, &d); - amd64_sse_andpd_reg_membase (code, ins->dreg, AMD64_RIP, 0); - break; + + if (cfg->compile_aot && cfg->code_exec_only) { + mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8_GOT, &d); + amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, sizeof (target_mgreg_t)); + amd64_sse_movsd_reg_membase (code, MONO_ARCH_FP_SCRATCH_REG, AMD64_R11, 0); + amd64_sse_andpd_reg_reg (code, ins->dreg, MONO_ARCH_FP_SCRATCH_REG); + } else { + mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, &d); + amd64_sse_andpd_reg_membase (code, ins->dreg, AMD64_RIP, 0); + } + break; } case OP_SQRT: EMIT_SSE2_FPFUNC (code, fsqrt, ins->dreg, ins->sreg1); @@ -6100,8 +6097,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert (ins->sreg1 == ins->dreg); - mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, &r4_0); - amd64_sse_movss_reg_membase (code, MONO_ARCH_FP_SCRATCH_REG, AMD64_RIP, 0); + if (cfg->compile_aot && cfg->code_exec_only) { + mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4_GOT, &r4_0); + amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, sizeof (target_mgreg_t)); + amd64_sse_movss_reg_membase (code, MONO_ARCH_FP_SCRATCH_REG, AMD64_R11, 0); + } else { + mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, &r4_0); + amd64_sse_movss_reg_membase (code, MONO_ARCH_FP_SCRATCH_REG, AMD64_RIP, 0); + } + amd64_sse_xorps_reg_reg (code, ins->dreg, MONO_ARCH_FP_SCRATCH_REG); break; } diff --git a/src/mono/mono/mini/mini-arm.c b/src/mono/mono/mini/mini-arm.c index 00c0be5fdfebb7..55825042dc64c2 100644 --- a/src/mono/mono/mini/mini-arm.c +++ b/src/mono/mono/mini/mini-arm.c @@ -916,19 +916,6 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) return 0; } -/* - * This function test for all SIMD functions supported. - * - * Returns a bitmask corresponding to all supported versions. - * - */ -guint32 -mono_arch_cpu_enumerate_simd_versions (void) -{ - /* SIMD is currently unimplemented */ - return 0; -} - gboolean mono_arm_is_hard_float (void) { diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 8452d6073f9b71..aa019c5e37adc7 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -258,12 +258,6 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) return 0; } -guint32 -mono_arch_cpu_enumerate_simd_versions (void) -{ - return 0; -} - void mono_arch_register_lowlevel_calls (void) { diff --git a/src/mono/mono/mini/mini-mips.c b/src/mono/mono/mini/mini-mips.c index 6f6fdba6699ef3..c816d01596a1d8 100644 --- a/src/mono/mono/mini/mini-mips.c +++ b/src/mono/mono/mini/mini-mips.c @@ -720,19 +720,6 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) return opts; } -/* - * This function test for all SIMD functions supported. - * - * Returns a bitmask corresponding to all supported versions. - * - */ -guint32 -mono_arch_cpu_enumerate_simd_versions (void) -{ - /* SIMD is currently unimplemented */ - return 0; -} - GList * mono_arch_get_allocatable_int_vars (MonoCompile *cfg) { diff --git a/src/mono/mono/mini/mini-ppc.c b/src/mono/mono/mini/mini-ppc.c index 1b2e38a01bed5b..0d65d4b88fb4eb 100644 --- a/src/mono/mono/mini/mini-ppc.c +++ b/src/mono/mono/mini/mini-ppc.c @@ -617,19 +617,6 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) return opts; } -/* - * This function test for all SIMD functions supported. - * - * Returns a bitmask corresponding to all supported versions. - * - */ -guint32 -mono_arch_cpu_enumerate_simd_versions (void) -{ - /* SIMD is currently unimplemented */ - return 0; -} - #ifdef __mono_ppc64__ #define CASE_PPC32(c) #define CASE_PPC64(c) case c: diff --git a/src/mono/mono/mini/mini-riscv.c b/src/mono/mono/mini/mini-riscv.c index f43a213ea71fef..6d46c884f8c8a7 100644 --- a/src/mono/mono/mini/mini-riscv.c +++ b/src/mono/mono/mini/mini-riscv.c @@ -136,12 +136,6 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) return 0; } -guint32 -mono_arch_cpu_enumerate_simd_versions (void) -{ - return 0; -} - gboolean mono_arch_have_fast_tls (void) { diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index 60d5860ab34f4b..a0ab6c43230bbf 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -130,7 +130,12 @@ gboolean mono_use_fast_math = FALSE; // Lists of whitelisted and blacklisted CPU features MonoCPUFeatures mono_cpu_features_enabled = (MonoCPUFeatures)0; + +#ifdef DISABLE_SIMD +MonoCPUFeatures mono_cpu_features_disabled = MONO_CPU_X86_FULL_SSEAVX_COMBINED; +#else MonoCPUFeatures mono_cpu_features_disabled = (MonoCPUFeatures)0; +#endif gboolean mono_use_interpreter = FALSE; const char *mono_interp_opts_string = NULL; diff --git a/src/mono/mono/mini/mini-s390x.c b/src/mono/mono/mini/mini-s390x.c index 2e7b2b7cc9cc5e..7771fec126dc0b 100644 --- a/src/mono/mono/mini/mini-s390x.c +++ b/src/mono/mono/mini/mini-s390x.c @@ -6721,31 +6721,6 @@ mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code) #endif -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_cpu_enumerate_simd_versions. */ -/* */ -/* Function - If this CPU supports vector operations then it */ -/* supports the equivalent of SSE1-4. */ -/* */ -/*------------------------------------------------------------------*/ - -guint32 -mono_arch_cpu_enumerate_simd_versions (void) -{ - guint32 sseOpts = 0; - - if (mono_hwcap_s390x_has_vec) - sseOpts = (SIMD_VERSION_SSE1 | SIMD_VERSION_SSE2 | - SIMD_VERSION_SSE3 | SIMD_VERSION_SSSE3 | - SIMD_VERSION_SSE41 | SIMD_VERSION_SSE42 | - SIMD_VERSION_SSE4a); - - return (sseOpts); -} - -/*========================= End of Function ========================*/ - /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_opcode_supported. */ diff --git a/src/mono/mono/mini/mini-sparc.c b/src/mono/mono/mini/mini-sparc.c index 0b4b7fccd975d8..e5bce3815348d6 100644 --- a/src/mono/mono/mini/mini-sparc.c +++ b/src/mono/mono/mini/mini-sparc.c @@ -246,19 +246,6 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) return opts; } -/* - * This function test for all SIMD functions supported. - * - * Returns a bitmask corresponding to all supported versions. - * - */ -guint32 -mono_arch_cpu_enumerate_simd_versions (void) -{ - /* SIMD is currently unimplemented */ - return 0; -} - #ifdef __GNUC__ #define flushi(addr) __asm__ __volatile__ ("iflush %0"::"r"(addr):"memory") #else /* assume Sun's compiler */ diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index 6840bec69aacd7..8f1eef7f0c150d 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -461,12 +461,6 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC g_error ("mono_arch_build_imt_trampoline"); } -guint32 -mono_arch_cpu_enumerate_simd_versions (void) -{ - return 0; -} - guint32 mono_arch_cpu_optimizations (guint32 *exclude_mask) { diff --git a/src/mono/mono/mini/mini-x86.c b/src/mono/mono/mini/mini-x86.c index fd66c80e8efeb7..464dc5d969d617 100644 --- a/src/mono/mono/mini/mini-x86.c +++ b/src/mono/mono/mini/mini-x86.c @@ -784,39 +784,30 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) return opts; } -/* - * This function test for all SSE functions supported. - * - * Returns a bitmask corresponding to all supported versions. - * - */ -guint32 -mono_arch_cpu_enumerate_simd_versions (void) +MonoCPUFeatures +mono_arch_get_cpu_features (void) { - guint32 sse_opts = 0; + guint64 features = MONO_CPU_INITED; if (mono_hwcap_x86_has_sse1) - sse_opts |= SIMD_VERSION_SSE1; + features |= MONO_CPU_X86_SSE; if (mono_hwcap_x86_has_sse2) - sse_opts |= SIMD_VERSION_SSE2; + features |= MONO_CPU_X86_SSE2; if (mono_hwcap_x86_has_sse3) - sse_opts |= SIMD_VERSION_SSE3; + features |= MONO_CPU_X86_SSE3; if (mono_hwcap_x86_has_ssse3) - sse_opts |= SIMD_VERSION_SSSE3; + features |= MONO_CPU_X86_SSSE3; if (mono_hwcap_x86_has_sse41) - sse_opts |= SIMD_VERSION_SSE41; + features |= MONO_CPU_X86_SSE41; if (mono_hwcap_x86_has_sse42) - sse_opts |= SIMD_VERSION_SSE42; - - if (mono_hwcap_x86_has_sse4a) - sse_opts |= SIMD_VERSION_SSE4a; + features |= MONO_CPU_X86_SSE42; - return sse_opts; + return (MonoCPUFeatures)features; } /* diff --git a/src/mono/mono/mini/mini.c b/src/mono/mono/mini/mini.c index 145c140fb456f5..3afab1f3129c31 100644 --- a/src/mono/mono/mini/mini.c +++ b/src/mono/mono/mini/mini.c @@ -3049,6 +3049,9 @@ init_backend (MonoBackend *backend) static gboolean is_simd_supported (MonoCompile *cfg) { +#ifdef DISABLE_SIMD + return FALSE; +#endif // FIXME: Clean this up #ifdef TARGET_WASM if ((mini_get_cpu_features (cfg) & MONO_CPU_WASM_SIMD) == 0) @@ -3175,6 +3178,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl cfg->interp = (flags & JIT_FLAG_INTERP) != 0; cfg->use_current_cpu = (flags & JIT_FLAG_USE_CURRENT_CPU) != 0; cfg->self_init = (flags & JIT_FLAG_SELF_INIT) != 0; + cfg->code_exec_only = (flags & JIT_FLAG_CODE_EXEC_ONLY) != 0; cfg->backend = current_backend; if (cfg->method->wrapper_type == MONO_WRAPPER_ALLOC) { @@ -4335,7 +4339,7 @@ mini_get_cpu_features (MonoCompile* cfg) // detect current CPU features if we are in JIT mode or AOT with use_current_cpu flag. #if defined(ENABLE_LLVM) features = mono_llvm_get_cpu_features (); // llvm has a nice built-in API to detect features -#elif defined(TARGET_AMD64) +#elif defined(TARGET_AMD64) || defined(TARGET_X86) features = mono_arch_get_cpu_features (); #endif } diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index a0bd7203c6ef4a..b7d70c2ffcb336 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -1447,6 +1447,7 @@ typedef struct { guint use_current_cpu : 1; guint self_init : 1; guint domainvar_inited : 1; + guint code_exec_only : 1; guint8 uses_simd_intrinsics; int r4_stack_type; gpointer debug_info; @@ -2783,28 +2784,6 @@ char* mono_get_method_from_ip (void *ip); /* SIMD support */ -/* -This enum MUST be kept in sync with its managed mirror Mono.Simd.AccelMode. - */ -enum { - SIMD_VERSION_SSE1 = 1 << 0, - SIMD_VERSION_SSE2 = 1 << 1, - SIMD_VERSION_SSE3 = 1 << 2, - SIMD_VERSION_SSSE3 = 1 << 3, - SIMD_VERSION_SSE41 = 1 << 4, - SIMD_VERSION_SSE42 = 1 << 5, - SIMD_VERSION_SSE4a = 1 << 6, - SIMD_VERSION_ALL = SIMD_VERSION_SSE1 | SIMD_VERSION_SSE2 | - SIMD_VERSION_SSE3 | SIMD_VERSION_SSSE3 | - SIMD_VERSION_SSE41 | SIMD_VERSION_SSE42 | - SIMD_VERSION_SSE4a, - - /* this value marks the end of the bit indexes used in - * this emum. - */ - SIMD_VERSION_INDEX_END = 6 -}; - typedef enum { /* Used for lazy initialization */ MONO_CPU_INITED = 1 << 0, @@ -2968,7 +2947,6 @@ typedef enum { } SimdOp; const char *mono_arch_xregname (int reg); -guint32 mono_arch_cpu_enumerate_simd_versions (void); MonoCPUFeatures mono_arch_get_cpu_features (void); #ifdef MONO_ARCH_SIMD_INTRINSICS diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 684aab360b08c4..95367010fe36ec 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -79,6 +79,20 @@ mono_simd_intrinsics_init (void) #define IS_DEBUG_ON(cfg) ((cfg)->verbose_level >= 3) #define DEBUG(a) do { if (IS_DEBUG_ON(cfg)) { a; } } while (0) + +/* +This enum MUST be kept in sync with its managed mirror Mono.Simd.AccelMode. + */ +enum { + SIMD_VERSION_SSE1 = 1 << 0, + SIMD_VERSION_SSE2 = 1 << 1, + SIMD_VERSION_SSE3 = 1 << 2, + SIMD_VERSION_SSSE3 = 1 << 3, + SIMD_VERSION_SSE41 = 1 << 4, + SIMD_VERSION_SSE42 = 1 << 5, + SIMD_VERSION_SSE4a = 1 << 6, +}; + enum { SIMD_EMIT_BINARY, SIMD_EMIT_UNARY, @@ -118,403 +132,403 @@ enum { typedef struct { guint16 name; guint16 opcode; - guint8 simd_version_flags; + guint32 simd_version; guint8 simd_emit_mode : 4; guint8 flags : 4; } SimdIntrinsic; static const SimdIntrinsic vector4f_intrinsics[] = { - { SN_ctor, OP_EXPAND_R4, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_AddSub, OP_ADDSUBPS, SIMD_VERSION_SSE3, SIMD_EMIT_BINARY}, - { SN_AndNot, OP_ANDNPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY}, - { SN_CompareEqual, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_EQ }, - { SN_CompareLessEqual, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_LE }, - { SN_CompareLessThan, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_LT }, - { SN_CompareNotEqual, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_NEQ }, - { SN_CompareNotLessEqual, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_NLE }, - { SN_CompareNotLessThan, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_NLT }, - { SN_CompareOrdered, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_ORD }, - { SN_CompareUnordered, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_UNORD }, - { SN_ConvertToDouble, OP_CVTPS2PD, SIMD_VERSION_SSE2, SIMD_EMIT_UNARY }, - { SN_ConvertToInt, OP_CVTPS2DQ, SIMD_VERSION_SSE2, SIMD_EMIT_UNARY }, - { SN_ConvertToIntTruncated, OP_CVTTPS2DQ, SIMD_VERSION_SSE2, SIMD_EMIT_UNARY }, - { SN_DuplicateHigh, OP_DUPPS_HIGH, SIMD_VERSION_SSE3, SIMD_EMIT_UNARY }, - { SN_DuplicateLow, OP_DUPPS_LOW, SIMD_VERSION_SSE3, SIMD_EMIT_UNARY }, - { SN_HorizontalAdd, OP_HADDPS, SIMD_VERSION_SSE3, SIMD_EMIT_BINARY }, - { SN_HorizontalSub, OP_HSUBPS, SIMD_VERSION_SSE3, SIMD_EMIT_BINARY }, - { SN_InterleaveHigh, OP_UNPACK_HIGHPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_InterleaveLow, OP_UNPACK_LOWPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_InvSqrt, OP_RSQRTPS, SIMD_VERSION_SSE1, SIMD_EMIT_UNARY }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_Max, OP_MAXPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_Min, OP_MINPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_Reciprocal, OP_RCPPS, SIMD_VERSION_SSE1, SIMD_EMIT_UNARY }, - { SN_Shuffle, OP_PSHUFLED, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_Sqrt, OP_SQRTPS, SIMD_VERSION_SSE1, SIMD_EMIT_UNARY }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_StoreNonTemporal, OP_STOREX_NTA_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_get_W, 3, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_Z, 2, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_op_Addition, OP_ADDPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_ANDPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_ORPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Division, OP_DIVPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Equality, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, - { SN_op_ExclusiveOr, OP_XORPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_Inequality, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, - { SN_op_Multiply, OP_MULPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Subtraction, OP_SUBPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_W, 3, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_Z, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER } + { SN_ctor, OP_EXPAND_R4, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_AddSub, OP_ADDSUBPS, MONO_CPU_X86_SSE3, SIMD_EMIT_BINARY}, + { SN_AndNot, OP_ANDNPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY}, + { SN_CompareEqual, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_EQ }, + { SN_CompareLessEqual, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_LE }, + { SN_CompareLessThan, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_LT }, + { SN_CompareNotEqual, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_NEQ }, + { SN_CompareNotLessEqual, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_NLE }, + { SN_CompareNotLessThan, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_NLT }, + { SN_CompareOrdered, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_ORD }, + { SN_CompareUnordered, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_UNORD }, + { SN_ConvertToDouble, OP_CVTPS2PD, MONO_CPU_X86_SSE2, SIMD_EMIT_UNARY }, + { SN_ConvertToInt, OP_CVTPS2DQ, MONO_CPU_X86_SSE2, SIMD_EMIT_UNARY }, + { SN_ConvertToIntTruncated, OP_CVTTPS2DQ, MONO_CPU_X86_SSE2, SIMD_EMIT_UNARY }, + { SN_DuplicateHigh, OP_DUPPS_HIGH, MONO_CPU_X86_SSE3, SIMD_EMIT_UNARY }, + { SN_DuplicateLow, OP_DUPPS_LOW, MONO_CPU_X86_SSE3, SIMD_EMIT_UNARY }, + { SN_HorizontalAdd, OP_HADDPS, MONO_CPU_X86_SSE3, SIMD_EMIT_BINARY }, + { SN_HorizontalSub, OP_HSUBPS, MONO_CPU_X86_SSE3, SIMD_EMIT_BINARY }, + { SN_InterleaveHigh, OP_UNPACK_HIGHPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_InterleaveLow, OP_UNPACK_LOWPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_InvSqrt, OP_RSQRTPS, MONO_CPU_X86_SSE, SIMD_EMIT_UNARY }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_Max, OP_MAXPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_Min, OP_MINPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_Reciprocal, OP_RCPPS, MONO_CPU_X86_SSE, SIMD_EMIT_UNARY }, + { SN_Shuffle, OP_PSHUFLED, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_Sqrt, OP_SQRTPS, MONO_CPU_X86_SSE, SIMD_EMIT_UNARY }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_StoreNonTemporal, OP_STOREX_NTA_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_get_W, 3, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_Z, 2, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_op_Addition, OP_ADDPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_ANDPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_ORPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Division, OP_DIVPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Equality, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, + { SN_op_ExclusiveOr, OP_XORPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_Inequality, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, + { SN_op_Multiply, OP_MULPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Subtraction, OP_SUBPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_W, 3, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_Z, 2, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER } }; static const SimdIntrinsic vector2d_intrinsics[] = { - { SN_ctor, OP_EXPAND_R8, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_AddSub, OP_ADDSUBPD, SIMD_VERSION_SSE3, SIMD_EMIT_BINARY,}, - { SN_AndNot, OP_ANDNPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_CompareEqual, OP_COMPPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_EQ }, - { SN_CompareLessEqual, OP_COMPPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_LE }, - { SN_CompareLessThan, OP_COMPPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_LT }, - { SN_CompareNotEqual, OP_COMPPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_NEQ }, - { SN_CompareNotLessEqual, OP_COMPPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_NLE }, - { SN_CompareNotLessThan, OP_COMPPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_NLT }, - { SN_CompareOrdered, OP_COMPPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_ORD }, - { SN_CompareUnordered, OP_COMPPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_COMP_UNORD }, - { SN_ConvertToFloat, OP_CVTPD2PS, SIMD_VERSION_SSE2, SIMD_EMIT_UNARY }, - { SN_ConvertToInt, OP_CVTPD2DQ, SIMD_VERSION_SSE2, SIMD_EMIT_UNARY }, - { SN_ConvertToIntTruncated, OP_CVTTPD2DQ, SIMD_VERSION_SSE2, SIMD_EMIT_UNARY }, - { SN_Duplicate, OP_DUPPD, SIMD_VERSION_SSE3, SIMD_EMIT_UNARY }, - { SN_HorizontalAdd, OP_HADDPD, SIMD_VERSION_SSE3, SIMD_EMIT_BINARY }, - { SN_HorizontalSub, OP_HSUBPD, SIMD_VERSION_SSE3, SIMD_EMIT_BINARY }, - { SN_InterleaveHigh, OP_UNPACK_HIGHPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_InterleaveLow, OP_UNPACK_LOWPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_Max, OP_MAXPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_Min, OP_MINPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_Shuffle, OP_SHUFPD, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_Sqrt, OP_SQRTPD, SIMD_VERSION_SSE1, SIMD_EMIT_UNARY }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_get_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER_QWORD }, - { SN_get_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER_QWORD }, - { SN_op_Addition, OP_ADDPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_ANDPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_ORPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Division, OP_DIVPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_ExclusiveOr, OP_XORPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_Multiply, OP_MULPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Subtraction, OP_SUBPD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, + { SN_ctor, OP_EXPAND_R8, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_AddSub, OP_ADDSUBPD, MONO_CPU_X86_SSE3, SIMD_EMIT_BINARY,}, + { SN_AndNot, OP_ANDNPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_CompareEqual, OP_COMPPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_EQ }, + { SN_CompareLessEqual, OP_COMPPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_LE }, + { SN_CompareLessThan, OP_COMPPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_LT }, + { SN_CompareNotEqual, OP_COMPPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_NEQ }, + { SN_CompareNotLessEqual, OP_COMPPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_NLE }, + { SN_CompareNotLessThan, OP_COMPPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_NLT }, + { SN_CompareOrdered, OP_COMPPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_ORD }, + { SN_CompareUnordered, OP_COMPPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, SIMD_COMP_UNORD }, + { SN_ConvertToFloat, OP_CVTPD2PS, MONO_CPU_X86_SSE2, SIMD_EMIT_UNARY }, + { SN_ConvertToInt, OP_CVTPD2DQ, MONO_CPU_X86_SSE2, SIMD_EMIT_UNARY }, + { SN_ConvertToIntTruncated, OP_CVTTPD2DQ, MONO_CPU_X86_SSE2, SIMD_EMIT_UNARY }, + { SN_Duplicate, OP_DUPPD, MONO_CPU_X86_SSE3, SIMD_EMIT_UNARY }, + { SN_HorizontalAdd, OP_HADDPD, MONO_CPU_X86_SSE3, SIMD_EMIT_BINARY }, + { SN_HorizontalSub, OP_HSUBPD, MONO_CPU_X86_SSE3, SIMD_EMIT_BINARY }, + { SN_InterleaveHigh, OP_UNPACK_HIGHPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_InterleaveLow, OP_UNPACK_LOWPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_Max, OP_MAXPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_Min, OP_MINPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_Shuffle, OP_SHUFPD, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_Sqrt, OP_SQRTPD, MONO_CPU_X86_SSE, SIMD_EMIT_UNARY }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_get_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER_QWORD }, + { SN_get_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER_QWORD }, + { SN_op_Addition, OP_ADDPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_ANDPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_ORPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Division, OP_DIVPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_ExclusiveOr, OP_XORPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_Multiply, OP_MULPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Subtraction, OP_SUBPD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, }; static const SimdIntrinsic vector2ul_intrinsics[] = { - { SN_ctor, OP_EXPAND_I8, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_CompareEqual, OP_PCMPEQQ, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_Shuffle, OP_SHUFPD, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_UnpackHigh, OP_UNPACK_HIGHQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackLow, OP_UNPACK_LOWQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_get_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER_QWORD }, - { SN_get_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER_QWORD }, - { SN_op_Addition, OP_PADDQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_PAND, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_POR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_ExclusiveOr, OP_PXOR, SIMD_EMIT_BINARY, SIMD_VERSION_SSE1 }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_LeftShift, OP_PSHLQ, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Multiply, OP_PMULQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_RightShift, OP_PSHRQ, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Subtraction, OP_PSUBQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, + { SN_ctor, OP_EXPAND_I8, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_CompareEqual, OP_PCMPEQQ, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_Shuffle, OP_SHUFPD, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_UnpackHigh, OP_UNPACK_HIGHQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackLow, OP_UNPACK_LOWQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_get_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER_QWORD }, + { SN_get_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER_QWORD }, + { SN_op_Addition, OP_PADDQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_PAND, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_POR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_ExclusiveOr, OP_PXOR, SIMD_EMIT_BINARY, MONO_CPU_X86_SSE }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_LeftShift, OP_PSHLQ, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Multiply, OP_PMULQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_RightShift, OP_PSHRQ, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Subtraction, OP_PSUBQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, }; static const SimdIntrinsic vector2l_intrinsics[] = { - { SN_ctor, OP_EXPAND_I8, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_CompareEqual, OP_PCMPEQQ, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_CompareGreaterThan, OP_PCMPGTQ, SIMD_VERSION_SSE42, SIMD_EMIT_BINARY }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_LogicalRightShift, OP_PSHRQ, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_Shuffle, OP_SHUFPD, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_UnpackHigh, OP_UNPACK_HIGHQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackLow, OP_UNPACK_LOWQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_get_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER_QWORD }, - { SN_get_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER_QWORD }, - { SN_op_Addition, OP_PADDQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_PAND, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_POR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_ExclusiveOr, OP_PXOR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_LeftShift, OP_PSHLQ, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Multiply, OP_PMULQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Subtraction, OP_PSUBQ, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, + { SN_ctor, OP_EXPAND_I8, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_CompareEqual, OP_PCMPEQQ, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_CompareGreaterThan, OP_PCMPGTQ, MONO_CPU_X86_SSE42, SIMD_EMIT_BINARY }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_LogicalRightShift, OP_PSHRQ, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_Shuffle, OP_SHUFPD, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_UnpackHigh, OP_UNPACK_HIGHQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackLow, OP_UNPACK_LOWQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_get_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER_QWORD }, + { SN_get_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER_QWORD }, + { SN_op_Addition, OP_PADDQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_PAND, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_POR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_ExclusiveOr, OP_PXOR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_LeftShift, OP_PSHLQ, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Multiply, OP_PMULQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Subtraction, OP_PSUBQ, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, }; static const SimdIntrinsic vector4ui_intrinsics[] = { - { SN_ctor, OP_EXPAND_I4, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_ArithmeticRightShift, OP_PSARD, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_CompareEqual, OP_PCMPEQD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_Max, OP_PMAXD_UN, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_Min, OP_PMIND_UN, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_Shuffle, OP_PSHUFLED, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_SignedPackWithSignedSaturation, OP_PACKD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_SignedPackWithUnsignedSaturation, OP_PACKD_UN, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_UnpackHigh, OP_UNPACK_HIGHD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackLow, OP_UNPACK_LOWD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_get_W, 3, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_Z, 2, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_op_Addition, OP_PADDD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_PAND, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_POR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Equality, OP_PCMPEQD, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, - { SN_op_ExclusiveOr, OP_PXOR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_Inequality, OP_PCMPEQD, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, - { SN_op_LeftShift, OP_PSHLD, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Multiply, OP_PMULD, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_op_RightShift, OP_PSHRD, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Subtraction, OP_PSUBD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_W, 3, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_Z, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, + { SN_ctor, OP_EXPAND_I4, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_ArithmeticRightShift, OP_PSARD, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_CompareEqual, OP_PCMPEQD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_Max, OP_PMAXD_UN, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_Min, OP_PMIND_UN, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_Shuffle, OP_PSHUFLED, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_SignedPackWithSignedSaturation, OP_PACKD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_SignedPackWithUnsignedSaturation, OP_PACKD_UN, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_UnpackHigh, OP_UNPACK_HIGHD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackLow, OP_UNPACK_LOWD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_get_W, 3, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_Z, 2, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_op_Addition, OP_PADDD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_PAND, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_POR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Equality, OP_PCMPEQD, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, + { SN_op_ExclusiveOr, OP_PXOR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_Inequality, OP_PCMPEQD, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, + { SN_op_LeftShift, OP_PSHLD, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Multiply, OP_PMULD, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_op_RightShift, OP_PSHRD, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Subtraction, OP_PSUBD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_W, 3, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_Z, 2, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, }; static const SimdIntrinsic vector4i_intrinsics[] = { - { SN_ctor, OP_EXPAND_I4, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_CompareEqual, OP_PCMPEQD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_CompareGreaterThan, OP_PCMPGTD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_ConvertToDouble, OP_CVTDQ2PD, SIMD_VERSION_SSE2, SIMD_EMIT_UNARY }, - { SN_ConvertToFloat, OP_CVTDQ2PS, SIMD_VERSION_SSE2, SIMD_EMIT_UNARY }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_LogicalRightShift, OP_PSHRD, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_Max, OP_PMAXD, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_Min, OP_PMIND, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_PackWithSignedSaturation, OP_PACKD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_PackWithUnsignedSaturation, OP_PACKD_UN, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_Shuffle, OP_PSHUFLED, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_UnpackHigh, OP_UNPACK_HIGHD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackLow, OP_UNPACK_LOWD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_get_W, 3, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_Z, 2, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_op_Addition, OP_PADDD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_PAND, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_POR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Equality, OP_PCMPEQD, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, - { SN_op_ExclusiveOr, OP_PXOR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_Inequality, OP_PCMPEQD, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, - { SN_op_LeftShift, OP_PSHLD, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Multiply, OP_PMULD, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_op_RightShift, OP_PSARD, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Subtraction, OP_PSUBD, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_W, 3, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_X, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_Y, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_Z, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, + { SN_ctor, OP_EXPAND_I4, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_CompareEqual, OP_PCMPEQD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_CompareGreaterThan, OP_PCMPGTD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_ConvertToDouble, OP_CVTDQ2PD, MONO_CPU_X86_SSE2, SIMD_EMIT_UNARY }, + { SN_ConvertToFloat, OP_CVTDQ2PS, MONO_CPU_X86_SSE2, SIMD_EMIT_UNARY }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_LogicalRightShift, OP_PSHRD, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_Max, OP_PMAXD, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_Min, OP_PMIND, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_PackWithSignedSaturation, OP_PACKD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_PackWithUnsignedSaturation, OP_PACKD_UN, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_Shuffle, OP_PSHUFLED, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_UnpackHigh, OP_UNPACK_HIGHD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackLow, OP_UNPACK_LOWD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_get_W, 3, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_Z, 2, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_op_Addition, OP_PADDD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_PAND, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_POR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Equality, OP_PCMPEQD, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, + { SN_op_ExclusiveOr, OP_PXOR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_Inequality, OP_PCMPEQD, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, + { SN_op_LeftShift, OP_PSHLD, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Multiply, OP_PMULD, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_op_RightShift, OP_PSARD, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Subtraction, OP_PSUBD, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_W, 3, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_X, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_Y, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_Z, 2, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, }; static const SimdIntrinsic vector8us_intrinsics[] = { - { SN_ctor, OP_EXPAND_I2, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_AddWithSaturation, OP_PADDW_SAT_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_ArithmeticRightShift, OP_PSARW, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_Average, OP_PAVGW_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_CompareEqual, OP_PCMPEQW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY, SIMD_VERSION_SSE1 }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_Max, OP_PMAXW_UN, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_Min, OP_PMINW_UN, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_MultiplyStoreHigh, OP_PMULW_HIGH_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_ShuffleHigh, OP_PSHUFLEW_HIGH, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_ShuffleLow, OP_PSHUFLEW_LOW, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_SignedPackWithSignedSaturation, OP_PACKW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_SignedPackWithUnsignedSaturation, OP_PACKW_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_SubtractWithSaturation, OP_PSUBW_SAT_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackHigh, OP_UNPACK_HIGHW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackLow, OP_UNPACK_LOWW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_get_V0, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V1, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V2, 2, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V3, 3, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V4, 4, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V5, 5, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V6, 6, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_op_Addition, OP_PADDW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_PAND, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_POR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Equality, OP_PCMPEQW, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, - { SN_op_ExclusiveOr, OP_PXOR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_Inequality, OP_PCMPEQW, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, - { SN_op_LeftShift, OP_PSHLW, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Multiply, OP_PMULW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_RightShift, OP_PSHRW, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Subtraction, OP_PSUBW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_V0, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V1, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V2, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V3, 3, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V4, 4, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V5, 5, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V6, 6, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, + { SN_ctor, OP_EXPAND_I2, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_AddWithSaturation, OP_PADDW_SAT_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_ArithmeticRightShift, OP_PSARW, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_Average, OP_PAVGW_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_CompareEqual, OP_PCMPEQW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY, MONO_CPU_X86_SSE }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_Max, OP_PMAXW_UN, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_Min, OP_PMINW_UN, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_MultiplyStoreHigh, OP_PMULW_HIGH_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_ShuffleHigh, OP_PSHUFLEW_HIGH, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_ShuffleLow, OP_PSHUFLEW_LOW, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_SignedPackWithSignedSaturation, OP_PACKW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_SignedPackWithUnsignedSaturation, OP_PACKW_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_SubtractWithSaturation, OP_PSUBW_SAT_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackHigh, OP_UNPACK_HIGHW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackLow, OP_UNPACK_LOWW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_get_V0, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V1, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V2, 2, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V3, 3, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V4, 4, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V5, 5, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V6, 6, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V7, 7, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_op_Addition, OP_PADDW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_PAND, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_POR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Equality, OP_PCMPEQW, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, + { SN_op_ExclusiveOr, OP_PXOR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_Inequality, OP_PCMPEQW, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, + { SN_op_LeftShift, OP_PSHLW, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Multiply, OP_PMULW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_RightShift, OP_PSHRW, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Subtraction, OP_PSUBW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_V0, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V1, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V2, 2, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V3, 3, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V4, 4, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V5, 5, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V6, 6, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V7, 7, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, }; static const SimdIntrinsic vector8s_intrinsics[] = { - { SN_ctor, OP_EXPAND_I2, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_AddWithSaturation, OP_PADDW_SAT, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_CompareEqual, OP_PCMPEQW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_CompareGreaterThan, OP_PCMPGTW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_LogicalRightShift, OP_PSHRW, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_Max, OP_PMAXW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_Min, OP_PMINW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_MultiplyStoreHigh, OP_PMULW_HIGH, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_PackWithSignedSaturation, OP_PACKW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_PackWithUnsignedSaturation, OP_PACKW_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_ShuffleHigh, OP_PSHUFLEW_HIGH, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_ShuffleLow, OP_PSHUFLEW_LOW, SIMD_VERSION_SSE1, SIMD_EMIT_SHUFFLE }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_SubtractWithSaturation, OP_PSUBW_SAT_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackHigh, OP_UNPACK_HIGHW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackLow, OP_UNPACK_LOWW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_get_V0, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V1, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V2, 2, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V3, 3, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V4, 4, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V5, 5, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V6, 6, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_op_Addition, OP_PADDW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_PAND, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_POR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Equality, OP_PCMPEQW, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, - { SN_op_ExclusiveOr, OP_PXOR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_Inequality, OP_PCMPEQW, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, - { SN_op_LeftShift, OP_PSHLW, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Multiply, OP_PMULW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_RightShift, OP_PSARW, SIMD_VERSION_SSE1, SIMD_EMIT_SHIFT }, - { SN_op_Subtraction, OP_PSUBW, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_V0, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V1, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V2, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V3, 3, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V4, 4, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V5, 5, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V6, 6, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, + { SN_ctor, OP_EXPAND_I2, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_AddWithSaturation, OP_PADDW_SAT, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_CompareEqual, OP_PCMPEQW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_CompareGreaterThan, OP_PCMPGTW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_LogicalRightShift, OP_PSHRW, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_Max, OP_PMAXW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_Min, OP_PMINW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_MultiplyStoreHigh, OP_PMULW_HIGH, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_PackWithSignedSaturation, OP_PACKW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_PackWithUnsignedSaturation, OP_PACKW_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_ShuffleHigh, OP_PSHUFLEW_HIGH, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_ShuffleLow, OP_PSHUFLEW_LOW, MONO_CPU_X86_SSE, SIMD_EMIT_SHUFFLE }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_SubtractWithSaturation, OP_PSUBW_SAT_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackHigh, OP_UNPACK_HIGHW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackLow, OP_UNPACK_LOWW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_get_V0, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V1, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V2, 2, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V3, 3, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V4, 4, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V5, 5, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V6, 6, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V7, 7, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_op_Addition, OP_PADDW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_PAND, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_POR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Equality, OP_PCMPEQW, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, + { SN_op_ExclusiveOr, OP_PXOR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_Inequality, OP_PCMPEQW, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, + { SN_op_LeftShift, OP_PSHLW, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Multiply, OP_PMULW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_RightShift, OP_PSARW, MONO_CPU_X86_SSE, SIMD_EMIT_SHIFT }, + { SN_op_Subtraction, OP_PSUBW, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_V0, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V1, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V2, 2, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V3, 3, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V4, 4, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V5, 5, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V6, 6, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V7, 7, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, }; static const SimdIntrinsic vector16b_intrinsics[] = { - { SN_ctor, OP_EXPAND_I1, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_AddWithSaturation, OP_PADDB_SAT_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_Average, OP_PAVGB_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_CompareEqual, OP_PCMPEQB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_ExtractByteMask, 0, SIMD_VERSION_SSE1, SIMD_EMIT_EXTRACT_MASK }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_Max, OP_PMAXB_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_Min, OP_PMINB_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_SubtractWithSaturation, OP_PSUBB_SAT_UN, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_SumOfAbsoluteDifferences, OP_PSUM_ABS_DIFF, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackHigh, OP_UNPACK_HIGHB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackLow, OP_UNPACK_LOWB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_get_V0, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V1, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V10, 10, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V11, 11, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V12, 12, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V13, 13, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V14, 14, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V15, 15, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V2, 2, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V3, 3, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V4, 4, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V5, 5, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V6, 6, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V8, 8, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V9, 9, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_op_Addition, OP_PADDB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_PAND, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_POR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Equality, OP_PCMPEQB, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, - { SN_op_ExclusiveOr, OP_PXOR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_Inequality, OP_PCMPEQB, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, - { SN_op_Subtraction, OP_PSUBB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_V0, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V1, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V10, 10, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V11, 11, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V12, 12, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V13, 13, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V14, 14, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V15, 15, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V2, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V3, 3, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V4, 4, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V5, 5, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V6, 6, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V8, 8, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V9, 9, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, + { SN_ctor, OP_EXPAND_I1, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_AddWithSaturation, OP_PADDB_SAT_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_Average, OP_PAVGB_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_CompareEqual, OP_PCMPEQB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_ExtractByteMask, 0, MONO_CPU_X86_SSE, SIMD_EMIT_EXTRACT_MASK }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_Max, OP_PMAXB_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_Min, OP_PMINB_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_SubtractWithSaturation, OP_PSUBB_SAT_UN, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_SumOfAbsoluteDifferences, OP_PSUM_ABS_DIFF, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackHigh, OP_UNPACK_HIGHB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackLow, OP_UNPACK_LOWB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_get_V0, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V1, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V10, 10, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V11, 11, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V12, 12, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V13, 13, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V14, 14, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V15, 15, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V2, 2, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V3, 3, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V4, 4, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V5, 5, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V6, 6, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V7, 7, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V8, 8, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V9, 9, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_op_Addition, OP_PADDB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_PAND, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_POR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Equality, OP_PCMPEQB, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, + { SN_op_ExclusiveOr, OP_PXOR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_Inequality, OP_PCMPEQB, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, + { SN_op_Subtraction, OP_PSUBB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_V0, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V1, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V10, 10, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V11, 11, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V12, 12, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V13, 13, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V14, 14, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V15, 15, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V2, 2, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V3, 3, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V4, 4, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V5, 5, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V6, 6, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V7, 7, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V8, 8, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V9, 9, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, }; /* @@ -522,66 +536,64 @@ static const SimdIntrinsic vector16b_intrinsics[] = { setters */ static const SimdIntrinsic vector16sb_intrinsics[] = { - { SN_ctor, OP_EXPAND_I1, SIMD_VERSION_SSE1, SIMD_EMIT_CTOR }, - { SN_AddWithSaturation, OP_PADDB_SAT, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_CompareEqual, OP_PCMPEQB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_CompareGreaterThan, OP_PCMPGTB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_ExtractByteMask, 0, SIMD_VERSION_SSE1, SIMD_EMIT_EXTRACT_MASK }, - { SN_LoadAligned, 0, SIMD_VERSION_SSE1, SIMD_EMIT_LOAD_ALIGNED }, - { SN_Max, OP_PMAXB, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_Min, OP_PMINB, SIMD_VERSION_SSE41, SIMD_EMIT_BINARY }, - { SN_PrefetchTemporalAllCacheLevels, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, - { SN_PrefetchTemporal1stLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, - { SN_PrefetchTemporal2ndLevelCache, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, - { SN_PrefetchNonTemporal, 0, SIMD_VERSION_SSE1, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, - { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, SIMD_VERSION_SSE1, SIMD_EMIT_STORE }, - { SN_SubtractWithSaturation, OP_PSUBB_SAT, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackHigh, OP_UNPACK_HIGHB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_UnpackLow, OP_UNPACK_LOWB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_get_V0, 0, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V1, 1, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V10, 10, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V11, 11, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V12, 12, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V13, 13, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V14, 14, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V15, 15, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V2, 2, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V3, 3, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V4, 4, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V5, 5, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V6, 6, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V8, 8, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_get_V9, 9, SIMD_VERSION_SSE1, SIMD_EMIT_GETTER }, - { SN_op_Addition, OP_PADDB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseAnd, OP_PAND, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_BitwiseOr, OP_POR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Equality, OP_PCMPEQB, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, - { SN_op_ExclusiveOr, OP_PXOR, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Explicit, 0, SIMD_VERSION_SSE1, SIMD_EMIT_CAST }, - { SN_op_Inequality, OP_PCMPEQB, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, - { SN_op_Subtraction, OP_PSUBB, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_set_V0, 0, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V1, 1, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V10, 10, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V11, 11, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V12, 12, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V13, 13, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V14, 14, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V15, 15, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V2, 2, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V3, 3, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V4, 4, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V5, 5, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V6, 6, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V7, 7, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V8, 8, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, - { SN_set_V9, 9, SIMD_VERSION_SSE1, SIMD_EMIT_SETTER }, + { SN_ctor, OP_EXPAND_I1, MONO_CPU_X86_SSE, SIMD_EMIT_CTOR }, + { SN_AddWithSaturation, OP_PADDB_SAT, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_CompareEqual, OP_PCMPEQB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_CompareGreaterThan, OP_PCMPGTB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_ExtractByteMask, 0, MONO_CPU_X86_SSE, SIMD_EMIT_EXTRACT_MASK }, + { SN_LoadAligned, 0, MONO_CPU_X86_SSE, SIMD_EMIT_LOAD_ALIGNED }, + { SN_Max, OP_PMAXB, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_Min, OP_PMINB, MONO_CPU_X86_SSE41, SIMD_EMIT_BINARY }, + { SN_PrefetchTemporalAllCacheLevels, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_0 }, + { SN_PrefetchTemporal1stLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_1 }, + { SN_PrefetchTemporal2ndLevelCache, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_2 }, + { SN_PrefetchNonTemporal, 0, MONO_CPU_X86_SSE, SIMD_EMIT_PREFETCH, SIMD_PREFETCH_MODE_NTA }, + { SN_StoreAligned, OP_STOREX_ALIGNED_MEMBASE_REG, MONO_CPU_X86_SSE, SIMD_EMIT_STORE }, + { SN_SubtractWithSaturation, OP_PSUBB_SAT, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackHigh, OP_UNPACK_HIGHB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_UnpackLow, OP_UNPACK_LOWB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_get_V0, 0, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V1, 1, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V10, 10, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V11, 11, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V12, 12, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V13, 13, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V14, 14, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V15, 15, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V2, 2, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V3, 3, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V4, 4, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V5, 5, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V6, 6, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V7, 7, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V8, 8, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_get_V9, 9, MONO_CPU_X86_SSE, SIMD_EMIT_GETTER }, + { SN_op_Addition, OP_PADDB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseAnd, OP_PAND, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_BitwiseOr, OP_POR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Equality, OP_PCMPEQB, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, + { SN_op_ExclusiveOr, OP_PXOR, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Explicit, 0, MONO_CPU_X86_SSE, SIMD_EMIT_CAST }, + { SN_op_Inequality, OP_PCMPEQB, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_NEQ }, + { SN_op_Subtraction, OP_PSUBB, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_set_V0, 0, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V1, 1, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V10, 10, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V11, 11, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V12, 12, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V13, 13, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V14, 14, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V15, 15, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V2, 2, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V3, 3, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V4, 4, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V5, 5, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V6, 6, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V7, 7, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V8, 8, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, + { SN_set_V9, 9, MONO_CPU_X86_SSE, SIMD_EMIT_SETTER }, }; -static guint32 simd_supported_versions; - static MonoInst* emit_sys_numerics_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args); static MonoInst* emit_sys_numerics_vectors_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args); @@ -603,8 +615,6 @@ typedef enum { void mono_simd_intrinsics_init (void) { - simd_supported_versions = mono_arch_cpu_enumerate_simd_versions (); - /*TODO log the supported flags*/ } static gboolean @@ -1874,28 +1884,6 @@ simd_intrinsic_emit_const (const SimdIntrinsic *intrinsic, MonoCompile *cfg, Mon return ins; } -static const char * -simd_version_name (guint32 version) -{ - switch (version) { - case SIMD_VERSION_SSE1: - return "sse1"; - case SIMD_VERSION_SSE2: - return "sse2"; - case SIMD_VERSION_SSE3: - return "sse3"; - case SIMD_VERSION_SSSE3: - return "ssse3"; - case SIMD_VERSION_SSE41: - return "sse41"; - case SIMD_VERSION_SSE42: - return "sse42"; - case SIMD_VERSION_SSE4a: - return "sse4a"; - } - return "n/a"; -} - static MonoInst* emit_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args, const SimdIntrinsic *intrinsics, guint32 size) { @@ -1913,17 +1901,14 @@ emit_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi mono_print_ins (args [i]); } } - if (result->simd_version_flags && !(result->simd_version_flags & simd_supported_versions)) { - if (IS_DEBUG_ON (cfg)) { - int x; - printf ("function %s::%s/%d requires one of unsuported SIMD instruction set(s): ", m_class_get_name (cmethod->klass), cmethod->name, fsig->param_count); - for (x = 1; x <= SIMD_VERSION_INDEX_END; x++) - if (result->simd_version_flags & (1 << x)) - printf ("%s ", simd_version_name (1 << x)); - - printf ("\n"); + if (result->simd_version) { + MonoCPUFeatures features = mini_get_cpu_features (cfg); + if ((result->simd_version & features) == 0) { + printf ("function %s::%s/%d requires one of unsuported SIMD instruction set(s). \n", m_class_get_name (cmethod->klass), cmethod->name, fsig->param_count); + if (IS_DEBUG_ON (cfg)) + printf ("function %s::%s/%d requires one of unsuported SIMD instruction set(s). \n", m_class_get_name (cmethod->klass), cmethod->name, fsig->param_count); + return NULL; } - return NULL; } switch (result->simd_emit_mode) { @@ -2040,12 +2025,34 @@ emit_array_extension_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMeth return NULL; } +static guint32 +get_simd_supported_versions (MonoCompile *cfg) +{ + MonoCPUFeatures features = mini_get_cpu_features (cfg); + guint32 versions = 0; + + if (features & MONO_CPU_X86_SSE) + versions |= SIMD_VERSION_SSE1; + if (features & MONO_CPU_X86_SSE2) + versions |= SIMD_VERSION_SSE2; + if (features & MONO_CPU_X86_SSE3) + versions |= SIMD_VERSION_SSE3; + if (features & MONO_CPU_X86_SSSE3) + versions |= SIMD_VERSION_SSSE3; + if (features & MONO_CPU_X86_SSE41) + versions |= SIMD_VERSION_SSE41; + if (features & MONO_CPU_X86_SSE42) + versions |= SIMD_VERSION_SSE42; + return versions; +} + static MonoInst* emit_simd_runtime_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { if (!strcmp ("get_AccelMode", cmethod->name) && fsig->param_count == 0) { MonoInst *ins; - EMIT_NEW_ICONST (cfg, ins, simd_supported_versions); + guint32 versions = get_simd_supported_versions (cfg); + EMIT_NEW_ICONST (cfg, ins, versions); return ins; } return NULL; @@ -2183,14 +2190,14 @@ static const SimdIntrinsic vector2_intrinsics[] = { { SN_ctor, OP_EXPAND_R4 }, { SN_Abs }, { SN_Dot, OP_DPPS }, - { SN_Equals, OP_COMPPS, SIMD_VERSION_SSE1, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, - { SN_Max, OP_MAXPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_Min, OP_MINPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_SquareRoot, OP_SQRTPS, SIMD_VERSION_SSE1, SIMD_EMIT_UNARY }, - { SN_op_Addition, OP_ADDPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Division, OP_DIVPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Multiply, OP_MULPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, - { SN_op_Subtraction, OP_SUBPS, SIMD_VERSION_SSE1, SIMD_EMIT_BINARY }, + { SN_Equals, OP_COMPPS, MONO_CPU_X86_SSE, SIMD_EMIT_EQUALITY, SIMD_COMP_EQ }, + { SN_Max, OP_MAXPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_Min, OP_MINPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_SquareRoot, OP_SQRTPS, MONO_CPU_X86_SSE, SIMD_EMIT_UNARY }, + { SN_op_Addition, OP_ADDPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Division, OP_DIVPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Multiply, OP_MULPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, + { SN_op_Subtraction, OP_SUBPS, MONO_CPU_X86_SSE, SIMD_EMIT_BINARY }, }; static MonoInst* @@ -2294,7 +2301,7 @@ emit_vector_is_hardware_accelerated_intrinsic (MonoCompile *cfg) { MonoInst *ins; - if (simd_supported_versions) + if (get_simd_supported_versions (cfg)) EMIT_NEW_ICONST (cfg, ins, 1); else EMIT_NEW_ICONST (cfg, ins, 0); diff --git a/src/mono/mono/tests/bug-10127.cs b/src/mono/mono/tests/bug-10127.cs index 32ca6309a127f2..bd24498229f13f 100644 --- a/src/mono/mono/tests/bug-10127.cs +++ b/src/mono/mono/tests/bug-10127.cs @@ -72,17 +72,6 @@ public void Stop () } - static class RandHelper { - public static string RandString(this Random rand, int len) - { - char[] table = new char[len]; - for (int idx = 0; idx < len; idx++) { - table[idx] = (char) ('a' + idx); - } - return new string(table, 0, len); - } - } - class MainClass { public static void Main (string[] args) diff --git a/src/mono/mono/utils/mono-state.c b/src/mono/mono/utils/mono-state.c index a144eb1e2f394a..717c88cfb07a9b 100644 --- a/src/mono/mono/utils/mono-state.c +++ b/src/mono/mono/utils/mono-state.c @@ -156,6 +156,12 @@ file_for_dump_reason_breadcrumb (const char *directory, const char *dump_reason, g_snprintf (buff, sizeof_buff, "%s%scrash_reason_%s", directory, G_DIR_SEPARATOR_S, dump_reason); } +static void +file_for_hash_breadcrumb (const char *directory, MonoStackHash hashes, gchar *buff, size_t sizeof_buff) +{ + g_snprintf (buff, sizeof_buff, "%s%scrash_hash_0x%" PRIx64 "", directory, G_DIR_SEPARATOR_S, (uint64_t)hashes.offset_rich_hash); +} + static void create_breadcrumb (const char *path) { int handle = g_open (path, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); @@ -184,6 +190,14 @@ create_dump_reason_breadcrumb (const char *dump_reason) create_breadcrumb (out_file); } +void +mono_create_crash_hash_breadcrumb (MonoThreadSummary *thread) +{ + char out_file [200]; + file_for_hash_breadcrumb (log.directory, thread->hashes, out_file, sizeof(out_file)); + create_breadcrumb (out_file); +} + gboolean mono_summarize_set_timeline_dir (const char *directory) { diff --git a/src/mono/mono/utils/mono-state.h b/src/mono/mono/utils/mono-state.h index 8b5e6b4dec050c..ae49faee1df5ca 100644 --- a/src/mono/mono/utils/mono-state.h +++ b/src/mono/mono/utils/mono-state.h @@ -123,6 +123,9 @@ mono_crash_save_failfast_msg (char *msg); const char* mono_crash_get_failfast_msg (void); +void +mono_create_crash_hash_breadcrumb (MonoThreadSummary *thread); + #endif // DISABLE_CRASH_REPORTING // Dump context functions (enter/leave) diff --git a/src/mono/mono/utils/mono-threads-state-machine.c b/src/mono/mono/utils/mono-threads-state-machine.c index f1146f5a634eab..2d9a06cd76f61b 100644 --- a/src/mono/mono/utils/mono-threads-state-machine.c +++ b/src/mono/mono/utils/mono-threads-state-machine.c @@ -832,12 +832,20 @@ mono_threads_transition_abort_blocking (THREAD_INFO_TYPE* info, const char *func * cases where we would be in ASYNC_SUSPEND_REQUESTED with * no_safepoints set, since those are polling points. */ - /* WISH: make this fatal. Unfortunately in that case, if a - * thread asserts somewhere because no_safepoints was set when it - * shouldn't have been, we get a second assertion here while - * unwinding. */ - if (no_safepoints) - g_warning ("Warning: no_safepoints = TRUE, but should be FALSE in state RUNNING with ABORT_BLOCKING"); + if (no_safepoints) { + /* reset the state to no safepoints and then abort. If a + * thread asserts somewhere because no_safepoints was set when it + * shouldn't have been, we would get a second assertion here while + * unwinding if we hadn't reset the no_safepoints flag. + */ + if (thread_state_cas (&info->thread_state, build_thread_state (STATE_RUNNING, suspend_count, FALSE), raw_state) != raw_state) + goto retry_state_change; + + /* record the current transition, in order to grab a backtrace */ + trace_state_change_with_func ("ABORT_BLOCKING", info, raw_state, STATE_RUNNING, FALSE, 0, func); + + mono_fatal_with_history ("no_safepoints = TRUE, but should be FALSE in state RUNNING with ABORT_BLOCKING"); + } trace_state_change_sigsafe ("ABORT_BLOCKING", info, raw_state, cur_state, no_safepoints, 0, func); return AbortBlockingIgnore; @@ -872,7 +880,7 @@ STATE_BLOCKING_SELF_SUSPENDED: This is an exit state of done blocking, can't hap STATE_BLOCKING_ASYNC_SUSPENDED: This is an exit state of abort blocking, can't happen here. */ default: - mono_fatal_with_history ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state)); + mono_fatal_with_history ("Cannot transition thread %p from %s with ABORT_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state)); } } @@ -951,7 +959,7 @@ mono_threads_transition_end_no_safepoints (MonoThreadInfo *info, const char *fun mono_fatal_with_history ("no_safepoints = FALSE, but should be TRUE with END_NO_SAFEPOINTS. Unbalanced no safepointing region"); if (thread_state_cas (&info->thread_state, build_thread_state (cur_state, suspend_count, FALSE), raw_state) != raw_state) goto retry_state_change; - trace_state_change_with_func ("END_NO_SAFEPOINTS", info, raw_state, cur_state, TRUE, 0, func); + trace_state_change_with_func ("END_NO_SAFEPOINTS", info, raw_state, cur_state, FALSE, 0, func); return; /* STATE_STARTING: diff --git a/src/mono/netcore/System.Private.CoreLib/src/Internal/Resources/WindowsRuntimeResourceManagerBase.cs b/src/mono/netcore/System.Private.CoreLib/src/Internal/Resources/WindowsRuntimeResourceManagerBase.cs index cad3f238e588a0..09da7285ad4d4d 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/Internal/Resources/WindowsRuntimeResourceManagerBase.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/Internal/Resources/WindowsRuntimeResourceManagerBase.cs @@ -11,7 +11,7 @@ public abstract class WindowsRuntimeResourceManagerBase { public abstract bool Initialize(string libpath, string reswFilename, out PRIExceptionInfo? exceptionInfo); - public abstract string GetString(string stringName, string? startingCulture, string? neutralResourcesCulture); + public abstract string? GetString(string stringName, string? startingCulture, string? neutralResourcesCulture); public abstract CultureInfo? GlobalResourceContextBestFitCultureInfo { diff --git a/src/mono/netcore/System.Private.CoreLib/src/Internal/Runtime/InteropServices/WindowsRuntime/ExceptionSupport.cs b/src/mono/netcore/System.Private.CoreLib/src/Internal/Runtime/InteropServices/WindowsRuntime/ExceptionSupport.cs index 34812bb73af31c..dcc2dc88d2b479 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/Internal/Runtime/InteropServices/WindowsRuntime/ExceptionSupport.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/Internal/Runtime/InteropServices/WindowsRuntime/ExceptionSupport.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; namespace Internal.Runtime.InteropServices.WindowsRuntime { @@ -12,6 +13,7 @@ public static class ExceptionSupport /// Attach restricted error information to the exception if it may apply to that exception, returning /// back the input value /// + [return: NotNullIfNotNull("e")] public static Exception? AttachRestrictedErrorInfo(Exception? e) => throw new PlatformNotSupportedException(); /// diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/GC.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/GC.Mono.cs index e5efe52cc405f8..5894af3b338ff1 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/GC.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/GC.Mono.cs @@ -246,17 +246,20 @@ static extern void _GetGCMemoryInfo (out long highMemoryLoadThresholdBytes, public static GCMemoryInfo GetGCMemoryInfo () { - _GetGCMemoryInfo(out long highMemoryLoadThresholdBytes, + _GetGCMemoryInfo (out long highMemoryLoadThresholdBytes, out long memoryLoadBytes, out long totalAvailableMemoryBytes, out long heapSizeBytes, out long fragmentedBytes ); - return new GCMemoryInfo(highMemoryLoadThresholdBytes, memoryLoadBytes, totalAvailableMemoryBytes, heapSizeBytes, fragmentedBytes); + return new GCMemoryInfo (highMemoryLoadThresholdBytes, memoryLoadBytes, totalAvailableMemoryBytes, heapSizeBytes, fragmentedBytes); } - internal static T[] AllocateUninitializedArray (int length) + public static T[] AllocateUninitializedArray (int length, bool pinned = false) { + if (pinned) + throw new NotImplementedException (); + // Mono only does explicit zeroning if the array is to big for the nursery, but less than 1 Mb - 4 kb. // If it is bigger than that, we grab memoroy directly from the OS which comes pre-zeroed. // Experimentation shows that if we just skip the zeroing in this case, we do not save a measurable @@ -264,5 +267,13 @@ internal static T[] AllocateUninitializedArray (int length) // Revist if we change LOS implementation. return new T [length]; } + + public static T[] AllocateArray (int length, bool pinned = false) + { + if (pinned) + throw new NotImplementedException (); + + return new T [length]; + } } } diff --git a/src/mono/netcore/sample/iOS/.gitignore b/src/mono/netcore/sample/iOS/.gitignore new file mode 100644 index 00000000000000..8a7ad91c1a79c9 --- /dev/null +++ b/src/mono/netcore/sample/iOS/.gitignore @@ -0,0 +1,4 @@ +bin/ +xcode/ +*.o +*.dll \ No newline at end of file diff --git a/src/mono/netcore/sample/iOS/CMakeLists.txt b/src/mono/netcore/sample/iOS/CMakeLists.txt new file mode 100644 index 00000000000000..2fe12cbc01c5a6 --- /dev/null +++ b/src/mono/netcore/sample/iOS/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.14.5) + +project(HelloiOS) + +file(GLOB DLLS *.dll) +file(GLOB DLLS_AOT *.dll.o) + +set(APP_RESOURCES + ${DLLS} +) + +add_executable( + HelloiOS + main.m + runtime.h + runtime.m + ${APP_RESOURCES} +) + +if (MONO_ARCH STREQUAL arm64) + add_definitions(-DDEVICE) +endif() + +include_directories("../../../../../artifacts/bin/mono/iOS.${MONO_ARCH}.${MONO_CONFIG}/include/mono-2.0") + +set_target_properties(HelloiOS PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Plist.in + XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" + XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING "NO" + RESOURCE "${APP_RESOURCES}" +) + +# FIXME: `XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING` should not be NO +# investigate why `PALEXPORT` doesn't preserve symbols + +target_link_libraries( + HelloiOS + "-framework Foundation" + "-framework UIKit" + "-framework GSS" + "-lz" + "-liconv" + "-force_load ../../../../../artifacts/bin/mono/iOS.${MONO_ARCH}.${MONO_CONFIG}/libmono.a" + "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.IO.Compression.Native.a" + "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Native.a" + "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Security.Cryptography.Native.Apple.a" + ${DLLS_AOT} +) \ No newline at end of file diff --git a/src/mono/netcore/sample/iOS/Makefile b/src/mono/netcore/sample/iOS/Makefile new file mode 100644 index 00000000000000..f2cbc1b36edc46 --- /dev/null +++ b/src/mono/netcore/sample/iOS/Makefile @@ -0,0 +1,76 @@ +MONO_CONFIG=Debug + +# change to x64 for simulator +MONO_ARCH=arm64 +ARTIFACTS_BIN=../../../../../artifacts/bin/ +ARTIFACTS_BCL=$(ARTIFACTS_BIN)runtime/netcoreapp5.0-iOS-$(MONO_CONFIG)-$(MONO_ARCH) +ARTIFACTS_MONO=$(ARTIFACTS_BIN)/mono/iOS.$(MONO_ARCH).$(MONO_CONFIG) + +DOTNET := $(shell cd ../../ && bash init-tools.sh | tail -1) +SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path) + +# once a new library is added here it should also be +# added in mono_ios_register_modules() (runtime.m) +all: prepare + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_MONO)/System.Private.CoreLib.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Runtime.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Runtime.Extensions.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Collections.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Core.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Threading.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Threading.Tasks.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Linq.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Memory.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Runtime.InteropServices.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Text.Encoding.Extensions.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/Microsoft.Win32.Primitives.dll + make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Console.dll + make Program.dll.o + +# recompile Program.cs AOT +Program.dll.o: bin/Program.dll Makefile + make aot-lib-${MONO_ARCH} LIB=bin/Program.dll + +# we need to copy some BCL libs to ARTIFACTS_MONO +# to be able to aot other bcl libs +prepare: + cp $(ARTIFACTS_BCL)/System.Memory.dll $(ARTIFACTS_MONO) + cp $(ARTIFACTS_BCL)/System.Collections.dll $(ARTIFACTS_MONO) + cp $(ARTIFACTS_BCL)/System.Threading.dll $(ARTIFACTS_MONO) + cp $(ARTIFACTS_BCL)/System.Threading.Thread.dll $(ARTIFACTS_MONO) + cp $(ARTIFACTS_BCL)/System.Runtime.dll $(ARTIFACTS_MONO) + cp $(ARTIFACTS_BCL)/System.Runtime.InteropServices.dll $(ARTIFACTS_MONO) + cp $(ARTIFACTS_BCL)/System.Text.Encoding.Extensions.dll $(ARTIFACTS_MONO) + cp $(ARTIFACTS_BCL)/Microsoft.Win32.Primitives.dll $(ARTIFACTS_MONO) + cp $(ARTIFACTS_BCL)/System.Console.dll $(ARTIFACTS_MONO) + +bin/Program.dll: Program.cs + $(DOTNET) build -c Debug Program.csproj + +# we'll use regular jit for simulator +aot-lib-x64: + cp $(LIB) $(notdir $(LIB)) + +aot-lib-arm64: + DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 MONO_PATH=$(ARTIFACTS_MONO) \ + $(ARTIFACTS_MONO)/cross/./mono-aot-cross -O=gsharedvt,float32 --nollvm --debug \ + --aot=mtriple=arm64-ios,static,asmonly,direct-icalls,no-direct-calls,dwarfdebug,full $(LIB) && \ + clang -isysroot $(SYSROOT) -miphoneos-version-min=10.1 -arch arm64 -c $(LIB).s + cp $(LIB) $(notdir $(LIB)) + +# generate an xcode project +xcode: all + cmake -S. -BXcode -GXcode \ + -DCMAKE_SYSTEM_NAME=iOS \ + "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=10.1 \ + -DCMAKE_INSTALL_PREFIX=`pwd`/_install \ + -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO \ + -DCMAKE_IOS_INSTALL_COMBINED=YES \ + -DMONO_CONFIG=$(MONO_CONFIG) \ + -DMONO_ARCH=$(MONO_ARCH) + +clean: + rm -rf *.dll + rm -rf *.dll.o + rm -rf Xcode \ No newline at end of file diff --git a/src/mono/netcore/sample/iOS/Plist.in b/src/mono/netcore/sample/iOS/Plist.in new file mode 100644 index 00000000000000..16b261c0240a65 --- /dev/null +++ b/src/mono/netcore/sample/iOS/Plist.in @@ -0,0 +1,37 @@ + + + + + CFBundleDevelopmentRegion + en-US + CFBundleExecutable + HelloiOS + CFBundleIdentifier + net.dot.HelloiOS + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + HelloiOS + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + + + diff --git a/src/mono/netcore/sample/iOS/Program.cs b/src/mono/netcore/sample/iOS/Program.cs new file mode 100644 index 00000000000000..6e3571df6f1d07 --- /dev/null +++ b/src/mono/netcore/sample/iOS/Program.cs @@ -0,0 +1,50 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Runtime.InteropServices; + +// it's not part of the BCL but runtime needs it for native-to-managed callbacks in AOT +// To be replaced with NativeCallableAttribute +public class MonoPInvokeCallbackAttribute : Attribute +{ + public MonoPInvokeCallbackAttribute(Type delegateType) { } +} + +public static class Program +{ + // Defined in main.m + [DllImport("__Internal")] + private extern static void ios_set_text(string value); + + [DllImport("__Internal")] + private extern static void ios_register_button_click(Action action); + + private static Action buttonClickHandler = null; + + private static int counter = 0; + + // Called by native code, see main.m + [MonoPInvokeCallback(typeof(Action))] + private static async void OnButtonClick() + { + ios_set_text("OnButtonClick! #" + counter++); + } + + public static async Task Main(string[] args) + { + // Register a managed callback (will be called by UIButton, see main.m) + // Also, keep the handler alive so GC won't collect it. + ios_register_button_click(buttonClickHandler = OnButtonClick); + + const string msg = "Hello World!\n.NET 5.0"; + for (int i = 0; i < msg.Length; i++) + { + // a kind of an animation + ios_set_text(msg.Substring(0, i + 1)); + await Task.Delay(100); + } + + // TODO: https://github.com/dotnet/runtime/issues/33667 + Console.WriteLine("Done!"); + } +} \ No newline at end of file diff --git a/src/mono/netcore/sample/iOS/Program.csproj b/src/mono/netcore/sample/iOS/Program.csproj new file mode 100644 index 00000000000000..0b65c426b4f93d --- /dev/null +++ b/src/mono/netcore/sample/iOS/Program.csproj @@ -0,0 +1,9 @@ + + + + Exe + bin + $(NetCoreAppCurrent) + + + diff --git a/src/mono/netcore/sample/iOS/main.m b/src/mono/netcore/sample/iOS/main.m new file mode 100644 index 00000000000000..d3c688109f8b3b --- /dev/null +++ b/src/mono/netcore/sample/iOS/main.m @@ -0,0 +1,77 @@ +#import +#import "runtime.h" + +@interface ViewController : UIViewController +@end + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@property (strong, nonatomic) ViewController *controller; +@end + +@implementation AppDelegate +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.controller = [[ViewController alloc] initWithNibName:nil bundle:nil]; + self.window.rootViewController = self.controller; + [self.window makeKeyAndVisible]; + return YES; +} +@end + +UILabel *label; +void (*clickHandlerPtr)(void); + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + label = [[UILabel alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + label.textColor = [UIColor greenColor]; + label.font = [UIFont boldSystemFontOfSize: 30]; + label.numberOfLines = 2; + label.textAlignment = NSTextAlignmentCenter; + [self.view addSubview:label]; + + UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoDark]; + [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; + [button setFrame:CGRectMake(50, 300, 200, 50)]; + [button setTitle:@"Click me" forState:UIControlStateNormal]; + [button setExclusiveTouch:YES]; + [self.view addSubview:button]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + mono_ios_runtime_init (); + }); +} +-(void) buttonClicked:(UIButton*)sender +{ + if (clickHandlerPtr) + clickHandlerPtr(); +} + +@end + +// called from C# sample +void +ios_register_button_click (void* ptr) +{ + clickHandlerPtr = ptr; +} + +// called from C# sample +void +ios_set_text (const char* value) +{ + NSString* nsstr = [NSString stringWithUTF8String:strdup(value)]; + dispatch_async(dispatch_get_main_queue(), ^{ + label.text = nsstr; + }); +} + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/src/mono/netcore/sample/iOS/runtime.h b/src/mono/netcore/sample/iOS/runtime.h new file mode 100644 index 00000000000000..ddddd96c8373c9 --- /dev/null +++ b/src/mono/netcore/sample/iOS/runtime.h @@ -0,0 +1,6 @@ +#ifndef runtime_h +#define runtime_h + +void mono_ios_runtime_init (void); + +#endif /* runtime_h */ diff --git a/src/mono/netcore/sample/iOS/runtime.m b/src/mono/netcore/sample/iOS/runtime.m new file mode 100644 index 00000000000000..a83f7589ad6596 --- /dev/null +++ b/src/mono/netcore/sample/iOS/runtime.m @@ -0,0 +1,295 @@ +#import +#include +#include +#include +#include +#include +#include + +#import +#include +#include + +static os_log_t stdout_log; + +/* These are not in public headers */ +typedef unsigned char* (*MonoLoadAotDataFunc) (MonoAssembly *assembly, int size, void *user_data, void **out_handle); +typedef void (*MonoFreeAotDataFunc) (MonoAssembly *assembly, int size, void *user_data, void *handle); +void mono_install_load_aot_data_hook (MonoLoadAotDataFunc load_func, MonoFreeAotDataFunc free_func, void *user_data); +void mono_trace_init (void); +void mono_gc_init_finalizer_thread (void); + +static char *bundle_path; + +const char * +get_bundle_path (void) +{ + if (bundle_path) + return bundle_path; + + NSBundle* main_bundle = [NSBundle mainBundle]; + NSString* path = [main_bundle bundlePath]; + bundle_path = strdup ([path UTF8String]); + + return bundle_path; +} + +static unsigned char * +load_aot_data (MonoAssembly *assembly, int size, void *user_data, void **out_handle) +{ + *out_handle = NULL; + + char path [1024]; + int res; + + MonoAssemblyName *assembly_name = mono_assembly_get_name (assembly); + const char *aname = mono_assembly_name_get_name (assembly_name); + const char *bundle = get_bundle_path (); + + os_log_info (OS_LOG_DEFAULT, "Looking for aot data for assembly '%s'.", aname); + res = snprintf (path, sizeof (path) - 1, "%s/%s.aotdata", bundle, aname); + assert (res > 0); + + int fd = open (path, O_RDONLY); + if (fd < 0) { + os_log_info (OS_LOG_DEFAULT, "Could not load the aot data for %s from %s: %s\n", aname, path, strerror (errno)); + return NULL; + } + + void *ptr = mmap (NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); + if (ptr == MAP_FAILED) { + os_log_info (OS_LOG_DEFAULT, "Could not map the aot file for %s: %s\n", aname, strerror (errno)); + close (fd); + return NULL; + } + + close (fd); + os_log_info (OS_LOG_DEFAULT, "Loaded aot data for %s.\n", aname); + *out_handle = ptr; + return (unsigned char *) ptr; +} + +static void +free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle) +{ + munmap (handle, size); +} + +static MonoAssembly* +load_assembly (const char *name, const char *culture) +{ + const char *bundle = get_bundle_path (); + char filename [1024]; + char path [1024]; + int res; + + os_log_info (OS_LOG_DEFAULT, "assembly_preload_hook: %{public}s %{public}s %{public}s\n", name, culture, bundle); + + int len = strlen (name); + int has_extension = len > 3 && name [len - 4] == '.' && (!strcmp ("exe", name + (len - 3)) || !strcmp ("dll", name + (len - 3))); + + // add extensions if required. + strlcpy (filename, name, sizeof (filename)); + if (!has_extension) { + strlcat (filename, ".dll", sizeof (filename)); + } + + if (culture && strcmp (culture, "")) + res = snprintf (path, sizeof (path) - 1, "%s/%s/%s", bundle, culture, filename); + else + res = snprintf (path, sizeof (path) - 1, "%s/%s", bundle, filename); + assert (res > 0); + + struct stat buffer; + if (stat (path, &buffer) == 0) { + MonoAssembly *assembly = mono_assembly_open (path, NULL); + assert (assembly); + return assembly; + } + return NULL; +} + +static MonoAssembly* +assembly_preload_hook (MonoAssemblyName *aname, char **assemblies_path, void* user_data) +{ + const char *name = mono_assembly_name_get_name (aname); + const char *culture = mono_assembly_name_get_culture (aname); + return load_assembly (name, culture); +} + +char * +strdup_printf (const char *msg, ...) +{ + va_list args; + char *formatted = NULL; + va_start (args, msg); + vasprintf (&formatted, msg, args); + va_end (args); + return formatted; +} + +static MonoObject * +fetch_exception_property (MonoObject *obj, const char *name, bool is_virtual) +{ + MonoMethod *get = NULL; + MonoMethod *get_virt = NULL; + MonoObject *exc = NULL; + + get = mono_class_get_method_from_name (mono_get_exception_class (), name, 0); + if (get) { + if (is_virtual) { + get_virt = mono_object_get_virtual_method (obj, get); + if (get_virt) + get = get_virt; + } + + return (MonoObject *) mono_runtime_invoke (get, obj, NULL, &exc); + } else { + printf ("Could not find the property System.Exception.%s", name); + } + + return NULL; +} + +static char * +fetch_exception_property_string (MonoObject *obj, const char *name, bool is_virtual) +{ + MonoString *str = (MonoString *) fetch_exception_property (obj, name, is_virtual); + return str ? mono_string_to_utf8 (str) : NULL; +} + +void +unhandled_exception_handler (MonoObject *exc, void *user_data) +{ + NSMutableString *msg = [[NSMutableString alloc] init]; + + MonoClass *type = mono_object_get_class (exc); + char *type_name = strdup_printf ("%s.%s", mono_class_get_namespace (type), mono_class_get_name (type)); + char *trace = fetch_exception_property_string (exc, "get_StackTrace", true); + char *message = fetch_exception_property_string (exc, "get_Message", true); + + [msg appendString:@"Unhandled managed exceptions:\n"]; + [msg appendFormat: @"%s (%s)\n%s\n", message, type_name, trace ? trace : ""]; + + free (trace); + free (message); + free (type_name); + + os_log_info (OS_LOG_DEFAULT, "%@", msg); + os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); + exit (1); +} + +void +log_callback (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) +{ + os_log_info (OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message); + if (fatal) { + os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); + exit (1); + } +} + +static void +register_dllmap (void) +{ + mono_dllmap_insert (NULL, "libSystem.Native", NULL, "__Internal", NULL); + mono_dllmap_insert (NULL, "libSystem.IO.Compression.Native", NULL, "__Internal", NULL); + mono_dllmap_insert (NULL, "libSystem.Security.Cryptography.Native.Apple", NULL, "__Internal", NULL); +} + +void mono_jit_set_aot_mode (MonoAotMode mode); + +#if DEVICE +extern void *mono_aot_module_Program_info; +extern void *mono_aot_module_System_Private_CoreLib_info; +extern void *mono_aot_module_System_Runtime_info; +extern void *mono_aot_module_System_Runtime_Extensions_info; +extern void *mono_aot_module_System_Collections_info; +extern void *mono_aot_module_System_Core_info; +extern void *mono_aot_module_System_Threading_info; +extern void *mono_aot_module_System_Threading_Tasks_info; +extern void *mono_aot_module_System_Linq_info; +extern void *mono_aot_module_System_Memory_info; +extern void *mono_aot_module_System_Runtime_InteropServices_info; +extern void *mono_aot_module_System_Text_Encoding_Extensions_info; +extern void *mono_aot_module_Microsoft_Win32_Primitives_info; +extern void *mono_aot_module_System_Console_info; +extern void *mono_aot_module_Program_info; + +void mono_ios_register_modules (void) +{ + mono_aot_register_module (mono_aot_module_Program_info); + mono_aot_register_module (mono_aot_module_System_Private_CoreLib_info); + mono_aot_register_module (mono_aot_module_System_Runtime_info); + mono_aot_register_module (mono_aot_module_System_Runtime_Extensions_info); + mono_aot_register_module (mono_aot_module_System_Collections_info); + mono_aot_register_module (mono_aot_module_System_Core_info); + mono_aot_register_module (mono_aot_module_System_Threading_info); + mono_aot_register_module (mono_aot_module_System_Threading_Tasks_info); + mono_aot_register_module (mono_aot_module_System_Linq_info); + mono_aot_register_module (mono_aot_module_System_Memory_info); + mono_aot_register_module (mono_aot_module_System_Runtime_InteropServices_info); + mono_aot_register_module (mono_aot_module_System_Text_Encoding_Extensions_info); + mono_aot_register_module (mono_aot_module_Microsoft_Win32_Primitives_info); + mono_aot_register_module (mono_aot_module_System_Console_info); + mono_aot_register_module (mono_aot_module_Program_info); +} + +void mono_ios_setup_execution_mode (void) +{ + mono_jit_set_aot_mode (MONO_AOT_MODE_FULL); +} +#endif + +void +mono_ios_runtime_init (void) +{ + // for now, only Invariant Mode is supported (FIXME: integrate ICU) + setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE); + + stdout_log = os_log_create ("net.dot.mono", "stdout"); + + bool wait_for_debugger = FALSE; + char* executable = "Program.dll"; + + const char* bundle = get_bundle_path (); + chdir (bundle); + + register_dllmap (); + +#if DEVICE + // register modules + mono_ios_register_modules (); + mono_ios_setup_execution_mode (); +#endif + + mono_debug_init (MONO_DEBUG_FORMAT_MONO); + mono_install_assembly_preload_hook (assembly_preload_hook, NULL); + mono_install_load_aot_data_hook (load_aot_data, free_aot_data, NULL); + mono_install_unhandled_exception_hook (unhandled_exception_handler, NULL); + mono_trace_init (); + mono_trace_set_log_handler (log_callback, NULL); + mono_set_signal_chaining (TRUE); + mono_set_crash_chaining (TRUE); + + if (wait_for_debugger) { + char* options[] = { "--debugger-agent=transport=dt_socket,server=y,address=0.0.0.0:55555" }; + mono_jit_parse_options (1, options); + } + mono_jit_init_version ("dotnet.ios", "mobile"); + +#if DEVICE + // device runtimes are configured to use lazy gc thread creation + mono_gc_init_finalizer_thread (); +#endif + + MonoAssembly *assembly = load_assembly (executable, NULL); + assert (assembly); + os_log_info (OS_LOG_DEFAULT, "Executable: %{public}s", executable); + + int res = mono_jit_exec (mono_domain_get (), assembly, 1, &executable); + // Print this so apps parsing logs can detect when we exited + os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", res); +} +