From 6dcb03913c7d55dca824abcd21617212bef62553 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 17 Jan 2022 07:46:40 -0800 Subject: [PATCH 001/308] Delete UMThkCallFrame (#63826) * Delete UMThkCallFrame * Place UnmanagedToManagedFrame under FEATURE_COMINTEROP --- src/coreclr/inc/vptr_list.h | 3 - src/coreclr/vm/amd64/cgencpu.h | 2 - src/coreclr/vm/arm64/asmhelpers.S | 179 -------------------------- src/coreclr/vm/dllimportcallback.cpp | 77 ++--------- src/coreclr/vm/dllimportcallback.h | 16 +-- src/coreclr/vm/frames.cpp | 40 +----- src/coreclr/vm/frames.h | 90 +------------ src/coreclr/vm/i386/asmhelpers.asm | 38 +++--- src/coreclr/vm/i386/cgenx86.cpp | 52 -------- src/coreclr/vm/i386/excepx86.cpp | 65 +--------- src/coreclr/vm/i386/stublinkerx86.cpp | 150 +++------------------ src/coreclr/vm/i386/stublinkerx86.h | 35 +++-- src/coreclr/vm/prestub.cpp | 12 -- 13 files changed, 81 insertions(+), 678 deletions(-) diff --git a/src/coreclr/inc/vptr_list.h b/src/coreclr/inc/vptr_list.h index 0fde8090d0699..ad17ef35a3b60 100644 --- a/src/coreclr/inc/vptr_list.h +++ b/src/coreclr/inc/vptr_list.h @@ -85,9 +85,6 @@ VPTR_CLASS(ExternalMethodFrame) #ifdef FEATURE_READYTORUN VPTR_CLASS(DynamicHelperFrame) #endif -#if defined(TARGET_X86) -VPTR_CLASS(UMThkCallFrame) -#endif #if defined(TARGET_X86) && !defined(UNIX_X86_ABI) VPTR_CLASS(TailCallFrame) #endif diff --git a/src/coreclr/vm/amd64/cgencpu.h b/src/coreclr/vm/amd64/cgencpu.h index 29b9dddfb7de4..33589c27bae39 100644 --- a/src/coreclr/vm/amd64/cgencpu.h +++ b/src/coreclr/vm/amd64/cgencpu.h @@ -415,8 +415,6 @@ extern "C" void setFPReturn(int fpSize, INT64 retVal); extern "C" void getFPReturn(int fpSize, INT64 *retval); -struct ComToManagedExRecord; // defined in cgencpu.cpp - #include struct DECLSPEC_ALIGN(8) UMEntryThunkCode { diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 7d8b3c7dd88b2..e7725cd16e63b 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -551,152 +551,6 @@ LOCAL_LABEL(LNullThis): LEAF_END SinglecastDelegateInvokeStub, _TEXT -#ifdef FEATURE_COMINTEROP - -#define ComCallPreStub_FrameSize (SIZEOF__GSCookie + SIZEOF__ComMethodFrame) -#define ComCallPreStub_FirstStackAdjust (8 + SIZEOF__ArgumentRegisters + 2 * 8) // x8, reg args , fp & lr already pushed -#define ComCallPreStub_StackAlloc0 (ComCallPreStub_FrameSize - ComCallPreStub_FirstStackAdjust) -#define ComCallPreStub_StackAlloc1 (ComCallPreStub_StackAlloc0 + SIZEOF__FloatArgumentRegisters + 8)// 8 for ErrorReturn -#define ComCallPreStub_StackAlloc (ComCallPreStub_StackAlloc1 + (ComCallPreStub_StackAlloc1 & 8)) - -#define ComCallPreStub_FrameOffset (ComCallPreStub_StackAlloc - (SIZEOF__ComMethodFrame - ComCallPreStub_FirstStackAdjust)) -#define ComCallPreStub_ErrorReturnOffset0 SIZEOF__FloatArgumentRegisters - -#define ComCallPreStub_FirstStackAdjust (ComCallPreStub_ErrorReturnOffset0 + (ComCallPreStub_ErrorReturnOffset0 & 8)) - -// ------------------------------------------------------------------ -// COM to CLR stub called the first time a particular method is invoked.// -// -// On entry: -// x12 : ComCallMethodDesc* provided by prepad thunk -// plus user arguments in registers and on the stack -// -// On exit: -// tail calls to real method -// -NESTED_ENTRY ComCallPreStub, _TEXT, NoHandler - - // Save arguments and return address - PROLOG_SAVE_REG_PAIR fp, lr, -ComCallPreStub_FirstStackAdjust! - PROLOG_STACK_ALLOC ComCallPreStub_StackAlloc - - SAVE_ARGUMENT_REGISTERS sp, (16+ComCallPreStub_StackAlloc) - - SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0 - - str x12, [sp, #(ComCallPreStub_FrameOffset + UnmanagedToManagedFrame__m_pvDatum)] - add x0, sp, #(ComCallPreStub_FrameOffset) - add x1, sp, #(ComCallPreStub_ErrorReturnOffset) - bl C_FUNC(ComPreStubWorker) - - cbz x0, LOCAL_LABEL(ComCallPreStub_ErrorExit) - - mov x12, x0 - - // pop the stack and restore original register state - RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 0 - RESTORE_ARGUMENT_REGISTERS sp, (16+ComCallPreStub_StackAlloc) - - EPILOG_STACK_FREE ComCallPreStub_StackAlloc - EPILOG_RESTORE_REG_PAIR fp, lr, ComCallPreStub_FirstStackAdjust! - - // and tailcall to the actual method - EPILOG_BRANCH_REG x12 - -ComCallPreStub_ErrorExit - ldr x0, [sp, #(ComCallPreStub_ErrorReturnOffset)] // ErrorReturn - - // pop the stack - EPILOG_STACK_FREE ComCallPreStub_StackAlloc - EPILOG_RESTORE_REG_PAIR fp, lr, ComCallPreStub_FirstStackAdjust! - - EPILOG_RETURN - -NESTED_END ComCallPreStub, _TEXT - -// ------------------------------------------------------------------ -// COM to CLR stub which sets up a ComMethodFrame and calls COMToCLRWorker. -// -// On entry: -// x12 : ComCallMethodDesc* provided by prepad thunk -// plus user arguments in registers and on the stack -// -// On exit: -// Result in x0/d0 as per the real method being called -// - NESTED_ENTRY GenericComCallStub, _TEXT, NoHandler - - // Save arguments and return address - PROLOG_SAVE_REG_PAIR fp, lr, -GenericComCallStub_FirstStackAdjust! - PROLOG_STACK_ALLOC GenericComCallStub_StackAlloc - - SAVE_ARGUMENT_REGISTERS sp, (16+GenericComCallStub_StackAlloc) - SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0 - - str x12, [sp, #(GenericComCallStub_FrameOffset + UnmanagedToManagedFrame__m_pvDatum)] - add x1, sp, #GenericComCallStub_FrameOffset - bl C_FUNC(COMToCLRWorker) - - // pop the stack - EPILOG_STACK_FREE GenericComCallStub_StackAlloc - EPILOG_RESTORE_REG_PAIR fp, lr, GenericComCallStub_FirstStackAdjust! - - EPILOG_RETURN - - NESTED_END GenericComCallStub, _TEXT - -// ------------------------------------------------------------------ -// COM to CLR stub called from COMToCLRWorker that actually dispatches to the real managed method. -// -// On entry: -// x0 : dwStackSlots, count of argument stack slots to copy -// x1 : pFrame, ComMethodFrame pushed by GenericComCallStub above -// x2 : pTarget, address of code to call -// x3 : pSecretArg, hidden argument passed to target above in x12 -// x4 : pDangerousThis, managed 'this' reference -// -// On exit: -// Result in x0/d0 as per the real method being called -// - NESTED_ENTRY COMToCLRDispatchHelper, _TEXT,CallDescrWorkerUnwindFrameChainHandler - - PROLOG_SAVE_REG_PAIR fp, lr, -16! - - cbz x0, LOCAL_LABEL(COMToCLRDispatchHelper_RegSetup) - - add x9, x1, #SIZEOF__ComMethodFrame - add x9, x9, x0, LSL #3 -COMToCLRDispatchHelper_StackLoop - ldr x8, [x9, #-8]! - str x8, [sp, #-8]! - sub x0, x0, #1 - cbnz x0, LOCAL_LABEL(COMToCLRDispatchHelper_StackLoop) - -COMToCLRDispatchHelper_RegSetup - - RESTORE_FLOAT_ARGUMENT_REGISTERS x1, -1 * GenericComCallStub_FrameOffset - - mov lr, x2 - mov x12, x3 - - mov x0, x4 - - ldp x2, x3, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 16)] - ldp x4, x5, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 32)] - ldp x6, x7, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 48)] - ldr x8, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters - 8)] - - ldr x1, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 8)] - - blr lr - - EPILOG_STACK_RESTORE - EPILOG_RESTORE_REG_PAIR fp, lr, 16! - EPILOG_RETURN - - NESTED_END COMToCLRDispatchHelper, _TEXT - -#endif // FEATURE_COMINTEROP // // x12 = UMEntryThunk* // @@ -1039,39 +893,6 @@ DynamicHelper DynamicHelperFrameFlags_ObjectArg, _Obj DynamicHelper DynamicHelperFrameFlags_ObjectArg | DynamicHelperFrameFlags_ObjectArg2, _ObjObj #endif -#ifdef FEATURE_COMINTEROP - -// Function used by COM interop to get floating point return value (since it's not in the same -// register(s) as non-floating point values). -// -// On entry// -// x0 : size of the FP result (4 or 8 bytes) -// x1 : pointer to 64-bit buffer to receive result -// -// On exit: -// buffer pointed to by x1 on entry contains the float or double argument as appropriate -// -LEAF_ENTRY getFPReturn, _TEXT - str d0, [x1] -LEAF_END getFPReturn, _TEXT - -// ------------------------------------------------------------------ -// Function used by COM interop to set floating point return value (since it's not in the same -// register(s) as non-floating point values). -// -// On entry: -// x0 : size of the FP result (4 or 8 bytes) -// x1 : 32-bit or 64-bit FP result -// -// On exit: -// s0 : float result if x0 == 4 -// d0 : double result if x0 == 8 -// -LEAF_ENTRY setFPReturn, _TEXT - fmov d0, x1 -LEAF_END setFPReturn, _TEXT -#endif - // // JIT Static access helpers when coreclr host specifies single appdomain flag // diff --git a/src/coreclr/vm/dllimportcallback.cpp b/src/coreclr/vm/dllimportcallback.cpp index 455d33813eec0..65d2afd7d0512 100644 --- a/src/coreclr/vm/dllimportcallback.cpp +++ b/src/coreclr/vm/dllimportcallback.cpp @@ -195,37 +195,6 @@ extern "C" VOID STDCALL ReversePInvokeBadTransition() ); } -// Disable from a place that is calling into managed code via a UMEntryThunk. -extern "C" VOID STDCALL UMThunkStubRareDisableWorker(Thread *pThread, UMEntryThunk *pUMEntryThunk) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - - // Do not add a CONTRACT here. We haven't set up SEH. - - // WARNING!!!! - // when we start executing here, we are actually in cooperative mode. But we - // haven't synchronized with the barrier to reentry yet. So we are in a highly - // dangerous mode. If we call managed code, we will potentially be active in - // the GC heap, even as GC's are occuring! - - // We must do the following in this order, because otherwise we would be constructing - // the exception for the abort without synchronizing with the GC. Also, we have no - // CLR SEH set up, despite the fact that we may throw a ThreadAbortException. - pThread->RareDisablePreemptiveGC(); - pThread->HandleThreadAbort(); - -#ifdef DEBUGGING_SUPPORTED - // If the debugger is attached, we use this opportunity to see if - // we're disabling preemptive GC on the way into the runtime from - // unmanaged code. We end up here because - // Increment/DecrementTraceCallCount() will bump - // g_TrapReturningThreads for us. - if (CORDebuggerTraceCall()) - g_pDebugInterface->TraceCall((const BYTE *)pUMEntryThunk->GetManagedTarget()); -#endif // DEBUGGING_SUPPORTED -} - PCODE TheUMEntryPrestubWorker(UMEntryThunk * pUMEntryThunk) { STATIC_CONTRACT_THROWS; @@ -234,39 +203,13 @@ PCODE TheUMEntryPrestubWorker(UMEntryThunk * pUMEntryThunk) Thread * pThread = GetThreadNULLOk(); if (pThread == NULL) - pThread = CreateThreadBlockThrow(); - - GCX_COOP_THREAD_EXISTS(pThread); - - if (pThread->IsAbortRequested()) - pThread->HandleThreadAbort(); - - UMEntryThunk::DoRunTimeInit(pUMEntryThunk); - - return (PCODE)pUMEntryThunk->GetCode(); -} - -void RunTimeInit_Wrapper(LPVOID /* UMThunkMarshInfo * */ ptr) -{ - WRAPPER_NO_CONTRACT; - - UMEntryThunk::DoRunTimeInit((UMEntryThunk*)ptr); -} - - -// asm entrypoint -void STDCALL UMEntryThunk::DoRunTimeInit(UMEntryThunk* pUMEntryThunk) -{ - - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - ENTRY_POINT; - PRECONDITION(CheckPointer(pUMEntryThunk)); + CREATETHREAD_IF_NULL_FAILFAST(pThread, W("Failed to setup new thread during reverse P/Invoke")); } - CONTRACTL_END; + + // Verify the current thread isn't in COOP mode. + if (pThread->PreemptiveGCDisabled()) + ReversePInvokeBadTransition(); INSTALL_MANAGED_EXCEPTION_DISPATCHER; // this method is called by stubs which are called by managed code, @@ -274,15 +217,13 @@ void STDCALL UMEntryThunk::DoRunTimeInit(UMEntryThunk* pUMEntryThunk) // exceptions don't leak out into managed code. INSTALL_UNWIND_AND_CONTINUE_HANDLER; - { - GCX_PREEMP(); - - ExecutableWriterHolder uMEntryThunkWriterHolder(pUMEntryThunk, sizeof(UMEntryThunk)); - uMEntryThunkWriterHolder.GetRW()->RunTimeInit(pUMEntryThunk); - } + ExecutableWriterHolder uMEntryThunkWriterHolder(pUMEntryThunk, sizeof(UMEntryThunk)); + uMEntryThunkWriterHolder.GetRW()->RunTimeInit(pUMEntryThunk); UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; + + return (PCODE)pUMEntryThunk->GetCode(); } UMEntryThunk* UMEntryThunk::CreateUMEntryThunk() diff --git a/src/coreclr/vm/dllimportcallback.h b/src/coreclr/vm/dllimportcallback.h index 14b7db5704824..fb2214a8c18d5 100644 --- a/src/coreclr/vm/dllimportcallback.h +++ b/src/coreclr/vm/dllimportcallback.h @@ -16,6 +16,12 @@ #include "class.h" #include "dllimport.h" +class UMThunkMarshInfo; +typedef DPTR(class UMThunkMarshInfo) PTR_UMThunkMarshInfo; + +class UMEntryThunk; +typedef DPTR(class UMEntryThunk) PTR_UMEntryThunk; + //---------------------------------------------------------------------- // This structure collects all information needed to marshal an // unmanaged->managed thunk. The only information missing is the @@ -189,9 +195,6 @@ class UMEntryThunk #endif // _DEBUG } - // asm entrypoint - static VOID STDCALL DoRunTimeInit(UMEntryThunk* pThis); - PCODE GetManagedTarget() const { CONTRACT (PCODE) @@ -396,14 +399,7 @@ class UMEntryThunkCache }; #if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL) -//------------------------------------------------------------------------- -// One-time creation of special prestub to initialize UMEntryThunks. -//------------------------------------------------------------------------- -Stub *GenerateUMThunkPrestub(); - EXCEPTION_HANDLER_DECL(FastNExportExceptHandler); -EXCEPTION_HANDLER_DECL(UMThunkPrestubHandler); - #endif // TARGET_X86 && !FEATURE_STUBS_AS_IL extern "C" void TheUMEntryPrestub(void); diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp index 2f7a4d91c9ec4..9377b4ec028b7 100644 --- a/src/coreclr/vm/frames.cpp +++ b/src/coreclr/vm/frames.cpp @@ -63,21 +63,12 @@ void Frame::Log() { MethodDesc* method = GetFunction(); -#ifdef TARGET_X86 - if (GetVTablePtr() == UMThkCallFrame::GetMethodFrameVPtr()) - method = ((UMThkCallFrame*) this)->GetUMEntryThunk()->GetMethod(); -#endif - STRESS_LOG3(LF_STUBS, LL_INFO1000000, "STUBS: In Stub with Frame %p assoc Method %pM FrameType = %pV\n", this, method, *((void**) this)); char buff[64]; const char* frameType; if (GetVTablePtr() == PrestubMethodFrame::GetMethodFrameVPtr()) frameType = "PreStub"; -#ifdef TARGET_X86 - else if (GetVTablePtr() == UMThkCallFrame::GetMethodFrameVPtr()) - frameType = "UMThkCallFrame"; -#endif else if (GetVTablePtr() == PInvokeCalliFrame::GetMethodFrameVPtr()) { sprintf_s(buff, ARRAY_SIZE(buff), "PInvoke CALLI target" FMT_ADDR, @@ -1603,32 +1594,6 @@ void ComMethodFrame::DoSecondPassHandlerCleanup(Frame * pCurFrame) #endif // FEATURE_COMINTEROP - -#ifdef TARGET_X86 - -PTR_UMEntryThunk UMThkCallFrame::GetUMEntryThunk() -{ - LIMITED_METHOD_DAC_CONTRACT; - return dac_cast(GetDatum()); -} - -#ifdef DACCESS_COMPILE -void UMThkCallFrame::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) -{ - WRAPPER_NO_CONTRACT; - UnmanagedToManagedFrame::EnumMemoryRegions(flags); - - // Pieces of the UMEntryThunk need to be saved. - UMEntryThunk *pThunk = GetUMEntryThunk(); - DacEnumMemoryRegion(dac_cast(pThunk), sizeof(UMEntryThunk)); - - UMThunkMarshInfo *pMarshInfo = pThunk->GetUMThunkMarshInfo(); - DacEnumMemoryRegion(dac_cast(pMarshInfo), sizeof(UMThunkMarshInfo)); -} -#endif - -#endif // TARGET_X86 - #ifndef DACCESS_COMPILE #if defined(_MSC_VER) && defined(TARGET_X86) @@ -1952,16 +1917,18 @@ VOID InlinedCallFrame::Init() } - +#ifdef FEATURE_COMINTEROP void UnmanagedToManagedFrame::ExceptionUnwind() { WRAPPER_NO_CONTRACT; AppDomain::ExceptionUnwind(this); } +#endif // FEATURE_COMINTEROP #endif // !DACCESS_COMPILE +#ifdef FEATURE_COMINTEROP PCODE UnmanagedToManagedFrame::GetReturnAddress() { WRAPPER_NO_CONTRACT; @@ -1980,6 +1947,7 @@ PCODE UnmanagedToManagedFrame::GetReturnAddress() return pRetAddr; } } +#endif // FEATURE_COMINTEROP #ifndef DACCESS_COMPILE //================================================================================= diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index c2946ced0b2f6..82e57cbbb0401 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -90,23 +90,18 @@ // | | // | +-TPMethodFrame - for calls on transparent proxy // | +#ifdef FEATURE_COMINTEROP // +-UnmanagedToManagedFrame - this frame represents a transition from // | | unmanaged code back to managed code. It's // | | main functions are to stop COM+ exception // | | propagation and to expose unmanaged parameters. // | | -#ifdef FEATURE_COMINTEROP -// | | // | +-ComMethodFrame - this frame represents a transition from // | | com to com+ // | | // | +-ComPrestubMethodFrame - prestub frame for calls from COM to CLR // | #endif //FEATURE_COMINTEROP -#ifdef TARGET_X86 -// | +-UMThkCallFrame - this frame represents an unmanaged->managed -// | transition through N/Direct -#endif #if defined(TARGET_X86) && !defined(UNIX_X86_ABI) // +-TailCallFrame - padding for tailcalls // | @@ -172,16 +167,9 @@ Delegate over a native function pointer: Reverse P/Invoke (used for C++ exports & fixups as well as delegates obtained from function pointers): Normal stub: - x86: The stub is generated by UMEntryThunk::CompileUMThunkWorker - (in DllImportCallback.cpp) and it is frameless. It calls directly - the managed target or to IL stub if marshaling is required. - non-x86: The stub exists statically as UMThunkStub and calls to IL stub. + The stub exists statically as UMThunkStub and calls to IL stub. Prestub: - The prestub is generated by GenerateUMThunkPrestub (x86) or exists statically - as TheUMEntryPrestub (64-bit), and it erects an UMThkCallFrame frame. - -Reverse P/Invoke AppDomain selector stub: - The asm helper is IJWNOADThunkJumpTarget (in asmhelpers.asm) and it is frameless. + The prestub exists statically as TheUMEntryPrestub. //------------------------------------------------------------------------ #endif // 0 @@ -212,8 +200,8 @@ FRAME_TYPE_NAME(HelperMethodFrame_3OBJ) FRAME_TYPE_NAME(HelperMethodFrame_PROTECTOBJ) FRAME_ABSTRACT_TYPE_NAME(FramedMethodFrame) FRAME_TYPE_NAME(MulticastFrame) -FRAME_ABSTRACT_TYPE_NAME(UnmanagedToManagedFrame) #ifdef FEATURE_COMINTEROP +FRAME_ABSTRACT_TYPE_NAME(UnmanagedToManagedFrame) FRAME_TYPE_NAME(ComMethodFrame) FRAME_TYPE_NAME(ComPlusMethodFrame) FRAME_TYPE_NAME(ComPrestubMethodFrame) @@ -238,9 +226,6 @@ FRAME_TYPE_NAME(DebuggerClassInitMarkFrame) FRAME_TYPE_NAME(DebuggerSecurityCodeMarkFrame) FRAME_TYPE_NAME(DebuggerExitFrame) FRAME_TYPE_NAME(DebuggerU2MCatchHandlerFrame) -#ifdef TARGET_X86 -FRAME_TYPE_NAME(UMThkCallFrame) -#endif FRAME_TYPE_NAME(InlinedCallFrame) #if defined(TARGET_X86) && !defined(UNIX_X86_ABI) FRAME_TYPE_NAME(TailCallFrame) @@ -281,9 +266,6 @@ class Frame; class FramedMethodFrame; typedef VPTR(class FramedMethodFrame) PTR_FramedMethodFrame; struct HijackArgs; -class UMEntryThunk; -class UMThunkMarshInfo; -class Marshaler; struct ResolveCacheElem; #if defined(DACCESS_COMPILE) class DacDbiInterfaceImpl; @@ -1814,6 +1796,8 @@ class MulticastFrame : public TransitionFrame }; +#ifdef FEATURE_COMINTEROP + //----------------------------------------------------------------------- // Transition frame from unmanaged to managed //----------------------------------------------------------------------- @@ -1922,8 +1906,6 @@ class UnmanagedToManagedFrame : public Frame #endif }; -#ifdef FEATURE_COMINTEROP - //------------------------------------------------------------------------ // This frame represents a transition from COM to COM+ //------------------------------------------------------------------------ @@ -2774,43 +2756,6 @@ class DebuggerU2MCatchHandlerFrame : public Frame DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerU2MCatchHandlerFrame) }; - -class UMThunkMarshInfo; -typedef DPTR(class UMThunkMarshInfo) PTR_UMThunkMarshInfo; - -class UMEntryThunk; -typedef DPTR(class UMEntryThunk) PTR_UMEntryThunk; - -#if defined(TARGET_X86) -//------------------------------------------------------------------------ -// This frame guards an unmanaged->managed transition thru a UMThk -//------------------------------------------------------------------------ - -class UMThkCallFrame : public UnmanagedToManagedFrame -{ - VPTR_VTABLE_CLASS(UMThkCallFrame, UnmanagedToManagedFrame) - -public: - -#ifdef DACCESS_COMPILE - virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); -#endif - - PTR_UMEntryThunk GetUMEntryThunk(); - - static int GetOffsetOfUMEntryThunk() - { - WRAPPER_NO_CONTRACT; - return GetOffsetOfDatum(); - } - -protected: - - // Keep as last entry in class - DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(UMThkCallFrame) -}; -#endif // TARGET_X86 && !TARGET_UNIX - // Frame for the Reverse PInvoke (i.e. UnmanagedCallersOnlyAttribute). struct ReversePInvokeFrame { @@ -2821,29 +2766,6 @@ struct ReversePInvokeFrame #endif }; -#if defined(TARGET_X86) && defined(FEATURE_COMINTEROP) -//------------------------------------------------------------------------- -// Exception handler for COM to managed frame -// and the layout of the exception registration record structure in the stack -// the layout is similar to the NT's EXCEPTIONREGISTRATION record -// followed by the UnmanagedToManagedFrame specific info - -struct ComToManagedExRecord -{ - EXCEPTION_REGISTRATION_RECORD m_ExReg; - ArgumentRegisters m_argRegs; - GSCookie m_gsCookie; - UMThkCallFrame m_frame; - - UnmanagedToManagedFrame * GetCurrFrame() - { - LIMITED_METHOD_CONTRACT; - return &m_frame; - } -}; -#endif // TARGET_X86 && FEATURE_COMINTEROP - - //------------------------------------------------------------------------ // This frame is pushed by any JIT'ted method that contains one or more // inlined N/Direct calls. Note that the JIT'ted method keeps it pushed diff --git a/src/coreclr/vm/i386/asmhelpers.asm b/src/coreclr/vm/i386/asmhelpers.asm index d3eb78da47256..896c249822c55 100644 --- a/src/coreclr/vm/i386/asmhelpers.asm +++ b/src/coreclr/vm/i386/asmhelpers.asm @@ -43,7 +43,6 @@ EXTERN _COMPlusFrameHandlerRevCom:PROC endif ; FEATURE_COMINTEROP EXTERN __alloca_probe:PROC EXTERN _NDirectImportWorker@4:PROC -EXTERN _UMThunkStubRareDisableWorker@8:PROC EXTERN _VarargPInvokeStubWorker@12:PROC EXTERN _GenericPInvokeCalliStubWorker@12:PROC @@ -53,6 +52,7 @@ EXTERN _CopyCtorCallStubWorker@4:PROC endif EXTERN _PreStubWorker@8:PROC +EXTERN _TheUMEntryPrestubWorker@4:PROC ifdef FEATURE_COMINTEROP EXTERN _CLRToCOMWorker@8:PROC @@ -255,9 +255,6 @@ COMPlusNestedExceptionHandler proto c FastNExportExceptHandler proto c .safeseh FastNExportExceptHandler -UMThunkPrestubHandler proto c -.safeseh UMThunkPrestubHandler - ifdef FEATURE_COMINTEROP COMPlusFrameHandlerRevCom proto c .safeseh COMPlusFrameHandlerRevCom @@ -872,23 +869,6 @@ getFPReturn4: retn 8 _getFPReturn@8 endp -; VOID __cdecl UMThunkStubRareDisable() -; -; @todo: this is very similar to StubRareDisable -; -_UMThunkStubRareDisable proc public - push eax - push ecx - - push eax ; Push the UMEntryThunk - push ecx ; Push thread - call _UMThunkStubRareDisableWorker@8 - - pop ecx - pop eax - retn -_UMThunkStubRareDisable endp - ; void __stdcall JIT_ProfilerEnterLeaveTailcallStub(UINT_PTR ProfilerHandle) _JIT_ProfilerEnterLeaveTailcallStub@4 proc public @@ -1432,6 +1412,22 @@ public _ThePreStubPatchLabel@0 ret _ThePreStubPatch@0 endp +_TheUMEntryPrestub@0 proc public + ; push argument registers + push ecx + push edx + + push eax ; UMEntryThunk* + call _TheUMEntryPrestubWorker@4 + + ; pop argument registers + pop edx + pop ecx + + ; eax = PCODE + jmp eax ; Tail Jmp +_TheUMEntryPrestub@0 endp + ifdef FEATURE_COMINTEROP ;========================================================================== ; CLR -> COM generic or late-bound call diff --git a/src/coreclr/vm/i386/cgenx86.cpp b/src/coreclr/vm/i386/cgenx86.cpp index f0a81d6daeea1..d2d5d1676e95c 100644 --- a/src/coreclr/vm/i386/cgenx86.cpp +++ b/src/coreclr/vm/i386/cgenx86.cpp @@ -931,58 +931,6 @@ WORD GetUnpatchedCodeData(LPCBYTE pAddr) #ifndef DACCESS_COMPILE -#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL) -//------------------------------------------------------------------------- -// One-time creation of special prestub to initialize UMEntryThunks. -//------------------------------------------------------------------------- -Stub *GenerateUMThunkPrestub() -{ - CONTRACT(Stub*) - { - STANDARD_VM_CHECK; - POSTCONDITION(CheckPointer(RETVAL)); - } - CONTRACT_END; - - CPUSTUBLINKER sl; - CPUSTUBLINKER *psl = &sl; - - CodeLabel* rgRareLabels[] = { psl->NewCodeLabel(), - psl->NewCodeLabel(), - psl->NewCodeLabel() - }; - - - CodeLabel* rgRejoinLabels[] = { psl->NewCodeLabel(), - psl->NewCodeLabel(), - psl->NewCodeLabel() - }; - - // emit the initial prolog - psl->EmitComMethodStubProlog(UMThkCallFrame::GetMethodFrameVPtr(), rgRareLabels, rgRejoinLabels, FALSE /*Don't profile*/); - - // mov ecx, [esi+UMThkCallFrame.pUMEntryThunk] - psl->X86EmitIndexRegLoad(kECX, kESI, UMThkCallFrame::GetOffsetOfUMEntryThunk()); - - // The call conv is a __stdcall - psl->X86EmitPushReg(kECX); - - // call UMEntryThunk::DoRunTimeInit - psl->X86EmitCall(psl->NewExternalCodeLabel((LPVOID)UMEntryThunk::DoRunTimeInit), 4); - - // mov ecx, [esi+UMThkCallFrame.pUMEntryThunk] - psl->X86EmitIndexRegLoad(kEAX, kESI, UMThkCallFrame::GetOffsetOfUMEntryThunk()); - - // lea eax, [eax + UMEntryThunk.m_code] // point to fixedup UMEntryThunk - psl->X86EmitOp(0x8d, kEAX, kEAX, - UMEntryThunk::GetCodeOffset() + UMEntryThunkCode::GetEntryPointOffset()); - - psl->EmitComMethodStubEpilog(UMThkCallFrame::GetMethodFrameVPtr(), rgRareLabels, rgRejoinLabels, FALSE /*Don't profile*/); - - RETURN psl->Link(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()); -} -#endif // TARGET_X86 && !FEATURE_STUBS_AS_IL - Stub *GenerateInitPInvokeFrameHelper() { CONTRACT(Stub*) diff --git a/src/coreclr/vm/i386/excepx86.cpp b/src/coreclr/vm/i386/excepx86.cpp index 3d2e0e4dddeca..15dd0667dd6c4 100644 --- a/src/coreclr/vm/i386/excepx86.cpp +++ b/src/coreclr/vm/i386/excepx86.cpp @@ -113,17 +113,6 @@ static void RtlUnwindCallback() _ASSERTE(!"Should never get here"); } -BOOL NExportSEH(EXCEPTION_REGISTRATION_RECORD* pEHR) -{ - LIMITED_METHOD_CONTRACT; - - if ((LPVOID)pEHR->Handler == (LPVOID)UMThunkPrestubHandler) - { - return TRUE; - } - return FALSE; -} - BOOL FastNExportSEH(EXCEPTION_REGISTRATION_RECORD* pEHR) { LIMITED_METHOD_CONTRACT; @@ -156,9 +145,8 @@ BOOL IsUnmanagedToManagedSEHHandler(EXCEPTION_REGISTRATION_RECORD *pEstablisherF // // ComPlusFrameSEH() is for COMPlusFrameHandler & COMPlusNestedExceptionHandler. // FastNExportSEH() is for FastNExportExceptHandler. - // NExportSEH() is for UMThunkPrestubHandler. // - return (ComPlusFrameSEH(pEstablisherFrame) || FastNExportSEH(pEstablisherFrame) || NExportSEH(pEstablisherFrame) || ReverseCOMSEH(pEstablisherFrame)); + return (ComPlusFrameSEH(pEstablisherFrame) || FastNExportSEH(pEstablisherFrame) || ReverseCOMSEH(pEstablisherFrame)); } Frame *GetCurrFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame) @@ -166,10 +154,7 @@ Frame *GetCurrFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame) Frame *pFrame; WRAPPER_NO_CONTRACT; _ASSERTE(IsUnmanagedToManagedSEHHandler(pEstablisherFrame)); - if (NExportSEH(pEstablisherFrame)) - pFrame = ((ComToManagedExRecord *)pEstablisherFrame)->GetCurrFrame(); - else - pFrame = ((FrameHandlerExRecord *)pEstablisherFrame)->GetCurrFrame(); + pFrame = ((FrameHandlerExRecord *)pEstablisherFrame)->GetCurrFrame(); // Assert that the exception frame is on the thread or that the exception frame is the top frame. _ASSERTE(GetThreadNULLOk() == NULL || GetThread()->GetFrame() == (Frame*)-1 || GetThread()->GetFrame() <= pFrame); @@ -3384,52 +3369,6 @@ EXCEPTION_HANDLER_IMPL(FastNExportExceptHandler) return retval; } - -// Just like a regular NExport handler -- except it pops an extra frame on unwind. A handler -// like this is needed by the COMMethodStubProlog code. It first pushes a frame -- and then -// pushes a handler. When we unwind, we need to pop the extra frame to avoid corrupting the -// frame chain in the event of an unmanaged catcher. -// -EXCEPTION_HANDLER_IMPL(UMThunkPrestubHandler) -{ - // @todo: we'd like to have a dynamic contract here, but there's a problem. (Bug 129180) Enter on the CRST used - // in HandleManagedFault leaves the no-trigger count incremented. The destructor of this contract will restore - // it to zero, then when we leave the CRST in LinkFrameAndThrow, we assert because we're trying to decrement the - // gc-trigger count down past zero. The solution is to fix what we're doing with this CRST. - STATIC_CONTRACT_THROWS; // COMPlusFrameHandler throws - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_ANY; - - EXCEPTION_DISPOSITION retval = ExceptionContinueSearch; - - // We must forward to the COMPlusFrameHandler. This will unwind the Frame Chain up to here, and also leave the - // preemptive GC mode set correctly. - retval = EXCEPTION_HANDLER_FWD(COMPlusFrameHandler); - -#ifdef _DEBUG - // If the exception is escaping the last CLR personality routine on the stack, - // then state a flag on the thread to indicate so. - if (retval == ExceptionContinueSearch) - { - SetReversePInvokeEscapingUnhandledExceptionStatus(IS_UNWINDING(pExceptionRecord->ExceptionFlags), pEstablisherFrame); - } -#endif // _DEBUG - - if (IS_UNWINDING(pExceptionRecord->ExceptionFlags)) - { - // Pops an extra frame on unwind. - - GCX_COOP(); // Must be cooperative to modify frame chain. - - Thread *pThread = GetThread(); - Frame *pFrame = pThread->GetFrame(); - pFrame->ExceptionUnwind(); - pFrame->Pop(pThread); - } - - return retval; -} - #ifdef FEATURE_COMINTEROP // The reverse COM interop path needs to be sure to pop the ComMethodFrame that is pushed, but we do not want // to have an additional FS:0 handler between the COM callsite and the call into managed. So we push this diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index 3f4a7ed531273..74d55fd4544db 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -2445,44 +2445,21 @@ VOID StubLinkerCPU::X86EmitCurrentThreadFetch(X86Reg dstreg, unsigned preservedR #endif // TARGET_UNIX } -#if defined(TARGET_X86) +#if defined(FEATURE_COMINTEROP) && defined(TARGET_X86) -#if defined(PROFILING_SUPPORTED) && !defined(FEATURE_STUBS_AS_IL) +#if defined(PROFILING_SUPPORTED) VOID StubLinkerCPU::EmitProfilerComCallProlog(TADDR pFrameVptr, X86Reg regFrame) { STANDARD_VM_CONTRACT; - if (pFrameVptr == UMThkCallFrame::GetMethodFrameVPtr()) - { - // Load the methoddesc into ECX (UMThkCallFrame->m_pvDatum->m_pMD) - X86EmitIndexRegLoad(kECX, regFrame, UMThkCallFrame::GetOffsetOfDatum()); - X86EmitIndexRegLoad(kECX, kECX, UMEntryThunk::GetOffsetOfMethodDesc()); - - // Push arguments and notify profiler - X86EmitPushImm32(COR_PRF_TRANSITION_CALL); // Reason - X86EmitPushReg(kECX); // MethodDesc* - X86EmitCall(NewExternalCodeLabel((LPVOID) ProfilerUnmanagedToManagedTransitionMD), 2*sizeof(void*)); - } - -#ifdef FEATURE_COMINTEROP - else if (pFrameVptr == ComMethodFrame::GetMethodFrameVPtr()) - { - // Load the methoddesc into ECX (Frame->m_pvDatum->m_pMD) - X86EmitIndexRegLoad(kECX, regFrame, ComMethodFrame::GetOffsetOfDatum()); - X86EmitIndexRegLoad(kECX, kECX, ComCallMethodDesc::GetOffsetOfMethodDesc()); - - // Push arguments and notify profiler - X86EmitPushImm32(COR_PRF_TRANSITION_CALL); // Reason - X86EmitPushReg(kECX); // MethodDesc* - X86EmitCall(NewExternalCodeLabel((LPVOID) ProfilerUnmanagedToManagedTransitionMD), 2*sizeof(void*)); - } -#endif // FEATURE_COMINTEROP + // Load the methoddesc into ECX (Frame->m_pvDatum->m_pMD) + X86EmitIndexRegLoad(kECX, regFrame, ComMethodFrame::GetOffsetOfDatum()); + X86EmitIndexRegLoad(kECX, kECX, ComCallMethodDesc::GetOffsetOfMethodDesc()); - // Unrecognized frame vtbl - else - { - _ASSERTE(!"Unrecognized vtble passed to EmitComMethodStubProlog with profiling turned on."); - } + // Push arguments and notify profiler + X86EmitPushImm32(COR_PRF_TRANSITION_CALL); // Reason + X86EmitPushReg(kECX); // MethodDesc* + X86EmitCall(NewExternalCodeLabel((LPVOID) ProfilerUnmanagedToManagedTransitionMD), 2*sizeof(void*)); } @@ -2491,50 +2468,21 @@ VOID StubLinkerCPU::EmitProfilerComCallEpilog(TADDR pFrameVptr, X86Reg regFrame) CONTRACTL { STANDARD_VM_CHECK; -#ifdef FEATURE_COMINTEROP - PRECONDITION(pFrameVptr == UMThkCallFrame::GetMethodFrameVPtr() || pFrameVptr == ComMethodFrame::GetMethodFrameVPtr()); -#else - PRECONDITION(pFrameVptr == UMThkCallFrame::GetMethodFrameVPtr()); -#endif // FEATURE_COMINTEROP + PRECONDITION(pFrameVptr == ComMethodFrame::GetMethodFrameVPtr()); } CONTRACTL_END; - if (pFrameVptr == UMThkCallFrame::GetMethodFrameVPtr()) - { - // Load the methoddesc into ECX (UMThkCallFrame->m_pvDatum->m_pMD) - X86EmitIndexRegLoad(kECX, regFrame, UMThkCallFrame::GetOffsetOfDatum()); - X86EmitIndexRegLoad(kECX, kECX, UMEntryThunk::GetOffsetOfMethodDesc()); - - // Push arguments and notify profiler - X86EmitPushImm32(COR_PRF_TRANSITION_RETURN); // Reason - X86EmitPushReg(kECX); // MethodDesc* - X86EmitCall(NewExternalCodeLabel((LPVOID) ProfilerManagedToUnmanagedTransitionMD), 2*sizeof(void*)); - } - -#ifdef FEATURE_COMINTEROP - else if (pFrameVptr == ComMethodFrame::GetMethodFrameVPtr()) - { - // Load the methoddesc into ECX (Frame->m_pvDatum->m_pMD) - X86EmitIndexRegLoad(kECX, regFrame, ComMethodFrame::GetOffsetOfDatum()); - X86EmitIndexRegLoad(kECX, kECX, ComCallMethodDesc::GetOffsetOfMethodDesc()); - - // Push arguments and notify profiler - X86EmitPushImm32(COR_PRF_TRANSITION_RETURN); // Reason - X86EmitPushReg(kECX); // MethodDesc* - X86EmitCall(NewExternalCodeLabel((LPVOID) ProfilerManagedToUnmanagedTransitionMD), 2*sizeof(void*)); - } -#endif // FEATURE_COMINTEROP + // Load the methoddesc into ECX (Frame->m_pvDatum->m_pMD) + X86EmitIndexRegLoad(kECX, regFrame, ComMethodFrame::GetOffsetOfDatum()); + X86EmitIndexRegLoad(kECX, kECX, ComCallMethodDesc::GetOffsetOfMethodDesc()); - // Unrecognized frame vtbl - else - { - _ASSERTE(!"Unrecognized vtble passed to EmitComMethodStubEpilog with profiling turned on."); - } + // Push arguments and notify profiler + X86EmitPushImm32(COR_PRF_TRANSITION_RETURN); // Reason + X86EmitPushReg(kECX); // MethodDesc* + X86EmitCall(NewExternalCodeLabel((LPVOID) ProfilerManagedToUnmanagedTransitionMD), 2*sizeof(void*)); } -#endif // PROFILING_SUPPORTED && !FEATURE_STUBS_AS_IL - +#endif // PROFILING_SUPPORTED -#ifndef FEATURE_STUBS_AS_IL //======================================================================== // Prolog for entering managed code from COM // pushes the appropriate frame ptr @@ -2584,13 +2532,6 @@ void StubLinkerCPU::EmitComMethodStubProlog(TADDR pFrameVptr, // lea esi, [esp+4] ;; set ESI -> new frame X86EmitEspOffset(0x8d, kESI, 4); // lea ESI, [ESP+4] - if (pFrameVptr == UMThkCallFrame::GetMethodFrameVPtr()) - { - // Preserve argument registers for thiscall/fastcall - X86EmitPushReg(kECX); - X86EmitPushReg(kEDX); - } - // Emit Setup thread EmitSetup(rgRareLabels[0]); // rareLabel for rare setup EmitLabel(rgRejoinLabels[0]); // rejoin label for rare setup @@ -2639,23 +2580,6 @@ void StubLinkerCPU::EmitComMethodStubProlog(TADDR pFrameVptr, // mov [ebx + Thread.GetFrame()], esi X86EmitIndexRegStore(kEBX, Thread::GetOffsetOfCurrentFrame(), kESI); - if (pFrameVptr == UMThkCallFrame::GetMethodFrameVPtr()) - { - // push UnmanagedToManagedExceptHandler - X86EmitPushImmPtr((LPVOID)UMThunkPrestubHandler); - - // mov eax, fs:[0] - static const BYTE codeSEH1[] = { 0x64, 0xA1, 0x0, 0x0, 0x0, 0x0}; - EmitBytes(codeSEH1, sizeof(codeSEH1)); - - // push eax - X86EmitPushReg(kEAX); - - // mov dword ptr fs:[0], esp - static const BYTE codeSEH2[] = { 0x64, 0x89, 0x25, 0x0, 0x0, 0x0, 0x0}; - EmitBytes(codeSEH2, sizeof(codeSEH2)); - } - #if _DEBUG if (Frame::ShouldLogTransitions()) { @@ -2692,19 +2616,6 @@ void StubLinkerCPU::EmitComMethodStubEpilog(TADDR pFrameVptr, EmitCheckGSCookie(kESI, UnmanagedToManagedFrame::GetOffsetOfGSCookie()); - if (pFrameVptr == UMThkCallFrame::GetMethodFrameVPtr()) - { - // if we are using exceptions, unlink the SEH - // mov ecx,[esp] ;;pointer to the next exception record - X86EmitEspOffset(0x8b, kECX, 0); - - // mov dword ptr fs:[0], ecx - static const BYTE codeSEH[] = { 0x64, 0x89, 0x0D, 0x0, 0x0, 0x0, 0x0 }; - EmitBytes(codeSEH, sizeof(codeSEH)); - - X86EmitAddEsp(sizeof(EXCEPTION_REGISTRATION_RECORD)); - } - // mov [ebx + Thread.GetFrame()], edi ;; restore previous frame X86EmitIndexRegStore(kEBX, Thread::GetOffsetOfCurrentFrame(), kEDI); @@ -2714,13 +2625,6 @@ void StubLinkerCPU::EmitComMethodStubEpilog(TADDR pFrameVptr, EmitEnable(rgRareLabels[2]); // rare gc EmitLabel(rgRejoinLabels[2]); // rejoin for rare gc - if (pFrameVptr == UMThkCallFrame::GetMethodFrameVPtr()) - { - // Restore argument registers for thiscall/fastcall - X86EmitPopReg(kEDX); - X86EmitPopReg(kECX); - } - // add esp, popstack X86EmitAddEsp(sizeof(GSCookie) + UnmanagedToManagedFrame::GetOffsetOfCalleeSavedRegisters()); @@ -2761,7 +2665,6 @@ void StubLinkerCPU::EmitComMethodStubEpilog(TADDR pFrameVptr, EmitLabel(rgRareLabels[0]); // label for rare setup thread EmitRareSetup(rgRejoinLabels[0], /*fThrow*/ TRUE); // emit rare setup thread } -#endif // !FEATURE_STUBS_AS_IL //--------------------------------------------------------------- // Emit code to store the setup current Thread structure in eax. @@ -2792,16 +2695,12 @@ VOID StubLinkerCPU::EmitRareSetup(CodeLabel *pRejoinPoint, BOOL fThrow) { STANDARD_VM_CONTRACT; -#ifndef FEATURE_COMINTEROP - _ASSERTE(fThrow); -#else // !FEATURE_COMINTEROP if (!fThrow) { X86EmitPushReg(kESI); X86EmitCall(NewExternalCodeLabel((LPVOID) CreateThreadBlockReturnHr), sizeof(void*)); } else -#endif // !FEATURE_COMINTEROP { X86EmitCall(NewExternalCodeLabel((LPVOID) CreateThreadBlockThrow), 0); } @@ -2811,10 +2710,6 @@ VOID StubLinkerCPU::EmitRareSetup(CodeLabel *pRejoinPoint, BOOL fThrow) X86EmitNearJump(pRejoinPoint); } -//======================================================================== -#endif // TARGET_X86 -//======================================================================== -#if defined(FEATURE_COMINTEROP) && defined(TARGET_X86) //======================================================================== // Epilog for stubs that enter managed code from COM // @@ -2920,9 +2815,9 @@ void StubLinkerCPU::EmitSharedComMethodStubEpilog(TADDR pFrameVptr, EmitRareSetup(rgRejoinLabels[0],/*fThrow*/ FALSE); // emit rare setup thread } -//======================================================================== #endif // defined(FEATURE_COMINTEROP) && defined(TARGET_X86) + #if !defined(FEATURE_STUBS_AS_IL) && defined(TARGET_X86) /*============================================================================== Pushes a TransitionFrame on the stack @@ -3437,7 +3332,7 @@ VOID StubLinkerCPU::EmitUnwindInfoCheckSubfunction() #endif // defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) -#ifdef TARGET_X86 +#if defined(FEATURE_COMINTEROP) && defined(TARGET_X86) //----------------------------------------------------------------------- // Generates the inline portion of the code to enable preemptive GC. Hopefully, @@ -3579,7 +3474,6 @@ VOID StubLinkerCPU::EmitRareDisable(CodeLabel *pRejoinPoint) X86EmitNearJump(pRejoinPoint); } -#ifdef FEATURE_COMINTEROP //----------------------------------------------------------------------- // Generates the out-of-line portion of the code to disable preemptive GC. // After the work is done, the code normally jumps back to the "pRejoinPoint" @@ -3611,10 +3505,8 @@ VOID StubLinkerCPU::EmitRareDisableHRESULT(CodeLabel *pRejoinPoint, CodeLabel *p X86EmitNearJump(pExitPoint); } -#endif // FEATURE_COMINTEROP - -#endif // TARGET_X86 +#endif // defined(FEATURE_COMINTEROP) && defined(TARGET_X86) VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index 02ab6e9d253ea..c719057e97ea3 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -250,17 +250,6 @@ class StubLinkerCPU : public StubLinker ); VOID X86EmitPushEBPframe(); -#if defined(TARGET_X86) -#if defined(PROFILING_SUPPORTED) && !defined(FEATURE_STUBS_AS_IL) - // These are used to emit calls to notify the profiler of transitions in and out of - // managed code through COM->COM+ interop or N/Direct - VOID EmitProfilerComCallProlog(TADDR pFrameVptr, X86Reg regFrame); - VOID EmitProfilerComCallEpilog(TADDR pFrameVptr, X86Reg regFrame); -#endif // PROFILING_SUPPORTED && !FEATURE_STUBS_AS_IL -#endif // TARGET_X86 - - - // Emits the most efficient form of the operation: // // opcode altreg, [basereg + scaledreg*scale + ofs] @@ -340,6 +329,7 @@ class StubLinkerCPU : public StubLinker #endif } +#if defined(FEATURE_COMINTEROP) && defined(TARGET_X86) VOID EmitEnable(CodeLabel *pForwardRef); VOID EmitRareEnable(CodeLabel *pRejoinPoint); @@ -349,20 +339,13 @@ class StubLinkerCPU : public StubLinker VOID EmitSetup(CodeLabel *pForwardRef); VOID EmitRareSetup(CodeLabel* pRejoinPoint, BOOL fThrow); +#endif // FEATURE_COMINTEROP && TARGET_X86 #ifndef FEATURE_STUBS_AS_IL VOID EmitMethodStubProlog(TADDR pFrameVptr, int transitionBlockOffset); VOID EmitMethodStubEpilog(WORD numArgBytes, int transitionBlockOffset); VOID EmitCheckGSCookie(X86Reg frameReg, int gsCookieOffset); - -#ifdef TARGET_X86 - void EmitComMethodStubProlog(TADDR pFrameVptr, CodeLabel** rgRareLabels, - CodeLabel** rgRejoinLabels, BOOL bShouldProfile); - - void EmitComMethodStubEpilog(TADDR pFrameVptr, CodeLabel** rgRareLabels, - CodeLabel** rgRejoinLabels, BOOL bShouldProfile); -#endif // TARGET_X86 #endif // !FEATURE_STUBS_AS_IL #ifdef TARGET_X86 @@ -379,6 +362,20 @@ class StubLinkerCPU : public StubLinker VOID EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, struct ShuffleEntry *pShuffleEntryArray, void* extraArg); #if defined(FEATURE_COMINTEROP) && defined(TARGET_X86) + +#if defined(PROFILING_SUPPORTED) + // These are used to emit calls to notify the profiler of transitions in and out of + // managed code through COM->COM+ interop or N/Direct + VOID EmitProfilerComCallProlog(TADDR pFrameVptr, X86Reg regFrame); + VOID EmitProfilerComCallEpilog(TADDR pFrameVptr, X86Reg regFrame); +#endif // PROFILING_SUPPORTED + + void EmitComMethodStubProlog(TADDR pFrameVptr, CodeLabel** rgRareLabels, + CodeLabel** rgRejoinLabels, BOOL bShouldProfile); + + void EmitComMethodStubEpilog(TADDR pFrameVptr, CodeLabel** rgRareLabels, + CodeLabel** rgRejoinLabels, BOOL bShouldProfile); + //======================================================================== // shared Epilog for stubs that enter managed code from COM // uses a return thunk within the method desc diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index d8488e7e583b8..a4fdb065285dd 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -2262,10 +2262,6 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo // use the prestub. //========================================================================== -#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL) -static PCODE g_UMThunkPreStub; -#endif // TARGET_X86 && !FEATURE_STUBS_AS_IL - #ifndef DACCESS_COMPILE void ThePreStubManager::Init(void) @@ -2286,10 +2282,6 @@ void InitPreStubManager(void) { STANDARD_VM_CONTRACT; -#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL) - g_UMThunkPreStub = GenerateUMThunkPrestub()->GetEntryPoint(); -#endif // TARGET_X86 && !FEATURE_STUBS_AS_IL - ThePreStubManager::Init(); } @@ -2297,11 +2289,7 @@ PCODE TheUMThunkPreStub() { LIMITED_METHOD_CONTRACT; -#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL) - return g_UMThunkPreStub; -#else // TARGET_X86 && !FEATURE_STUBS_AS_IL return GetEEFuncEntryPoint(TheUMEntryPrestub); -#endif // TARGET_X86 && !FEATURE_STUBS_AS_IL } PCODE TheVarargNDirectStub(BOOL hasRetBuffArg) From d48a44f2ee2f6b4b039ca10cfd5dc01c331669f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 18 Jan 2022 02:11:44 +0900 Subject: [PATCH 002/308] Separate variance information in mangled names (#63866) Fixes https://github.com/dotnet/runtimelab/issues/1821. Eventually we'll need to have a holistic look at how we mangle things. --- .../Compiler/DependencyAnalysis/GenericCompositionNode.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericCompositionNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericCompositionNode.cs index a4388b4eeb4a9..9857c633784db 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericCompositionNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericCompositionNode.cs @@ -36,6 +36,7 @@ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) if (_details.Variance != null) { + sb.Append("__Variance__"); for (int i = 0; i < _details.Variance.Length; i++) { sb.Append('_'); From d0e2dac3a828b6afda5cff812b7b09b9dba213b7 Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Tue, 18 Jan 2022 01:23:41 +0300 Subject: [PATCH 003/308] Actually properly type primary selectors (#63752) * Use only one [out] parameter in IsFieldAddr Since only one is needed. * Actually properly type primary selectors --- src/coreclr/jit/compiler.h | 16 ++++-- src/coreclr/jit/compiler.hpp | 4 +- src/coreclr/jit/gentree.cpp | 30 +++++----- src/coreclr/jit/gentree.h | 2 +- src/coreclr/jit/optimizer.cpp | 31 ++++------- src/coreclr/jit/valuenum.cpp | 101 ++++++++++++++++------------------ 6 files changed, 87 insertions(+), 97 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 5a16ac8a58bf8..422944fed8e7c 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6731,6 +6731,12 @@ class Compiler CALLINT_ALL, // kills everything (normal method call) }; + enum class FieldKindForVN + { + SimpleStatic, + WithBaseAddr + }; + public: // A "LoopDsc" describes a ("natural") loop. We (currently) require the body of a loop to be a contiguous (in // bbNext order) sequence of basic blocks. (At times, we may require the blocks in a loop to be "properly numbered" @@ -6785,9 +6791,9 @@ class Compiler int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or across this loop - typedef JitHashTable, bool> FieldHandleSet; - FieldHandleSet* lpFieldsModified; // This has entries (mappings to "true") for all static field and object - // instance fields modified + typedef JitHashTable, FieldKindForVN> + FieldHandleSet; + FieldHandleSet* lpFieldsModified; // This has entries for all static field and object instance fields modified // in the loop. typedef JitHashTable, bool> ClassHandleSet; @@ -6798,7 +6804,7 @@ class Compiler // Adds the variable liveness information for 'blk' to 'this' LoopDsc void AddVariableLiveness(Compiler* comp, BasicBlock* blk); - inline void AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd); + inline void AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd, FieldKindForVN fieldKind); // This doesn't *always* take a class handle -- it can also take primitive types, encoded as class handles // (shifted left, with a low-order bit set to distinguish.) // Use the {Encode/Decode}ElemType methods to construct/destruct these. @@ -7045,7 +7051,7 @@ class Compiler void AddVariableLivenessAllContainingLoops(unsigned lnum, BasicBlock* blk); // Adds "fldHnd" to the set of modified fields of "lnum" and any parent loops. - void AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd); + void AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd, FieldKindForVN fieldKind); // Adds "elemType" to the set of modified array element types of "lnum" and any parent loops. void AddModifiedElemTypeAllContainingLoops(unsigned lnum, CORINFO_CLASS_HANDLE elemType); diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index b75828d4cc68a..937d144d70ead 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3346,14 +3346,14 @@ inline void Compiler::optAssertionRemove(AssertionIndex index) } } -inline void Compiler::LoopDsc::AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd) +inline void Compiler::LoopDsc::AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd, FieldKindForVN fieldKind) { if (lpFieldsModified == nullptr) { lpFieldsModified = new (comp->getAllocatorLoopHoist()) Compiler::LoopDsc::FieldHandleSet(comp->getAllocatorLoopHoist()); } - lpFieldsModified->Set(fldHnd, true, FieldHandleSet::Overwrite); + lpFieldsModified->Set(fldHnd, fieldKind, FieldHandleSet::Overwrite); } inline void Compiler::LoopDsc::AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 280c2f7087590..59c47e4246c7e 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -15930,26 +15930,26 @@ bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp) // this: ADD(CONST FldSeq, baseAddr) // // Arguments: -// comp - the Compiler object -// pObj - [out] parameter for instance fields, the object reference -// pStatic - [out] parameter for static fields, the base address -// pFldSeq - [out] parameter for the field sequence +// comp - the Compiler object +// pBaseAddr - [out] parameter for "the base address" +// pFldSeq - [out] parameter for the field sequence // // Return Value: // If "this" matches patterns denoted above, and the FldSeq found is "full", // i. e. starts with a class field or a static field, and includes all the // struct fields that this tree represents the address of, this method will -// return "true" and set either "pObj" or "pStatic" to some value, which must -// be used by the caller as the key into the "first field map" to obtain the -// actual value for the field. +// return "true" and set either "pBaseAddr" to some value, which must be used +// by the caller as the key into the "first field map" to obtain the actual +// value for the field. For instance fields, "base address" will be the object +// reference, for statics - the address to which the field offset with the +// field sequence is added, see "impImportStaticFieldAccess" and "fgMorphField". // -bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pObj, GenTree** pStatic, FieldSeqNode** pFldSeq) +bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pFldSeq) { assert(TypeIs(TYP_I_IMPL, TYP_BYREF, TYP_REF)); - *pObj = nullptr; - *pStatic = nullptr; - *pFldSeq = FieldSeqStore::NotAField(); + *pBaseAddr = nullptr; + *pFldSeq = FieldSeqStore::NotAField(); GenTree* baseAddr = nullptr; FieldSeqNode* fldSeq = nullptr; @@ -16006,8 +16006,8 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pObj, GenTree** pStatic, Fie // TODO-VNTypes: we will always return the "baseAddr" here for now, but strictly speaking, // we only need to do that if we have a shared field, to encode the logical "instantiation" // argument. In all other cases, this serves no purpose and just leads to redundant maps. - *pStatic = baseAddr; - *pFldSeq = fldSeq; + *pBaseAddr = baseAddr; + *pFldSeq = fldSeq; return true; } @@ -16015,8 +16015,8 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pObj, GenTree** pStatic, Fie { assert(!comp->eeIsValueClass(comp->info.compCompHnd->getFieldClass(fldSeq->GetFieldHandle()))); - *pObj = baseAddr; - *pFldSeq = fldSeq; + *pBaseAddr = baseAddr; + *pFldSeq = fldSeq; return true; } diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 3c5fff088cef1..e7a03d26547d3 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1917,7 +1917,7 @@ struct GenTree // where Y is an arbitrary tree, and X is a lclVar. unsigned IsLclVarUpdateTree(GenTree** otherTree, genTreeOps* updateOper); - bool IsFieldAddr(Compiler* comp, GenTree** pObj, GenTree** pStatic, FieldSeqNode** pFldSeq); + bool IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pFldSeq); // Requires "this" to be the address of an array (the child of a GT_IND labeled with GTF_IND_ARR_INDEX). // Sets "pArr" to the node representing the array (either an array object pointer, or perhaps a byref to the some diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 2d3aedc94ba0a..77394d4b5d1e4 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -7850,24 +7850,16 @@ bool Compiler::optComputeLoopSideEffectsOfBlock(BasicBlock* blk) } else { - // We are only interested in IsFieldAddr()'s fldSeq out parameter. - // - GenTree* obj = nullptr; // unused - GenTree* staticOffset = nullptr; // unused - FieldSeqNode* fldSeq = nullptr; - - if (arg->IsFieldAddr(this, &obj, &staticOffset, &fldSeq) && - (fldSeq != FieldSeqStore::NotAField())) + GenTree* baseAddr = nullptr; + FieldSeqNode* fldSeq = nullptr; + if (arg->IsFieldAddr(this, &baseAddr, &fldSeq)) { - // Get the first (object) field from field seq. GcHeap[field] will yield the "field map". - assert(fldSeq != nullptr); - if (fldSeq->IsFirstElemFieldSeq()) - { - fldSeq = fldSeq->m_next; - assert(fldSeq != nullptr); - } + assert((fldSeq != nullptr) && (fldSeq != FieldSeqStore::NotAField()) && + !fldSeq->IsPseudoField()); - AddModifiedFieldAllContainingLoops(mostNestedLoop, fldSeq->m_fieldHnd); + FieldKindForVN fieldKind = + (baseAddr != nullptr) ? FieldKindForVN::WithBaseAddr : FieldKindForVN::SimpleStatic; + AddModifiedFieldAllContainingLoops(mostNestedLoop, fldSeq->GetFieldHandle(), fieldKind); // Conservatively assume byrefs may alias this object. memoryHavoc |= memoryKindSet(ByrefExposed); } @@ -7893,7 +7885,8 @@ bool Compiler::optComputeLoopSideEffectsOfBlock(BasicBlock* blk) } else if (lhs->OperGet() == GT_CLS_VAR) { - AddModifiedFieldAllContainingLoops(mostNestedLoop, lhs->AsClsVar()->gtClsVarHnd); + AddModifiedFieldAllContainingLoops(mostNestedLoop, lhs->AsClsVar()->gtClsVarHnd, + FieldKindForVN::SimpleStatic); // Conservatively assume byrefs may alias this static field memoryHavoc |= memoryKindSet(ByrefExposed); } @@ -8073,12 +8066,12 @@ void Compiler::AddVariableLivenessAllContainingLoops(unsigned lnum, BasicBlock* } // Adds "fldHnd" to the set of modified fields of "lnum" and any parent loops. -void Compiler::AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd) +void Compiler::AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd, FieldKindForVN fieldKind) { assert(0 <= lnum && lnum < optLoopCount); while (lnum != BasicBlock::NOT_IN_LOOP) { - optLoopTable[lnum].AddModifiedField(this, fldHnd); + optLoopTable[lnum].AddModifiedField(this, fldHnd, fieldKind); lnum = optLoopTable[lnum].lpParent; } } diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 1c4341e147009..cc9fb0f38d249 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -7128,8 +7128,9 @@ ValueNum Compiler::fgMemoryVNForLoopSideEffects(MemoryKind memoryKind, for (Compiler::LoopDsc::FieldHandleSet::KeyIterator ki = fieldsMod->Begin(); !ki.Equal(fieldsMod->End()); ++ki) { - CORINFO_FIELD_HANDLE fldHnd = ki.Get(); - ValueNum fldHndVN = vnStore->VNForHandle(ssize_t(fldHnd), GTF_ICON_FIELD_HDL); + CORINFO_FIELD_HANDLE fldHnd = ki.Get(); + FieldKindForVN fieldKind = ki.GetValue(); + ValueNum fldHndVN = vnStore->VNForHandle(ssize_t(fldHnd), GTF_ICON_FIELD_HDL); #ifdef DEBUG if (verbose) @@ -7140,9 +7141,9 @@ ValueNum Compiler::fgMemoryVNForLoopSideEffects(MemoryKind memoryKind, } #endif // DEBUG - // Instance field maps get a placeholder type - they do not represent "singular" - // values. Static field maps, on the other hand, do, and so must be given proper types. - var_types fldMapType = eeIsFieldStatic(fldHnd) ? eeGetFieldType(fldHnd) : TYP_MEM; + // Instance fields and "complex" statics select "first field maps" + // with a placeholder type. "Simple" statics select their own types. + var_types fldMapType = (fieldKind == FieldKindForVN::WithBaseAddr) ? TYP_MEM : eeGetFieldType(fldHnd); newMemoryVN = vnStore->VNForMapStore(newMemoryVN, fldHndVN, vnStore->VNForExpr(entryBlock, fldMapType)); } @@ -7735,9 +7736,8 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) // Was the argument of the GT_IND the address of a local, handled above? if (!wasLocal) { - GenTree* obj = nullptr; - GenTree* staticOffset = nullptr; - FieldSeqNode* fldSeq = nullptr; + GenTree* baseAddr = nullptr; + FieldSeqNode* fldSeq = nullptr; // Is the LHS an array index expression? if (argIsVNFunc && funcApp.m_func == VNF_PtrToArrElem) @@ -7796,7 +7796,7 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) rhsVNPair.GetLiberal(), lhs->TypeGet()); recordGcHeapStore(tree, heapVN DEBUGARG("ArrIndexAssign (case 2)")); } - else if (arg->IsFieldAddr(this, &obj, &staticOffset, &fldSeq)) + else if (arg->IsFieldAddr(this, &baseAddr, &fldSeq)) { assert((fldSeq != nullptr) && (fldSeq != FieldSeqStore::NotAField()) && !fldSeq->IsPseudoField()); @@ -7807,11 +7807,10 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) // We will check that the final field in the sequence matches 'indType'. var_types indType = lhs->TypeGet(); - // when (obj != nullptr) we have an instance field, otherwise a static field - // when (staticOffset != nullptr) it represents a offset into a static or the call to - // Shared Static Base - if ((obj != nullptr) || (staticOffset != nullptr)) + if (baseAddr != nullptr) { + // Instance field / "complex" static: heap[field][baseAddr][struct fields...] = storeVal. + var_types firstFieldType; ValueNum firstFieldSelectorVN = vnStore->VNForFieldSelector(fldSeq->GetFieldHandle(), &firstFieldType); @@ -7821,15 +7820,7 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) ValueNum fldMapVN = vnStore->VNForMapSelect(VNK_Liberal, TYP_MEM, fgCurMemoryVN[GcHeap], firstFieldSelectorVN); - ValueNum firstFieldValueSelectorVN = ValueNumStore::NoVN; - if (obj != nullptr) - { - firstFieldValueSelectorVN = vnStore->VNLiberalNormalValue(obj->gtVNPair); - } - else // (staticOffset != nullptr) - { - firstFieldValueSelectorVN = vnStore->VNLiberalNormalValue(staticOffset->gtVNPair); - } + ValueNum firstFieldValueSelectorVN = vnStore->VNLiberalNormalValue(baseAddr->gtVNPair); ValueNum newFirstFieldValueVN = ValueNumStore::NoVN; // Optimization: avoid traversting the maps for the value of the first field if @@ -7840,12 +7831,12 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) } else { - // Construct the ValueNumber for fldMap[obj/offset]. This (struct) + // Construct the ValueNumber for fldMap[baseAddr]. This (struct) // map represents the specific field we're looking to store to. ValueNum firstFieldValueVN = vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, firstFieldValueSelectorVN); - // Construct the maps updating the rest of the fields in the sequence. + // Construct the maps updating the struct fields in the sequence. newFirstFieldValueVN = vnStore->VNApplySelectorsAssign(VNK_Liberal, firstFieldValueVN, fldSeq->m_next, storeVal, indType); } @@ -7859,7 +7850,7 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) } else { - // Plain static field. + // "Simple" static: heap[field][struct fields...] = storeVal. newHeapVN = vnStore->VNApplySelectorsAssign(VNK_Liberal, fgCurMemoryVN[GcHeap], fldSeq, storeVal, indType); } @@ -8771,12 +8762,11 @@ void Compiler::fgValueNumberTree(GenTree* tree) // a pointer to an object field or array element. Other cases become uses of // the current ByrefExposed value and the pointer value, so that at least we // can recognize redundant loads with no stores between them. - GenTree* addr = tree->AsIndir()->Addr(); - GenTreeLclVarCommon* lclVarTree = nullptr; - FieldSeqNode* fldSeq2 = nullptr; - GenTree* obj = nullptr; - GenTree* staticOffset = nullptr; - bool isVolatile = (tree->gtFlags & GTF_IND_VOLATILE) != 0; + GenTree* addr = tree->AsIndir()->Addr(); + GenTreeLclVarCommon* lclVarTree = nullptr; + FieldSeqNode* fldSeq = nullptr; + GenTree* baseAddr = nullptr; + bool isVolatile = (tree->gtFlags & GTF_IND_VOLATILE) != 0; // See if the addr has any exceptional part. ValueNumPair addrNvnp; @@ -8964,41 +8954,42 @@ void Compiler::fgValueNumberTree(GenTree* tree) { fgValueNumberArrIndexVal(tree, &funcApp, addrXvnp.GetLiberal()); } - else if (addr->IsFieldAddr(this, &obj, &staticOffset, &fldSeq2)) + else if (addr->IsFieldAddr(this, &baseAddr, &fldSeq)) { - assert((fldSeq2 != nullptr) && (fldSeq2 != FieldSeqStore::NotAField()) && - !fldSeq2->IsPseudoField()); + assert((fldSeq != nullptr) && (fldSeq != FieldSeqStore::NotAField()) && !fldSeq->IsPseudoField()); // The size of the ultimate value we will select, if it is of a struct type. - size_t structSize = 0; + size_t structSize = 0; + ValueNum valueVN = ValueNumStore::NoVN; - // Get the selector for the first field. - var_types firstFieldType; - ValueNum firstFieldSelectorVN = - vnStore->VNForFieldSelector(fldSeq2->GetFieldHandle(), &firstFieldType, &structSize); + if (baseAddr != nullptr) + { + // Instance field / "complex" static: heap[field][baseAddr][struct fields...]. - ValueNum fldMapVN = - vnStore->VNForMapSelect(VNK_Liberal, TYP_MEM, fgCurMemoryVN[GcHeap], firstFieldSelectorVN); + // Get the selector for the first field. + var_types firstFieldType; + ValueNum firstFieldSelectorVN = + vnStore->VNForFieldSelector(fldSeq->GetFieldHandle(), &firstFieldType, &structSize); - ValueNum firstFieldValueSelectorVN; - if (obj != nullptr) - { - firstFieldValueSelectorVN = vnStore->VNLiberalNormalValue(obj->gtVNPair); + ValueNum fldMapVN = + vnStore->VNForMapSelect(VNK_Liberal, TYP_MEM, fgCurMemoryVN[GcHeap], firstFieldSelectorVN); + + ValueNum firstFieldValueSelectorVN = vnStore->VNLiberalNormalValue(baseAddr->gtVNPair); + + // Construct the value number for fldMap[baseAddr]. + ValueNum firstFieldValueVN = + vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, firstFieldValueSelectorVN); + + // Finally, account for the rest of the fields in the sequence. + valueVN = + vnStore->VNApplySelectors(VNK_Liberal, firstFieldValueVN, fldSeq->m_next, &structSize); } else { - assert(staticOffset != nullptr); - firstFieldValueSelectorVN = vnStore->VNLiberalNormalValue(staticOffset->gtVNPair); + // "Simple" static: heap[static][struct fields...]. + valueVN = vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap], fldSeq, &structSize); } - // Construct the value number for fldMap[obj/offset]. - ValueNum firstFieldValueVN = - vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, firstFieldValueSelectorVN); - - // Finally, account for the rest of the fields in the sequence. - ValueNum valueVN = - vnStore->VNApplySelectors(VNK_Liberal, firstFieldValueVN, fldSeq2->m_next, &structSize); - valueVN = vnStore->VNApplySelectorsTypeCheck(valueVN, tree->TypeGet(), structSize); tree->gtVNPair.SetLiberal(valueVN); From 126db6dd10fcf618a9ab17ed93347044cc5a3a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 18 Jan 2022 14:19:20 +0900 Subject: [PATCH 004/308] Disable warnings as errors in the repro project (#63910) --- src/coreclr/tools/aot/ILCompiler/repro/repro.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler/repro/repro.csproj b/src/coreclr/tools/aot/ILCompiler/repro/repro.csproj index 52b0f44fc4891..c0df3bfd2c6ee 100644 --- a/src/coreclr/tools/aot/ILCompiler/repro/repro.csproj +++ b/src/coreclr/tools/aot/ILCompiler/repro/repro.csproj @@ -9,7 +9,7 @@ linux-x64;win-x64;osx-x64 Debug;Release;Checked true - 649;169;414 + false Date: Tue, 18 Jan 2022 10:41:02 +0100 Subject: [PATCH 005/308] [main] Update dependencies from dotnet/linker (#63445) Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a2cfe2c769fe8..f2f65abdb43a3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -234,9 +234,9 @@ https://github.com/dotnet/runtime a2af6294767b4a3f4c2ce787c5dda2abeeda7a00 - + https://github.com/dotnet/linker - 1a6468ff722c8d362f37638989ec01ab9975ac28 + e485816b48273d03bd6266a64dad9bea97f861d5 https://github.com/dotnet/xharness diff --git a/eng/Versions.props b/eng/Versions.props index 8bc9373cc09ac..ceff6ee674bc4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -176,7 +176,7 @@ 6.0.0-preview-20211019.1 - 7.0.100-1.22053.1 + 7.0.100-1.22063.2 $(MicrosoftNETILLinkTasksVersion) 7.0.0-alpha.1.22060.1 From 8d8ef6dac58acf2ab944289c69dd46ee9e12d717 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Tue, 18 Jan 2022 11:00:35 +0100 Subject: [PATCH 006/308] FileSystemEntry.Unix: don't make a syscall to check hidden on Linux. (#63878) --- .../Interop/Unix/System.Native/Interop.LChflags.cs | 6 ++++++ .../System/IO/Enumeration/FileSystemEntry.Unix.cs | 2 +- .../src/System/IO/FileStatus.Unix.cs | 12 +++++++++--- src/native/libs/System.Native/entrypoints.c | 1 + src/native/libs/System.Native/pal_io.c | 11 ++++++++++- src/native/libs/System.Native/pal_io.h | 7 +++++++ 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.LChflags.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.LChflags.cs index 1353fbc3acec6..a5bc36dfa3d2f 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.LChflags.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.LChflags.cs @@ -22,5 +22,11 @@ internal enum UserFlags : uint [GeneratedDllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LChflagsCanSetHiddenFlag")] [SuppressGCTransition] private static partial int LChflagsCanSetHiddenFlag(); + + internal static readonly bool SupportsHiddenFlag = (CanGetHiddenFlag() != 0); + + [GeneratedDllImport(Libraries.SystemNative, EntryPoint = "SystemNative_CanGetHiddenFlag")] + [SuppressGCTransition] + private static partial int CanGetHiddenFlag(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEntry.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEntry.Unix.cs index 1be3942011b2f..89c38584eea32 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEntry.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEntry.Unix.cs @@ -145,7 +145,7 @@ public FileAttributes Attributes public DateTimeOffset CreationTimeUtc => _status.GetCreationTime(FullPath, continueOnError: true); public DateTimeOffset LastAccessTimeUtc => _status.GetLastAccessTime(FullPath, continueOnError: true); public DateTimeOffset LastWriteTimeUtc => _status.GetLastWriteTime(FullPath, continueOnError: true); - public bool IsHidden => _status.IsHidden(FullPath, FileName, continueOnError: true); + public bool IsHidden => _status.IsFileSystemEntryHidden(FullPath, FileName); internal bool IsReadOnly => _status.IsReadOnly(FullPath, continueOnError: true); public bool IsDirectory => _status.InitiallyDirectory; diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs index 05b4bbcff6a2a..20961a8fbbc2e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs @@ -145,14 +145,20 @@ internal bool IsReadOnly(ReadOnlySpan path, bool continueOnError = false) return HasReadOnlyFlag; } - internal bool IsHidden(ReadOnlySpan path, ReadOnlySpan fileName, bool continueOnError = false) + internal bool IsFileSystemEntryHidden(ReadOnlySpan path, ReadOnlySpan fileName) { - // Avoid disk hit first + // Because this is called for FileSystemEntry we can assume the entry exists and + // avoid initialization in some cases. if (IsNameHidden(fileName)) { return true; } - EnsureCachesInitialized(path, continueOnError); + if (!Interop.Sys.SupportsHiddenFlag) + { + return false; + } + + EnsureCachesInitialized(path, continueOnError: true); return HasHiddenFlag; } diff --git a/src/native/libs/System.Native/entrypoints.c b/src/native/libs/System.Native/entrypoints.c index 0e54f4b5f1519..9ac04de3e0d66 100644 --- a/src/native/libs/System.Native/entrypoints.c +++ b/src/native/libs/System.Native/entrypoints.c @@ -109,6 +109,7 @@ static const Entry s_sysNative[] = DllImportEntry(SystemNative_LockFileRegion) DllImportEntry(SystemNative_LChflags) DllImportEntry(SystemNative_LChflagsCanSetHiddenFlag) + DllImportEntry(SystemNative_CanGetHiddenFlag) DllImportEntry(SystemNative_ReadProcessStatusInfo) DllImportEntry(SystemNative_Log) DllImportEntry(SystemNative_LogError) diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index 66c934ed182fa..d11ce950f1246 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -1553,7 +1553,16 @@ int32_t SystemNative_LChflags(const char* path, uint32_t flags) int32_t SystemNative_LChflagsCanSetHiddenFlag(void) { -#if defined(UF_HIDDEN) && defined(HAVE_STAT_FLAGS) && defined(HAVE_LCHFLAGS) +#if defined(HAVE_LCHFLAGS) + return SystemNative_CanGetHiddenFlag(); +#else + return false; +#endif +} + +int32_t SystemNative_CanGetHiddenFlag(void) +{ +#if defined(UF_HIDDEN) && defined(HAVE_STAT_FLAGS) return true; #else return false; diff --git a/src/native/libs/System.Native/pal_io.h b/src/native/libs/System.Native/pal_io.h index 726b097aff133..6ebde79230af9 100644 --- a/src/native/libs/System.Native/pal_io.h +++ b/src/native/libs/System.Native/pal_io.h @@ -744,6 +744,13 @@ PALEXPORT int32_t SystemNative_LChflags(const char* path, uint32_t flags); */ PALEXPORT int32_t SystemNative_LChflagsCanSetHiddenFlag(void); +/** + * Determines if the current platform supports getting UF_HIDDEN (0x8000) flag + * + * Returns true (non-zero) if supported, false (zero) if not. + */ +PALEXPORT int32_t SystemNative_CanGetHiddenFlag(void); + /** * Reads the psinfo_t struct and converts into ProcessStatus. * From 7a0388a9f1a11b723aa09aeae3436a078b32bb43 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Tue, 18 Jan 2022 13:33:57 +0000 Subject: [PATCH 007/308] Extend triage board automation to more pods (#63897) --- .github/fabricbot.json | 1189 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 1167 insertions(+), 22 deletions(-) diff --git a/.github/fabricbot.json b/.github/fabricbot.json index 72acfd8440a06..c885e48256630 100644 --- a/.github/fabricbot.json +++ b/.github/fabricbot.json @@ -6003,25 +6003,7 @@ { "name": "hasLabel", "parameters": { - "label": "area-System.Collections" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "area-System.Linq" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "area-System.Text.Json" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "area-System.Xml" + "label": "area-Meta" } } ] @@ -6032,7 +6014,7 @@ { "name": "isInProject", "parameters": { - "projectName": "Area Pod: Eirik / Krzysztof / Layomi - PRs", + "projectName": "Area Pod: Eric / Jeff - PRs", "isOrgProject": true } } @@ -6046,12 +6028,12 @@ "issues", "project_card" ], - "taskName": "[Area Pod: Eirik / Krzysztof / Layomi - PRs] Add new PR to Board", + "taskName": "[Area Pod: Eric / Jeff - PRs] Add new PR to Board", "actions": [ { "name": "addToProject", "parameters": { - "projectName": "Area Pod: Eirik / Krzysztof / Layomi - PRs", + "projectName": "Area Pod: Eric / Jeff - PRs", "columnName": "Needs Champion", "isOrgProject": true } @@ -6723,6 +6705,119 @@ ] } }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.CodeDom" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Configuration" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Reflection" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Reflection.Emit" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Reflection.Metadata" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Resources" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Runtime.CompilerServices" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Text.RegularExpressions" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Threading.Channels" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Threading.Tasks" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.DirectoryServices" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Buyaa / Jose / Steve - PRs", + "isOrgProject": true + } + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "[Area Pod: Buyaa / Jose / Steve - PRs] Add new PR to Board", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Buyaa / Jose / Steve - PRs", + "columnName": "Needs Champion", + "isOrgProject": true + } + } + ] + } + }, { "taskType": "trigger", "capabilityId": "IssueResponder", @@ -7294,6 +7389,77 @@ ] } }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Collections" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Linq" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Text.Json" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Xml" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Eirik / Krzysztof / Layomi - PRs", + "isOrgProject": true + } + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "[Area Pod: Eirik / Krzysztof / Layomi - PRs] Add new PR to Board", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Eirik / Krzysztof / Layomi - PRs", + "columnName": "Needs Champion", + "isOrgProject": true + } + } + ] + } + }, { "taskType": "trigger", "capabilityId": "IssueResponder", @@ -7379,5 +7545,984 @@ } ] } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-DependencyModel" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Caching" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Configuration" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-DependencyInjection" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Hosting" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Logging" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Options" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Primitives" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel.Composition" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Composition" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Activity" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Globalization" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "reopened" + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isInMilestone", + "parameters": {} + } + ] + } + ] + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "area-DependencyModel" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-Extensions-Caching" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-Extensions-Configuration" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-Extensions-DependencyInjection" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-Extensions-Hosting" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-Extensions-Logging" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-Extensions-Options" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-Extensions-Primitives" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.ComponentModel" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.ComponentModel.Composition" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Composition" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Diagnostics.Activity" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Globalization" + } + } + ] + } + ] + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "operator": "or", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "isOrgProject": true + } + } + ] + }, + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "isOrgProject": true, + "columnName": "Triaged" + } + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "[Area Pod: Eric / Maryam / Tarek - Issue Triage] Add new issue to Board", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "columnName": "Needs Triage", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueCommentResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-DependencyModel" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Caching" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Configuration" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-DependencyInjection" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Hosting" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Logging" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Options" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Primitives" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel.Composition" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Composition" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Activity" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Globalization" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isCloseAndComment", + "parameters": {} + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "activitySenderHasPermissions", + "parameters": { + "permissions": "write" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "isOrgProject": true + } + } + ] + }, + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "columnName": "Triaged", + "isOrgProject": true + } + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issue_comment" + ], + "taskName": "[Area Pod: Eric / Maryam / Tarek - Issue Triage] Needs Further Triage", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "columnName": "Needs Triage", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "columnName": "Needs Triage", + "isOrgProject": true + } + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-DependencyModel" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Caching" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Configuration" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-DependencyInjection" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Hosting" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Logging" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Options" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Primitives" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel.Composition" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Composition" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Activity" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Globalization" + } + } + ] + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "[Area Pod: Eric / Maryam / Tarek - Issue Triage] Remove relabeled issues", + "actions": [ + { + "name": "removeFromProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "isOrgProject": true + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "columnName": "Triaged" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "addedToMilestone", + "parameters": {} + }, + { + "name": "labelAdded", + "parameters": { + "label": "needs more info" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "api-ready-for-review" + } + }, + { + "name": "isAction", + "parameters": { + "action": "closed" + } + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "[Area Pod: Eric / Maryam / Tarek - Issue Triage] Move to Triaged Column", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - Issue Triage", + "columnName": "Triaged", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-DependencyModel" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Caching" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Configuration" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-DependencyInjection" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Hosting" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Logging" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Options" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Primitives" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel.Composition" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Composition" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Activity" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Globalization" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - PRs", + "isOrgProject": true + } + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "[Area Pod: Eric / Maryam / Tarek - PRs] Add new PR to Board", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - PRs", + "columnName": "Needs Champion", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - PRs", + "columnName": "Needs Champion", + "isOrgProject": true + } + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-DependencyModel" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Caching" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Configuration" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-DependencyInjection" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Hosting" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Logging" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Options" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Primitives" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel.Composition" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Composition" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Activity" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Globalization" + } + } + ] + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "[Area Pod: Eric / Maryam / Tarek - PRs] Remove relabeled PRs", + "actions": [ + { + "name": "removeFromProject", + "parameters": { + "projectName": "Area Pod: Eric / Maryam / Tarek - PRs", + "isOrgProject": true + } + } + ] + } } ] \ No newline at end of file From dfb36ae68d9a099c9b90317c97bdf485bab4121e Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 18 Jan 2022 09:31:12 -0500 Subject: [PATCH 008/308] Fix a few IndexOf{Any} uses (#63852) --- .../src/Microsoft/Win32/RegistryKey.cs | 6 ++-- .../AuthenticationHelper.Digest.cs | 25 +++++-------- .../src/System/Net/Mail/Attachment.cs | 3 +- .../src/System/Globalization/CultureData.cs | 2 +- .../src/System/Security/SecurityElement.cs | 36 +++++-------------- .../src/System/Xml/Xsl/Xslt/QilGenerator.cs | 6 ++-- .../src/System/Web/Util/UriUtil.cs | 6 ++-- 7 files changed, 26 insertions(+), 58 deletions(-) diff --git a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs index ea5a83315216d..c82feafee9f0c 100644 --- a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs +++ b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/RegistryKey.cs @@ -728,16 +728,16 @@ private static void ValidateKeyName(string name) throw new ArgumentNullException(nameof(name)); } - int nextSlash = name.IndexOf("\\", StringComparison.OrdinalIgnoreCase); + int nextSlash = name.IndexOf('\\'); int current = 0; - while (nextSlash != -1) + while (nextSlash >= 0) { if ((nextSlash - current) > MaxKeyLength) { throw new ArgumentException(SR.Arg_RegKeyStrLenBug, nameof(name)); } current = nextSlash + 1; - nextSlash = name.IndexOf("\\", current, StringComparison.OrdinalIgnoreCase); + nextSlash = name.IndexOf('\\', current); } if ((name.Length - current) > MaxKeyLength) 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 234ca135aa9bd..c754dff03e59d 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 @@ -422,31 +422,25 @@ private void Parse(string challenge) internal static class StringBuilderExtensions { - // Characters that require escaping in quoted string - private static readonly char[] SpecialCharacters = new[] { '"', '\\' }; - public static void AppendKeyValue(this StringBuilder sb, string key, string value, bool includeQuotes = true, bool includeComma = true) { - sb.Append(key); - sb.Append('='); + sb.Append(key).Append('='); + if (includeQuotes) { + ReadOnlySpan valueSpan = value; sb.Append('"'); - int lastSpecialIndex = 0; - int specialIndex; while (true) { - specialIndex = value.IndexOfAny(SpecialCharacters, lastSpecialIndex); - if (specialIndex >= 0) + int i = valueSpan.IndexOfAny('"', '\\'); // Characters that require escaping in quoted string + if (i >= 0) { - sb.Append(value, lastSpecialIndex, specialIndex - lastSpecialIndex); - sb.Append('\\'); - sb.Append(value[specialIndex]); - lastSpecialIndex = specialIndex + 1; + sb.Append(valueSpan.Slice(0, i)).Append('\\').Append(valueSpan[i]); + valueSpan = valueSpan.Slice(i + 1); } else { - sb.Append(value, lastSpecialIndex, value.Length - lastSpecialIndex); + sb.Append(valueSpan); break; } } @@ -459,8 +453,7 @@ public static void AppendKeyValue(this StringBuilder sb, string key, string valu if (includeComma) { - sb.Append(','); - sb.Append(' '); + sb.Append(',').Append(' '); } } } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/Attachment.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/Attachment.cs index 0ea9aa12af67e..aaca28f6a4c8c 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/Attachment.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/Attachment.cs @@ -12,7 +12,6 @@ public abstract class AttachmentBase : IDisposable { internal bool disposed; private readonly MimePart _part = new MimePart(); - private static readonly char[] s_contentCIDInvalidChars = new char[] { '<', '>' }; internal AttachmentBase() { @@ -248,7 +247,7 @@ public string ContentId } else { - if (value.IndexOfAny(s_contentCIDInvalidChars) != -1) + if (value.AsSpan().IndexOfAny('<', '>') >= 0) // invalid chars { throw new ArgumentException(SR.MailHeaderInvalidCID, nameof(value)); } 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 048ad3b125ca0..bdee108ba076f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs @@ -2094,7 +2094,7 @@ private static string GetSeparator(string format, string timeParts) private static int IndexOfTimePart(string format, int startIndex, string timeParts) { Debug.Assert(startIndex >= 0, "startIndex cannot be negative"); - Debug.Assert(timeParts.IndexOfAny(new char[] { '\'', '\\' }) < 0, "timeParts cannot include quote characters"); + Debug.Assert(timeParts.AsSpan().IndexOfAny('\'', '\\') < 0, "timeParts cannot include quote characters"); bool inQuote = false; for (int i = startIndex; i < format.Length; ++i) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs b/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs index 9703d8016eadb..f48c702651fec 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs @@ -18,9 +18,6 @@ public sealed class SecurityElement private const int AttributesTypical = 4 * 2; // 4 attributes, times 2 strings per attribute private const int ChildrenTypical = 1; - private static readonly char[] s_tagIllegalCharacters = new char[] { ' ', '<', '>' }; - private static readonly char[] s_textIllegalCharacters = new char[] { '<', '>' }; - private static readonly char[] s_valueIllegalCharacters = new char[] { '<', '>', '\"' }; private static readonly char[] s_escapeChars = new char[] { '<', '>', '\"', '\'', '&' }; private static readonly string[] s_escapeStringPairs = new string[] { @@ -298,34 +295,17 @@ public SecurityElement Copy() return element; } - public static bool IsValidTag([NotNullWhen(true)] string? tag) - { - if (tag == null) - return false; - - return tag.IndexOfAny(s_tagIllegalCharacters) < 0; - } - - public static bool IsValidText([NotNullWhen(true)] string? text) - { - if (text == null) - return false; + public static bool IsValidTag([NotNullWhen(true)] string? tag) => + tag != null && tag.AsSpan().IndexOfAny(' ', '<', '>') < 0; - return text.IndexOfAny(s_textIllegalCharacters) < 0; - } - - public static bool IsValidAttributeName([NotNullWhen(true)] string? name) - { - return IsValidTag(name); - } + public static bool IsValidText([NotNullWhen(true)] string? text) => + text != null && text.AsSpan().IndexOfAny('<', '>') < 0; - public static bool IsValidAttributeValue([NotNullWhen(true)] string? value) - { - if (value == null) - return false; + public static bool IsValidAttributeName([NotNullWhen(true)] string? name) => + IsValidTag(name); - return value.IndexOfAny(s_valueIllegalCharacters) < 0; - } + public static bool IsValidAttributeValue([NotNullWhen(true)] string? value) => + value != null && value.AsSpan().IndexOfAny('<', '>', '\"') < 0; private static string GetEscapeSequence(char c) { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/QilGenerator.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/QilGenerator.cs index 6df66d73c106e..4b4a5c508615f 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/QilGenerator.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/QilGenerator.cs @@ -1055,8 +1055,6 @@ private QilNode CompileAvt(string source) return result; } - private static readonly char[] s_curlyBraces = { '{', '}' }; - [return: NotNullIfNotNull("avt")] private QilNode? CompileStringAvt(string? avt) { @@ -1064,7 +1062,7 @@ private QilNode CompileAvt(string source) { return null; } - if (avt.IndexOfAny(s_curlyBraces) == -1) + if (avt.AsSpan().IndexOfAny('{', '}') < 0) { return _f.String(avt); } @@ -1074,7 +1072,7 @@ private QilNode CompileAvt(string source) private QilNode CompileTextAvt(string avt) { Debug.Assert(avt != null); - if (avt.IndexOfAny(s_curlyBraces) == -1) + if (avt.AsSpan().IndexOfAny('{', '}') < 0) { return _f.TextCtor(_f.String(avt)); } diff --git a/src/libraries/System.Web.HttpUtility/src/System/Web/Util/UriUtil.cs b/src/libraries/System.Web.HttpUtility/src/System/Web/Util/UriUtil.cs index 64e88be64f5d0..9ef10f6f68944 100644 --- a/src/libraries/System.Web.HttpUtility/src/System/Web/Util/UriUtil.cs +++ b/src/libraries/System.Web.HttpUtility/src/System/Web/Util/UriUtil.cs @@ -7,15 +7,13 @@ namespace System.Web.Util { internal static class UriUtil { - private static readonly char[] s_queryFragmentSeparators = { '?', '#' }; - // Just extracts the query string and fragment from the input path by splitting on the separator characters. // Doesn't perform any validation as to whether the input represents a valid URL. // Concatenating the pieces back together will form the original input string. private static void ExtractQueryAndFragment(string input, out string path, out string? queryAndFragment) { - int queryFragmentSeparatorPos = input.IndexOfAny(s_queryFragmentSeparators); - if (queryFragmentSeparatorPos != -1) + int queryFragmentSeparatorPos = input.AsSpan().IndexOfAny('?', '#'); // query fragment separators + if (queryFragmentSeparatorPos >= 0) { path = input.Substring(0, queryFragmentSeparatorPos); queryAndFragment = input.Substring(queryFragmentSeparatorPos); From e6ad043996419f04b1c0ae9fea113318f61e234f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 18 Jan 2022 23:32:28 +0900 Subject: [PATCH 009/308] Split CheckNotDisposed to allow inlining (#63863) * Split CheckNotDisposed to allow inlining `CheckNotDisposed` is not getting inlined because RyuJIT thinks it's not profitable (ldstr/newobj/throw is expensive). If we extract the rare path into a separate method, it changes the profitability math and allows inlining to happen. * Review feedback --- .../System.Text.Json/src/System/Text/Json/ThrowHelper.cs | 6 ++++++ .../src/System/Text/Json/Writer/Utf8JsonWriter.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs index e5cd6d024ee1a..a164e71c13993 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs @@ -646,6 +646,12 @@ public static void ThrowInvalidOperationException_ExpectedChar(JsonTokenType tok { throw GetInvalidOperationException("char", tokenType); } + + [DoesNotReturn] + public static void ThrowObjectDisposedException_Utf8JsonWriter() + { + throw new ObjectDisposedException(nameof(Utf8JsonWriter)); + } } internal enum ExceptionResource diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs index 084b7c65c6350..9b22c33ac7d8f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs @@ -238,7 +238,7 @@ private void CheckNotDisposed() // The conditions are ordered with stream first as that would be the most common mode if (_output == null) { - throw new ObjectDisposedException(nameof(Utf8JsonWriter)); + ThrowHelper.ThrowObjectDisposedException_Utf8JsonWriter(); } } } From e30fe9b4d3afabc4acdfcaa539ecf213c16aea1a Mon Sep 17 00:00:00 2001 From: Theodore Tsirpanis Date: Tue, 18 Jan 2022 16:58:11 +0200 Subject: [PATCH 010/308] Encapsulate the logic of caching the last synchronously completed task. (#61781) * Encapsulate the logic of caching the last synchronously completed task. * Apply suggestions from code review Co-authored-by: Adam Sitnik --- .../System.Private.CoreLib.Shared.projitems | 3 +- .../src/System/IO/BufferedStream.cs | 33 ++++---------- .../src/System/IO/MemoryStream.cs | 9 ++-- .../Strategies/BufferedFileStreamStrategy.cs | 17 +------- .../src/System/IO/UnmanagedMemoryStream.cs | 7 ++- .../Tasks/CachedCompletedInt32Task.cs | 43 +++++++++++++++++++ 6 files changed, 62 insertions(+), 50 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/CachedCompletedInt32Task.cs 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 f69cec24a2626..0a587f370875a 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 @@ -1059,6 +1059,7 @@ + @@ -2358,4 +2359,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BufferedStream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BufferedStream.cs index c7c1434d69cba..5c25031957d45 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BufferedStream.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BufferedStream.cs @@ -48,16 +48,14 @@ public sealed class BufferedStream : Stream private const int MaxShadowBufferSize = 81920; // Make sure not to get to the Large Object Heap. private const int DefaultBufferSize = 4096; - private Stream? _stream; // Underlying stream. Close sets _stream to null. - private byte[]? _buffer; // Shared read/write buffer. Alloc on first use. - private readonly int _bufferSize; // Length of internal buffer (not counting the shadow buffer). - private int _readPos; // Read pointer within shared buffer. - private int _readLen; // Number of bytes read in buffer from _stream. - private int _writePos; // Write pointer within shared buffer. - private Task? _lastSyncCompletedReadTask; // The last successful Task returned from ReadAsync - // (perf optimization for successive reads of the same size) - // Removing a private default constructor is a breaking change for the DataDebugSerializer. - // Because this ctor was here previously we need to keep it around. + private Stream? _stream; // Underlying stream. Close sets _stream to null. + private byte[]? _buffer; // Shared read/write buffer. Alloc on first use. + private readonly int _bufferSize; // Length of internal buffer (not counting the shadow buffer). + private int _readPos; // Read pointer within shared buffer. + private int _readLen; // Number of bytes read in buffer from _stream. + private int _writePos; // Write pointer within shared buffer. + private CachedCompletedInt32Task _lastSyncCompletedReadTask; // The last successful Task returned from ReadAsync + // (perf optimization for successive reads of the same size) public BufferedStream(Stream stream) : this(stream, DefaultBufferSize) @@ -571,19 +569,6 @@ public override int Read(Span destination) } } - private Task LastSyncCompletedReadTask(int val) - { - Task? t = _lastSyncCompletedReadTask; - Debug.Assert(t == null || t.IsCompletedSuccessfully); - - if (t != null && t.Result == val) - return t; - - t = Task.FromResult(val); - _lastSyncCompletedReadTask = t; - return t; - } - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { ValidateBufferArguments(buffer, offset, count); @@ -622,7 +607,7 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel { return (error == null) - ? LastSyncCompletedReadTask(bytesFromBuffer) + ? _lastSyncCompletedReadTask.GetTask(bytesFromBuffer) : Task.FromException(error); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs index 9677f82426a84..0c1739873f403 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs @@ -32,7 +32,7 @@ public class MemoryStream : Stream private readonly bool _exposable; // Whether the array can be returned to the user. private bool _isOpen; // Is this stream open or closed? - private Task? _lastReadTask; // The last successful task returned from ReadAsync + private CachedCompletedInt32Task _lastReadTask; // The last successful task returned from ReadAsync private const int MemStreamMaxLength = int.MaxValue; @@ -127,7 +127,7 @@ protected override void Dispose(bool disposing) _writable = false; _expandable = false; // Don't set buffer to null - allow TryGetBuffer, GetBuffer & ToArray to work. - _lastReadTask = null; + _lastReadTask = default; } } finally @@ -389,10 +389,7 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel try { int n = Read(buffer, offset, count); - Task? t = _lastReadTask; - Debug.Assert(t == null || t.Status == TaskStatus.RanToCompletion, - "Expected that a stored last task completed successfully"); - return (t != null && t.Result == n) ? t : (_lastReadTask = Task.FromResult(n)); + return _lastReadTask.GetTask(n); } catch (OperationCanceledException oce) { diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs index 9de42145c00de..c1f62e92e4b25 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/BufferedFileStreamStrategy.cs @@ -21,7 +21,7 @@ internal sealed class BufferedFileStreamStrategy : FileStreamStrategy private int _readPos; private int _readLen; // The last successful Task returned from ReadAsync (perf optimization for successive reads of the same size) - private Task? _lastSyncCompletedReadTask; + private CachedCompletedInt32Task _lastSyncCompletedReadTask; internal BufferedFileStreamStrategy(FileStreamStrategy strategy, int bufferSize) { @@ -310,21 +310,8 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel ValueTask readResult = ReadAsync(new Memory(buffer, offset, count), cancellationToken); return readResult.IsCompletedSuccessfully - ? LastSyncCompletedReadTask(readResult.Result) + ? _lastSyncCompletedReadTask.GetTask(readResult.Result) : readResult.AsTask(); - - Task LastSyncCompletedReadTask(int val) - { - Task? t = _lastSyncCompletedReadTask; - Debug.Assert(t == null || t.IsCompletedSuccessfully); - - if (t != null && t.Result == val) - return t; - - t = Task.FromResult(val); - _lastSyncCompletedReadTask = t; - return t; - } } public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryStream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryStream.cs index c116c17e69ad8..47b190dde4b49 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryStream.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryStream.cs @@ -46,7 +46,7 @@ public class UnmanagedMemoryStream : Stream private long _offset; private FileAccess _access; private bool _isOpen; - private Task? _lastReadTask; // The last successful task returned from ReadAsync + private CachedCompletedInt32Task _lastReadTask; // The last successful task returned from ReadAsync /// /// Creates a closed stream. @@ -437,12 +437,11 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel try { int n = Read(buffer, offset, count); - Task? t = _lastReadTask; - return (t != null && t.Result == n) ? t : (_lastReadTask = Task.FromResult(n)); + return _lastReadTask.GetTask(n); } catch (Exception ex) { - Debug.Assert(!(ex is OperationCanceledException)); + Debug.Assert(ex is not OperationCanceledException); return Task.FromException(ex); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/CachedCompletedInt32Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/CachedCompletedInt32Task.cs new file mode 100644 index 0000000000000..911c2676b4531 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/CachedCompletedInt32Task.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. + +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; + +namespace System.Threading.Tasks +{ + /// + /// Encapsulates the logic of caching the last synchronously completed task of integer. + /// Used in classes like to reduce allocations. + /// + internal struct CachedCompletedInt32Task + { + private Task? _task; + + /// + /// Gets a completed whose result is . + /// + /// + /// This method will try to return an already cached task if available. + /// + /// The task's result. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Task GetTask(int result) + { + Task? task; +#pragma warning disable CA1849 // Call async methods when in an async method + if ((task = _task) is not null && task.Result == result) +#pragma warning restore CA1849 // Call async methods when in an async method + { + Debug.Assert(task.IsCompletedSuccessfully, + "Expected that a stored last task completed successfully"); + return task; + } + else + { + return _task = Task.FromResult(result); + } + } + } +} From 207590a7b82afa086e889f3fc695b104713f7c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 19 Jan 2022 00:10:36 +0900 Subject: [PATCH 011/308] Fold coreclr/ToolBox into coreclr/tools (#63917) This separation only existed because of Razzle build sequencing of desktop CLR. It doesn't make sense for CoreCLR. The only thing the extra directory is doing now is that it breaks tab completion when navigating the CoreCLR source tree because ToolBox comes before tools alphabetically and most things live in tools. --- docs/design/features/standalone-gc-loading.md | 2 +- docs/project/glossary.md | 2 +- src/coreclr/CMakeLists.txt | 1 - src/coreclr/ToolBox/CMakeLists.txt | 2 -- src/coreclr/gc/gcinterface.dac.h | 2 +- src/coreclr/inc/dacvars.h | 2 +- src/coreclr/pal/src/exception/seh-unwind.cpp | 2 +- src/coreclr/runtime-prereqs.proj | 2 +- src/coreclr/scripts/superpmi.md | 2 +- src/coreclr/tools/CMakeLists.txt | 3 +++ src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.bat | 2 +- src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.sh | 2 +- src/coreclr/{ToolBox => tools}/SOS/CMakeLists.txt | 0 src/coreclr/{ToolBox => tools}/SOS/DIALib/DIALib.il | 0 src/coreclr/{ToolBox => tools}/SOS/DIALib/DIALib.ilproj | 0 .../{ToolBox => tools}/SOS/DacTableGen/DacTableGen.csproj | 0 .../{ToolBox => tools}/SOS/DacTableGen/MapSymbolProvider.cs | 0 src/coreclr/{ToolBox => tools}/SOS/DacTableGen/cvconst.cs | 0 src/coreclr/{ToolBox => tools}/SOS/DacTableGen/diautil.cs | 0 src/coreclr/{ToolBox => tools}/SOS/DacTableGen/main.cs | 0 src/coreclr/{ToolBox => tools}/SOS/Directory.Build.props | 0 src/coreclr/{ToolBox => tools}/SOS/SOS_README.md | 0 src/coreclr/{ToolBox => tools}/superpmi/.clang-format | 0 src/coreclr/{ToolBox => tools}/superpmi/CMakeLists.txt | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/CMakeLists.txt | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/commandline.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/commandline.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/mcs.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/mcs.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/removedup.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/removedup.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbasmdump.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbasmdump.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbconcat.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbconcat.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdump.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdump.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdumpmap.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdumpmap.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdumptoc.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdumptoc.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbfracture.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbfracture.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbildump.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbildump.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbinteg.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbinteg.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbjitflags.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbjitflags.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbmerge.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbmerge.h | 0 .../{ToolBox => tools}/superpmi/mcs/verbprintjiteeversion.cpp | 0 .../{ToolBox => tools}/superpmi/mcs/verbprintjiteeversion.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbremovedup.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbremovedup.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbstat.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbstat.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbstrip.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbstrip.h | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbtoc.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/mcs/verbtoc.h | 0 src/coreclr/{ToolBox => tools}/superpmi/readme.md | 2 +- .../{ToolBox => tools}/superpmi/superpmi-shared/agnostic.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/asmdumper.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/asmdumper.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/callutils.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/callutils.h | 0 .../superpmi/superpmi-shared/compileresult.cpp | 0 .../superpmi/superpmi-shared/compileresult.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/crlwmlist.h | 0 .../superpmi/superpmi-shared/errorhandling.cpp | 0 .../superpmi/superpmi-shared/errorhandling.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/hash.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/hash.h | 0 .../superpmi/superpmi-shared/icorjitcompilerimpl.h | 0 .../superpmi/superpmi-shared/icorjithostimpl.h | 0 .../superpmi/superpmi-shared/icorjitinfoimpl.h | 0 .../superpmi/superpmi-shared/lightweightmap.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/logging.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/logging.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/lwmlist.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/mclist.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/mclist.h | 0 .../superpmi/superpmi-shared/methodcontext.cpp | 0 .../superpmi/superpmi-shared/methodcontext.h | 0 .../superpmi/superpmi-shared/methodcontextiterator.cpp | 0 .../superpmi/superpmi-shared/methodcontextiterator.h | 0 .../superpmi/superpmi-shared/methodcontextreader.cpp | 0 .../superpmi/superpmi-shared/methodcontextreader.h | 0 .../superpmi/superpmi-shared/runtimedetails.h | 0 .../superpmi/superpmi-shared/simpletimer.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/simpletimer.h | 0 .../superpmi/superpmi-shared/spmidumphelper.cpp | 0 .../superpmi/superpmi-shared/spmidumphelper.h | 0 .../superpmi/superpmi-shared/spmirecordhelper.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/spmiutil.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/spmiutil.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/standardpch.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/tocfile.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/tocfile.h | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/typeutils.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi-shared/typeutils.h | 0 .../superpmi/superpmi-shim-collector/CMakeLists.txt | 0 .../superpmi/superpmi-shim-collector/icorjitcompiler.cpp | 0 .../superpmi/superpmi-shim-collector/icorjitcompiler.h | 0 .../superpmi/superpmi-shim-collector/icorjitinfo.cpp | 0 .../superpmi/superpmi-shim-collector/icorjitinfo.h | 0 .../superpmi/superpmi-shim-collector/jithost.cpp | 0 .../superpmi/superpmi-shim-collector/jithost.h | 0 .../superpmi-shim-collector/superpmi-shim-collector.cpp | 0 .../superpmi-shim-collector/superpmi-shim-collector.def | 0 .../superpmi/superpmi-shim-collector/superpmi-shim-collector.h | 0 .../superpmi/superpmi-shim-counter/CMakeLists.txt | 0 .../superpmi/superpmi-shim-counter/icorjitcompiler.cpp | 0 .../superpmi/superpmi-shim-counter/icorjitcompiler.h | 0 .../superpmi/superpmi-shim-counter/icorjitinfo.cpp | 0 .../superpmi/superpmi-shim-counter/icorjitinfo.h | 0 .../superpmi/superpmi-shim-counter/jithost.cpp | 0 .../superpmi/superpmi-shim-counter/jithost.h | 0 .../superpmi/superpmi-shim-counter/methodcallsummarizer.cpp | 0 .../superpmi/superpmi-shim-counter/methodcallsummarizer.h | 0 .../superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp | 0 .../superpmi/superpmi-shim-counter/superpmi-shim-counter.def | 0 .../superpmi/superpmi-shim-counter/superpmi-shim-counter.h | 0 .../superpmi/superpmi-shim-simple/CMakeLists.txt | 0 .../superpmi/superpmi-shim-simple/icorjitcompiler.cpp | 0 .../superpmi/superpmi-shim-simple/icorjitcompiler.h | 0 .../superpmi/superpmi-shim-simple/icorjitinfo.cpp | 0 .../superpmi/superpmi-shim-simple/icorjitinfo.h | 0 .../superpmi/superpmi-shim-simple/jithost.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi-shim-simple/jithost.h | 0 .../superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp | 0 .../superpmi/superpmi-shim-simple/superpmi-shim-simple.def | 0 .../superpmi/superpmi-shim-simple/superpmi-shim-simple.h | 0 .../{ToolBox => tools}/superpmi/superpmi/CMakeLists.txt | 0 .../{ToolBox => tools}/superpmi/superpmi/commandline.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/commandline.h | 0 .../{ToolBox => tools}/superpmi/superpmi/cycletimer.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/cycletimer.h | 0 .../{ToolBox => tools}/superpmi/superpmi/icorjitinfo.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/icorjitinfo.h | 0 .../{ToolBox => tools}/superpmi/superpmi/jitdebugger.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/jitdebugger.h | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/jithost.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/jithost.h | 0 .../{ToolBox => tools}/superpmi/superpmi/jitinstance.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/jitinstance.h | 0 .../superpmi/superpmi/methodstatsemitter.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi/methodstatsemitter.h | 0 .../{ToolBox => tools}/superpmi/superpmi/metricssummary.cpp | 0 .../{ToolBox => tools}/superpmi/superpmi/metricssummary.h | 0 .../{ToolBox => tools}/superpmi/superpmi/neardiffer.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/neardiffer.h | 0 .../{ToolBox => tools}/superpmi/superpmi/parallelsuperpmi.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/superpmi.cpp | 0 src/coreclr/{ToolBox => tools}/superpmi/superpmi/superpmi.h | 0 156 files changed, 13 insertions(+), 13 deletions(-) delete mode 100644 src/coreclr/ToolBox/CMakeLists.txt rename src/coreclr/{ToolBox => tools}/SOS/CMakeLists.txt (100%) rename src/coreclr/{ToolBox => tools}/SOS/DIALib/DIALib.il (100%) rename src/coreclr/{ToolBox => tools}/SOS/DIALib/DIALib.ilproj (100%) rename src/coreclr/{ToolBox => tools}/SOS/DacTableGen/DacTableGen.csproj (100%) rename src/coreclr/{ToolBox => tools}/SOS/DacTableGen/MapSymbolProvider.cs (100%) rename src/coreclr/{ToolBox => tools}/SOS/DacTableGen/cvconst.cs (100%) rename src/coreclr/{ToolBox => tools}/SOS/DacTableGen/diautil.cs (100%) rename src/coreclr/{ToolBox => tools}/SOS/DacTableGen/main.cs (100%) rename src/coreclr/{ToolBox => tools}/SOS/Directory.Build.props (100%) rename src/coreclr/{ToolBox => tools}/SOS/SOS_README.md (100%) rename src/coreclr/{ToolBox => tools}/superpmi/.clang-format (100%) rename src/coreclr/{ToolBox => tools}/superpmi/CMakeLists.txt (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/CMakeLists.txt (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/commandline.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/commandline.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/mcs.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/mcs.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/removedup.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/removedup.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbasmdump.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbasmdump.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbconcat.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbconcat.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdump.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdump.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdumpmap.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdumpmap.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdumptoc.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbdumptoc.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbfracture.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbfracture.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbildump.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbildump.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbinteg.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbinteg.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbjitflags.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbjitflags.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbmerge.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbmerge.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbprintjiteeversion.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbprintjiteeversion.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbremovedup.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbremovedup.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbstat.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbstat.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbstrip.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbstrip.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbtoc.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/mcs/verbtoc.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/readme.md (99%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/agnostic.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/asmdumper.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/asmdumper.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/callutils.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/callutils.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/compileresult.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/compileresult.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/crlwmlist.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/errorhandling.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/errorhandling.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/hash.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/hash.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/icorjitcompilerimpl.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/icorjithostimpl.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/icorjitinfoimpl.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/lightweightmap.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/logging.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/logging.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/lwmlist.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/mclist.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/mclist.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/methodcontext.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/methodcontext.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/methodcontextiterator.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/methodcontextiterator.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/methodcontextreader.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/methodcontextreader.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/runtimedetails.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/simpletimer.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/simpletimer.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/spmidumphelper.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/spmidumphelper.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/spmirecordhelper.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/spmiutil.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/spmiutil.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/standardpch.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/tocfile.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/tocfile.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/typeutils.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shared/typeutils.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/CMakeLists.txt (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/icorjitcompiler.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/icorjitcompiler.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/icorjitinfo.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/icorjitinfo.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/jithost.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/jithost.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/superpmi-shim-collector.def (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-collector/superpmi-shim-collector.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/CMakeLists.txt (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/icorjitcompiler.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/icorjitcompiler.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/icorjitinfo.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/icorjitinfo.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/jithost.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/jithost.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/methodcallsummarizer.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/superpmi-shim-counter.def (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-counter/superpmi-shim-counter.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/CMakeLists.txt (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/icorjitcompiler.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/icorjitcompiler.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/icorjitinfo.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/icorjitinfo.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/jithost.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/jithost.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/superpmi-shim-simple.def (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi-shim-simple/superpmi-shim-simple.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/CMakeLists.txt (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/commandline.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/commandline.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/cycletimer.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/cycletimer.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/icorjitinfo.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/icorjitinfo.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/jitdebugger.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/jitdebugger.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/jithost.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/jithost.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/jitinstance.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/jitinstance.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/methodstatsemitter.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/methodstatsemitter.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/metricssummary.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/metricssummary.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/neardiffer.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/neardiffer.h (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/parallelsuperpmi.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/superpmi.cpp (100%) rename src/coreclr/{ToolBox => tools}/superpmi/superpmi/superpmi.h (100%) diff --git a/docs/design/features/standalone-gc-loading.md b/docs/design/features/standalone-gc-loading.md index 3373bf5559f55..ed7440002e8da 100644 --- a/docs/design/features/standalone-gc-loading.md +++ b/docs/design/features/standalone-gc-loading.md @@ -47,7 +47,7 @@ Worth noting is that the JIT (both RyuJIT and the legacy JIT(s) before it) can b and have realized these same benefits. The existence of an interface and an implementation loadable from shared libraries has enabled RyuJIT in particular to be used as the code generator for both the CoreRT compiler and crossgen, while still being flexible enough to be tested using tools that implement -very non-standard execution engines such as [SuperPMI](https://github.com/dotnet/runtime/blob/main/src/coreclr/ToolBox/superpmi/readme.txt). +very non-standard execution engines such as [SuperPMI](https://github.com/dotnet/runtime/blob/main/src/coreclr/tools/superpmi/readme.md). The below loading protocol is inspired directly by the JIT loader and many aspects of the GC loader are identical to what the JIT does when loading dynamic shared libraries. diff --git a/docs/project/glossary.md b/docs/project/glossary.md index cb7e0b21538b8..9104049e947ec 100644 --- a/docs/project/glossary.md +++ b/docs/project/glossary.md @@ -43,7 +43,7 @@ terminology. | SDK | Software Development Kit. The [.NET SDK](https://docs.microsoft.com/dotnet/core/sdk) contains the .NET CLI, .NET libraries and runtime, and the dotnet driver. | | SEH | [Structured Exception Handling](https://docs.microsoft.com/windows/win32/debug/structured-exception-handling). Unified mechanism for handling hardware and software exceptions on Windows. | | SOS | [Son of Strike](https://docs.microsoft.com/archive/blogs/jasonz/sos-debugging-of-the-clr-part-1). The debugging extension for DbgEng based debuggers. Uses the DAC as an abstraction layer for its operation. | -| SuperPMI | JIT component test framework (super fast JIT testing - it mocks/replays EE in EE-JIT interface) - see [SuperPMI details](https://github.com/dotnet/runtime/blob/main/src/coreclr/ToolBox/superpmi/readme.txt). | +| SuperPMI | JIT component test framework (super fast JIT testing - it mocks/replays EE in EE-JIT interface) - see [SuperPMI details](https://github.com/dotnet/runtime/blob/main/src/coreclr/tools/superpmi/readme.md). | | SVR | The CLR used to be built as two variants, with one called "mscorsvr.dll", to mean the "server" version. In particular, it contained the server GC implementation, which was intended for multi-threaded apps capable of taking advantage of multiple processors. In the .NET Framework 2 release, the two variants were merged into "mscorwks.dll". The WKS version was the default, however the SVR version remained available. | | TFM | [Target Framework Moniker](https://docs.microsoft.com/dotnet/standard/frameworks) such as `net6.0` or `netstandard2.0`. | | TPA | Trusted Platform Assemblies used to be a special set of assemblies that comprised the platform assemblies, when it was originally designed. As of today, it is simply the set of assemblies known to constitute the application. | diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 2440f6ca999ca..38e5488938b6d 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -247,7 +247,6 @@ add_subdirectory(debug) add_subdirectory(binder) add_subdirectory(classlibnative) add_subdirectory(dlls) -add_subdirectory(ToolBox) add_subdirectory(tools) add_subdirectory(unwinder) add_subdirectory(interop) diff --git a/src/coreclr/ToolBox/CMakeLists.txt b/src/coreclr/ToolBox/CMakeLists.txt deleted file mode 100644 index 4e7f4368681d1..0000000000000 --- a/src/coreclr/ToolBox/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(SOS) -add_subdirectory(superpmi) diff --git a/src/coreclr/gc/gcinterface.dac.h b/src/coreclr/gc/gcinterface.dac.h index cfffcf1221a81..c7d72c7145baf 100644 --- a/src/coreclr/gc/gcinterface.dac.h +++ b/src/coreclr/gc/gcinterface.dac.h @@ -111,7 +111,7 @@ enum oom_reason /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ /* If you modify failure_get_memory and */ /* oom_reason be sure to make the corresponding */ -/* changes in toolbox\sos\strike\strike.cpp. */ +/* changes in tools\sos\strike\strike.cpp. */ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ enum failure_get_memory { diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index fdae380a90cb4..686c77217395e 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -5,7 +5,7 @@ // 1. in daccess.h to build the table of DAC globals // 2. in enummem.cpp to dump out the related memory of static and globals // in a mini dump or heap dump -// 3. in DacUpdateDll and toolbox\DacTablenGen\main.cs +// 3. in DacUpdateDll and tools\DacTablenGen\main.cs // // To use this functionality for other tools or purposes, define the // DEFINE_DACVAR macro & include dacvars.h like so (see enummem.cpp and/or diff --git a/src/coreclr/pal/src/exception/seh-unwind.cpp b/src/coreclr/pal/src/exception/seh-unwind.cpp index 4b149f941b5dc..750f19109fbaa 100644 --- a/src/coreclr/pal/src/exception/seh-unwind.cpp +++ b/src/coreclr/pal/src/exception/seh-unwind.cpp @@ -699,7 +699,7 @@ PAL_FreeExceptionRecords(IN EXCEPTION_RECORD *exceptionRecord, IN CONTEXT *conte Note: The name of this function and the name of the ExceptionRecord parameter is used in the sos lldb plugin code to read the exception - record. See coreclr\ToolBox\SOS\lldbplugin\services.cpp. + record. See coreclr\tools\SOS\lldbplugin\services.cpp. This function must not be inlined or optimized so the below PAL_VirtualUnwind calls end up with RaiseException caller's context and so the above debugger diff --git a/src/coreclr/runtime-prereqs.proj b/src/coreclr/runtime-prereqs.proj index 1127c3df8bdf3..36ed2ce497be1 100644 --- a/src/coreclr/runtime-prereqs.proj +++ b/src/coreclr/runtime-prereqs.proj @@ -7,7 +7,7 @@ - + diff --git a/src/coreclr/scripts/superpmi.md b/src/coreclr/scripts/superpmi.md index d9404dc32d740..36e24711637ae 100644 --- a/src/coreclr/scripts/superpmi.md +++ b/src/coreclr/scripts/superpmi.md @@ -1,7 +1,7 @@ # Documentation for the superpmi.py tool SuperPMI is a tool for developing and testing the JIT compiler. -General information on SuperPMI can be found [here](../ToolBox/superpmi/readme.md). +General information on SuperPMI can be found [here](../tools/superpmi/readme.md). ## Overview diff --git a/src/coreclr/tools/CMakeLists.txt b/src/coreclr/tools/CMakeLists.txt index a50b1e6a1afbd..db59797e26f78 100644 --- a/src/coreclr/tools/CMakeLists.txt +++ b/src/coreclr/tools/CMakeLists.txt @@ -1,3 +1,6 @@ +add_subdirectory(SOS) +add_subdirectory(superpmi) + if (CLR_CMAKE_TARGET_WIN32 AND NOT CLR_CMAKE_CROSS_ARCH) add_subdirectory(GenClrDebugResource) add_subdirectory(InjectResource) diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.bat b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.bat index c775755558de9..69e3367c4e094 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.bat +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.bat @@ -1,4 +1,4 @@ pushd %~dp0 -call ..\..\..\..\..\..\dotnet.cmd run -- ThunkInput.txt ..\CorInfoBase.cs ..\..\..\aot\jitinterface\jitinterface.h ..\..\..\..\jit\ICorJitInfo_API_names.h ..\..\..\..\jit\ICorJitInfo_API_wrapper.hpp ..\..\..\..\inc\icorjitinfoimpl_generated.h ..\..\..\..\ToolBox\superpmi\superpmi-shim-counter\icorjitinfo.cpp ..\..\..\..\ToolBox\superpmi\superpmi-shim-simple\icorjitinfo.cpp +call ..\..\..\..\..\..\dotnet.cmd run -- ThunkInput.txt ..\CorInfoBase.cs ..\..\..\aot\jitinterface\jitinterface.h ..\..\..\..\jit\ICorJitInfo_API_names.h ..\..\..\..\jit\ICorJitInfo_API_wrapper.hpp ..\..\..\..\inc\icorjitinfoimpl_generated.h ..\..\..\..\tools\superpmi\superpmi-shim-counter\icorjitinfo.cpp ..\..\..\..\tools\superpmi\superpmi-shim-simple\icorjitinfo.cpp call ..\..\..\..\..\..\dotnet.cmd run -- InstructionSetGenerator InstructionSetDesc.txt ..\..\Internal\Runtime\ReadyToRunInstructionSet.cs ..\..\Internal\Runtime\ReadyToRunInstructionSetHelper.cs ..\CorInfoInstructionSet.cs ..\..\..\..\inc\corinfoinstructionset.h ..\..\..\..\inc\readytoruninstructionset.h popd diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.sh b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.sh index 7dc71bd378d85..ca9cdcb52ef11 100755 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.sh +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/gen.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash cd "$(dirname ${BASH_SOURCE[0]})" -../../../../../../dotnet.sh run -- ThunkInput.txt ../CorInfoBase.cs ../../../aot/jitinterface/jitinterface.h ../../../../jit/ICorJitInfo_API_names.h ../../../../jit/ICorJitInfo_API_wrapper.hpp ../../../../inc/icorjitinfoimpl_generated.h ../../../../ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp ../../../../ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp +../../../../../../dotnet.sh run -- ThunkInput.txt ../CorInfoBase.cs ../../../aot/jitinterface/jitinterface.h ../../../../jit/ICorJitInfo_API_names.h ../../../../jit/ICorJitInfo_API_wrapper.hpp ../../../../inc/icorjitinfoimpl_generated.h ../../../../tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp ../../../../tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp ../../../../../../dotnet.sh run -- InstructionSetGenerator InstructionSetDesc.txt ../../Internal/Runtime/ReadyToRunInstructionSet.cs ../../Internal/Runtime/ReadyToRunInstructionSetHelper.cs ../CorInfoInstructionSet.cs ../../../../inc/corinfoinstructionset.h ../../../../inc/readytoruninstructionset.h diff --git a/src/coreclr/ToolBox/SOS/CMakeLists.txt b/src/coreclr/tools/SOS/CMakeLists.txt similarity index 100% rename from src/coreclr/ToolBox/SOS/CMakeLists.txt rename to src/coreclr/tools/SOS/CMakeLists.txt diff --git a/src/coreclr/ToolBox/SOS/DIALib/DIALib.il b/src/coreclr/tools/SOS/DIALib/DIALib.il similarity index 100% rename from src/coreclr/ToolBox/SOS/DIALib/DIALib.il rename to src/coreclr/tools/SOS/DIALib/DIALib.il diff --git a/src/coreclr/ToolBox/SOS/DIALib/DIALib.ilproj b/src/coreclr/tools/SOS/DIALib/DIALib.ilproj similarity index 100% rename from src/coreclr/ToolBox/SOS/DIALib/DIALib.ilproj rename to src/coreclr/tools/SOS/DIALib/DIALib.ilproj diff --git a/src/coreclr/ToolBox/SOS/DacTableGen/DacTableGen.csproj b/src/coreclr/tools/SOS/DacTableGen/DacTableGen.csproj similarity index 100% rename from src/coreclr/ToolBox/SOS/DacTableGen/DacTableGen.csproj rename to src/coreclr/tools/SOS/DacTableGen/DacTableGen.csproj diff --git a/src/coreclr/ToolBox/SOS/DacTableGen/MapSymbolProvider.cs b/src/coreclr/tools/SOS/DacTableGen/MapSymbolProvider.cs similarity index 100% rename from src/coreclr/ToolBox/SOS/DacTableGen/MapSymbolProvider.cs rename to src/coreclr/tools/SOS/DacTableGen/MapSymbolProvider.cs diff --git a/src/coreclr/ToolBox/SOS/DacTableGen/cvconst.cs b/src/coreclr/tools/SOS/DacTableGen/cvconst.cs similarity index 100% rename from src/coreclr/ToolBox/SOS/DacTableGen/cvconst.cs rename to src/coreclr/tools/SOS/DacTableGen/cvconst.cs diff --git a/src/coreclr/ToolBox/SOS/DacTableGen/diautil.cs b/src/coreclr/tools/SOS/DacTableGen/diautil.cs similarity index 100% rename from src/coreclr/ToolBox/SOS/DacTableGen/diautil.cs rename to src/coreclr/tools/SOS/DacTableGen/diautil.cs diff --git a/src/coreclr/ToolBox/SOS/DacTableGen/main.cs b/src/coreclr/tools/SOS/DacTableGen/main.cs similarity index 100% rename from src/coreclr/ToolBox/SOS/DacTableGen/main.cs rename to src/coreclr/tools/SOS/DacTableGen/main.cs diff --git a/src/coreclr/ToolBox/SOS/Directory.Build.props b/src/coreclr/tools/SOS/Directory.Build.props similarity index 100% rename from src/coreclr/ToolBox/SOS/Directory.Build.props rename to src/coreclr/tools/SOS/Directory.Build.props diff --git a/src/coreclr/ToolBox/SOS/SOS_README.md b/src/coreclr/tools/SOS/SOS_README.md similarity index 100% rename from src/coreclr/ToolBox/SOS/SOS_README.md rename to src/coreclr/tools/SOS/SOS_README.md diff --git a/src/coreclr/ToolBox/superpmi/.clang-format b/src/coreclr/tools/superpmi/.clang-format similarity index 100% rename from src/coreclr/ToolBox/superpmi/.clang-format rename to src/coreclr/tools/superpmi/.clang-format diff --git a/src/coreclr/ToolBox/superpmi/CMakeLists.txt b/src/coreclr/tools/superpmi/CMakeLists.txt similarity index 100% rename from src/coreclr/ToolBox/superpmi/CMakeLists.txt rename to src/coreclr/tools/superpmi/CMakeLists.txt diff --git a/src/coreclr/ToolBox/superpmi/mcs/CMakeLists.txt b/src/coreclr/tools/superpmi/mcs/CMakeLists.txt similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/CMakeLists.txt rename to src/coreclr/tools/superpmi/mcs/CMakeLists.txt diff --git a/src/coreclr/ToolBox/superpmi/mcs/commandline.cpp b/src/coreclr/tools/superpmi/mcs/commandline.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/commandline.cpp rename to src/coreclr/tools/superpmi/mcs/commandline.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/commandline.h b/src/coreclr/tools/superpmi/mcs/commandline.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/commandline.h rename to src/coreclr/tools/superpmi/mcs/commandline.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/mcs.cpp b/src/coreclr/tools/superpmi/mcs/mcs.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/mcs.cpp rename to src/coreclr/tools/superpmi/mcs/mcs.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/mcs.h b/src/coreclr/tools/superpmi/mcs/mcs.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/mcs.h rename to src/coreclr/tools/superpmi/mcs/mcs.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/removedup.cpp b/src/coreclr/tools/superpmi/mcs/removedup.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/removedup.cpp rename to src/coreclr/tools/superpmi/mcs/removedup.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/removedup.h b/src/coreclr/tools/superpmi/mcs/removedup.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/removedup.h rename to src/coreclr/tools/superpmi/mcs/removedup.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbasmdump.cpp b/src/coreclr/tools/superpmi/mcs/verbasmdump.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbasmdump.cpp rename to src/coreclr/tools/superpmi/mcs/verbasmdump.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbasmdump.h b/src/coreclr/tools/superpmi/mcs/verbasmdump.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbasmdump.h rename to src/coreclr/tools/superpmi/mcs/verbasmdump.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbconcat.cpp b/src/coreclr/tools/superpmi/mcs/verbconcat.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbconcat.cpp rename to src/coreclr/tools/superpmi/mcs/verbconcat.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbconcat.h b/src/coreclr/tools/superpmi/mcs/verbconcat.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbconcat.h rename to src/coreclr/tools/superpmi/mcs/verbconcat.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbdump.cpp b/src/coreclr/tools/superpmi/mcs/verbdump.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbdump.cpp rename to src/coreclr/tools/superpmi/mcs/verbdump.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbdump.h b/src/coreclr/tools/superpmi/mcs/verbdump.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbdump.h rename to src/coreclr/tools/superpmi/mcs/verbdump.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbdumpmap.cpp b/src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbdumpmap.cpp rename to src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbdumpmap.h b/src/coreclr/tools/superpmi/mcs/verbdumpmap.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbdumpmap.h rename to src/coreclr/tools/superpmi/mcs/verbdumpmap.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbdumptoc.cpp b/src/coreclr/tools/superpmi/mcs/verbdumptoc.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbdumptoc.cpp rename to src/coreclr/tools/superpmi/mcs/verbdumptoc.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbdumptoc.h b/src/coreclr/tools/superpmi/mcs/verbdumptoc.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbdumptoc.h rename to src/coreclr/tools/superpmi/mcs/verbdumptoc.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbfracture.cpp b/src/coreclr/tools/superpmi/mcs/verbfracture.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbfracture.cpp rename to src/coreclr/tools/superpmi/mcs/verbfracture.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbfracture.h b/src/coreclr/tools/superpmi/mcs/verbfracture.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbfracture.h rename to src/coreclr/tools/superpmi/mcs/verbfracture.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbildump.cpp b/src/coreclr/tools/superpmi/mcs/verbildump.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbildump.cpp rename to src/coreclr/tools/superpmi/mcs/verbildump.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbildump.h b/src/coreclr/tools/superpmi/mcs/verbildump.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbildump.h rename to src/coreclr/tools/superpmi/mcs/verbildump.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbinteg.cpp b/src/coreclr/tools/superpmi/mcs/verbinteg.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbinteg.cpp rename to src/coreclr/tools/superpmi/mcs/verbinteg.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbinteg.h b/src/coreclr/tools/superpmi/mcs/verbinteg.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbinteg.h rename to src/coreclr/tools/superpmi/mcs/verbinteg.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbjitflags.cpp b/src/coreclr/tools/superpmi/mcs/verbjitflags.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbjitflags.cpp rename to src/coreclr/tools/superpmi/mcs/verbjitflags.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbjitflags.h b/src/coreclr/tools/superpmi/mcs/verbjitflags.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbjitflags.h rename to src/coreclr/tools/superpmi/mcs/verbjitflags.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbmerge.cpp b/src/coreclr/tools/superpmi/mcs/verbmerge.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbmerge.cpp rename to src/coreclr/tools/superpmi/mcs/verbmerge.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbmerge.h b/src/coreclr/tools/superpmi/mcs/verbmerge.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbmerge.h rename to src/coreclr/tools/superpmi/mcs/verbmerge.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbprintjiteeversion.cpp b/src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbprintjiteeversion.cpp rename to src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbprintjiteeversion.h b/src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbprintjiteeversion.h rename to src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbremovedup.cpp b/src/coreclr/tools/superpmi/mcs/verbremovedup.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbremovedup.cpp rename to src/coreclr/tools/superpmi/mcs/verbremovedup.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbremovedup.h b/src/coreclr/tools/superpmi/mcs/verbremovedup.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbremovedup.h rename to src/coreclr/tools/superpmi/mcs/verbremovedup.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbstat.cpp b/src/coreclr/tools/superpmi/mcs/verbstat.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbstat.cpp rename to src/coreclr/tools/superpmi/mcs/verbstat.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbstat.h b/src/coreclr/tools/superpmi/mcs/verbstat.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbstat.h rename to src/coreclr/tools/superpmi/mcs/verbstat.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbstrip.cpp b/src/coreclr/tools/superpmi/mcs/verbstrip.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbstrip.cpp rename to src/coreclr/tools/superpmi/mcs/verbstrip.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbstrip.h b/src/coreclr/tools/superpmi/mcs/verbstrip.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbstrip.h rename to src/coreclr/tools/superpmi/mcs/verbstrip.h diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbtoc.cpp b/src/coreclr/tools/superpmi/mcs/verbtoc.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbtoc.cpp rename to src/coreclr/tools/superpmi/mcs/verbtoc.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbtoc.h b/src/coreclr/tools/superpmi/mcs/verbtoc.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/mcs/verbtoc.h rename to src/coreclr/tools/superpmi/mcs/verbtoc.h diff --git a/src/coreclr/ToolBox/superpmi/readme.md b/src/coreclr/tools/superpmi/readme.md similarity index 99% rename from src/coreclr/ToolBox/superpmi/readme.md rename to src/coreclr/tools/superpmi/readme.md index c3de3dfe94288..b84e8d01697bd 100644 --- a/src/coreclr/ToolBox/superpmi/readme.md +++ b/src/coreclr/tools/superpmi/readme.md @@ -1,6 +1,6 @@ # Overview -This directory (`src/coreclr/ToolBox/superpmi` in the GitHub +This directory (`src/coreclr/tools/superpmi` in the GitHub https://github.com/dotnet/runtime repository) contains the SuperPMI tool used for testing the .NET just-in-time (JIT) compiler. diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/agnostic.h rename to src/coreclr/tools/superpmi/superpmi-shared/agnostic.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/asmdumper.cpp b/src/coreclr/tools/superpmi/superpmi-shared/asmdumper.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/asmdumper.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/asmdumper.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/asmdumper.h b/src/coreclr/tools/superpmi/superpmi-shared/asmdumper.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/asmdumper.h rename to src/coreclr/tools/superpmi/superpmi-shared/asmdumper.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/callutils.cpp b/src/coreclr/tools/superpmi/superpmi-shared/callutils.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/callutils.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/callutils.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/callutils.h b/src/coreclr/tools/superpmi/superpmi-shared/callutils.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/callutils.h rename to src/coreclr/tools/superpmi/superpmi-shared/callutils.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/compileresult.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/compileresult.h b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/compileresult.h rename to src/coreclr/tools/superpmi/superpmi-shared/compileresult.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/crlwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/crlwmlist.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/crlwmlist.h rename to src/coreclr/tools/superpmi/superpmi-shared/crlwmlist.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/errorhandling.cpp b/src/coreclr/tools/superpmi/superpmi-shared/errorhandling.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/errorhandling.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/errorhandling.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/errorhandling.h b/src/coreclr/tools/superpmi/superpmi-shared/errorhandling.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/errorhandling.h rename to src/coreclr/tools/superpmi/superpmi-shared/errorhandling.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/hash.cpp b/src/coreclr/tools/superpmi/superpmi-shared/hash.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/hash.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/hash.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/hash.h b/src/coreclr/tools/superpmi/superpmi-shared/hash.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/hash.h rename to src/coreclr/tools/superpmi/superpmi-shared/hash.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/icorjitcompilerimpl.h b/src/coreclr/tools/superpmi/superpmi-shared/icorjitcompilerimpl.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/icorjitcompilerimpl.h rename to src/coreclr/tools/superpmi/superpmi-shared/icorjitcompilerimpl.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/icorjithostimpl.h b/src/coreclr/tools/superpmi/superpmi-shared/icorjithostimpl.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/icorjithostimpl.h rename to src/coreclr/tools/superpmi/superpmi-shared/icorjithostimpl.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/coreclr/tools/superpmi/superpmi-shared/icorjitinfoimpl.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h rename to src/coreclr/tools/superpmi/superpmi-shared/icorjitinfoimpl.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/lightweightmap.h b/src/coreclr/tools/superpmi/superpmi-shared/lightweightmap.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/lightweightmap.h rename to src/coreclr/tools/superpmi/superpmi-shared/lightweightmap.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/logging.cpp b/src/coreclr/tools/superpmi/superpmi-shared/logging.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/logging.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/logging.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/logging.h b/src/coreclr/tools/superpmi/superpmi-shared/logging.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/logging.h rename to src/coreclr/tools/superpmi/superpmi-shared/logging.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h rename to src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/mclist.cpp b/src/coreclr/tools/superpmi/superpmi-shared/mclist.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/mclist.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/mclist.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/mclist.h b/src/coreclr/tools/superpmi/superpmi-shared/mclist.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/mclist.h rename to src/coreclr/tools/superpmi/superpmi-shared/mclist.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h rename to src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontextiterator.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontextiterator.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontextiterator.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontextiterator.h rename to src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontextreader.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontextreader.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontextreader.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontextreader.h rename to src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/runtimedetails.h b/src/coreclr/tools/superpmi/superpmi-shared/runtimedetails.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/runtimedetails.h rename to src/coreclr/tools/superpmi/superpmi-shared/runtimedetails.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/simpletimer.cpp b/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/simpletimer.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/simpletimer.h b/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/simpletimer.h rename to src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/spmidumphelper.cpp b/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/spmidumphelper.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/spmidumphelper.h b/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/spmidumphelper.h rename to src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h b/src/coreclr/tools/superpmi/superpmi-shared/spmirecordhelper.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h rename to src/coreclr/tools/superpmi/superpmi-shared/spmirecordhelper.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/spmiutil.cpp b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/spmiutil.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/spmiutil.h b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/spmiutil.h rename to src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/standardpch.h b/src/coreclr/tools/superpmi/superpmi-shared/standardpch.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/standardpch.h rename to src/coreclr/tools/superpmi/superpmi-shared/standardpch.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/tocfile.cpp b/src/coreclr/tools/superpmi/superpmi-shared/tocfile.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/tocfile.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/tocfile.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/tocfile.h b/src/coreclr/tools/superpmi/superpmi-shared/tocfile.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/tocfile.h rename to src/coreclr/tools/superpmi/superpmi-shared/tocfile.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/typeutils.cpp b/src/coreclr/tools/superpmi/superpmi-shared/typeutils.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/typeutils.cpp rename to src/coreclr/tools/superpmi/superpmi-shared/typeutils.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/typeutils.h b/src/coreclr/tools/superpmi/superpmi-shared/typeutils.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shared/typeutils.h rename to src/coreclr/tools/superpmi/superpmi-shared/typeutils.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/CMakeLists.txt rename to src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.h b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.h rename to src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.h b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.h rename to src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/jithost.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/jithost.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/jithost.h b/src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/jithost.h rename to src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.def b/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.def similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.def rename to src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.def diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.h b/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-collector/superpmi-shim-collector.h rename to src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/CMakeLists.txt rename to src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitcompiler.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitcompiler.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitcompiler.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitcompiler.h rename to src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.h rename to src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/jithost.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/jithost.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/jithost.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/jithost.h rename to src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/methodcallsummarizer.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/methodcallsummarizer.h rename to src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/superpmi-shim-counter.def b/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.def similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/superpmi-shim-counter.def rename to src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.def diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/superpmi-shim-counter.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-counter/superpmi-shim-counter.h rename to src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/CMakeLists.txt rename to src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.h b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.h rename to src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h rename to src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/jithost.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/jithost.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/jithost.h b/src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/jithost.h rename to src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp rename to src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.def b/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.def similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.def rename to src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.def diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.h b/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.h rename to src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi/CMakeLists.txt similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/CMakeLists.txt rename to src/coreclr/tools/superpmi/superpmi/CMakeLists.txt diff --git a/src/coreclr/ToolBox/superpmi/superpmi/commandline.cpp b/src/coreclr/tools/superpmi/superpmi/commandline.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/commandline.cpp rename to src/coreclr/tools/superpmi/superpmi/commandline.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/commandline.h b/src/coreclr/tools/superpmi/superpmi/commandline.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/commandline.h rename to src/coreclr/tools/superpmi/superpmi/commandline.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/cycletimer.cpp b/src/coreclr/tools/superpmi/superpmi/cycletimer.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/cycletimer.cpp rename to src/coreclr/tools/superpmi/superpmi/cycletimer.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/cycletimer.h b/src/coreclr/tools/superpmi/superpmi/cycletimer.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/cycletimer.h rename to src/coreclr/tools/superpmi/superpmi/cycletimer.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp rename to src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.h b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.h rename to src/coreclr/tools/superpmi/superpmi/icorjitinfo.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/jitdebugger.cpp b/src/coreclr/tools/superpmi/superpmi/jitdebugger.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/jitdebugger.cpp rename to src/coreclr/tools/superpmi/superpmi/jitdebugger.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/jitdebugger.h b/src/coreclr/tools/superpmi/superpmi/jitdebugger.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/jitdebugger.h rename to src/coreclr/tools/superpmi/superpmi/jitdebugger.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/jithost.cpp b/src/coreclr/tools/superpmi/superpmi/jithost.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/jithost.cpp rename to src/coreclr/tools/superpmi/superpmi/jithost.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/jithost.h b/src/coreclr/tools/superpmi/superpmi/jithost.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/jithost.h rename to src/coreclr/tools/superpmi/superpmi/jithost.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.cpp b/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/jitinstance.cpp rename to src/coreclr/tools/superpmi/superpmi/jitinstance.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.h b/src/coreclr/tools/superpmi/superpmi/jitinstance.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/jitinstance.h rename to src/coreclr/tools/superpmi/superpmi/jitinstance.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/methodstatsemitter.cpp b/src/coreclr/tools/superpmi/superpmi/methodstatsemitter.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/methodstatsemitter.cpp rename to src/coreclr/tools/superpmi/superpmi/methodstatsemitter.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/methodstatsemitter.h b/src/coreclr/tools/superpmi/superpmi/methodstatsemitter.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/methodstatsemitter.h rename to src/coreclr/tools/superpmi/superpmi/methodstatsemitter.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/metricssummary.cpp b/src/coreclr/tools/superpmi/superpmi/metricssummary.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/metricssummary.cpp rename to src/coreclr/tools/superpmi/superpmi/metricssummary.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/metricssummary.h b/src/coreclr/tools/superpmi/superpmi/metricssummary.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/metricssummary.h rename to src/coreclr/tools/superpmi/superpmi/metricssummary.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/neardiffer.cpp b/src/coreclr/tools/superpmi/superpmi/neardiffer.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/neardiffer.cpp rename to src/coreclr/tools/superpmi/superpmi/neardiffer.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/neardiffer.h b/src/coreclr/tools/superpmi/superpmi/neardiffer.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/neardiffer.h rename to src/coreclr/tools/superpmi/superpmi/neardiffer.h diff --git a/src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp b/src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp rename to src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp rename to src/coreclr/tools/superpmi/superpmi/superpmi.cpp diff --git a/src/coreclr/ToolBox/superpmi/superpmi/superpmi.h b/src/coreclr/tools/superpmi/superpmi/superpmi.h similarity index 100% rename from src/coreclr/ToolBox/superpmi/superpmi/superpmi.h rename to src/coreclr/tools/superpmi/superpmi/superpmi.h From 2f366a85444570429f8739b13bde18226a10bc86 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Tue, 18 Jan 2022 17:12:47 +0200 Subject: [PATCH 012/308] Delete a few unused PAL APIs (#63916) * Delete _fullpath PAL API * Delete PAL_wcscspn * Delete PAL_wcstok --- .../dlls/mscordac/mscordac_unixexports.src | 1 - src/coreclr/pal/inc/pal.h | 4 - src/coreclr/pal/inc/palprivate.h | 2 - src/coreclr/pal/src/CMakeLists.txt | 2 - src/coreclr/pal/src/cruntime/path.cpp | 113 ---------------- src/coreclr/pal/src/cruntime/wchar.cpp | 49 ------- src/coreclr/pal/src/cruntime/wchartls.cpp | 125 ------------------ src/coreclr/pal/src/include/pal/palinternal.h | 2 - src/coreclr/pal/tests/palsuite/CMakeLists.txt | 1 - .../palsuite/c_runtime/wcstok/test1/test1.cpp | 113 ---------------- .../pal/tests/palsuite/compilableTests.txt | 1 - .../LoadLibraryA/test6/loadlibrarya.cpp | 46 +++---- .../LoadLibraryA/test8/loadlibrarya.cpp | 57 ++++---- .../pal/tests/palsuite/paltestlist.txt | 1 - 14 files changed, 49 insertions(+), 468 deletions(-) delete mode 100644 src/coreclr/pal/src/cruntime/path.cpp delete mode 100644 src/coreclr/pal/src/cruntime/wchartls.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/c_runtime/wcstok/test1/test1.cpp diff --git a/src/coreclr/dlls/mscordac/mscordac_unixexports.src b/src/coreclr/dlls/mscordac/mscordac_unixexports.src index 2a529b2f4a779..a518b2dca2c8c 100644 --- a/src/coreclr/dlls/mscordac/mscordac_unixexports.src +++ b/src/coreclr/dlls/mscordac/mscordac_unixexports.src @@ -65,7 +65,6 @@ nativeStringResourceTable_mscorrc #PAL_wcsrchr #PAL_wcscmp #PAL_wcschr -#PAL_wcscspn #PAL_wcscat #PAL_wcsstr #PAL__open diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index 237b75275cec9..bc531d4367174 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -3934,8 +3934,6 @@ PAL_GetCurrentThreadAffinitySet(SIZE_T size, UINT_PTR* data); #define wcspbrk PAL_wcspbrk #define wcscmp PAL_wcscmp #define wcsncpy PAL_wcsncpy -#define wcstok PAL_wcstok -#define wcscspn PAL_wcscspn #define realloc PAL_realloc #define fopen PAL_fopen #define strtok PAL_strtok @@ -4125,8 +4123,6 @@ PALIMPORT DLLEXPORT const WCHAR * __cdecl PAL_wcschr(const WCHAR *, WCHAR); PALIMPORT DLLEXPORT const WCHAR * __cdecl PAL_wcsrchr(const WCHAR *, WCHAR); PALIMPORT WCHAR _WConst_return * __cdecl PAL_wcspbrk(const WCHAR *, const WCHAR *); PALIMPORT DLLEXPORT WCHAR _WConst_return * __cdecl PAL_wcsstr(const WCHAR *, const WCHAR *); -PALIMPORT WCHAR * __cdecl PAL_wcstok(WCHAR *, const WCHAR *); -PALIMPORT DLLEXPORT size_t __cdecl PAL_wcscspn(const WCHAR *, const WCHAR *); PALIMPORT int __cdecl PAL_swprintf(WCHAR *, const WCHAR *, ...); PALIMPORT int __cdecl PAL_vswprintf(WCHAR *, const WCHAR *, va_list); PALIMPORT int __cdecl PAL_swscanf(const WCHAR *, const WCHAR *, ...); diff --git a/src/coreclr/pal/inc/palprivate.h b/src/coreclr/pal/inc/palprivate.h index 097229eb64ef4..f90352b32355e 100644 --- a/src/coreclr/pal/inc/palprivate.h +++ b/src/coreclr/pal/inc/palprivate.h @@ -203,8 +203,6 @@ CompareFileTime( IN CONST FILETIME *lpFileTime1, IN CONST FILETIME *lpFileTime2); -PALIMPORT char * __cdecl _fullpath(char *, const char *, size_t); - /* These are from the file in windows. They are needed for _open_osfhandle.*/ #define _O_RDONLY 0x0000 diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt index 4f071b21046b0..afab5e6518455 100644 --- a/src/coreclr/pal/src/CMakeLists.txt +++ b/src/coreclr/pal/src/CMakeLists.txt @@ -123,7 +123,6 @@ set(SOURCES cruntime/malloc.cpp cruntime/math.cpp cruntime/misc.cpp - cruntime/path.cpp cruntime/printf.cpp cruntime/printfcpp.cpp cruntime/silent_printf.cpp @@ -131,7 +130,6 @@ set(SOURCES cruntime/stringtls.cpp cruntime/thread.cpp cruntime/wchar.cpp - cruntime/wchartls.cpp debug/debug.cpp exception/seh.cpp exception/signal.cpp diff --git a/src/coreclr/pal/src/cruntime/path.cpp b/src/coreclr/pal/src/cruntime/path.cpp deleted file mode 100644 index c25636771bc61..0000000000000 --- a/src/coreclr/pal/src/cruntime/path.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*++ - - - -Module Name: - - path.c - -Abstract: - - Implementation of path functions part of Windows runtime library. - -Revision History: - - - ---*/ - -#include "pal/palinternal.h" -#include "pal/dbgmsg.h" -#include "pal/file.h" -#include "pal/printfcpp.hpp" - -#include -#include -#include -#include -#include - -SET_DEFAULT_DEBUG_CHANNEL(CRT); - -/*++ -Function: - _fullpath - -See MSDN doc. - ---*/ -char * -__cdecl -_fullpath( - char *absPath, - const char *relPath, - size_t maxLength) -{ - char realpath_buf[PATH_MAX+1]; - char path_copy[PATH_MAX+1]; - char *retval = NULL; - DWORD cPathCopy = sizeof(path_copy)/sizeof(path_copy[0]); - size_t min_length; - BOOL fBufAllocated = FALSE; - - PERF_ENTRY(_fullpath); - ENTRY("_fullpath (absPath=%p, relPath=%p (%s), maxLength = %lu)\n", - absPath, relPath ? relPath:"NULL", relPath ? relPath:"NULL", maxLength); - - if (strncpy_s(path_copy, sizeof(path_copy), relPath ? relPath : ".", cPathCopy) != SAFECRT_SUCCESS) - { - TRACE("_fullpath: strncpy_s failed!\n"); - goto fullpathExit; - } - - FILEDosToUnixPathA(path_copy); - - if(NULL == realpath(path_copy, realpath_buf)) - { - ERROR("realpath() failed; problem path is '%s'. errno is %d (%s)\n", - realpath_buf, errno, strerror(errno)); - goto fullpathExit; - } - - TRACE("real path is %s\n", realpath_buf); - min_length = strlen(realpath_buf)+1; // +1 for the NULL terminator - - if(NULL == absPath) - { - absPath = static_cast( - PAL_malloc(_MAX_PATH * sizeof(char))); - if (!absPath) - { - ERROR("PAL_malloc failed with error %d\n", errno); - goto fullpathExit; - } - maxLength = _MAX_PATH; - fBufAllocated = TRUE; - } - - if(min_length > maxLength) - { - ERROR("maxLength is %lu, we need at least %lu\n", - maxLength, min_length); - if (fBufAllocated) - { - PAL_free(absPath); - fBufAllocated = FALSE; - } - goto fullpathExit; - } - - strcpy_s(absPath, maxLength, realpath_buf); - retval = absPath; - -fullpathExit: - LOGEXIT("_fullpath returns char * %p\n", retval); - PERF_EXIT(_fullpath); - return retval; -} - - - diff --git a/src/coreclr/pal/src/cruntime/wchar.cpp b/src/coreclr/pal/src/cruntime/wchar.cpp index 5c21d7bd01533..3d887aecdb883 100644 --- a/src/coreclr/pal/src/cruntime/wchar.cpp +++ b/src/coreclr/pal/src/cruntime/wchar.cpp @@ -3,8 +3,6 @@ /*++ - - Module Name: wchar.c @@ -13,11 +11,8 @@ Module Name: Implementation of wide char string functions. - - --*/ - #include "pal/palinternal.h" #include "pal/cruntime.h" #include "pal/dbgmsg.h" @@ -25,7 +20,6 @@ Module Name: #include "pal/thread.hpp" #include "pal/threadsusp.hpp" - #if HAVE_CONFIG_H #include "config.h" #endif @@ -950,46 +944,3 @@ PAL_wcstod( const wchar_16 * nptr, wchar_16 **endptr ) PERF_EXIT(wcstod); return RetVal; } - -/*++ -Function: - PAL_wcscspn - -Finds the number of consecutive characters from the start of the string -that are not in the set. - -Return value: - -The number of characters from the start of the string that are not in -the set. - -Parameters: -string String -strCharSet Set of delimiter characters - ---*/ -size_t -__cdecl -PAL_wcscspn(const wchar_16 *string, const wchar_16 *strCharSet) -{ - const wchar_16 *temp; - size_t count = 0; - - PERF_ENTRY(wcscspn); - - while(*string != 0) - { - for(temp = strCharSet; *temp != 0; temp++) - { - if (*string == *temp) - { - PERF_EXIT(wcscspn); - return count; - } - } - count++; - string++; - } - PERF_EXIT(wcscspn); - return count; -} diff --git a/src/coreclr/pal/src/cruntime/wchartls.cpp b/src/coreclr/pal/src/cruntime/wchartls.cpp deleted file mode 100644 index 35b73359889a5..0000000000000 --- a/src/coreclr/pal/src/cruntime/wchartls.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*++ - - - -Module Name: - - wchartls.c - -Abstract: - - Implementation of wide char string functions that depend on per-thread data - - - ---*/ - -#include "pal/palinternal.h" -#include "pal/thread.hpp" -#include "pal/dbgmsg.h" - -using namespace CorUnix; - - -SET_DEFAULT_DEBUG_CHANNEL(CRT); - -/*++ -Function: - PAL_wcstok - -Finds the next token in a wide character string. - -Return value: - -A pointer to the next token found in strToken. Returns NULL when no more -tokens are found. Each call modifies strToken by substituting a NULL -character for each delimiter that is encountered. - -Parameters: -strToken String containing token(s) -strDelimit Set of delimiter characters - ---*/ -WCHAR * -__cdecl -PAL_wcstok(WCHAR *strToken, const WCHAR *strDelimit) -{ - CPalThread *pThread = NULL; - WCHAR *retval = NULL; - WCHAR *delim_ptr; - WCHAR *next_context; /* string to save in TLS for future calls */ - - PERF_ENTRY(wcstok); - ENTRY("PAL_wcstok (strToken=%p (%S), strDelimit=%p (%S))\n", - strToken?strToken:W16_NULLSTRING, - strToken?strToken:W16_NULLSTRING, - strDelimit?strDelimit:W16_NULLSTRING, - strDelimit?strDelimit:W16_NULLSTRING); - - /* Get the per-thread buffer from the thread structure. */ - pThread = InternalGetCurrentThread(); - - if(NULL == strDelimit) - { - ERROR("delimiter string is NULL\n"); - goto done; - } - - /* get token string from TLS if none is provided */ - if(NULL == strToken) - { - TRACE("wcstok() called with NULL string, using previous string\n"); - strToken = pThread->crtInfo.wcstokContext; - if(NULL == strToken) - { - ERROR("wcstok called with NULL string without a previous call\n"); - goto done; - } - } - - /* first, skip all leading delimiters */ - while ((*strToken != '\0') && (PAL_wcschr(strDelimit,*strToken))) - { - strToken++; - } - - /* if there were only delimiters, there's no string */ - if('\0' == strToken[0]) - { - TRACE("end of string already reached, returning NULL\n"); - goto done; - } - - /* we're now at the beginning of the token; look for the first delimiter */ - delim_ptr = PAL_wcspbrk(strToken,strDelimit); - if(NULL == delim_ptr) - { - TRACE("no delimiters found, this is the last token\n"); - /* place the next context at the end of the string, so that subsequent - calls will return NULL */ - next_context = strToken+PAL_wcslen(strToken); - retval = strToken; - } - else - { - /* null-terminate current token */ - *delim_ptr=0; - - /* place the next context right after the delimiter */ - next_context = delim_ptr+1; - retval = strToken; - - TRACE("found delimiter; next token will be %p\n",next_context); - } - - pThread->crtInfo.wcstokContext = next_context; - -done: - LOGEXIT("PAL_wcstok() returns %p (%S)\n", retval?retval:W16_NULLSTRING, retval?retval:W16_NULLSTRING); - PERF_EXIT(wcstok); - return(retval); -} - diff --git a/src/coreclr/pal/src/include/pal/palinternal.h b/src/coreclr/pal/src/include/pal/palinternal.h index 3a12d78910364..ff3703c6ae4f7 100644 --- a/src/coreclr/pal/src/include/pal/palinternal.h +++ b/src/coreclr/pal/src/include/pal/palinternal.h @@ -526,8 +526,6 @@ function_name() to call the system's implementation #undef wcsstr #undef wcscmp #undef wcsncpy -#undef wcstok -#undef wcscspn #undef iswupper #undef iswspace #undef towlower diff --git a/src/coreclr/pal/tests/palsuite/CMakeLists.txt b/src/coreclr/pal/tests/palsuite/CMakeLists.txt index f58757a1f6d5f..d7b3faca6b366 100644 --- a/src/coreclr/pal/tests/palsuite/CMakeLists.txt +++ b/src/coreclr/pal/tests/palsuite/CMakeLists.txt @@ -415,7 +415,6 @@ add_executable_clr(paltests c_runtime/wcsstr/test1/test1.cpp c_runtime/wcstod/test1/test1.cpp c_runtime/wcstod/test2/test2.cpp - c_runtime/wcstok/test1/test1.cpp c_runtime/wcstoul/test1/test1.cpp c_runtime/wcstoul/test2/test2.cpp c_runtime/wcstoul/test3/test3.cpp diff --git a/src/coreclr/pal/tests/palsuite/c_runtime/wcstok/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/c_runtime/wcstok/test1/test1.cpp deleted file mode 100644 index 564466c2a4e7f..0000000000000 --- a/src/coreclr/pal/tests/palsuite/c_runtime/wcstok/test1/test1.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================================ -** -** Source: test1.c -** -** Purpose: -** Search for a number of tokens within strings. Check that the return values -** are what is expected, and also that the strings match up with our expected -** results. -** -** -**==========================================================================*/ - -#include - -PALTEST(c_runtime_wcstok_test1_paltest_wcstok_test1, "c_runtime/wcstok/test1/paltest_wcstok_test1") -{ - /* foo bar baz */ - WCHAR str[] = {'f','o','o',' ','b','a','r',' ','b','a','z','\0'}; - - /* foo \0ar baz */ - WCHAR result1[] = {'f','o','o',' ','\0','a','r',' ','b','a','z','\0'}; - - /* foo \0a\0 baz */ - WCHAR result2[] = {'f','o','o',' ','\0','a','\0',' ','b','a','z','\0'}; - - WCHAR* tempString; - int len = 0; - WCHAR *ptr; - - if (PAL_Initialize(argc, argv)) - { - return FAIL; - } - - len = (wcslen(str)*sizeof(WCHAR)) + 2; - - /* Tokenize 'str'. It will hit the 'b' delimiter first. Check to see - that the ptr is pointing to the start of the string and do a compare - to ensure the tokenized string is what we expected. - */ - - tempString = convert("bz"); - ptr = wcstok(str, tempString); - free(tempString); - - if (ptr != str) - { - Fail("ERROR: Expected wcstok() to return %p, got %p!\n", str, ptr); - } - - if (memcmp(str, result1, len) != 0) - { - Fail("ERROR: wcstok altered the string in an unexpected fashion."); - } - - /* If NULL is passed as the first parameter, wcstok will continue - tokenizing the same string. Test that this works properly. - */ - tempString = convert("r "); - ptr = wcstok(NULL, tempString); - free(tempString); - - if (ptr != str + 5) - { - Fail("ERROR: Expected wcstok() to return %p, got %p!\n", str+5, ptr); - } - - if (memcmp(str, result2, len) != 0) - { - Fail("ERROR: wcstok altered the string in an unexpected fashion."); - } - - /* Continue onward, and search for 'X' now, which won't be found. The - pointer should point just after the last NULL in the string. And - the string itself shouldn't have changed. - */ - tempString = convert("X"); - ptr = wcstok(NULL, tempString); - free(tempString); - - if (ptr != str + 7) - { - Fail("ERROR: Expected wcstok() to return %p, got %p!\n", str + 7, ptr); - } - - if (memcmp(str, result2, len) != 0) - { - Fail("ERROR: wcstok altered the string in an unexpeced fashion.\n"); - } - - /* Call wcstok again. Now the ptr should point to the end of the - string at NULL. And the string itself shouldn't have changed. - */ - tempString = convert("X"); - ptr = wcstok(NULL, tempString); - free(tempString); - - if (ptr != NULL) - { - Fail("ERROR: Expected wcstok() to return %p, got %p!\n", NULL, ptr); - } - - if (memcmp(str, result2, len) != 0) - { - Fail("ERROR: wcstok altered the string in an unexpeced fashion.\n"); - } - - PAL_Terminate(); - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/compilableTests.txt b/src/coreclr/pal/tests/palsuite/compilableTests.txt index c674de294db45..df727bc277be4 100644 --- a/src/coreclr/pal/tests/palsuite/compilableTests.txt +++ b/src/coreclr/pal/tests/palsuite/compilableTests.txt @@ -348,7 +348,6 @@ c_runtime/wcsrchr/test1/paltest_wcsrchr_test1 c_runtime/wcsstr/test1/paltest_wcsstr_test1 c_runtime/wcstod/test1/paltest_wcstod_test1 c_runtime/wcstod/test2/paltest_wcstod_test2 -c_runtime/wcstok/test1/paltest_wcstok_test1 c_runtime/wcstoul/test1/paltest_wcstoul_test1 c_runtime/wcstoul/test2/paltest_wcstoul_test2 c_runtime/wcstoul/test3/paltest_wcstoul_test3 diff --git a/src/coreclr/pal/tests/palsuite/loader/LoadLibraryA/test6/loadlibrarya.cpp b/src/coreclr/pal/tests/palsuite/loader/LoadLibraryA/test6/loadlibrarya.cpp index d71e0ea85c333..93363488bc61d 100644 --- a/src/coreclr/pal/tests/palsuite/loader/LoadLibraryA/test6/loadlibrarya.cpp +++ b/src/coreclr/pal/tests/palsuite/loader/LoadLibraryA/test6/loadlibrarya.cpp @@ -7,9 +7,9 @@ ** ** Purpose: Positive test the LoadLibrary API. Test will verify ** that it is unable to load the library twice. Once by -** using the full path name and secondly by using the +** using the full path name and secondly by using the ** short name. -** +** ** **============================================================*/ @@ -25,14 +25,13 @@ typedef int (*dllfunct)(); #define GETATTACHCOUNTNAME "_GetAttachCount@0" #endif - /* Helper function to test the loaded library. */ BOOL PALAPI TestDll(HMODULE hLib) { int RetVal; char FunctName[] = GETATTACHCOUNTNAME; - FARPROC DllFunc; + FARPROC DllFunc; /* Access a function from the loaded library. */ @@ -45,7 +44,7 @@ BOOL PALAPI TestDll(HMODULE hLib) return (FALSE); } - /* Verify that the DLL_PROCESS_ATTACH is only + /* Verify that the DLL_PROCESS_ATTACH is only * accessed once.*/ RetVal = DllFunc(); if (RetVal != 1) @@ -70,7 +69,7 @@ PALTEST(loader_LoadLibraryA_test6_paltest_loadlibrarya_test6, "loader/LoadLibrar char fname[_MAX_FNAME]; char ext[_MAX_EXT]; - + /* Initialize the PAL. */ if ((PAL_Initialize(argc, argv)) != 0) @@ -84,15 +83,15 @@ PALTEST(loader_LoadLibraryA_test6_paltest_loadlibrarya_test6, "loader/LoadLibrar /* Get the full path to the library (DLL). */ - - if (NULL != _fullpath(fullPath,argv[0],_MAX_DIR)) { - + + if (NULL != realpath(argv[0],fullpath)) { + _splitpath(fullPath,drive,dir,fname,ext); _makepath(fullPath,drive,dir,LibraryName,""); - - + + } else { - Fail("ERROR: conversion from relative path \" %s \" to absolute path failed. _fullpath returned NULL\n",argv[0]); + Fail("ERROR: conversion from relative path \" %s \" to absolute path failed. realpath returned NULL\n",argv[0]); } /* Call Load library with the short name of @@ -101,11 +100,11 @@ PALTEST(loader_LoadLibraryA_test6_paltest_loadlibrarya_test6, "loader/LoadLibrar hShortLib = LoadLibrary(LibraryName); if(hShortLib == NULL) { - Fail("ERROR:%u:Unable to load library %s\n", - GetLastError(), + Fail("ERROR:%u:Unable to load library %s\n", + GetLastError(), LibraryName); } - + /* Test the loaded library. */ if (!TestDll(hShortLib)) @@ -120,8 +119,8 @@ PALTEST(loader_LoadLibraryA_test6_paltest_loadlibrarya_test6, "loader/LoadLibrar hFullLib = LoadLibrary(fullPath); if(hFullLib == NULL) { - Trace("ERROR:%u:Unable to load library %s\n", - GetLastError(), + Trace("ERROR:%u:Unable to load library %s\n", + GetLastError(), fullPath); iRetVal = FAIL; goto cleanUpTwo; @@ -141,11 +140,11 @@ PALTEST(loader_LoadLibraryA_test6_paltest_loadlibrarya_test6, "loader/LoadLibrar cleanUpTwo: - /* Call the FreeLibrary API. - */ + /* Call the FreeLibrary API. + */ if (!FreeLibrary(hFullLib)) { - Trace("ERROR:%u: Unable to free library \"%s\"\n", + Trace("ERROR:%u: Unable to free library \"%s\"\n", GetLastError(), fullPath); iRetVal = FAIL; @@ -153,11 +152,11 @@ PALTEST(loader_LoadLibraryA_test6_paltest_loadlibrarya_test6, "loader/LoadLibrar cleanUpOne: - /* Call the FreeLibrary API. - */ + /* Call the FreeLibrary API. + */ if (!FreeLibrary(hShortLib)) { - Trace("ERROR:%u: Unable to free library \"%s\"\n", + Trace("ERROR:%u: Unable to free library \"%s\"\n", GetLastError(), LibraryName); iRetVal = FAIL; @@ -167,5 +166,4 @@ PALTEST(loader_LoadLibraryA_test6_paltest_loadlibrarya_test6, "loader/LoadLibrar */ PAL_TerminateEx(iRetVal); return iRetVal; - } diff --git a/src/coreclr/pal/tests/palsuite/loader/LoadLibraryA/test8/loadlibrarya.cpp b/src/coreclr/pal/tests/palsuite/loader/LoadLibraryA/test8/loadlibrarya.cpp index b489ef27f965e..1bbf9a6d08ad1 100644 --- a/src/coreclr/pal/tests/palsuite/loader/LoadLibraryA/test8/loadlibrarya.cpp +++ b/src/coreclr/pal/tests/palsuite/loader/LoadLibraryA/test8/loadlibrarya.cpp @@ -7,9 +7,9 @@ ** ** Purpose: Positive test the LoadLibrary API. Test will verify ** that it is unable to load the library twice. Once by -** using the full path name and secondly by using the +** using the full path name and secondly by using the ** short name. -** +** ** **============================================================*/ @@ -25,14 +25,13 @@ typedef int (*dllfunct)(); #define GETATTACHCOUNTNAME "_GetAttachCount@0" #endif - /* Helper function to test the loaded library. */ BOOL PALAPI TestDll(HMODULE hLib) { int RetVal; char FunctName[] = GETATTACHCOUNTNAME; - FARPROC DllFunc; + FARPROC DllFunc; /* Access a function from the loaded library. */ @@ -45,7 +44,7 @@ BOOL PALAPI TestDll(HMODULE hLib) return (FALSE); } - /* Verify that the DLL_PROCESS_ATTACH is only + /* Verify that the DLL_PROCESS_ATTACH is only * accessed once.*/ RetVal = DllFunc(); if (RetVal != 1) @@ -72,7 +71,7 @@ PALTEST(loader_LoadLibraryA_test8_paltest_loadlibrarya_test8, "loader/LoadLibrar char relTestDir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; - + BOOL bRc = FALSE; char relLibPath[_MAX_DIR]; @@ -89,15 +88,15 @@ PALTEST(loader_LoadLibraryA_test8_paltest_loadlibrarya_test8, "loader/LoadLibrar /* Get the full path to the library (DLL). */ - - if (NULL != _fullpath(fullPath,argv[0],_MAX_DIR)) { - + + if (NULL != realpath(argv[0],fullpath)) { + _splitpath(fullPath,drive,dir,fname,ext); _makepath(fullPath,drive,dir,LibraryName,""); - - + + } else { - Fail("ERROR: conversion from relative path \" %s \" to absolute path failed. _fullpath returned NULL\n",argv[0]); + Fail("ERROR: conversion from relative path \" %s \" to absolute path failed. realpath returned NULL\n",argv[0]); } /* Get relative path to the library @@ -112,11 +111,11 @@ PALTEST(loader_LoadLibraryA_test8_paltest_loadlibrarya_test8, "loader/LoadLibrar hShortLib = LoadLibrary(LibraryName); if(hShortLib == NULL) { - Fail("ERROR:%u:Short:Unable to load library %s\n", - GetLastError(), + Fail("ERROR:%u:Short:Unable to load library %s\n", + GetLastError(), LibraryName); } - + /* Test the loaded library. */ if (!TestDll(hShortLib)) @@ -131,8 +130,8 @@ PALTEST(loader_LoadLibraryA_test8_paltest_loadlibrarya_test8, "loader/LoadLibrar hFullLib = LoadLibrary(fullPath); if(hFullLib == NULL) { - Trace("ERROR:%u:Full:Unable to load library %s\n", - GetLastError(), + Trace("ERROR:%u:Full:Unable to load library %s\n", + GetLastError(), fullPath); iRetVal = FAIL; goto cleanUpTwo; @@ -148,14 +147,14 @@ PALTEST(loader_LoadLibraryA_test8_paltest_loadlibrarya_test8, "loader/LoadLibrar /* ** Call the load library with the relative path - ** wrt to the directory ./testloadlibrary/.. + ** wrt to the directory ./testloadlibrary/.. ** since we don't want to make any assumptions ** regarding the type of build */ hRelLib = LoadLibrary(relLibPath); if(hRelLib == NULL) { - Trace("ERROR:%u:Rel:Unable to load library at %s\n", + Trace("ERROR:%u:Rel:Unable to load library at %s\n", GetLastError(), relLibPath); iRetVal = FAIL; goto cleanUpTwo; @@ -190,12 +189,12 @@ PALTEST(loader_LoadLibraryA_test8_paltest_loadlibrarya_test8, "loader/LoadLibrar cleanUpThree: - /* Call the FreeLibrary API. - */ + /* Call the FreeLibrary API. + */ if (!FreeLibrary(hRelLib)) { - Trace("ERROR:%u: Unable to free library \"%s\"\n", + Trace("ERROR:%u: Unable to free library \"%s\"\n", GetLastError(), relLibPath); iRetVal = FAIL; @@ -203,11 +202,11 @@ PALTEST(loader_LoadLibraryA_test8_paltest_loadlibrarya_test8, "loader/LoadLibrar cleanUpTwo: - /* Call the FreeLibrary API. - */ + /* Call the FreeLibrary API. + */ if (!FreeLibrary(hFullLib)) { - Trace("ERROR:%u: Unable to free library \"%s\"\n", + Trace("ERROR:%u: Unable to free library \"%s\"\n", GetLastError(), fullPath); iRetVal = FAIL; @@ -215,20 +214,18 @@ PALTEST(loader_LoadLibraryA_test8_paltest_loadlibrarya_test8, "loader/LoadLibrar cleanUpOne: - /* Call the FreeLibrary API. - */ + /* Call the FreeLibrary API. + */ if (!FreeLibrary(hShortLib)) { - Trace("ERROR:%u: Unable to free library \"%s\"\n", + Trace("ERROR:%u: Unable to free library \"%s\"\n", GetLastError(), LibraryName); iRetVal = FAIL; } - /* Terminate the PAL. */ PAL_TerminateEx(iRetVal); return iRetVal; - } diff --git a/src/coreclr/pal/tests/palsuite/paltestlist.txt b/src/coreclr/pal/tests/palsuite/paltestlist.txt index 2b9ac7ccd4eb1..514cd52f1a590 100644 --- a/src/coreclr/pal/tests/palsuite/paltestlist.txt +++ b/src/coreclr/pal/tests/palsuite/paltestlist.txt @@ -333,7 +333,6 @@ c_runtime/wcsrchr/test1/paltest_wcsrchr_test1 c_runtime/wcsstr/test1/paltest_wcsstr_test1 c_runtime/wcstod/test1/paltest_wcstod_test1 c_runtime/wcstod/test2/paltest_wcstod_test2 -c_runtime/wcstok/test1/paltest_wcstok_test1 c_runtime/wcstoul/test1/paltest_wcstoul_test1 c_runtime/wcstoul/test2/paltest_wcstoul_test2 c_runtime/wcstoul/test3/paltest_wcstoul_test3 From 856e8c3510cb0aaaa3b1a1679552c03ae5308b9e Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Tue, 18 Jan 2022 17:16:10 +0200 Subject: [PATCH 013/308] Fix compilation with older gcc (#63721) --- src/coreclr/binder/assemblybindercommon.cpp | 2 +- src/coreclr/binder/bindertracing.cpp | 4 ++-- src/coreclr/binder/inc/bindertracing.h | 2 +- src/coreclr/gc/unix/gcenv.unix.cpp | 4 ++++ src/coreclr/jit/compiler.h | 2 +- src/coreclr/pal/inc/rt/sal.h | 4 ++++ src/coreclr/vm/dacenumerablehash.inl | 4 ++-- src/native/corehost/fxr/host_context.cpp | 4 ++-- src/native/libs/Common/pal_utilities.h | 4 ++++ 9 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/coreclr/binder/assemblybindercommon.cpp b/src/coreclr/binder/assemblybindercommon.cpp index 830c673ea06a6..7b48a0a90ce83 100644 --- a/src/coreclr/binder/assemblybindercommon.cpp +++ b/src/coreclr/binder/assemblybindercommon.cpp @@ -972,7 +972,7 @@ namespace BINDER_SPACE { // Search Assembly.ni.dll, then Assembly.dll // The Assembly.ni.dll paths are rare, and intended for supporting managed C++ R2R assemblies. - SString candidates[] = { W(".ni.dll"), W(".dll") }; + const WCHAR* const candidates[] = { W(".ni.dll"), W(".dll") }; // Loop through the binding paths looking for a matching assembly for (int i = 0; i < 2; i++) diff --git a/src/coreclr/binder/bindertracing.cpp b/src/coreclr/binder/bindertracing.cpp index 499e20d928887..e349b99b3c14e 100644 --- a/src/coreclr/binder/bindertracing.cpp +++ b/src/coreclr/binder/bindertracing.cpp @@ -176,8 +176,8 @@ namespace BinderTracing { static thread_local bool t_AssemblyLoadStartInProgress = false; - AssemblyBindOperation::AssemblyBindOperation(AssemblySpec *assemblySpec, const WCHAR *assemblyPath) - : m_bindRequest { assemblySpec, nullptr, assemblyPath } + AssemblyBindOperation::AssemblyBindOperation(AssemblySpec *assemblySpec, const SString& assemblyPath) + : m_bindRequest { assemblySpec, SString::Empty(), assemblyPath } , m_populatedBindRequest { false } , m_checkedIgnoreBind { false } , m_ignoreBind { false } diff --git a/src/coreclr/binder/inc/bindertracing.h b/src/coreclr/binder/inc/bindertracing.h index 75d8270b8eee5..ca28c04519638 100644 --- a/src/coreclr/binder/inc/bindertracing.h +++ b/src/coreclr/binder/inc/bindertracing.h @@ -27,7 +27,7 @@ namespace BinderTracing { public: // This class assumes the assembly spec will have a longer lifetime than itself - AssemblyBindOperation(AssemblySpec *assemblySpec, const WCHAR *assemblyPath = nullptr); + AssemblyBindOperation(AssemblySpec *assemblySpec, const SString& assemblyPath = SString::Empty()); ~AssemblyBindOperation(); void SetResult(PEAssembly *assembly, bool cached = false); diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp index 431421afc87e4..2d979c395610e 100644 --- a/src/coreclr/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/gc/unix/gcenv.unix.cpp @@ -28,6 +28,10 @@ #undef min #undef max +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) (0) +#endif + #if __has_cpp_attribute(fallthrough) #define FALLTHROUGH [[fallthrough]] #else diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 422944fed8e7c..d5dcf4cd92c81 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -1735,7 +1735,7 @@ struct fgArgTabEntry // In this case, it must be removed by GenTreeCall::ResetArgInfo. bool isNonStandardArgAddedLate() const { - switch (nonStandardArgKind) + switch (static_cast(nonStandardArgKind)) { case NonStandardArgKind::None: case NonStandardArgKind::PInvokeFrame: diff --git a/src/coreclr/pal/inc/rt/sal.h b/src/coreclr/pal/inc/rt/sal.h index 198b46d4a4e06..ef976be402fdc 100644 --- a/src/coreclr/pal/inc/rt/sal.h +++ b/src/coreclr/pal/inc/rt/sal.h @@ -2862,6 +2862,10 @@ of each annotation, see the advanced annotations section. #define __useHeader _Use_decl_anno_impl_ #define __on_failure(annotes) _On_failure_impl_(annotes _SAL_nop_impl_) +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) (0) +#endif + #ifndef __fallthrough // [ #if __has_cpp_attribute(fallthrough) #define __fallthrough [[fallthrough]] diff --git a/src/coreclr/vm/dacenumerablehash.inl b/src/coreclr/vm/dacenumerablehash.inl index e4e5de3b11f3f..049329bbfbc67 100644 --- a/src/coreclr/vm/dacenumerablehash.inl +++ b/src/coreclr/vm/dacenumerablehash.inl @@ -400,8 +400,8 @@ namespace HashTableDetail { // Use the C++ detection idiom (https://isocpp.org/blog/2017/09/detection-idiom-a-stopgap-for-concepts-simon-brand) to call the // derived table's EnumMemoryRegionsForEntry method if it defines one. - template - using void_t = void; + template struct make_void { using type = void; }; + template using void_t = typename make_void::type; template struct negation : std::integral_constant { }; diff --git a/src/native/corehost/fxr/host_context.cpp b/src/native/corehost/fxr/host_context.cpp index 82fe8c2b494dc..73af214ed3b8a 100644 --- a/src/native/corehost/fxr/host_context.cpp +++ b/src/native/corehost/fxr/host_context.cpp @@ -129,8 +129,8 @@ host_context_t::host_context_t( const corehost_context_contract &hostpolicy_context_contract) : marker { valid_host_context_marker } , type { type } - , hostpolicy_contract { hostpolicy_contract } - , hostpolicy_context_contract { hostpolicy_context_contract } + , hostpolicy_contract (hostpolicy_contract) + , hostpolicy_context_contract (hostpolicy_context_contract) { } void host_context_t::initialize_frameworks(const corehost_init_t& init) diff --git a/src/native/libs/Common/pal_utilities.h b/src/native/libs/Common/pal_utilities.h index 4e582ed6cd002..0bab812bd613e 100644 --- a/src/native/libs/Common/pal_utilities.h +++ b/src/native/libs/Common/pal_utilities.h @@ -43,6 +43,10 @@ #define CONST_CAST2(TOTYPE, FROMTYPE, X) ((union { FROMTYPE _q; TOTYPE _nq; }){ ._q = (X) }._nq) #define CONST_CAST(TYPE, X) CONST_CAST2(TYPE, const TYPE, (X)) +#ifndef __has_attribute +#define __has_attribute(x) (0) +#endif + #if __has_attribute(fallthrough) #define FALLTHROUGH __attribute__((fallthrough)) #else From 39ef452edcf90bae76a1e4c8c1c24209e17ac5f2 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Tue, 18 Jan 2022 18:20:15 +0300 Subject: [PATCH 014/308] Disable DllImportGenerator.Unit.Tests test suite on macOS+arm64+CoreCLR (#63887) --- src/libraries/tests.proj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index f1698345fcbbf..fe7ed9dcf4a2a 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -342,6 +342,11 @@ Roslyn4.0.Tests.csproj" /> + + + + + From 5a12420546d7f0d963bcccf082400c1b057e38ef Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Tue, 18 Jan 2022 18:21:33 +0300 Subject: [PATCH 015/308] Remove individual exclusions for DllImportGenerator.Unit.Tests in favor of the general one for the entire set of mobile targets (#63924) --- src/libraries/tests.proj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index fe7ed9dcf4a2a..c560a65102156 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -222,8 +222,6 @@ Roslyn4.0.Tests.csproj" /> - - @@ -277,9 +275,6 @@ Roslyn4.0.Tests.csproj" /> - - - @@ -301,9 +296,6 @@ Roslyn4.0.Tests.csproj" /> - - - From 64896116e66377aa8e951abb9e9505aff8a25f89 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Tue, 18 Jan 2022 11:36:15 -0500 Subject: [PATCH 016/308] Fix OpenSSL 3 reporting an OutOfMemoryException for missing private key --- .../Interop.EvpPkey.cs | 22 ++++++--- .../opensslshim.h | 2 + .../pal_evp_pkey.c | 45 +++++++++++++++++-- .../pal_evp_pkey.h | 8 +++- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs index 593c6f4e593f6..95e9ab89fc505 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs @@ -105,18 +105,28 @@ internal static unsafe SafeEvpPKeyHandle DecodePkcs8PrivateKey( } [GeneratedDllImport(Libraries.CryptoNative)] - private static partial int CryptoNative_GetPkcs8PrivateKeySize(IntPtr pkey); + private static partial int CryptoNative_GetPkcs8PrivateKeySize(IntPtr pkey, out int p8size); private static int GetPkcs8PrivateKeySize(IntPtr pkey) { - int ret = CryptoNative_GetPkcs8PrivateKeySize(pkey); + const int Success = 1; + const int Error = -1; + const int MissingPrivateKey = -2; - if (ret < 0) + int ret = CryptoNative_GetPkcs8PrivateKeySize(pkey, out int p8size); + + switch (ret) { - throw CreateOpenSslCryptographicException(); + case Success: + return p8size; + case Error: + throw CreateOpenSslCryptographicException(); + case MissingPrivateKey: + throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); + default: + Debug.Fail($"Unexpected return '{ret}' value from {nameof(CryptoNative_GetPkcs8PrivateKeySize)}."); + throw new CryptographicException(); } - - return ret; } [GeneratedDllImport(Libraries.CryptoNative)] diff --git a/src/native/libs/System.Security.Cryptography.Native/opensslshim.h b/src/native/libs/System.Security.Cryptography.Native/opensslshim.h index 0b38944d502e8..a64aac0c676e9 100644 --- a/src/native/libs/System.Security.Cryptography.Native/opensslshim.h +++ b/src/native/libs/System.Security.Cryptography.Native/opensslshim.h @@ -270,6 +270,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); LEGACY_FUNCTION(ERR_load_crypto_strings) \ LIGHTUP_FUNCTION(ERR_new) \ REQUIRED_FUNCTION(ERR_peek_error) \ + REQUIRED_FUNCTION(ERR_peek_error_line) \ REQUIRED_FUNCTION(ERR_peek_last_error) \ FALLBACK_FUNCTION(ERR_put_error) \ REQUIRED_FUNCTION(ERR_reason_error_string) \ @@ -728,6 +729,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define ERR_load_crypto_strings ERR_load_crypto_strings_ptr #define ERR_new ERR_new_ptr #define ERR_peek_error ERR_peek_error_ptr +#define ERR_peek_error_line ERR_peek_error_line_ptr #define ERR_peek_last_error ERR_peek_last_error_ptr #define ERR_put_error ERR_put_error_ptr #define ERR_reason_error_string ERR_reason_error_string_ptr diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c index 6839d4c2fe04e..79de386f09721 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c @@ -152,20 +152,59 @@ EVP_PKEY* CryptoNative_DecodePkcs8PrivateKey(const uint8_t* buf, int32_t len, in return key; } -int32_t CryptoNative_GetPkcs8PrivateKeySize(EVP_PKEY* pkey) +int32_t CryptoNative_GetPkcs8PrivateKeySize(EVP_PKEY* pkey, int32_t* p8size) { assert(pkey != NULL); + assert(p8size != NULL); + + *p8size = 0; + ERR_clear_error(); PKCS8_PRIV_KEY_INFO* p8 = EVP_PKEY2PKCS8(pkey); if (p8 == NULL) { + // OpenSSL 1.1 and 3 have a behavioral change with EVP_PKEY2PKCS8 + // with regard to handling EVP_PKEYs that do not contain a private key. + // + // In OpenSSL 1.1, it would always succeed, but the private parameters + // would be missing (thus making an invalid PKCS8 structure). + // Over in the managed side, we detect these invalid PKCS8 blobs and + // convert that to a "no private key" error. + // + // In OpenSSL 3, this now correctly errors, with the error + // ASN1_R_ILLEGAL_ZERO_CONTENT. We want to preserve allocation failures + // as OutOfMemoryException. So we peek at the error. If it's a malloc + // failure, -1 is returned to indcate "throw what is on the error queue". + // If the error is not a malloc failure, return -2 to mean "no private key". + // If OpenSSL ever changes the error to something more to explicitly mean + // "no private key" then we should test for that explicitly. Until then, + // we treat all errors, except a malloc error, to mean "no private key". + + const char* file = NULL; + int line = 0; + unsigned long error = ERR_peek_error_line(&file, &line); + + // If it's not a malloc failure, assume it's because the private key is + // missing. + if (ERR_GET_REASON(error) != ERR_R_MALLOC_FAILURE) + { + ERR_clear_error(); + return -2; + } + + // It is a malloc failure. Clear the error queue and set the error + // as a malloc error so it's the only error in the queue. + ERR_clear_error(); + ERR_put_error(ERR_GET_LIB(error), 0, ERR_R_MALLOC_FAILURE, file, line); + return -1; } - int ret = i2d_PKCS8_PRIV_KEY_INFO(p8, NULL); + *p8size = i2d_PKCS8_PRIV_KEY_INFO(p8, NULL); PKCS8_PRIV_KEY_INFO_free(p8); - return ret; + + return *p8size < 0 ? -1 : 1; } int32_t CryptoNative_EncodePkcs8PrivateKey(EVP_PKEY* pkey, uint8_t* buf) diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h index 012ac98e03db2..fac7ee32b5bbc 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h +++ b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h @@ -58,9 +58,13 @@ Requres a non-null buf, and len > 0. PALEXPORT EVP_PKEY* CryptoNative_DecodePkcs8PrivateKey(const uint8_t* buf, int32_t len, int32_t algId); /* -Reports the number of bytes rqeuired to encode an EVP_PKEY* as a Pkcs8PrivateKeyInfo, or a negative value on error. +Gets the number of bytes rqeuired to encode an EVP_PKEY* as a Pkcs8PrivateKeyInfo. + +On success, 1 is returned and p8size contains the size of the Pkcs8PrivateKeyInfo. +On failure, -1 is used to indicate the openssl error queue contains the error. +On failure, -2 is used to indcate that the supplied EVP_PKEY* is possibly missing a private key. */ -PALEXPORT int32_t CryptoNative_GetPkcs8PrivateKeySize(EVP_PKEY* pkey); +PALEXPORT int32_t CryptoNative_GetPkcs8PrivateKeySize(EVP_PKEY* pkey, int32_t* p8size); /* Encodes the EVP_PKEY* as a Pkcs8PrivateKeyInfo, writing the encoded value to buf. From d18d6c703295555d466fb159f8dec64857f68ed9 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Tue, 18 Jan 2022 12:15:11 -0500 Subject: [PATCH 017/308] Update SAN test to account for OpenSSL 3 changes --- .../tests/TestUtilities/System/PlatformDetection.Unix.cs | 5 +++++ .../tests/AsnEncodedDataTests.cs | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs index ac167ec7cecaf..207cd17f3b538 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs @@ -57,6 +57,11 @@ public static partial class PlatformDetection GetOpenSslVersion() : throw new PlatformNotSupportedException(); + private static readonly Version s_openssl3Version = new Version(3, 0, 0); + public static bool IsOpenSsl3 => !IsOSXLike && !IsWindows && !IsAndroid && !IsBrowser ? + GetOpenSslVersion() >= s_openssl3Version : + false; + /// /// If gnulibc is available, returns the release, such as "stable". /// Otherwise returns "glibc_not_found". diff --git a/src/libraries/System.Security.Cryptography/tests/AsnEncodedDataTests.cs b/src/libraries/System.Security.Cryptography/tests/AsnEncodedDataTests.cs index a72d6814fea80..0e5ba9cb08806 100644 --- a/src/libraries/System.Security.Cryptography/tests/AsnEncodedDataTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/AsnEncodedDataTests.cs @@ -101,11 +101,12 @@ public static void TestSubjectAlternativeName_Unix() sanExtension); string s = asnData.Format(false); + bool isOpenSsl3 = PlatformDetection.IsOpenSsl3; string expected = string.Join( ", ", // Choice[0]: OtherName - "othername:", + isOpenSsl3 ? "othername: UPN::subjectupn1@example.org" : "othername:", // Choice[1]: Rfc822Name (EmailAddress) "email:sanemail1@example.org", // Choice[2]: DnsName @@ -123,7 +124,7 @@ public static void TestSubjectAlternativeName_Unix() // Choice[7]: IPAddress (IPv6) "IP Address:2001:DB8:AC10:FE01:0:0:0:0", // Choice[7]: IPAddress (unknown type) - "IP Address:", + isOpenSsl3 ? "IP Address:" : "IP Address:", // Choice[7]: IPAddress (IPv4, longer string) "IP Address:255.255.255.255", // Choice[7]: IPAddress (IPv4, medium string) From 2eb2e883dc807897fe07dd6559462e37e8613693 Mon Sep 17 00:00:00 2001 From: Tomas Weinfurt Date: Tue, 18 Jan 2022 09:18:29 -0800 Subject: [PATCH 018/308] improve protocol detection in jail (#63565) * improve protocol detection in jail * add comment --- .../Common/src/System/Net/SocketProtocolSupportPal.Unix.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs b/src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs index 8de1e2a0f4ce3..c755c16517c77 100644 --- a/src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs +++ b/src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs @@ -15,7 +15,9 @@ private static unsafe bool IsSupported(AddressFamily af) IntPtr socket = invalid; try { - return Interop.Sys.Socket(af, SocketType.Dgram, 0, &socket) != Interop.Error.EAFNOSUPPORT; + Interop.Error result = Interop.Sys.Socket(af, SocketType.Dgram, 0, &socket); + // we get EAFNOSUPPORT when family is not supported by Kernel, EPROTONOSUPPORT may come from policy enforcement like FreeBSD jail() + return result != Interop.Error.EAFNOSUPPORT && result != Interop.Error.EPROTONOSUPPORT; } finally { From f04a24249835096eea1a1a66e4af03cfec5ed32b Mon Sep 17 00:00:00 2001 From: Artem Kliatchkine Date: Tue, 18 Jan 2022 18:18:45 +0100 Subject: [PATCH 019/308] Set zero (infinite) options timeout in case of Timeout.InfiniteTimeSpan (#55984) (#63733) Co-authored-by: Artem Kliatchkine --- .../MsQuic/Interop/SafeMsQuicConfigurationHandle.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/SafeMsQuicConfigurationHandle.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/SafeMsQuicConfigurationHandle.cs index 24200021ec054..d536dfa58dbdc 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/SafeMsQuicConfigurationHandle.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Interop/SafeMsQuicConfigurationHandle.cs @@ -156,9 +156,13 @@ private static unsafe SafeMsQuicConfigurationHandle Create(QuicOptions options, ulong ms = (ulong)options.IdleTimeout.Ticks / TimeSpan.TicksPerMillisecond; if (ms > (1ul << 62) - 1) throw new Exception("IdleTimeout is too large (max 2^62-1 milliseconds)"); - settings.IsSetFlags |= QuicSettingsIsSetFlags.IdleTimeoutMs; settings.IdleTimeoutMs = (ulong)options.IdleTimeout.TotalMilliseconds; } + else + { + settings.IdleTimeoutMs = 0; + } + settings.IsSetFlags |= QuicSettingsIsSetFlags.IdleTimeoutMs; uint status; SafeMsQuicConfigurationHandle? configurationHandle; From 82b8d79b6f858f0d44791e3eab36735b7093d935 Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Tue, 18 Jan 2022 13:56:09 -0500 Subject: [PATCH 020/308] Fix NullabilityInfoContext.Create to properly analyze types with nested generic types (#63556) --- .../Reflection/NullabilityInfoContext.cs | 35 +++++++++-------- .../Reflection/NullabilityInfoContextTests.cs | 38 +++++++++++++++++++ 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs index b09bb83a5a687..b58e03aeb6e44 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs @@ -341,10 +341,13 @@ private NotAnnotatedStatus PopulateAnnotationInfo(IList cus return NotAnnotatedStatus.None; } - private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, IList customAttributes) => - GetNullabilityInfo(memberInfo, type, customAttributes, 0); + private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, IList customAttributes) + { + int index = 0; + return GetNullabilityInfo(memberInfo, type, customAttributes, ref index); + } - private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, IList customAttributes, int index) + private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, IList customAttributes, ref int index) { NullabilityState state = NullabilityState.Unknown; NullabilityInfo? elementState = null; @@ -364,17 +367,22 @@ private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, ILi underlyingType = type; state = NullabilityState.NotNull; } + + if (underlyingType.IsGenericType) + { + index++; + } } else { - if (!ParseNullableState(customAttributes, index, ref state)) + if (!ParseNullableState(customAttributes, index++, ref state)) { state = GetNullableContext(memberInfo); } if (type.IsArray) { - elementState = GetNullabilityInfo(memberInfo, type.GetElementType()!, customAttributes, index + 1); + elementState = GetNullabilityInfo(memberInfo, type.GetElementType()!, customAttributes, ref index); } } @@ -383,16 +391,9 @@ private NullabilityInfo GetNullabilityInfo(MemberInfo memberInfo, Type type, ILi Type[] genericArguments = underlyingType.GetGenericArguments(); genericArgumentsState = new NullabilityInfo[genericArguments.Length]; - for (int i = 0, offset = 0; i < genericArguments.Length; i++) + for (int i = 0; i < genericArguments.Length; i++) { - Type t = Nullable.GetUnderlyingType(genericArguments[i]) ?? genericArguments[i]; - - if (!t.IsValueType || t.IsGenericType) - { - offset++; - } - - genericArgumentsState[i] = GetNullabilityInfo(memberInfo, genericArguments[i], customAttributes, index + offset); + genericArgumentsState[i] = GetNullabilityInfo(memberInfo, genericArguments[i], customAttributes, ref index); } } @@ -500,7 +501,8 @@ private void CheckGenericParameters(NullabilityInfo nullability, MemberInfo meta { if (genericArguments[i].IsGenericParameter) { - NullabilityInfo n = GetNullabilityInfo(metaMember, genericArguments[i], genericArguments[i].GetCustomAttributesData(), i + 1); + int index = i + 1; + NullabilityInfo n = GetNullabilityInfo(metaMember, genericArguments[i], genericArguments[i].GetCustomAttributesData(), ref index); nullability.GenericTypeArguments[i].ReadState = n.ReadState; nullability.GenericTypeArguments[i].WriteState = n.WriteState; } @@ -523,7 +525,8 @@ private void UpdateGenericArrayElements(NullabilityInfo? elementState, MemberInf && metaType.GetElementType()!.IsGenericParameter) { Type elementType = metaType.GetElementType()!; - NullabilityInfo n = GetNullabilityInfo(metaMember, elementType, elementType.GetCustomAttributesData(), 0); + int index = 0; + NullabilityInfo n = GetNullabilityInfo(metaMember, elementType, elementType.GetCustomAttributesData(), ref index); elementState.ReadState = n.ReadState; elementState.WriteState = n.WriteState; } diff --git a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs index f444a5624c6bb..ce939d4526302 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs @@ -850,6 +850,42 @@ public void AttributedParametersTest() Assert.Equal(NullabilityState.NotNull, nullabilityContext.Create(tryGetOutParameters[0]).ReadState); } + public static IEnumerable NestedGenericsCorrectOrderData() + { + yield return new object[] { + "MethodReturnsNonTupleNonTupleNullStringNullStringNullString", + new[] { NullabilityState.NotNull, NullabilityState.NotNull, NullabilityState.Nullable, NullabilityState.Nullable, NullabilityState.Nullable }, + new[] { typeof(Tuple, string>), typeof(Tuple), typeof(string), typeof(string), typeof(string) } + }; + yield return new object[] { + "MethodReturnsNonTupleNonTupleNullStringNullStringNonString", + new[] { NullabilityState.NotNull, NullabilityState.NotNull, NullabilityState.Nullable, NullabilityState.Nullable, NullabilityState.NotNull }, + new[] { typeof(Tuple, string>), typeof(Tuple), typeof(string), typeof(string), typeof(string) } + }; + } + + [Theory] + [MemberData(nameof(NestedGenericsCorrectOrderData))] + [SkipOnMono("Nullability attributes trimmed on Mono")] + public void NestedGenericsCorrectOrderTest(string methodName, NullabilityState[] nullStates, Type[] types) + { + NullabilityInfo parentInfo = nullabilityContext.Create(typeof(TypeWithNotNullContext).GetMethod(methodName)!.ReturnParameter); + var dataIndex = 0; + Examine(parentInfo); + Assert.Equal(nullStates.Length, dataIndex); + Assert.Equal(types.Length, dataIndex); + + void Examine(NullabilityInfo info) + { + Assert.Equal(types[dataIndex], info.Type); + Assert.Equal(nullStates[dataIndex++], info.ReadState); + for (var i = 0; i < info.GenericTypeArguments.Length; i++) + { + Examine(info.GenericTypeArguments[i]); + } + } + } + public static IEnumerable NestedGenericsReturnParameterData() { // public IEnumerable?> MethodReturnsEnumerableNonTupleNonNonNullValueTupleNonNullNon() => null!; @@ -1089,6 +1125,8 @@ public void MethodParametersUnknown(string s, IDictionary dict) public IEnumerable?, int>?>? MethodReturnsEnumerableNullStructNullNonNullTupleNonNullNull() => null; public IEnumerable?, int>?>? MethodReturnsEnumerableNullTupleNullNonNullStructNonNullNull() => null; public IEnumerable<(GenericStruct str, int? count)> MethodReturnsEnumerableNonValueTupleNonNullNonStructNonNullNon() => null!; + public Tuple, string?> MethodReturnsNonTupleNonTupleNullStringNullStringNullString() => null!; + public Tuple, string> MethodReturnsNonTupleNonTupleNullStringNullStringNonString() => null!; public void MethodNullNonNullNonNon(string? s, IDictionary dict) { } public void MethodNonNullNonNullNotNull(string s, [NotNull] IDictionary? dict) { dict = new Dictionary(); } public void MethodNullNonNullNullNon(string? s, IDictionary dict) { } From 078da6c37e2ab602fe37ab699051ef71161ce2cc Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Tue, 18 Jan 2022 11:04:22 -0800 Subject: [PATCH 021/308] Introduce `BasicBlock::KindIs()` for checking bbJumpKind (#63203) * Introduce `BasicBlock::KindIs()` for checking bbJumpKind This can simplify code that is checking for multiple `bbJumpKind` kinds with an `if` statement, where a `switch` is not warranted. It's the same usage model as `GenTree::OperIs()`. e.g., ``` if (block->KindIs(BBJ_COND, BBJ_SWITCH, BBJ_RETURN)) ``` * Fix argument name --- src/coreclr/jit/block.h | 11 +++++++++++ src/coreclr/jit/fgbasic.cpp | 12 ++++++------ src/coreclr/jit/fgdiagnostic.cpp | 2 +- src/coreclr/jit/fgopt.cpp | 19 +++++++++---------- src/coreclr/jit/fgprofile.cpp | 6 +++--- src/coreclr/jit/fgstmt.cpp | 2 +- src/coreclr/jit/flowgraph.cpp | 22 +++------------------- src/coreclr/jit/importer.cpp | 4 ++-- src/coreclr/jit/lir.cpp | 2 +- src/coreclr/jit/loopcloning.cpp | 4 ++-- src/coreclr/jit/lsra.cpp | 10 +++++----- src/coreclr/jit/optimizer.cpp | 26 ++++++++++++-------------- src/coreclr/jit/rangecheck.cpp | 2 +- 13 files changed, 57 insertions(+), 65 deletions(-) diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index c5996ac8239d7..81a511f4bceed 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -825,6 +825,17 @@ struct BasicBlock : private LIR::Range BBswtDesc* bbJumpSwt; // switch descriptor }; + bool KindIs(BBjumpKinds kind) const + { + return bbJumpKind == kind; + } + + template + bool KindIs(BBjumpKinds kind, T... rest) const + { + return KindIs(kind) || KindIs(rest...); + } + // NumSucc() gives the number of successors, and GetSucc() returns a given numbered successor. // // There are two versions of these functions: ones that take a Compiler* and ones that don't. You must diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 73695932cb543..eb98143713818 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -321,7 +321,7 @@ bool Compiler::fgFirstBBisScratch() // Normally, the first scratch block is a fall-through block. However, if the block after it was an empty // BBJ_ALWAYS block, it might get removed, and the code that removes it will make the first scratch block // a BBJ_ALWAYS block. - assert((fgFirstBBScratch->bbJumpKind == BBJ_NONE) || (fgFirstBBScratch->bbJumpKind == BBJ_ALWAYS)); + assert(fgFirstBBScratch->KindIs(BBJ_NONE, BBJ_ALWAYS)); return true; } @@ -2407,7 +2407,7 @@ void Compiler::fgLinkBasicBlocks() /* Is the next block reachable? */ - if (curBBdesc->bbJumpKind == BBJ_ALWAYS || curBBdesc->bbJumpKind == BBJ_LEAVE) + if (curBBdesc->KindIs(BBJ_ALWAYS, BBJ_LEAVE)) { break; } @@ -4369,7 +4369,7 @@ BasicBlock* Compiler::fgSplitBlockAtBeginning(BasicBlock* curr) BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ) { - assert(curr->bbJumpKind == BBJ_COND || curr->bbJumpKind == BBJ_SWITCH || curr->bbJumpKind == BBJ_ALWAYS); + assert(curr->KindIs(BBJ_COND, BBJ_SWITCH, BBJ_ALWAYS)); if (fgComputePredsDone) { @@ -4670,7 +4670,7 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable) } #endif // DEBUG - noway_assert(block->bbJumpKind == BBJ_NONE || block->bbJumpKind == BBJ_ALWAYS); + noway_assert(block->KindIs(BBJ_NONE, BBJ_ALWAYS)); /* Who is the "real" successor of this block? */ @@ -5182,7 +5182,7 @@ bool Compiler::fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc /* = NULL * { bool result = false; - if ((bJump->bbJumpKind == BBJ_COND) || (bJump->bbJumpKind == BBJ_ALWAYS)) + if (bJump->KindIs(BBJ_COND, BBJ_ALWAYS)) { BasicBlock* bDest = bJump->bbJumpDest; BasicBlock* bTemp = (bSrc == nullptr) ? bJump : bSrc; @@ -5799,7 +5799,7 @@ bool Compiler::fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt) noway_assert(bAlt != nullptr); // We only handle the cases when bAlt is a BBJ_ALWAYS or a BBJ_COND - if ((bAlt->bbJumpKind != BBJ_ALWAYS) && (bAlt->bbJumpKind != BBJ_COND)) + if (!bAlt->KindIs(BBJ_ALWAYS, BBJ_COND)) { return false; } diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index 7fd7b5d562563..3b3a84007fa45 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -2503,7 +2503,7 @@ bool BBPredsChecker::CheckEhTryDsc(BasicBlock* block, BasicBlock* blockPred, EHb bool BBPredsChecker::CheckEhHndDsc(BasicBlock* block, BasicBlock* blockPred, EHblkDsc* ehHndlDsc) { // You can do a BBJ_EHFINALLYRET or BBJ_EHFILTERRET into a handler region - if ((blockPred->bbJumpKind == BBJ_EHFINALLYRET) || (blockPred->bbJumpKind == BBJ_EHFILTERRET)) + if (blockPred->KindIs(BBJ_EHFINALLYRET, BBJ_EHFILTERRET)) { return true; } diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 361ff92ee8099..4e446837bcb18 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -145,16 +145,16 @@ bool Compiler::fgReachable(BasicBlock* b1, BasicBlock* b2) if (b1->bbNum > fgDomBBcount) { - noway_assert(b1->bbJumpKind == BBJ_NONE || b1->bbJumpKind == BBJ_ALWAYS || b1->bbJumpKind == BBJ_COND); + noway_assert(b1->KindIs(BBJ_NONE, BBJ_ALWAYS, BBJ_COND)); - if (b1->bbFallsThrough() && fgReachable(b1->bbNext, b2)) + if (b1->KindIs(BBJ_NONE, BBJ_COND) && fgReachable(b1->bbNext, b2)) { return true; } - if (b1->bbJumpKind == BBJ_ALWAYS || b1->bbJumpKind == BBJ_COND) + if (b1->KindIs(BBJ_ALWAYS, BBJ_COND) && fgReachable(b1->bbJumpDest, b2)) { - return fgReachable(b1->bbJumpDest, b2); + return true; } return false; @@ -3549,7 +3549,7 @@ bool Compiler::fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* // bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev) { - assert(block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS); + assert(block->KindIs(BBJ_COND, BBJ_ALWAYS)); assert(block->bbJumpDest == bNext); assert(block->bbNext == bNext); assert(block->bbPrev == bPrev); @@ -4604,7 +4604,7 @@ bool Compiler::fgReorderBlocks() bool backwardBranch = false; // Setup bDest - if ((bPrev->bbJumpKind == BBJ_COND) || (bPrev->bbJumpKind == BBJ_ALWAYS)) + if (bPrev->KindIs(BBJ_COND, BBJ_ALWAYS)) { bDest = bPrev->bbJumpDest; forwardBranch = fgIsForwardBranch(bPrev); @@ -4854,8 +4854,7 @@ bool Compiler::fgReorderBlocks() // to bTmp (which is a higher weighted block) then it is better to keep out current // candidateBlock and have it fall into bTmp // - if ((candidateBlock == nullptr) || - ((candidateBlock->bbJumpKind != BBJ_COND) && (candidateBlock->bbJumpKind != BBJ_ALWAYS)) || + if ((candidateBlock == nullptr) || !candidateBlock->KindIs(BBJ_COND, BBJ_ALWAYS) || (candidateBlock->bbJumpDest != bTmp)) { // otherwise we have a new candidateBlock @@ -5796,7 +5795,7 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication) // Remove JUMPS to the following block // and optimize any JUMPS to JUMPS - if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_ALWAYS) + if (block->KindIs(BBJ_COND, BBJ_ALWAYS)) { bDest = block->bbJumpDest; if (bDest == bNext) @@ -5935,7 +5934,7 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication) // Add fall through fixup block, if needed. // - if ((bDest->bbJumpKind == BBJ_NONE) || (bDest->bbJumpKind == BBJ_COND)) + if (bDest->KindIs(BBJ_NONE, BBJ_COND)) { BasicBlock* const bFixup = fgNewBBafter(BBJ_ALWAYS, bDest, true); bFixup->inheritWeight(bDestNext); diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index f94cb8615be40..27b16ababf96b 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -3417,7 +3417,7 @@ weight_t Compiler::fgComputeMissingBlockWeights() // Sum up the weights of all of the return blocks and throw blocks // This is used when we have a back-edge into block 1 // - if (bDst->hasProfileWeight() && ((bDst->bbJumpKind == BBJ_RETURN) || (bDst->bbJumpKind == BBJ_THROW))) + if (bDst->hasProfileWeight() && bDst->KindIs(BBJ_RETURN, BBJ_THROW)) { returnWeight += bDst->bbWeight; } @@ -3988,7 +3988,7 @@ void Compiler::fgDebugCheckProfileData() // Exit blocks // - if ((block->bbJumpKind == BBJ_RETURN) || (block->bbJumpKind == BBJ_THROW)) + if (block->KindIs(BBJ_RETURN, BBJ_THROW)) { exitWeight += blockWeight; exitProfiled = true; @@ -4157,7 +4157,7 @@ bool Compiler::fgDebugCheckOutgoingProfileData(BasicBlock* block) // We won't check finally or filter returns (for now). // - if ((block->bbJumpKind == BBJ_EHFINALLYRET) || (block->bbJumpKind == BBJ_EHFILTERRET)) + if (block->KindIs(BBJ_EHFINALLYRET, BBJ_EHFILTERRET)) { return true; } diff --git a/src/coreclr/jit/fgstmt.cpp b/src/coreclr/jit/fgstmt.cpp index 24140b3fc52b9..f5f07399a1d37 100644 --- a/src/coreclr/jit/fgstmt.cpp +++ b/src/coreclr/jit/fgstmt.cpp @@ -182,7 +182,7 @@ void Compiler::fgInsertStmtNearEnd(BasicBlock* block, Statement* stmt) // This routine can only be used when in tree order. assert(fgOrder == FGOrderTree); - if ((block->bbJumpKind == BBJ_COND) || (block->bbJumpKind == BBJ_SWITCH) || (block->bbJumpKind == BBJ_RETURN)) + if (block->KindIs(BBJ_COND, BBJ_SWITCH, BBJ_RETURN)) { Statement* firstStmt = block->firstStmt(); noway_assert(firstStmt != nullptr); diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 188e44ab7f7f6..ba032045e74b7 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -108,23 +108,8 @@ PhaseStatus Compiler::fgInsertGCPolls() // the test. // If we're doing GCPOLL_CALL, just insert a GT_CALL node before the last node in the block. - CLANG_FORMAT_COMMENT_ANCHOR; -#ifdef DEBUG - switch (block->bbJumpKind) - { - case BBJ_RETURN: - case BBJ_ALWAYS: - case BBJ_COND: - case BBJ_SWITCH: - case BBJ_NONE: - case BBJ_THROW: - case BBJ_CALLFINALLY: - break; - default: - assert(!"Unexpected block kind"); - } -#endif // DEBUG + assert(block->KindIs(BBJ_RETURN, BBJ_ALWAYS, BBJ_COND, BBJ_SWITCH, BBJ_NONE, BBJ_THROW, BBJ_CALLFINALLY)); GCPollType pollType = GCPOLL_INLINE; @@ -245,10 +230,9 @@ BasicBlock* Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block) createdPollBlocks = false; Statement* newStmt = nullptr; - if ((block->bbJumpKind == BBJ_ALWAYS) || (block->bbJumpKind == BBJ_CALLFINALLY) || - (block->bbJumpKind == BBJ_NONE)) + if (block->KindIs(BBJ_ALWAYS, BBJ_CALLFINALLY, BBJ_NONE)) { - // For BBJ_ALWAYS, BBJ_CALLFINALLY, and BBJ_NONE and we don't need to insert it before the condition. + // For BBJ_ALWAYS, BBJ_CALLFINALLY, and BBJ_NONE we don't need to insert it before the condition. // Just append it. newStmt = fgNewStmtAtEnd(block, call); } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index aab024d3ac30d..64c0eb44c5891 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -10766,7 +10766,7 @@ void Compiler::impImportLeave(BasicBlock* block) * scope */ exitBlock = fgNewBBinRegion(BBJ_EHCATCHRET, 0, XTnum + 1, step); - assert(step->bbJumpKind == BBJ_ALWAYS || step->bbJumpKind == BBJ_EHCATCHRET); + assert(step->KindIs(BBJ_ALWAYS, BBJ_EHCATCHRET)); step->bbJumpDest = exitBlock; // the previous step (maybe a call to a nested finally, or a nested catch // exit) returns to this block step->bbJumpDest->bbRefs++; @@ -10874,7 +10874,7 @@ void Compiler::impImportLeave(BasicBlock* block) // never returns to the call-to-finally call, and the finally-protected 'try' region doesn't appear on // stack walks.) - assert(step->bbJumpKind == BBJ_ALWAYS || step->bbJumpKind == BBJ_EHCATCHRET); + assert(step->KindIs(BBJ_ALWAYS, BBJ_EHCATCHRET)); #if FEATURE_EH_CALLFINALLY_THUNKS if (step->bbJumpKind == BBJ_EHCATCHRET) diff --git a/src/coreclr/jit/lir.cpp b/src/coreclr/jit/lir.cpp index 97f9e4f4807d2..81d03b93f7b34 100644 --- a/src/coreclr/jit/lir.cpp +++ b/src/coreclr/jit/lir.cpp @@ -1636,7 +1636,7 @@ void LIR::InsertBeforeTerminator(BasicBlock* block, LIR::Range&& range) LIR::Range& blockRange = LIR::AsRange(block); GenTree* insertionPoint = nullptr; - if ((block->bbJumpKind == BBJ_COND) || (block->bbJumpKind == BBJ_SWITCH) || (block->bbJumpKind == BBJ_RETURN)) + if (block->KindIs(BBJ_COND, BBJ_SWITCH, BBJ_RETURN)) { insertionPoint = blockRange.LastNode(); assert(insertionPoint != nullptr); diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp index c206249a43740..bdd8d763aa4c7 100644 --- a/src/coreclr/jit/loopcloning.cpp +++ b/src/coreclr/jit/loopcloning.cpp @@ -767,7 +767,7 @@ BasicBlock* LoopCloneContext::CondToStmtInBlock(Compiler* { noway_assert(conds.Size() > 0); assert(slowHead != nullptr); - assert((insertAfter->bbJumpKind == BBJ_NONE) || (insertAfter->bbJumpKind == BBJ_COND)); + assert(insertAfter->KindIs(BBJ_NONE, BBJ_COND)); // Choose how to generate the conditions const bool generateOneConditionPerBlock = true; @@ -1847,7 +1847,7 @@ void Compiler::optCloneLoop(unsigned loopInd, LoopCloneContext* context) // X BasicBlock* h = loop.lpHead; - if (h->bbJumpKind != BBJ_NONE && h->bbJumpKind != BBJ_ALWAYS) + if (!h->KindIs(BBJ_NONE, BBJ_ALWAYS)) { // Make a new block to be the unique entry to the loop. JITDUMP("Create new unique single-successor entry to loop\n"); diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 9308836ff78fc..3e7177c48a99a 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -6415,7 +6415,7 @@ void LinearScan::insertUpperVectorRestore(GenTree* tree, else { JITDUMP("at end of " FMT_BB ":\n", block->bbNum); - if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_SWITCH) + if (block->KindIs(BBJ_COND, BBJ_SWITCH)) { noway_assert(!blockRange.IsEmpty()); @@ -6427,7 +6427,7 @@ void LinearScan::insertUpperVectorRestore(GenTree* tree, } else { - assert(block->bbJumpKind == BBJ_NONE || block->bbJumpKind == BBJ_ALWAYS); + assert(block->KindIs(BBJ_NONE, BBJ_ALWAYS)); blockRange.InsertAtEnd(LIR::SeqTree(compiler, simdNode)); } } @@ -7291,7 +7291,7 @@ void LinearScan::insertMove( { // Put the copy at the bottom GenTree* lastNode = blockRange.LastNode(); - if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_SWITCH) + if (block->KindIs(BBJ_COND, BBJ_SWITCH)) { noway_assert(!blockRange.IsEmpty()); @@ -7359,7 +7359,7 @@ void LinearScan::insertSwap( { // Put the copy at the bottom // If there's a branch, make an embedded statement that executes just prior to the branch - if (block->bbJumpKind == BBJ_COND || block->bbJumpKind == BBJ_SWITCH) + if (block->KindIs(BBJ_COND, BBJ_SWITCH)) { noway_assert(!blockRange.IsEmpty()); @@ -7371,7 +7371,7 @@ void LinearScan::insertSwap( } else { - assert(block->bbJumpKind == BBJ_NONE || block->bbJumpKind == BBJ_ALWAYS); + assert(block->KindIs(BBJ_NONE, BBJ_ALWAYS)); blockRange.InsertAtEnd(std::move(swapRange)); } } diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 77394d4b5d1e4..b5465259f1719 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -302,7 +302,7 @@ void Compiler::optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk) } // We only consider back-edges that are BBJ_COND or BBJ_ALWAYS for loops. - if ((predBlock->bbJumpKind != BBJ_COND) && (predBlock->bbJumpKind != BBJ_ALWAYS)) + if (!predBlock->KindIs(BBJ_COND, BBJ_ALWAYS)) { continue; } @@ -580,12 +580,12 @@ void Compiler::optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmar reportAfter(); } - if ((skipUnmarkLoop == false) && // - ((block->bbJumpKind == BBJ_ALWAYS) || (block->bbJumpKind == BBJ_COND)) && // - block->bbJumpDest->isLoopHead() && // - (block->bbJumpDest->bbNum <= block->bbNum) && // - fgDomsComputed && // - (fgCurBBEpochSize == fgDomBBcount + 1) && // + if ((skipUnmarkLoop == false) && // + block->KindIs(BBJ_ALWAYS, BBJ_COND) && // + block->bbJumpDest->isLoopHead() && // + (block->bbJumpDest->bbNum <= block->bbNum) && // + fgDomsComputed && // + (fgCurBBEpochSize == fgDomBBcount + 1) && // fgReachable(block->bbJumpDest, block)) { optUnmarkLoopBlocks(block->bbJumpDest, block); @@ -1685,9 +1685,7 @@ class LoopSearch return false; } - if ((bottom->bbJumpKind == BBJ_EHFINALLYRET) || (bottom->bbJumpKind == BBJ_EHFILTERRET) || - (bottom->bbJumpKind == BBJ_EHCATCHRET) || (bottom->bbJumpKind == BBJ_CALLFINALLY) || - (bottom->bbJumpKind == BBJ_SWITCH)) + if (bottom->KindIs(BBJ_EHFINALLYRET, BBJ_EHFILTERRET, BBJ_EHCATCHRET, BBJ_CALLFINALLY, BBJ_SWITCH)) { // BBJ_EHFINALLYRET, BBJ_EHFILTERRET, BBJ_EHCATCHRET, and BBJ_CALLFINALLY can never form a loop. // BBJ_SWITCH that has a backward jump appears only for labeled break. @@ -1829,7 +1827,7 @@ class LoopSearch } } // Can we fall through into the loop? - else if (head->bbJumpKind == BBJ_NONE || head->bbJumpKind == BBJ_COND) + else if (head->KindIs(BBJ_NONE, BBJ_COND)) { // The ENTRY is at the TOP (a do-while loop) return top; @@ -2139,7 +2137,7 @@ class LoopSearch return nullptr; } - if ((newMoveAfter->bbJumpKind == BBJ_ALWAYS) || (newMoveAfter->bbJumpKind == BBJ_COND)) + if (newMoveAfter->KindIs(BBJ_ALWAYS, BBJ_COND)) { unsigned int destNum = newMoveAfter->bbJumpDest->bbNum; if ((destNum >= top->bbNum) && (destNum <= bottom->bbNum) && !loopBlocks.IsMember(destNum)) @@ -2329,8 +2327,8 @@ class LoopSearch } // Make sure we don't leave around a goto-next unless it's marked KEEP_BBJ_ALWAYS. - assert(((block->bbJumpKind != BBJ_COND) && (block->bbJumpKind != BBJ_ALWAYS)) || - (block->bbJumpDest != newNext) || ((block->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0)); + assert(!block->KindIs(BBJ_COND, BBJ_ALWAYS) || (block->bbJumpDest != newNext) || + ((block->bbFlags & BBF_KEEP_BBJ_ALWAYS) != 0)); return newBlock; } diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp index 4a475806148b7..56ad0323fd6de 100644 --- a/src/coreclr/jit/rangecheck.cpp +++ b/src/coreclr/jit/rangecheck.cpp @@ -869,7 +869,7 @@ void RangeCheck::MergeAssertion(BasicBlock* block, GenTree* op, Range* pRange DE JITDUMP("Merge assertions from pred " FMT_BB " edge: ", pred->bbNum); Compiler::optDumpAssertionIndices(assertions, "\n"); } - else if ((pred->bbJumpKind == BBJ_COND || pred->bbJumpKind == BBJ_ALWAYS) && pred->bbJumpDest == block) + else if (pred->KindIs(BBJ_COND, BBJ_ALWAYS) && (pred->bbJumpDest == block)) { if (m_pCompiler->bbJtrueAssertionOut != nullptr) { From 0266f034221188bc7d0156ba76a571c71885c68f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 18 Jan 2022 11:04:48 -0800 Subject: [PATCH 022/308] Fix decoding errors (#63929) --- src/coreclr/scripts/jitutil.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/scripts/jitutil.py b/src/coreclr/scripts/jitutil.py index c7906124b45d4..9552869dffa97 100644 --- a/src/coreclr/scripts/jitutil.py +++ b/src/coreclr/scripts/jitutil.py @@ -119,15 +119,15 @@ def run_command(command_to_run, _cwd=None, _exit_on_fail=False, _output_file=Non if proc.poll() is not None: break if output: - output_str = output.strip().decode("utf-8") + output_str = output.strip().decode("utf-8", errors='replace') print(output_str) of.write(output_str + "\n") else: command_stdout, command_stderr = proc.communicate() if len(command_stdout) > 0: - print(command_stdout.decode("utf-8")) + print(command_stdout.decode("utf-8", errors='replace')) if len(command_stderr) > 0: - print(command_stderr.decode("utf-8")) + print(command_stderr.decode("utf-8", errors='replace')) return_code = proc.returncode if _exit_on_fail and return_code != 0: From b0de23b1677fbaf4fbcde814ec0bad6f60094920 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Tue, 18 Jan 2022 13:37:41 -0800 Subject: [PATCH 023/308] Revert "Enable GC Regions by default (#59283)" (#63935) This reverts commit cf91716. This looks to be creating a lot of crashes in a lot of different unit tests on Mac. Reverting seems to halt the Mac failures (see https://dev.azure.com/dnceng/public/_build/results?buildId=1557880) Fixes #63439 --- src/coreclr/gc/gcpriv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h index 14bf3ef290889..bed8857bc8328 100644 --- a/src/coreclr/gc/gcpriv.h +++ b/src/coreclr/gc/gcpriv.h @@ -51,8 +51,8 @@ inline void FATAL_GC_ERROR() // // This means any empty regions can be freely used for any generation. For // Server GC we will balance regions between heaps. -// For now disable regions StandAlone GC builds -#if defined (HOST_64BIT) && !defined (BUILD_AS_STANDALONE) +// For now disable regions outside of StandAlone GC builds +#if defined (HOST_64BIT) && defined (BUILD_AS_STANDALONE) #define USE_REGIONS #endif //HOST_64BIT && BUILD_AS_STANDALONE From 83b52cdc310ebd77cddff7efd772a0800a403f47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Tue, 18 Jan 2022 23:13:58 +0100 Subject: [PATCH 024/308] [iOS/tvOS] Remove P/Invokes to libproc from System.Private.CoreLib (#63934) They aren't allowed by Apple when submitting to the App Store. Finishes https://github.com/dotnet/runtime/issues/61265 --- .../src/System.Private.CoreLib.Shared.projitems | 5 +++-- .../src/System/Environment.iOS.cs | 13 +++++++++++++ .../tests/System/EnvironmentTests.cs | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs 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 0a587f370875a..59796633cc4db 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 @@ -2188,12 +2188,13 @@ - + - + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.cs new file mode 100644 index 0000000000000..90512ca598bd8 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.iOS.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. + +using System.Runtime.InteropServices; + +namespace System +{ + public static partial class Environment + { + // iOS/tvOS aren't allowed to call libproc APIs so return 0 here, this also matches what we returned in earlier releases + public static long WorkingSet => 0; + } +} diff --git a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs index 415cafb9f02c2..5d2bf2785491f 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs @@ -236,7 +236,7 @@ public void Version_Valid() [Fact] public void WorkingSet_Valid() { - if (PlatformDetection.IsBrowser) + if (PlatformDetection.IsBrowser || PlatformDetection.IsiOS || PlatformDetection.IstvOS) Assert.Equal(0, Environment.WorkingSet); else Assert.True(Environment.WorkingSet > 0, "Expected positive WorkingSet value"); From 8d5f5267d33f7703c014cc89670f1f7aa47544f9 Mon Sep 17 00:00:00 2001 From: Andrii Kurdiumov Date: Wed, 19 Jan 2022 05:23:32 +0600 Subject: [PATCH 025/308] Update links to the project for DllImportGenerator (#63940) As coincidence, I think `RestoreAdditionalProjectSources` not needed anymore. --- .../gen/DllImportGenerator/DllImportGenerator.csproj | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportGenerator.csproj b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportGenerator.csproj index 85f7a7c0c00bc..b3baca91121a9 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportGenerator.csproj +++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportGenerator.csproj @@ -16,8 +16,8 @@ Microsoft - https://github.com/dotnet/runtimelab/tree/feature/DllImportGenerator - https://github.com/dotnet/runtimelab/tree/feature/DllImportGenerator + https://github.com/dotnet/runtime/tree/main/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator + https://github.com/dotnet/runtime/ false DllImportGenerator Summary of changes made in this release of the package. @@ -26,10 +26,6 @@ true - - https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json ;$(RestoreAdditionalProjectSources) - - From d2844ebf57568de4926517c521a94a721d9c26a8 Mon Sep 17 00:00:00 2001 From: Bradley Grainger Date: Tue, 18 Jan 2022 15:32:16 -0800 Subject: [PATCH 026/308] Add `UnicodeRange.ArabicExtendedB` (#63901) --- .../ref/System.Text.Encodings.Web.cs | 1 + .../src/System/Text/Unicode/UnicodeRanges.generated.cs | 9 +++++++++ .../tests/UnicodeRangesTests.generated.cs | 1 + 3 files changed, 11 insertions(+) diff --git a/src/libraries/System.Text.Encodings.Web/ref/System.Text.Encodings.Web.cs b/src/libraries/System.Text.Encodings.Web/ref/System.Text.Encodings.Web.cs index f38e07bfbb2a5..72e30ff774322 100644 --- a/src/libraries/System.Text.Encodings.Web/ref/System.Text.Encodings.Web.cs +++ b/src/libraries/System.Text.Encodings.Web/ref/System.Text.Encodings.Web.cs @@ -83,6 +83,7 @@ public static partial class UnicodeRanges public static System.Text.Unicode.UnicodeRange AlphabeticPresentationForms { get { throw null; } } public static System.Text.Unicode.UnicodeRange Arabic { get { throw null; } } public static System.Text.Unicode.UnicodeRange ArabicExtendedA { get { throw null; } } + public static System.Text.Unicode.UnicodeRange ArabicExtendedB { get { throw null; } } public static System.Text.Unicode.UnicodeRange ArabicPresentationFormsA { get { throw null; } } public static System.Text.Unicode.UnicodeRange ArabicPresentationFormsB { get { throw null; } } public static System.Text.Unicode.UnicodeRange ArabicSupplement { get { throw null; } } diff --git a/src/libraries/System.Text.Encodings.Web/src/System/Text/Unicode/UnicodeRanges.generated.cs b/src/libraries/System.Text.Encodings.Web/src/System/Text/Unicode/UnicodeRanges.generated.cs index c95e2ebc71bca..5ab03229dc03d 100644 --- a/src/libraries/System.Text.Encodings.Web/src/System/Text/Unicode/UnicodeRanges.generated.cs +++ b/src/libraries/System.Text.Encodings.Web/src/System/Text/Unicode/UnicodeRanges.generated.cs @@ -190,6 +190,15 @@ public static partial class UnicodeRanges public static UnicodeRange SyriacSupplement => _u0860 ?? CreateRange(ref _u0860, first: '\u0860', last: '\u086F'); private static UnicodeRange? _u0860; + /// + /// A corresponding to the 'Arabic Extended-B' Unicode block (U+0870..U+089F). + /// + /// + /// See https://www.unicode.org/charts/PDF/U0870.pdf for the full set of characters in this block. + /// + public static UnicodeRange ArabicExtendedB => _u0870 ?? CreateRange(ref _u0870, first: '\u0870', last: '\u089F'); + private static UnicodeRange? _u0870; + /// /// A corresponding to the 'Arabic Extended-A' Unicode block (U+08A0..U+08FF). /// diff --git a/src/libraries/System.Text.Encodings.Web/tests/UnicodeRangesTests.generated.cs b/src/libraries/System.Text.Encodings.Web/tests/UnicodeRangesTests.generated.cs index fcf41b771ff10..69479ad534768 100644 --- a/src/libraries/System.Text.Encodings.Web/tests/UnicodeRangesTests.generated.cs +++ b/src/libraries/System.Text.Encodings.Web/tests/UnicodeRangesTests.generated.cs @@ -32,6 +32,7 @@ public static partial class UnicodeRangesTests new object[] { '\u0800', '\u083F', nameof(UnicodeRanges.Samaritan) }, new object[] { '\u0840', '\u085F', nameof(UnicodeRanges.Mandaic) }, new object[] { '\u0860', '\u086F', nameof(UnicodeRanges.SyriacSupplement) }, + new object[] { '\u0870', '\u089F', nameof(UnicodeRanges.ArabicExtendedB) }, new object[] { '\u08A0', '\u08FF', nameof(UnicodeRanges.ArabicExtendedA) }, new object[] { '\u0900', '\u097F', nameof(UnicodeRanges.Devanagari) }, new object[] { '\u0980', '\u09FF', nameof(UnicodeRanges.Bengali) }, From c50185bb24ace683f2ce6c5e4351ce2104bd1349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksey=20Kliger=20=28=CE=BBgeek=29?= Date: Tue, 18 Jan 2022 18:40:42 -0500 Subject: [PATCH 027/308] [mono] Hot Reload: initial push to support adding lambdas (#63513) Adds support for: * Adding static lambdas to existing methods, whether or not they had lambdas before. * Adding lambdas that capture `this` to existing methods that already captured `this` before * Adding new static or instance methods to existing types * Adding static fields to existing types * Adding new types (note that adding instance fields currently will fail. It'll go in in a future PR that will address https://github.com/dotnet/runtime/issues/63643). Note that reflection on newly added members isn't tested yet and likely doesn't work. Fixes https://github.com/dotnet/runtime/issues/50249 Contributes to https://github.com/dotnet/runtime/issues/57365 * Add AddStaticField test; cleanup AddLambdaCapturingThis * Add AddNestedClass testcase * hot_reload: add a comment about remaining work * move per-class metadata update info to MonoClassMetadataUpdateInfo Use a property on the class instead of a hash table in the baseline image to keep track of added fields and methods * Cleanup pass1 to check add/update against prior gen Instead of the baseline image * adding a class Working on making mono_metadata_nested_in_typedef do the right thing for nested classes Contributes to making mono_class_create_from_typedef do the right thing for nested classes. * fix: correct mutant table population when the baseline table is empty In that case the table row_size and size_bitmap of the baseline are both 0, so offset calculations don't work. In that case when we know we need to add rows to the mutant table, use the uncompressed layout (32-bit columns, always) same as the EnC delta. * Calling new methods on a nested class works * adding fields Doesn't work yet. Dies in mono_class_get_field, called from mono_field_from_token_checked. The problem we're going to have to deal with is that unlike MonoMethod which is allocated upon lookup, the MonoClassFields of a class are allocated contiguously in class initialization. And there are not really enough fields in MonoClassField to indicate "this is not an ordinary field, don't do pointer arithmetic with it". One idea is to steal a bit from MonoClassField:parent and always check it as a trigger to go on a slower path. * adding static fields Rework the delta info to store info about "members" (rather than methods and fields separately). Add a MonoClassMetadataUpdateField subclass of MonoClassField that has extra info. Add new component methods to go from a MonoClassField to an index, and from a field token to a MonoClassField. Set MonoClassField:offset to -1 to generally go down the "special static field" codepath since we will need to do some one-off work to make a storage area for added static fields. Instance fields are not supported yet and error out during the update pass for now. * fix custom attribute lookups on new classes/methods/fields * Add a sketch of HotReloadInstanceFieldTable This is a class that manages the lifetime for added instance fields for reference types that had new fields added to them by EnC It's basically ConditionalWeakTable> where the outer key is the object instance, the inner key is the fielddef token, and the value is a Store. The store has a single object? field which the location where the field's value will go. For reference types this is the reference directly, and for valuetypes and primitives, this is the boxed object (so to get the actual storage address you need to add sizeof(MonoObject)). * mono_metadata_update_get_static_field_addr two reminders: 1. The static field area needs to be GC-visible 2. We should really handle added fields on un-inited classes by allocating the instances in the normal way - in the layout algorithm. * Free MonoClassMetadataUpdateInfo when BaselineInfo is destroyed * placeholder struct for runtime class data; instance offset placeholder * static field storage Need to store the fields in a GC root, and in pinned allocations. * Implement hot_reload_get_static_field_addr() * Add mono_metadata_update_find_method_by_name Now we can find .cctor This is enough that a basic sample with an added static lambda works * Fix infinite loop * fix build * fix dynamic components builds * fix windows build * Fix inadvertent fallthru in previous fix * Report new capabilities NewTypeDefinition is not completely functional because adding instance fields is not supported yet. But adding classes with only static methods works. * tests: describe what existing tests do, add placeholder static lambda test * tests: Add AddStaticLambda test case Adding a brand new static lambda to an existing method body is supported * Destroy the runtime part of MonoClassMetadataUpdateInfo, too * rename Mono.HotReload file it has more classes than just the instance table * tests: add ActiveIssue for supporting adding instance fields * ifdef out Mono.HotReload.InstanceFieldTable it's not ready yet * Remove get_added_members from hot reload component interface Doesn't seem necessary to expose this yet. It's only used in hot_reload.c right now * Change the AddStaticLambda sample to use Func To check that lambdas with parameters work * Use a mempool allocated GSlist for the added members This avoids invalidating iterators in case we add members on one thread while another thread is iterating. If it turns out we need random access, we can switch to a GArray with locking. But so far we only ever iterate. * Use mono_get_corlib instead of passing MonoDefaults to hot_reload * use normal GENERATE_TRY_GET_CLASS_WITH_CACHE * [metadata] make m_field_set_parent and m_field_set_meta_flags inline m_ prefix functions are supposed to be inline --- .../AddLambdaCapturingThis.cs | 22 +- .../AddLambdaCapturingThis_v1.cs | 28 +- .../AddNestedClass.cs | 20 + .../AddNestedClass_v1.cs | 29 + ...ata.ApplyUpdate.Test.AddNestedClass.csproj | 11 + .../deltascript.json | 6 + .../AddStaticField.cs | 22 + .../AddStaticField_v1.cs | 25 + ...ata.ApplyUpdate.Test.AddStaticField.csproj | 11 + .../deltascript.json | 6 + .../AddStaticLambda.cs | 18 + .../AddStaticLambda_v1.cs | 18 + ...ta.ApplyUpdate.Test.AddStaticLambda.csproj | 11 + .../deltascript.json | 6 + .../tests/ApplyUpdateTest.cs | 96 ++- .../tests/System.Runtime.Loader.Tests.csproj | 3 + .../System.Private.CoreLib.csproj | 1 + .../src/ILLink/ILLink.Descriptors.xml | 3 + .../src/Mono/HotReload.cs | 114 +++ .../Reflection/Metadata/MetadataUpdater.cs | 3 +- src/mono/mono/component/CMakeLists.txt | 1 + .../mono/component/hot_reload-internals.h | 53 ++ src/mono/mono/component/hot_reload-stub.c | 65 +- src/mono/mono/component/hot_reload.c | 663 +++++++++++++++--- src/mono/mono/component/hot_reload.h | 9 +- src/mono/mono/metadata/class-accessors.c | 64 +- src/mono/mono/metadata/class-init.c | 61 +- src/mono/mono/metadata/class-inlines.h | 14 + src/mono/mono/metadata/class-internals.h | 22 +- src/mono/mono/metadata/class.c | 36 +- src/mono/mono/metadata/custom-attrs.c | 19 +- src/mono/mono/metadata/loader-internals.h | 12 + src/mono/mono/metadata/metadata-update.c | 35 + src/mono/mono/metadata/metadata-update.h | 16 + src/mono/mono/metadata/metadata.c | 30 +- src/mono/mono/metadata/object-internals.h | 2 +- src/mono/mono/metadata/object.c | 4 + src/mono/mono/utils/mono-error-internals.h | 1 + 38 files changed, 1366 insertions(+), 194 deletions(-) create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/AddNestedClass.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/AddNestedClass_v1.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass.csproj create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/deltascript.json create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/AddStaticField.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/AddStaticField_v1.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField.csproj create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/deltascript.json create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/AddStaticLambda.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/AddStaticLambda_v1.cs create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda.csproj create mode 100644 src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/deltascript.json create mode 100644 src/mono/System.Private.CoreLib/src/Mono/HotReload.cs create mode 100644 src/mono/mono/component/hot_reload-internals.h diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis/AddLambdaCapturingThis.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis/AddLambdaCapturingThis.cs index 186144e290e35..a5ec0d11b1f5c 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis/AddLambdaCapturingThis.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis/AddLambdaCapturingThis.cs @@ -7,19 +7,21 @@ namespace System.Reflection.Metadata.ApplyUpdate.Test { public class AddLambdaCapturingThis { - public AddLambdaCapturingThis () { - field = "abcd"; - } + public AddLambdaCapturingThis() + { + field = "abcd"; + } - public string GetField => field; + public string GetField => field; - private string field; + private string field; - public string TestMethod () { - // capture 'this' but no locals - Func fn = s => field; - return "123"; - } + public string TestMethod() + { + // capture 'this' but no locals + Func fn = s => field; + return "123"; + } } } diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis/AddLambdaCapturingThis_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis/AddLambdaCapturingThis_v1.cs index 22dd869021dc3..44ff73ab1d591 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis/AddLambdaCapturingThis_v1.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis/AddLambdaCapturingThis_v1.cs @@ -7,23 +7,21 @@ namespace System.Reflection.Metadata.ApplyUpdate.Test { public class AddLambdaCapturingThis { - public AddLambdaCapturingThis () { - field = "abcd"; - } + public AddLambdaCapturingThis() + { + field = "abcd"; + } - public string GetField => field; + public string GetField => field; - private string field; - - public string TestMethod () { - // capture 'this' but no locals - Func fn = s => NewMethod (s + field, 42); - return fn ("123"); - } - - private string NewMethod (string s, int i) { - return i.ToString() + s; - } + private string field; + public string TestMethod() + { + // capture 'this' but no locals + Func fn = s => field; + Func fn2 = s => "42" + s + field; + return fn2 ("123"); + } } } diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/AddNestedClass.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/AddNestedClass.cs new file mode 100644 index 0000000000000..d5bd6ce27fd0e --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/AddNestedClass.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. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class AddNestedClass + { + public AddNestedClass() + { + } + + public string TestMethod() + { + return "123"; + } + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/AddNestedClass_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/AddNestedClass_v1.cs new file mode 100644 index 0000000000000..04fc6992631d9 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/AddNestedClass_v1.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. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class AddNestedClass + { + public AddNestedClass() + { + } + + public string TestMethod() + { + var n = new Nested(); + n.f = "123"; + return n.M(); + } + + private class Nested { + public Nested() { } + internal string f; + public string M () { + return f + "456"; + } + } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass.csproj new file mode 100644 index 0000000000000..26f3348462094 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass.csproj @@ -0,0 +1,11 @@ + + + System.Runtime.Loader.Tests + $(NetCoreAppCurrent) + true + deltascript.json + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/deltascript.json b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/deltascript.json new file mode 100644 index 0000000000000..e70a3b3bbafbc --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass/deltascript.json @@ -0,0 +1,6 @@ +{ + "changes": [ + {"document": "AddNestedClass.cs", "update": "AddNestedClass_v1.cs"}, + ] +} + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/AddStaticField.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/AddStaticField.cs new file mode 100644 index 0000000000000..6ac1360c3581b --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/AddStaticField.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. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class AddStaticField + { + public AddStaticField () { + } + + public string GetField => s_field; + + private static string s_field; + + public void TestMethod () { + s_field = "abcd"; + } + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/AddStaticField_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/AddStaticField_v1.cs new file mode 100644 index 0000000000000..f9282469a4fce --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/AddStaticField_v1.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. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class AddStaticField + { + public AddStaticField () { + } + + public string GetField => s_field2; + + private static string s_field; + + private static string s_field2; + + public void TestMethod () { + s_field = "spqr"; + s_field2 = "4567"; + } + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField.csproj new file mode 100644 index 0000000000000..0a3f60146cac3 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField.csproj @@ -0,0 +1,11 @@ + + + System.Runtime.Loader.Tests + $(NetCoreAppCurrent) + true + deltascript.json + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/deltascript.json b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/deltascript.json new file mode 100644 index 0000000000000..3c0d7a0fc6866 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField/deltascript.json @@ -0,0 +1,6 @@ +{ + "changes": [ + {"document": "AddStaticField.cs", "update": "AddStaticField_v1.cs"}, + ] +} + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/AddStaticLambda.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/AddStaticLambda.cs new file mode 100644 index 0000000000000..9e759e6075b5b --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/AddStaticLambda.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. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class AddStaticLambda + { + public string TestMethod() + { + return "abcd"; + } + + public string Double(Func f) => f("") + f("1"); + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/AddStaticLambda_v1.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/AddStaticLambda_v1.cs new file mode 100644 index 0000000000000..6f9e94b08a7f4 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/AddStaticLambda_v1.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. +using System; + + +namespace System.Reflection.Metadata.ApplyUpdate.Test +{ + public class AddStaticLambda + { + public string TestMethod() + { + return Double(static (s) => s + "abcd"); + } + + public string Double(Func f) => f("") + f("1"); + + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda.csproj b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda.csproj new file mode 100644 index 0000000000000..3b402585aa298 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda.csproj @@ -0,0 +1,11 @@ + + + System.Runtime.Loader.Tests + $(NetCoreAppCurrent) + true + deltascript.json + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/deltascript.json b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/deltascript.json new file mode 100644 index 0000000000000..1d60513f4a43f --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdate/System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda/deltascript.json @@ -0,0 +1,6 @@ +{ + "changes": [ + {"document": "AddStaticLambda.cs", "update": "AddStaticLambda_v1.cs"}, + ] +} + diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index dd5c49c396335..9e28894b6bbf3 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -71,6 +71,7 @@ void LambdaBodyChange() [ActiveIssue("https://github.com/dotnet/runtime/issues/54617", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))] void LambdaCapturesThis() { + // Tests that changes to the body of a lambda that captures 'this' is supported. ApplyUpdateUtil.TestCase(static () => { var assm = typeof (ApplyUpdate.Test.LambdaCapturesThis).Assembly; @@ -263,25 +264,92 @@ public void AsyncMethodChanges() }); } - [ActiveIssue ("https://github.com/dotnet/runtime/issues/50249", TestRuntimes.Mono)] - [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))] - public static void TestAddLambdaCapturingThis() - { - ApplyUpdateUtil.TestCase(static () => - { - var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis).Assembly; + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))] + public static void TestAddLambdaCapturingThis() + { + // Test that adding a lambda that captures 'this' (to a method that already has a lambda that captures 'this') is supported + ApplyUpdateUtil.TestCase(static () => + { + var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis).Assembly; + + var x = new System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis(); + + Assert.Equal("123", x.TestMethod()); + + ApplyUpdateUtil.ApplyUpdate(assm); + + string result = x.TestMethod(); + Assert.Equal("42123abcd", result); + }); + } + + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))] + public static void TestAddStaticField() + { + // Test that adding a new static field to an existing class is supported + ApplyUpdateUtil.TestCase(static () => + { + var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField).Assembly; + + var x = new System.Reflection.Metadata.ApplyUpdate.Test.AddStaticField(); + + x.TestMethod(); + + Assert.Equal ("abcd", x.GetField); + + ApplyUpdateUtil.ApplyUpdate(assm); + + x.TestMethod(); + + string result = x.GetField; + Assert.Equal("4567", result); + }); + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/63643", TestRuntimes.Mono)] + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))] + public static void TestAddNestedClass() + { + // Test that adding a new nested class to an existing class is supported + ApplyUpdateUtil.TestCase(static () => + { + var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass).Assembly; + + var x = new System.Reflection.Metadata.ApplyUpdate.Test.AddNestedClass(); + + var r = x.TestMethod(); + + Assert.Equal ("123", r); + + ApplyUpdateUtil.ApplyUpdate(assm); + + r = x.TestMethod(); - var x = new System.Reflection.Metadata.ApplyUpdate.Test.AddLambdaCapturingThis(); + Assert.Equal("123456", r); + }); + } + + [ConditionalFact(typeof(ApplyUpdateUtil), nameof(ApplyUpdateUtil.IsSupported))] + public static void TestAddStaticLambda() + { + // Test that adding a new static lambda to an existing method body is supported + ApplyUpdateUtil.TestCase(static () => + { + var assm = typeof(System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda).Assembly; - Assert.Equal("123", x.TestMethod()); + var x = new System.Reflection.Metadata.ApplyUpdate.Test.AddStaticLambda(); - ApplyUpdateUtil.ApplyUpdate(assm); + var r = x.TestMethod(); - string result = x.TestMethod(); - Assert.Equal("42123abcd", result); - }); - } + Assert.Equal ("abcd", r); + ApplyUpdateUtil.ApplyUpdate(assm); + + r = x.TestMethod(); + + Assert.Equal("abcd1abcd", r); + }); + } class NonRuntimeAssembly : Assembly { diff --git a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj index d678320e01740..e21bc7e673f5f 100644 --- a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj +++ b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj @@ -53,6 +53,9 @@ + + + diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index cb143f5d381be..da99b06e81b8e 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -290,6 +290,7 @@ + diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml index 4a8ffce034109..2f578bdf50ab6 100644 --- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml +++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml @@ -647,5 +647,8 @@ + + + diff --git a/src/mono/System.Private.CoreLib/src/Mono/HotReload.cs b/src/mono/System.Private.CoreLib/src/Mono/HotReload.cs new file mode 100644 index 0000000000000..c1cd977ceb6b2 --- /dev/null +++ b/src/mono/System.Private.CoreLib/src/Mono/HotReload.cs @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Mono.HotReload; + +// TODO: this is just a sketch, instance field additions aren't supported by Mono yet until https://github.com/dotnet/runtime/issues/63643 is fixed +#if false +internal class InstanceFieldTable +{ + // Q: Does CoreCLR EnC allow adding fields to a valuetype? + // A: No, see EEClass::AddField - if the type has layout or is a valuetype, you can't add fields to it. + + // See EnCAddedField::Allocate for a description of the CoreCLR version of this. + // + // This is substantially the same design, except instead of using dependent handles + // (ephemerons) directly from native (storing a linked list of ephemerons off the sync block + // of the instance), we use a ConditionalWeakTable from managed that's keyed on the + // instances (so the value dies when the instance dies) and whose value is another + // dictionary, keyed on the fielddef token with values that are storage for the actual field values. + // + // for reference types, the storage just stores it as an object. For valuetypes and + // primitives, the storage stores the value as a boxed value. + // + // The whole thing is basically a ConditionalWeakTable> but + // with locking on the inner dictionary. + // + + // This should behave somewhat like EditAndContinueModule::ResolveOrAddField (and EnCAddedField::Allocate) + // we want to create some storage space that has the same lifetime as the instance object. + + // // TODO: should the linker keep this if Hot Reload stuff is enabled? Hot Reload is predicated on the linker not rewriting user modules, but maybe trimming SPC is ok? + internal static FieldStore GetInstanceFieldFieldStore(object inst, RuntimeTypeHandle type, uint fielddef_token) + => _singleton.GetOrCreateInstanceFields(inst).LookupOrAdd(type, fielddef_token); + + private static InstanceFieldTable _singleton = new(); + + private ConditionalWeakTable _table; + + private InstanceFieldTable() + { + _table = new(); + } + + private InstanceFields GetOrCreateInstanceFields(object key) + => _table.GetOrCreateValue(key); + + private class InstanceFields + { + private Dictionary _fields; + private object _lock; + + public InstanceFields() + { + _fields = new(); + _lock = new(); + } + + public FieldStore LookupOrAdd(RuntimeTypeHandle type, uint key) + { + if (_fields.TryGetValue(key, out FieldStore? v)) + return v; + lock (_lock) + { + if (_fields.TryGetValue (key, out FieldStore? v2)) + return v2; + + FieldStore s = FieldStore.Create(type); + _fields.Add(key, s); + return s; + } + } + } + +} +#endif + +// This is similar to System.Diagnostics.EditAndContinueHelper in CoreCLR, except instead of +// having the allocation logic in native (see EditAndContinueModule::ResolveOrAllocateField, +// and EnCSyncBlockInfo::ResolveOrAllocateField), the logic is in managed. +// +// Additionally Mono uses this for storing added static fields. +[StructLayout(LayoutKind.Sequential)] +internal class FieldStore +{ + // keep in sync with hot_reload-internals.h + private object? _loc; + + private FieldStore (object? loc) + { + _loc = loc; + } + + public object? Location => _loc; + + public static FieldStore Create (RuntimeTypeHandle type) + { + Type t = Type.GetTypeFromHandle(type) ?? throw new ArgumentException(nameof(type), "Type handle was null"); + object? loc; + if (t.IsPrimitive || t.IsValueType) + loc = RuntimeHelpers.GetUninitializedObject(t); + else if (t.IsClass || t.IsInterface) + loc = null; + else + throw new ArgumentException("EnC: Expected a primitive, valuetype, class or interface field"); + /* FIXME: do we want FieldStore to be pinned? */ + return new FieldStore(loc); + } +} diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs index 973eb43d91ca7..afac9bf5e88da 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Metadata/MetadataUpdater.cs @@ -55,7 +55,8 @@ public static void ApplyUpdate(Assembly assembly, ReadOnlySpan metadataDel private static string InitializeApplyUpdateCapabilities() { - return ApplyUpdateEnabled(justComponentCheck: 1) != 0 ? "Baseline" : string.Empty ; + const string caps = "Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition"; + return ApplyUpdateEnabled(justComponentCheck: 1) != 0 ? caps : string.Empty ; } [MethodImpl (MethodImplOptions.InternalCall)] diff --git a/src/mono/mono/component/CMakeLists.txt b/src/mono/mono/component/CMakeLists.txt index 595f6d889442b..faab69a9b68e9 100644 --- a/src/mono/mono/component/CMakeLists.txt +++ b/src/mono/mono/component/CMakeLists.txt @@ -41,6 +41,7 @@ list(APPEND components ) set(${MONO_HOT_RELOAD_COMPONENT_NAME}-sources ${MONO_COMPONENT_PATH}/hot_reload.c + ${MONO_COMPONENT_PATH}/hot_reload-internals.h ${MONO_COMPONENT_PATH}/hot_reload.h ) set(${MONO_HOT_RELOAD_COMPONENT_NAME}-stub-sources diff --git a/src/mono/mono/component/hot_reload-internals.h b/src/mono/mono/component/hot_reload-internals.h new file mode 100644 index 0000000000000..36d3606e17e4a --- /dev/null +++ b/src/mono/mono/component/hot_reload-internals.h @@ -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. +// + +#ifndef _MONO_COMPONENT_HOT_RELOAD_INTERNALS_H +#define _MONO_COMPONENT_HOT_RELOAD_INTERNALS_H + +#include +#include "mono/metadata/object-forward.h" +#include "mono/metadata/metadata-internals.h" +#include "mono/metadata/class-internals.h" + +/* Execution-time info for an updated class. */ +typedef struct _MonoClassRuntimeMetadataUpdateInfo { + MonoCoopMutex static_fields_lock; /* protects the static_fields hashtable. Values can be used outside the lock (since they're allocated pinned). */ + MonoGHashTable *static_fields; /* key is field token, value is a pinned managed object: either a boxed valuetype (the static field address is the value address) or a Mono.HotReload.FieldStore object (in which case the static field address is the address of the _loc field in the object.) */ + gboolean inited; +} MonoClassRuntimeMetadataUpdateInfo; + +/* Class-specific metadata update info. See + * mono_class_get_metadata_update_info() Note that this info is associated with + * class _definitions_ that can be edited, so primitives, generic instances, + * arrays, pointers, etc do not have this info. + */ +struct _MonoClassMetadataUpdateInfo { + /* FIXME: use a struct that allocates out of the MonoClass mempool! or maybe add the GArray + * to the BaselineInfo for the image and cleanup from there. */ + GSList *added_members; /* a set of Method or Field table tokens of any methods or fields added to this class, allocated from the MonoClass mempool */ + + GPtrArray *added_fields; /* a set of MonoClassMetadataUpdateField* values for every added field. */ + + MonoClassRuntimeMetadataUpdateInfo runtime; +}; + + +/* Keep in sync with Mono.HotReload.FieldStore in managed */ +typedef struct _MonoHotReloadFieldStoreObject { + MonoObject object; + MonoObject *_loc; +} MonoHotReloadFieldStoreObject; + +typedef struct _MonoClassMetadataUpdateField { + MonoClassField field; + uint32_t generation; /* when this field was added */ + uint32_t token; /* the Field table token where this field was defined. (this won't make + * sense for generic instances, once EnC is supported there) */ + /* if non-zero the EnC update came before the parent class was initialized. The field is + * stored in the instance at this offset. MonoClassField:offset is -1. Not used for static + * fields. */ + int before_init_instance_offset; +} MonoClassMetadataUpdateField; + +#endif/*_MONO_COMPONENT_HOT_RELOAD_INTERNALS_H*/ diff --git a/src/mono/mono/component/hot_reload-stub.c b/src/mono/mono/component/hot_reload-stub.c index 6064a6a78f875..2377b948a7b0a 100644 --- a/src/mono/mono/component/hot_reload-stub.c +++ b/src/mono/mono/component/hot_reload-stub.c @@ -65,12 +65,27 @@ hot_reload_stub_has_modified_rows (const MonoTableInfo *table); static int hot_reload_stub_table_num_rows_slow (MonoImage *image, int table_index); -static GArray* -hot_reload_stub_get_added_methods (MonoClass *klass); - static uint32_t hot_reload_stub_method_parent (MonoImage *image, uint32_t method_index); +static void* +hot_reload_stub_metadata_linear_search (MonoImage *base_image, MonoTableInfo *base_table, const void *key, BinarySearchComparer comparer); + +static uint32_t +hot_reload_stub_field_parent (MonoImage *image, uint32_t field_index); + +static uint32_t +hot_reload_stub_get_field_idx (MonoClassField *field); + +static MonoClassField * +hot_reload_stub_get_field (MonoClass *klass, uint32_t fielddef_token); + +static gpointer +hot_reload_stub_get_static_field_addr (MonoClassField *field); + +static MonoMethod * +hot_reload_stub_find_method_by_name (MonoClass *klass, const char *name, int param_count, int flags, MonoError *error); + static MonoComponentHotReload fn_table = { { MONO_COMPONENT_ITF_VERSION, &hot_reload_stub_available }, &hot_reload_stub_set_fastpath_data, @@ -89,8 +104,13 @@ static MonoComponentHotReload fn_table = { &hot_reload_stub_get_updated_method_ppdb, &hot_reload_stub_has_modified_rows, &hot_reload_stub_table_num_rows_slow, - &hot_reload_stub_get_added_methods, &hot_reload_stub_method_parent, + &hot_reload_stub_metadata_linear_search, + &hot_reload_stub_field_parent, + &hot_reload_stub_get_field_idx, + &hot_reload_stub_get_field, + &hot_reload_stub_get_static_field_addr, + &hot_reload_stub_find_method_by_name, }; static bool @@ -200,18 +220,49 @@ hot_reload_stub_table_num_rows_slow (MonoImage *image, int table_index) g_assert_not_reached (); /* should always take the fast path */ } -static GArray* -hot_reload_stub_get_added_methods (MonoClass *klass) +static uint32_t +hot_reload_stub_method_parent (MonoImage *image, uint32_t method_index) +{ + return 0; +} + + +static void* +hot_reload_stub_metadata_linear_search (MonoImage *base_image, MonoTableInfo *base_table, const void *key, BinarySearchComparer comparer) { return NULL; } static uint32_t -hot_reload_stub_method_parent (MonoImage *image, uint32_t method_index) +hot_reload_stub_field_parent (MonoImage *image, uint32_t field_index) { return 0; } +static uint32_t +hot_reload_stub_get_field_idx (MonoClassField *field) +{ + return 0; +} + +static MonoClassField * +hot_reload_stub_get_field (MonoClass *klass, uint32_t fielddef_token) +{ + return NULL; +} + +static gpointer +hot_reload_stub_get_static_field_addr (MonoClassField *field) +{ + return NULL; +} + +static MonoMethod * +hot_reload_stub_find_method_by_name (MonoClass *klass, const char *name, int param_count, int flags, MonoError *error) +{ + return NULL; +} + MONO_COMPONENT_EXPORT_ENTRYPOINT MonoComponentHotReload * diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index bd8c3db635c88..e44ae56e5f4af 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -8,8 +8,11 @@ #include #include "mono/utils/mono-compiler.h" +#include "mono/component/hot_reload-internals.h" + #include #include "mono/metadata/assembly-internals.h" +#include "mono/metadata/mono-hash-internals.h" #include "mono/metadata/metadata-internals.h" #include "mono/metadata/metadata-update.h" #include "mono/metadata/object-internals.h" @@ -22,14 +25,18 @@ #include "mono/metadata/debug-internals.h" #include "mono/metadata/mono-debug.h" #include "mono/metadata/debug-mono-ppdb.h" +#include "mono/utils/bsearch.h" #include #include -#undef ALLOW_METHOD_ADD +#define ALLOW_CLASS_ADD +#define ALLOW_METHOD_ADD +#define ALLOW_FIELD_ADD +typedef struct _BaselineInfo BaselineInfo; typedef struct _DeltaInfo DeltaInfo; static void @@ -89,12 +96,32 @@ hot_reload_has_modified_rows (const MonoTableInfo *table); static int hot_reload_table_num_rows_slow (MonoImage *image, int table_index); -static GArray* -hot_reload_get_added_methods (MonoClass *klass); +static GSList* +hot_reload_get_added_members (MonoClass *klass); static uint32_t hot_reload_method_parent (MonoImage *base, uint32_t method_token); +static void* +hot_reload_metadata_linear_search (MonoImage *base_image, MonoTableInfo *base_table, const void *key, BinarySearchComparer comparer); + +static uint32_t +hot_reload_field_parent (MonoImage *base, uint32_t field_token); + +static uint32_t +hot_reload_get_field_idx (MonoClassField *field); + +static MonoClassField * +hot_reload_get_field (MonoClass *klass, uint32_t fielddef_token); + +static gpointer +hot_reload_get_static_field_addr (MonoClassField *field); + +static MonoMethod * +hot_reload_find_method_by_name (MonoClass *klass, const char *name, int param_count, int flags, MonoError *error); + +static MonoClassMetadataUpdateField * +metadata_update_field_setup_basic_info_and_resolve (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, DeltaInfo *delta_info, MonoClass *parent_klass, uint32_t fielddef_token, MonoError *error); static MonoComponentHotReload fn_table = { { MONO_COMPONENT_ITF_VERSION, &hot_reload_available }, @@ -114,8 +141,13 @@ static MonoComponentHotReload fn_table = { &hot_reload_get_updated_method_ppdb, &hot_reload_has_modified_rows, &hot_reload_table_num_rows_slow, - &hot_reload_get_added_methods, &hot_reload_method_parent, + &hot_reload_metadata_linear_search, + &hot_reload_field_parent, + &hot_reload_get_field_idx, + &hot_reload_get_field, + &hot_reload_get_static_field_addr, + &hot_reload_find_method_by_name, }; MonoComponentHotReload * @@ -190,7 +222,7 @@ struct _DeltaInfo { /* Additional informaiton for baseline MonoImages */ -typedef struct _BaselineInfo { +struct _BaselineInfo { /* List of DeltaInfos of deltas*/ GList *delta_info; /* Tail of delta_info for fast appends */ @@ -202,9 +234,12 @@ typedef struct _BaselineInfo { /* TRUE if any published update modified an existing row */ gboolean any_modified_rows [MONO_TABLE_NUM]; - GHashTable *added_methods; /* maps each MonoClass to a GArray of added method tokens */ - GHashTable *method_parent; /* maps added methoddef tokens to typedef tokens */ -} BaselineInfo; + /* A list of MonoClassMetadataUpdateInfo* that need to be cleaned up */ + GSList *klass_info; + + /* Parents for added methods, fields, etc */ + GHashTable *member_parent; /* maps added methoddef or fielddef tokens to typedef tokens */ +}; #define DOTNET_MODIFIABLE_ASSEMBLIES "DOTNET_MODIFIABLE_ASSEMBLIES" @@ -312,11 +347,34 @@ baseline_info_init (MonoImage *image_base) return baseline_info; } +static void +klass_info_destroy (gpointer value, gpointer user_data G_GNUC_UNUSED) +{ + MonoClassMetadataUpdateInfo *info = (MonoClassMetadataUpdateInfo *)value; + /* added_members is allocated from the class mempool, don't free it here */ + /* The MonoClassMetadataUpdateField is allocated from the class mempool, don't free it here */ + g_ptr_array_free (info->added_fields, TRUE); + + if (info->runtime.static_fields) { + mono_g_hash_table_destroy (info->runtime.static_fields); + info->runtime.static_fields = NULL; + } + + mono_coop_mutex_destroy (&info->runtime.static_fields_lock); + + /* The MonoClassMetadataUpdateInfo itself is allocated from the class mempool, don't free it here */ +} + static void baseline_info_destroy (BaselineInfo *info) { if (info->method_table_update) g_hash_table_destroy (info->method_table_update); + + if (info->klass_info) { + g_slist_foreach (info->klass_info, klass_info_destroy, NULL); + g_slist_free (info->klass_info); + } g_free (info); } @@ -515,9 +573,15 @@ image_open_dmeta_from_data (MonoImage *base_image, uint32_t generation, gconstpo static DeltaInfo* image_append_delta (MonoImage *base, BaselineInfo *base_info, MonoImage *delta, DeltaInfo *delta_info); +/* common method, don't use directly, use add_method_to_baseline, add_field_to_baseline, etc */ +static void +add_member_to_baseline (BaselineInfo *base_info, DeltaInfo *delta_info, MonoClass *klass, uint32_t member_token); + static void add_method_to_baseline (BaselineInfo *base_info, DeltaInfo *delta_info, MonoClass *klass, uint32_t method_token, MonoDebugInformationEnc* pdb_address); +static void +add_field_to_baseline (BaselineInfo *base_info, DeltaInfo *delta_info, MonoClass *klass, uint32_t field_token); void hot_reload_init (void) @@ -660,6 +724,33 @@ hot_reload_update_cancel (uint32_t generation) publish_unlock (); } +static void +add_class_info_to_baseline (MonoClass *klass, MonoClassMetadataUpdateInfo *klass_info) +{ + MonoImage *image = m_class_get_image (klass); + BaselineInfo *baseline_info = baseline_info_lookup (image); + baseline_info->klass_info = g_slist_prepend (baseline_info->klass_info, klass_info); +} + +static MonoClassMetadataUpdateInfo * +mono_class_get_or_add_metadata_update_info (MonoClass *klass) +{ + MonoClassMetadataUpdateInfo *info = NULL; + info = mono_class_get_metadata_update_info (klass); + if (info) + return info; + mono_loader_lock (); + info = mono_class_get_metadata_update_info (klass); + if (!info) { + info = mono_class_alloc0 (klass, sizeof (MonoClassMetadataUpdateInfo)); + add_class_info_to_baseline (klass, info); + mono_class_set_metadata_update_info (klass, info); + } + mono_loader_unlock (); + g_assert (info); + return info; +} + /* * Given a baseline and an (optional) previous delta, allocate space for new tables for the current delta. * @@ -695,12 +786,6 @@ delta_info_initialize_mutants (const MonoImage *base, const BaselineInfo *base_i guint32 rows = count->prev_gen_rows + count->inserted_rows; - MonoTableInfo *tbl = &delta->mutants [i]; - tbl->row_size = base->tables[i].row_size; - tbl->size_bitfield = base->tables[i].size_bitfield; - tbl->rows_ = rows; - - tbl->base = mono_mempool_alloc (delta->pool, tbl->row_size * rows); const MonoTableInfo *prev_table; if (!prev_delta || prev_delta->mutants [i].base == NULL) prev_table = &base->tables [i]; @@ -708,6 +793,21 @@ delta_info_initialize_mutants (const MonoImage *base, const BaselineInfo *base_i prev_table = &prev_delta->mutants [i]; g_assert (prev_table != NULL); + + MonoTableInfo *tbl = &delta->mutants [i]; + if (prev_table->rows_ == 0) { + /* table was empty in the baseline and it was empty in the prior generation, but now we have some rows. Use the format of the mutant table. */ + g_assert (prev_table->row_size == 0); + tbl->row_size = delta->delta_image->tables [i].row_size; + tbl->size_bitfield = delta->delta_image->tables [i].size_bitfield; + } else { + tbl->row_size = prev_table->row_size; + tbl->size_bitfield = prev_table->size_bitfield; + } + tbl->rows_ = rows; + g_assert (tbl->rows_ > 0 && tbl->row_size != 0); + + tbl->base = mono_mempool_alloc (delta->pool, tbl->row_size * rows); g_assert (table_info_get_rows (prev_table) == count->prev_gen_rows); /* copy the old rows and zero out the new ones */ @@ -877,8 +977,13 @@ dump_update_summary (MonoImage *image_base, MonoImage *image_dmeta) } +/* + * Finds the latest mutated version of the table given by tbl_index + * + * On success returns TRUE, modifies *t and optionally updates *delta_out + */ static gboolean -effective_table_mutant (MonoImage *base, BaselineInfo *info, int tbl_index, const MonoTableInfo **t, int idx) +effective_table_mutant (MonoImage *base, BaselineInfo *info, int tbl_index, const MonoTableInfo **t, DeltaInfo **delta_out) { GList *ptr =info->delta_info_last; uint32_t exposed_gen = hot_reload_get_thread_generation (); @@ -899,6 +1004,8 @@ effective_table_mutant (MonoImage *base, BaselineInfo *info, int tbl_index, cons g_assert (delta_info != NULL); *t = &delta_info->mutants [tbl_index]; + if (delta_out) + *delta_out = delta_info; return TRUE; } @@ -917,7 +1024,7 @@ hot_reload_effective_table_slow (const MonoTableInfo **t, int idx) if (!info) return; - gboolean success = effective_table_mutant (base, info, tbl_index, t, idx); + gboolean success = effective_table_mutant (base, info, tbl_index, t, NULL); g_assert (success); } @@ -1129,7 +1236,7 @@ funccode_to_str (int func_code) * */ static void -delta_info_mutate_row (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *cur_delta, guint32 log_token) +delta_info_mutate_row (MonoImage *image_dmeta, DeltaInfo *cur_delta, guint32 log_token) { int token_table = mono_metadata_token_table (log_token); int token_index = mono_metadata_token_index (log_token); /* 1-based */ @@ -1139,16 +1246,16 @@ delta_info_mutate_row (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo int delta_index = hot_reload_relative_delta_index (image_dmeta, cur_delta, log_token); /* The complication here is that we want the mutant table to look like the table in - * image_base with respect to column widths, but the delta tables are generally coming in + * the baseline image with respect to column widths, but the delta tables are generally coming in * uncompressed (4-byte columns). So we have to copy one column at a time and adjust the * widths as we go. */ - guint32 dst_bitfield = image_base->tables [token_table].size_bitfield; + guint32 dst_bitfield = cur_delta->mutants [token_table].size_bitfield; guint32 src_bitfield = image_dmeta->tables [token_table].size_bitfield; const char *src_base = image_dmeta->tables [token_table].base + (delta_index - 1) * image_dmeta->tables [token_table].row_size; - char *dst_base = (char*)cur_delta->mutants [token_table].base + (token_index - 1) * image_base->tables [token_table].row_size; + char *dst_base = (char*)cur_delta->mutants [token_table].base + (token_index - 1) * cur_delta->mutants [token_table].row_size; guint32 src_offset = 0, dst_offset = 0; for (int col = 0; col < mono_metadata_table_count (dst_bitfield); ++col) { @@ -1190,12 +1297,11 @@ delta_info_mutate_row (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo default: g_assert_not_reached (); } - } src_offset += src_col_size; dst_offset += dst_col_size; } - g_assert (dst_offset == image_base->tables [token_table].row_size); + g_assert (dst_offset == cur_delta->mutants [token_table].row_size); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "mutate: table=0x%02x row=0x%04x delta row=0x%04x %s", token_table, token_index, delta_index, modified ? "Mod" : "Add"); } @@ -1215,7 +1321,7 @@ prepare_mutated_rows (const MonoTableInfo *table_enclog, MonoImage *image_base, if (func_code != ENC_FUNC_DEFAULT) continue; - delta_info_mutate_row (image_base, image_dmeta, delta_info, log_token); + delta_info_mutate_row (image_dmeta, delta_info, log_token); } } @@ -1248,7 +1354,10 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de int token_table = mono_metadata_token_table (log_token); int token_index = mono_metadata_token_index (log_token); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "row[0x%02x]:0x%08x (%s idx=0x%02x) (base table has 0x%04x rows)\tfunc=0x%02x (\"%s\")\n", i, log_token, mono_meta_table_name (token_table), token_index, table_info_get_rows (&image_base->tables [token_table]), func_code, funccode_to_str (func_code)); + gboolean is_addition = token_index-1 >= delta_info->count[token_table].prev_gen_rows ; + + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "row[0x%02x]:0x%08x (%s idx=0x%02x) (base table has 0x%04x rows; prev gen had 0x%04x rows)\t%s\tfunc=0x%02x (\"%s\")\n", i, log_token, mono_meta_table_name (token_table), token_index, table_info_get_rows (&image_base->tables [token_table]), delta_info->count[token_table].prev_gen_rows, (is_addition ? "ADD" : "UPDATE"), func_code, funccode_to_str (func_code)); if (token_table != MONO_TABLE_METHOD) @@ -1256,7 +1365,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de #ifndef ALLOW_METHOD_ADD - if (token_index > table_info_get_rows (&image_base->tables [token_table])) { + if (is_addition) { mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "\tcannot add new method with token 0x%08x", log_token); mono_error_set_type_load_name (error, NULL, image_base->name, "EnC: cannot add new method with token 0x%08x", log_token); unsupported_edits = TRUE; @@ -1266,8 +1375,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de #ifdef ALLOW_METHOD_ADD /* adding a new parameter to a new method is ok */ - /* FIXME: total rows, not just the baseline rows */ - if (func_code == ENC_FUNC_ADD_PARAM && token_index > table_info_get_rows (&image_base->tables [token_table])) + if (func_code == ENC_FUNC_ADD_PARAM && is_addition) continue; #endif @@ -1284,6 +1392,8 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de int token_table = mono_metadata_token_table (log_token); int token_index = mono_metadata_token_index (log_token); + gboolean is_addition = token_index-1 >= delta_info->count[token_table].prev_gen_rows ; + switch (token_table) { case MONO_TABLE_ASSEMBLYREF: /* okay, supported */ @@ -1295,9 +1405,20 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de #endif /* handled above */ break; + case MONO_TABLE_FIELD: +#ifdef ALLOW_FIELD_ADD + if (func_code == ENC_FUNC_DEFAULT) + continue; /* ok, allowed */ +#else + /* adding or modifying a field */ + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "row[0x%02x]:0x%08x we do not support adding or modifying fields.", i, log_token); + mono_error_set_type_load_name (error, NULL, image_base->name, "EnC: we do not support adding or modifying fields. token=0x%08x", log_token); + unsupported_edits = TRUE; + break; +#endif case MONO_TABLE_PROPERTY: { /* modifying a property, ok */ - if (token_index <= table_info_get_rows (&image_base->tables [token_table])) + if (!is_addition) break; /* adding a property */ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "row[0x%02x]:0x%08x we do not support adding new properties.", i, log_token); @@ -1306,8 +1427,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de continue; } case MONO_TABLE_METHODSEMANTICS: { - /* FIXME: this should get the current table size, not the base stable size */ - if (token_index > table_info_get_rows (&image_base->tables [token_table])) { + if (is_addition) { /* new rows are fine, as long as they point at existing methods */ guint32 sema_cols [MONO_METHOD_SEMA_SIZE]; int mapped_token = hot_reload_relative_delta_index (image_dmeta, delta_info, mono_metadata_make_token (token_table, token_index)); @@ -1319,7 +1439,8 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de case METHOD_SEMANTIC_SETTER: { int prop_method_index = sema_cols [MONO_METHOD_SEMA_METHOD]; /* ok, if it's pointing to an existing getter/setter */ - if (prop_method_index < table_info_get_rows (&image_base->tables [MONO_TABLE_METHOD])) + gboolean is_prop_method_add = prop_method_index-1 >= delta_info->count[MONO_TABLE_METHOD].prev_gen_rows; + if (!is_prop_method_add) break; mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "row[0x%02x]:0x%08x adding new getter/setter method 0x%08x to a property is not supported", i, log_token, prop_method_index); mono_error_set_type_load_name (error, NULL, image_base->name, "EnC: we do not support adding a new getter or setter to a property, token=0x%08x", log_token); @@ -1340,8 +1461,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de } } case MONO_TABLE_CUSTOMATTRIBUTE: { - /* FIXME: this should get the current table size, not the base stable size */ - if (token_index <= table_info_get_rows (&image_base->tables [token_table])) { + if (!is_addition) { /* modifying existing rows is ok, as long as the parent and ctor are the same */ guint32 ca_upd_cols [MONO_CUSTOM_ATTR_SIZE]; guint32 ca_base_cols [MONO_CUSTOM_ATTR_SIZE]; @@ -1375,8 +1495,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de } } case MONO_TABLE_PARAM: { - /* FIXME: this should get the current table size, not the base stable size */ - if (token_index <= table_info_get_rows (&image_base->tables [token_table])) { + if (!is_addition) { /* We only allow modifications where the parameter name doesn't change. */ uint32_t base_param [MONO_PARAM_SIZE]; uint32_t upd_param [MONO_PARAM_SIZE]; @@ -1401,11 +1520,14 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de break; /* added a row. ok */ } case MONO_TABLE_TYPEDEF: { + gboolean new_class G_GNUC_UNUSED = is_addition; #ifdef ALLOW_METHOD_ADD - /* FIXME: wrong for cumulative updates - need to look at DeltaInfo:count.prev_gen_rows */ - gboolean new_class = token_index > table_info_get_rows (&image_base->tables [token_table]); /* only allow adding methods to existing classes for now */ - if (!new_class && func_code == ENC_FUNC_ADD_METHOD) { + if ( +#ifndef ALLOW_CLASS_ADD + !new_class && +#endif + func_code == ENC_FUNC_ADD_METHOD) { /* next record should be a MONO_TABLE_METHOD addition (func == default) */ g_assert (i + 1 < rows); guint32 next_cols [MONO_ENCLOG_SIZE]; @@ -1415,7 +1537,29 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de int next_table = mono_metadata_token_table (next_token); int next_index = mono_metadata_token_index (next_token); g_assert (next_table == MONO_TABLE_METHOD); - g_assert (next_index > table_info_get_rows (&image_base->tables [next_table])); + /* expecting an added method */ + g_assert (next_index-1 >= delta_info->count[next_table].prev_gen_rows); + i++; /* skip the next record */ + continue; + } +#endif +#ifdef ALLOW_FIELD_ADD + if ( +#ifndef ALLOW_CLASS_ADD + !new_class && +#endif + func_code == ENC_FUNC_ADD_FIELD) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "row[0x%02x]:0x%08x AddField to klass 0x%08x, skipping next EnClog record", i, log_token, token_index); + g_assert (i + 1 < rows); + guint32 next_cols [MONO_ENCLOG_SIZE]; + mono_metadata_decode_row (table_enclog, i + 1, next_cols, MONO_ENCLOG_SIZE); + g_assert (next_cols [MONO_ENCLOG_FUNC_CODE] == ENC_FUNC_DEFAULT); + int next_token = next_cols [MONO_ENCLOG_TOKEN]; + int next_table = mono_metadata_token_table (next_token); + int next_index = mono_metadata_token_index (next_token); + g_assert (next_table == MONO_TABLE_FIELD); + /* expecting an added field */ + g_assert (next_index-1 >= delta_info->count[next_table].prev_gen_rows); i++; /* skip the next record */ continue; } @@ -1423,8 +1567,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, DeltaInfo *de /* fallthru */ } default: - /* FIXME: this bounds check is wrong for cumulative updates - need to look at the DeltaInfo:count.prev_gen_rows */ - if (token_index <= table_info_get_rows (&image_base->tables [token_table])) { + if (!is_addition) { mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "row[0x%02x]:0x%08x we do not support patching of existing table cols.", i, log_token); mono_error_set_type_load_name (error, NULL, image_base->name, "EnC: we do not support patching of existing table cols. token=0x%08x", log_token); unsupported_edits = TRUE; @@ -1544,9 +1687,12 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen * have it in writable memory (and not mmap-ed pages), so we can rewrite the table values. */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "Pass 2 begin: base '%s' delta image=%p", image_base->name, image_dmeta); +#if defined(ALLOW_METHOD_ADD) || defined(ALLOW_FIELD_ADD) + MonoClass *add_member_klass = NULL; +#endif #ifdef ALLOW_METHOD_ADD - MonoClass *add_method_klass = NULL; uint32_t add_param_method_index = 0; #endif @@ -1560,7 +1706,11 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen int token_table = mono_metadata_token_table (log_token); int token_index = mono_metadata_token_index (log_token); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "enclog i=%d: token=0x%08x (table=%s): %d", i, log_token, mono_meta_table_name (token_table), func_code); + + gboolean is_addition = token_index-1 >= delta_info->count[token_table].prev_gen_rows ; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "enclog i=%d: token=0x%08x (table=%s): %d:\t%s", i, log_token, mono_meta_table_name (token_table), func_code, (is_addition ? "ADD" : "UPDATE")); + /* TODO: See CMiniMdRW::ApplyDelta for how to drive this. */ @@ -1570,14 +1720,12 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen #ifdef ALLOW_METHOD_ADD case ENC_FUNC_ADD_METHOD: { g_assert (token_table == MONO_TABLE_TYPEDEF); - /* FIXME: this bounds check is wrong for cumulative updates - need to look at the DeltaInfo:count.prev_gen_rows */ - /* should've been caught by pass1 if we're adding a new method to a new class. */ MonoClass *klass = mono_class_get_checked (image_base, log_token, error); if (!is_ok (error)) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "Can't get class with token 0x%08x due to: %s", log_token, mono_error_get_message (error)); return FALSE; } - add_method_klass = klass; + add_member_klass = klass; break; } @@ -1586,6 +1734,18 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen add_param_method_index = token_index; break; } +#endif +#ifdef ALLOW_FIELD_ADD + case ENC_FUNC_ADD_FIELD: { + g_assert (token_table == MONO_TABLE_TYPEDEF); + MonoClass *klass = mono_class_get_checked (image_base, log_token, error); + if (!is_ok (error)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "Can't get class with token 0x%08x due to: %s", log_token, mono_error_get_message (error)); + return FALSE; + } + add_member_klass = klass; + break; + } #endif default: g_error ("EnC: unsupported FuncCode, should be caught by pass1"); @@ -1637,14 +1797,14 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen if (func_code == ENC_FUNC_ADD_PARAM) break; - if (token_index > table_info_get_rows (&image_base->tables [token_table])) { - if (!add_method_klass) + if (is_addition) { + if (!add_member_klass) g_error ("EnC: new method added but I don't know the class, should be caught by pass1"); - g_assert (add_method_klass); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "Adding new method 0x%08x to class %s.%s", token_index, m_class_get_name_space (add_method_klass), m_class_get_name (add_method_klass)); + g_assert (add_member_klass); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "Adding new method 0x%08x to class %s.%s", log_token, m_class_get_name_space (add_member_klass), m_class_get_name (add_member_klass)); MonoDebugInformationEnc *method_debug_information = hot_reload_get_method_debug_information (delta_info->ppdb_file, token_index); - add_method_to_baseline (base_info, delta_info, add_method_klass, token_index, method_debug_information); - add_method_klass = NULL; + add_method_to_baseline (base_info, delta_info, add_member_klass, log_token, method_debug_information); + add_member_klass = NULL; } #endif @@ -1666,17 +1826,78 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen /* rva points probably into image_base IL stream. can this ever happen? */ g_print ("TODO: this case is still a bit contrived. token=0x%08x with rva=0x%04x\n", log_token, rva); } -#ifdef ALLOW_METHOD_ADD - add_method_klass = NULL; +#if defined(ALLOW_METHOD_ADD) || defined(ALLOW_FIELD_ADD) + add_member_klass = NULL; #endif break; } - case MONO_TABLE_TYPEDEF: { - /* TODO: throw? */ - /* TODO: happens changing the class (adding field or method). we ignore it, but dragons are here */ + case MONO_TABLE_FIELD: { +#ifdef ALLOW_FIELD_ADD + g_assert (is_addition); + g_assert (add_member_klass); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "Adding new field 0x%08x to class %s.%s", log_token, m_class_get_name_space (add_member_klass), m_class_get_name (add_member_klass)); + + uint32_t mapped_token = hot_reload_relative_delta_index (image_dmeta, delta_info, log_token); + uint32_t field_flags = mono_metadata_decode_row_col (&image_dmeta->tables [MONO_TABLE_FIELD], mapped_token - 1, MONO_FIELD_FLAGS); + + if ((field_flags & FIELD_ATTRIBUTE_STATIC) == 0) { + /* TODO: implement instance (and literal?) fields */ + mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_METADATA_UPDATE, "Adding non-static fields isn't implemented yet (token 0x%08x, class %s.%s)", log_token, m_class_get_name_space (add_member_klass), m_class_get_name (add_member_klass)); + mono_error_set_not_implemented (error, "Adding non-static fields isn't implemented yet (token 0x%08x, class %s.%s)", log_token, m_class_get_name_space (add_member_klass), m_class_get_name (add_member_klass)); + return FALSE; + } - /* existing entries are supposed to be patched */ - g_assert (token_index <= table_info_get_rows (&image_base->tables [token_table])); + add_field_to_baseline (base_info, delta_info, add_member_klass, log_token); + + /* This actually does more than mono_class_setup_basic_field_info and + * resolves MonoClassField:type and sets MonoClassField:offset to -1 to make + * it easier to spot that the field is special. + */ + metadata_update_field_setup_basic_info_and_resolve (image_base, base_info, generation, delta_info, add_member_klass, log_token, error); + if (!is_ok (error)) { + mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_METADATA_UPDATE, "Could not setup field (token 0x%08x) due to: %s", log_token, mono_error_get_message (error)); + return FALSE; + } + + add_member_klass = NULL; +#else + g_assert_not_reached (); +#endif + break; + } + case MONO_TABLE_TYPEDEF: { +#ifdef ALLOW_CLASS_ADD + if (is_addition) { + /* Adding a new class. ok */ + switch (func_code) { + case ENC_FUNC_DEFAULT: + /* ok, added a new class */ + /* TODO: do things here */ + break; + case ENC_FUNC_ADD_METHOD: + case ENC_FUNC_ADD_FIELD: + /* ok, adding a new field or method to a new class */ + /* TODO: do we need to do anything special? Conceptually + * this is the same as modifying an existing class - + * especially since from the next generation's point of view + * that's what adding a field/method will be. */ + break; + case ENC_FUNC_ADD_PROPERTY: + case ENC_FUNC_ADD_EVENT: + g_assert_not_reached (); /* FIXME: implement me */ + default: + g_assert_not_reached (); /* unknown func_code */ + } + break; + } +#endif + /* modifying an existing class by adding a method or field, etc. */ + g_assert (!is_addition); +#if !defined(ALLOW_METHOD_ADD) && !defined(ALLOW_FIELD_ADD) + g_assert_not_reached (); +#else + g_assert (func_code != ENC_FUNC_DEFAULT); +#endif break; } case MONO_TABLE_PROPERTY: { @@ -1709,7 +1930,7 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen * * So by the time we see the param additions, the methods are already in. * - * FIXME: we need a lookaside table (like method_parent) for every place + * FIXME: we need a lookaside table (like member_parent) for every place * that looks at MONO_METHOD_PARAMLIST */ break; @@ -1909,8 +2130,9 @@ hot_reload_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx) if (G_UNLIKELY (gen > 0)) { loc = get_method_update_rva (base_image, info, idx, TRUE); } - /* Check the method_parent table as a way of checking if the method was added by a later generation. If so, still look for its PPDB info in our update tables */ - if (G_UNLIKELY (loc == 0 && info->method_parent && GPOINTER_TO_UINT (g_hash_table_lookup (info->method_parent, GUINT_TO_POINTER (idx))) > 0)) { + /* Check the member_parent table as a way of checking if the method was added by a later generation. If so, still look for its PPDB info in our update tables */ + uint32_t token = mono_metadata_make_token (MONO_TABLE_METHOD, mono_metadata_token_index (idx)); + if (G_UNLIKELY (loc == 0 && info->member_parent && GPOINTER_TO_UINT (g_hash_table_lookup (info->member_parent, GUINT_TO_POINTER (token))) > 0)) { loc = get_method_update_rva (base_image, info, idx, TRUE); } } @@ -2039,52 +2261,321 @@ hot_reload_table_num_rows_slow (MonoImage *base, int table_index) } static void -add_method_to_baseline (BaselineInfo *base_info, DeltaInfo *delta_info, MonoClass *klass, uint32_t method_token, MonoDebugInformationEnc* pdb_address) +add_member_to_baseline (BaselineInfo *base_info, DeltaInfo *delta_info, MonoClass *klass, uint32_t member_token) { - if (!base_info->added_methods) { - base_info->added_methods = g_hash_table_new (g_direct_hash, g_direct_equal); - } - if (!base_info->method_parent) { - base_info->method_parent = g_hash_table_new (g_direct_hash, g_direct_equal); - } - /* FIXME: locking for readers/writers of the GArray */ - GArray *arr = g_hash_table_lookup (base_info->added_methods, klass); - if (!arr) { - arr = g_array_new (FALSE, FALSE, sizeof(uint32_t)); - g_hash_table_insert (base_info->added_methods, klass, arr); + /* Check they really passed a table token, not just a table row index */ + g_assert (mono_metadata_token_table (member_token) != 0); + + if (!base_info->member_parent) { + base_info->member_parent = g_hash_table_new (g_direct_hash, g_direct_equal); } - g_array_append_val (arr, method_token); - g_hash_table_insert (base_info->method_parent, GUINT_TO_POINTER (method_token), GUINT_TO_POINTER (m_class_get_type_token (klass))); + MonoClassMetadataUpdateInfo *klass_info = mono_class_get_or_add_metadata_update_info (klass); + GSList *members = klass_info->added_members; + klass_info->added_members = g_slist_prepend_mem_manager (m_class_get_mem_manager (klass), members, GUINT_TO_POINTER (member_token)); + g_hash_table_insert (base_info->member_parent, GUINT_TO_POINTER (member_token), GUINT_TO_POINTER (m_class_get_type_token (klass))); +} + +static void +add_method_to_baseline (BaselineInfo *base_info, DeltaInfo *delta_info, MonoClass *klass, uint32_t method_token, MonoDebugInformationEnc* pdb_address) +{ + add_member_to_baseline (base_info, delta_info, klass, method_token); if (pdb_address) set_delta_method_debug_info (delta_info, method_token, pdb_address); } -static GArray* -hot_reload_get_added_methods (MonoClass *klass) +static GSList* +hot_reload_get_added_members (MonoClass *klass) { /* FIXME: locking for the GArray? */ MonoImage *image = m_class_get_image (klass); if (!image->has_updates) return NULL; - BaselineInfo *base_info = baseline_info_lookup (image); - if (!base_info || base_info->added_methods == NULL) + MonoClassMetadataUpdateInfo *klass_info = mono_class_get_metadata_update_info (klass); + if (!klass_info) return NULL; - - return g_hash_table_lookup (base_info->added_methods, klass); + return klass_info->added_members; } static uint32_t -hot_reload_method_parent (MonoImage *base_image, uint32_t method_token) +hot_reload_member_parent (MonoImage *base_image, uint32_t member_token) { + /* make sure they passed a token, not just a table row index */ + g_assert (mono_metadata_token_table (member_token) != 0); + if (!base_image->has_updates) return 0; BaselineInfo *base_info = baseline_info_lookup (base_image); - if (!base_info || base_info->method_parent == NULL) + if (!base_info || base_info->member_parent == NULL) return 0; - uint32_t res = GPOINTER_TO_UINT (g_hash_table_lookup (base_info->method_parent, GUINT_TO_POINTER (method_token))); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "method_parent lookup: 0x%08x returned 0x%08x\n", method_token, res); + uint32_t res = GPOINTER_TO_UINT (g_hash_table_lookup (base_info->member_parent, GUINT_TO_POINTER (member_token))); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "member_parent lookup: 0x%08x returned 0x%08x\n", member_token, res); + + return res; +} + +static uint32_t +hot_reload_method_parent (MonoImage *base_image, uint32_t method_token) +{ + /* the callers might pass just an index without a table */ + uint32_t lookup_token = mono_metadata_make_token (MONO_TABLE_METHOD, mono_metadata_token_index (method_token)); + + return hot_reload_member_parent (base_image, lookup_token); +} + +static void +add_field_to_baseline (BaselineInfo *base_info, DeltaInfo *delta_info, MonoClass *klass, uint32_t field_token) +{ + add_member_to_baseline (base_info, delta_info, klass, field_token); +} + +static uint32_t +hot_reload_field_parent (MonoImage *base_image, uint32_t field_token) +{ + /* the callers might pass just an index without a table */ + uint32_t lookup_token = mono_metadata_make_token (MONO_TABLE_FIELD, mono_metadata_token_index (field_token)); + + return hot_reload_member_parent (base_image, lookup_token); +} + + +/* HACK - keep in sync with locator_t in metadata/metadata.c */ +typedef struct { + int idx; /* The index that we are trying to locate */ + int col_idx; /* The index in the row where idx may be stored */ + MonoTableInfo *t; /* pointer to the table */ + guint32 result; +} upd_locator_t; + +void* +hot_reload_metadata_linear_search (MonoImage *base_image, MonoTableInfo *base_table, const void *key, BinarySearchComparer comparer) +{ + BaselineInfo *base_info = baseline_info_lookup (base_image); + g_assert (base_info); + + g_assert (base_image->tables < base_table && base_table < &base_image->tables [MONO_TABLE_LAST]); + + int tbl_index; + { + size_t s = ALIGN_TO (sizeof (MonoTableInfo), sizeof (gpointer)); + tbl_index = ((intptr_t) base_table - (intptr_t) base_image->tables) / s; + } + + DeltaInfo *delta_info = NULL; + const MonoTableInfo *latest_mod_table = base_table; + gboolean success = effective_table_mutant (base_image, base_info, tbl_index, &latest_mod_table, &delta_info); + g_assert (success); + uint32_t rows = table_info_get_rows (latest_mod_table); + + upd_locator_t *loc = (upd_locator_t*)key; + g_assert (loc); + loc->result = 0; + /* HACK: this is so that the locator can compute the row index of the given row. but passing the mutant table to other metadata functions could backfire. */ + loc->t = (MonoTableInfo*)latest_mod_table; + for (uint32_t idx = 0; idx < rows; ++idx) { + const char *row = latest_mod_table->base + idx * latest_mod_table->row_size; + if (!comparer (loc, row)) + return (void*)row; + } + return NULL; +} + +static uint32_t +hot_reload_get_field_idx (MonoClassField *field) +{ + g_assert (m_field_is_from_update (field)); + MonoClassMetadataUpdateField *field_info = (MonoClassMetadataUpdateField*)field; + return mono_metadata_token_index (field_info->token); +} + +static MonoClassField * +hot_reload_get_field (MonoClass *klass, uint32_t fielddef_token) { + MonoClassMetadataUpdateInfo *info = mono_class_get_or_add_metadata_update_info (klass); + g_assert (mono_metadata_token_table (fielddef_token) == MONO_TABLE_FIELD); + /* FIXME: this needs locking in the multi-threaded case. There could be an update happening that resizes the array. */ + GPtrArray *added_fields = info->added_fields; + uint32_t count = added_fields->len; + for (uint32_t i = 0; i < count; ++i) { + MonoClassMetadataUpdateField *field = (MonoClassMetadataUpdateField *)g_ptr_array_index (added_fields, i); + if (field->token == fielddef_token) + return &field->field; + } + return NULL; +} + + +static MonoClassMetadataUpdateField * +metadata_update_field_setup_basic_info_and_resolve (MonoImage *image_base, BaselineInfo *base_info, uint32_t generation, DeltaInfo *delta_info, MonoClass *parent_klass, uint32_t fielddef_token, MonoError *error) +{ + // TODO: hang a "pending field" struct off the parent_klass if !parent_klass->fields + // In that case we can do things simpler, maybe by just creating the MonoClassField array as usual, and just relying on the normal layout algorithm to make space for the instance. + + MonoClassMetadataUpdateInfo *parent_info = mono_class_get_or_add_metadata_update_info (parent_klass); + + MonoClassMetadataUpdateField *field = mono_class_alloc0 (parent_klass, sizeof (MonoClassMetadataUpdateField)); + + m_field_set_parent (&field->field, parent_klass); + m_field_set_meta_flags (&field->field, MONO_CLASS_FIELD_META_FLAG_FROM_UPDATE); + /* It's a special field */ + field->field.offset = -1; + field->generation = generation; + field->token = fielddef_token; + + uint32_t name_idx = mono_metadata_decode_table_row_col (image_base, MONO_TABLE_FIELD, mono_metadata_token_index (fielddef_token) - 1, MONO_FIELD_NAME); + field->field.name = mono_metadata_string_heap (image_base, name_idx); + + mono_field_resolve_type (&field->field, error); + if (!is_ok (error)) + return NULL; + + if (!parent_info->added_fields) { + parent_info->added_fields = g_ptr_array_new (); + } + + g_ptr_array_add (parent_info->added_fields, field); + + return field; +} + +static void +ensure_class_runtime_info_inited (MonoClass *klass, MonoClassRuntimeMetadataUpdateInfo *runtime_info) +{ + if (runtime_info->inited) + return; + mono_loader_lock (); + if (runtime_info->inited) { + mono_loader_unlock (); + return; + } + + mono_coop_mutex_init (&runtime_info->static_fields_lock); + + /* FIXME: is it ok to re-use MONO_ROOT_SOURCE_STATIC here? */ + runtime_info->static_fields = mono_g_hash_table_new_type_internal (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_STATIC, NULL, "Hot Reload Static Fields"); + + runtime_info->inited = TRUE; + + mono_loader_unlock (); +} + +static void +class_runtime_info_static_fields_lock (MonoClassRuntimeMetadataUpdateInfo *runtime_info) +{ + mono_coop_mutex_lock (&runtime_info->static_fields_lock); +} + +static void +class_runtime_info_static_fields_unlock (MonoClassRuntimeMetadataUpdateInfo *runtime_info) +{ + mono_coop_mutex_unlock (&runtime_info->static_fields_lock); +} + +static GENERATE_GET_CLASS_WITH_CACHE_DECL (hot_reload_field_store); + +static GENERATE_GET_CLASS_WITH_CACHE(hot_reload_field_store, "Mono.HotReload", "FieldStore"); + + +static MonoObject* +create_static_field_storage (MonoType *t, MonoError *error) +{ + MonoClass *klass; + if (!mono_type_is_reference (t)) + klass = mono_class_from_mono_type_internal (t); + else + klass = mono_class_get_hot_reload_field_store_class (); + + return mono_object_new_pinned (klass, error); +} + +static gpointer +hot_reload_get_static_field_addr (MonoClassField *field) +{ + g_assert (m_field_is_from_update (field)); + MonoClassMetadataUpdateField *f = (MonoClassMetadataUpdateField *)field; + g_assert ((f->field.type->attrs & FIELD_ATTRIBUTE_STATIC) != 0); + g_assert (!m_type_is_byref(f->field.type)); // byref fields only in ref structs, which aren't allowed in EnC updates + + MonoClass *parent = m_field_get_parent (&f->field); + MonoClassMetadataUpdateInfo *parent_info = mono_class_get_or_add_metadata_update_info (parent); + MonoClassRuntimeMetadataUpdateInfo *runtime_info = &parent_info->runtime; + + ensure_class_runtime_info_inited (parent, runtime_info); + + MonoObject *obj = NULL; + class_runtime_info_static_fields_lock (runtime_info); + obj = (MonoObject*) mono_g_hash_table_lookup (runtime_info->static_fields, GUINT_TO_POINTER (f->token)); + class_runtime_info_static_fields_unlock (runtime_info); + if (!obj) { + ERROR_DECL (error); + obj = create_static_field_storage (f->field.type, error); + class_runtime_info_static_fields_lock (runtime_info); + mono_error_assert_ok (error); + MonoObject *obj2 = (MonoObject*) mono_g_hash_table_lookup (runtime_info->static_fields, GUINT_TO_POINTER (f->token)); + if (!obj2) { + // Noone else created it, use ours + mono_g_hash_table_insert_internal (runtime_info->static_fields, GUINT_TO_POINTER (f->token), obj); + } else { + /* beaten by another thread, silently drop our storage object and use theirs */ + obj = obj2; + } + class_runtime_info_static_fields_unlock (runtime_info); + } + g_assert (obj); + + gpointer addr = NULL; + if (!mono_type_is_reference (f->field.type)) { + // object is just the boxed value + addr = mono_object_unbox_internal (obj); + } else { + // object is a Mono.HotReload.FieldStore, and the static field value is obj._loc + MonoHotReloadFieldStoreObject *store = (MonoHotReloadFieldStoreObject *)obj; + addr = (gpointer)&store->_loc; + } + g_assert (addr); + + return addr; +} + +static MonoMethod * +hot_reload_find_method_by_name (MonoClass *klass, const char *name, int param_count, int flags, MonoError *error) +{ + GSList *members = hot_reload_get_added_members (klass); + if (!members) + return NULL; + + MonoImage *image = m_class_get_image (klass); + MonoMethod *res = NULL; + for (GSList *ptr = members; ptr; ptr = ptr->next) { + uint32_t token = GPOINTER_TO_UINT(ptr->data); + if (mono_metadata_token_table (token) != MONO_TABLE_METHOD) + continue; + uint32_t idx = mono_metadata_token_index (token); + uint32_t cols [MONO_METHOD_SIZE]; + mono_metadata_decode_table_row (image, MONO_TABLE_METHOD, idx - 1, cols, MONO_METHOD_SIZE); + + if (!strcmp (mono_metadata_string_heap (image, cols [MONO_METHOD_NAME]), name)) { + ERROR_DECL (local_error); + MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, local_error); + if (!method) { + mono_error_cleanup (local_error); + continue; + } + if (param_count == -1) { + res = method; + break; + } + MonoMethodSignature *sig = mono_method_signature_checked (method, local_error); + if (!sig) { + mono_error_cleanup (error); + continue; + } + if ((method->flags & flags) == flags && sig->param_count == param_count) { + res = method; + break; + } + } + } return res; } diff --git a/src/mono/mono/component/hot_reload.h b/src/mono/mono/component/hot_reload.h index 416ff56e70eab..790234e557718 100644 --- a/src/mono/mono/component/hot_reload.h +++ b/src/mono/mono/component/hot_reload.h @@ -8,7 +8,9 @@ #include #include "mono/metadata/object-forward.h" #include "mono/metadata/metadata-internals.h" +#include "mono/metadata/class-internals.h" #include "mono/metadata/metadata-update.h" +#include "mono/utils/bsearch.h" #include "mono/utils/mono-error.h" #include "mono/utils/mono-compiler.h" #include "mono/component/component.h" @@ -31,8 +33,13 @@ typedef struct _MonoComponentHotReload { gpointer (*get_updated_method_ppdb) (MonoImage *base_image, uint32_t idx); gboolean (*has_modified_rows) (const MonoTableInfo *table); gboolean (*table_num_rows_slow) (MonoImage *base_image, int table_index); - GArray* (*get_added_methods) (MonoClass *klass); uint32_t (*method_parent) (MonoImage *base_image, uint32_t method_index); + void* (*metadata_linear_search) (MonoImage *base_image, MonoTableInfo *base_table, const void *key, BinarySearchComparer comparer); + uint32_t (*field_parent) (MonoImage *base_image, uint32_t method_index); + uint32_t (*get_field_idx) (MonoClassField *field); + MonoClassField* (*get_field) (MonoClass *klass, uint32_t fielddef_token); + gpointer (*get_static_field_addr) (MonoClassField *field); + MonoMethod* (*find_method_by_name) (MonoClass *klass, const char *name, int param_count, int flags, MonoError *error); } MonoComponentHotReload; MONO_COMPONENT_EXPORT_ENTRYPOINT diff --git a/src/mono/mono/metadata/class-accessors.c b/src/mono/mono/metadata/class-accessors.c index 76065cb45c456..609ad55b40494 100644 --- a/src/mono/mono/metadata/class-accessors.c +++ b/src/mono/mono/metadata/class-accessors.c @@ -28,7 +28,8 @@ typedef enum { PROP_DIM_CONFLICTS = 10, /* GSList of MonoMethod* */ PROP_FIELD_DEF_VALUES_2BYTESWIZZLE = 11, /* MonoFieldDefaultValue* with default values swizzled at 2 byte boundaries*/ PROP_FIELD_DEF_VALUES_4BYTESWIZZLE = 12, /* MonoFieldDefaultValue* with default values swizzled at 4 byte boundaries*/ - PROP_FIELD_DEF_VALUES_8BYTESWIZZLE = 13 /* MonoFieldDefaultValue* with default values swizzled at 8 byte boundaries*/ + PROP_FIELD_DEF_VALUES_8BYTESWIZZLE = 13, /* MonoFieldDefaultValue* with default values swizzled at 8 byte boundaries*/ + PROP_METADATA_UPDATE_INFO = 14, /* MonoClassMetadataUpdateInfo* */ } InfrequentDataKind; /* Accessors based on class kind*/ @@ -589,6 +590,67 @@ mono_class_publish_gc_descriptor (MonoClass *klass, MonoGCDescriptor gc_descr) return ret; } +MonoClassMetadataUpdateInfo* +mono_class_get_metadata_update_info (MonoClass *klass) +{ + switch (m_class_get_class_kind (klass)) { + case MONO_CLASS_GTD: + return NULL; + case MONO_CLASS_DEF: + return (MonoClassMetadataUpdateInfo *)get_pointer_property (klass, PROP_METADATA_UPDATE_INFO); + case MONO_CLASS_GINST: + case MONO_CLASS_GPARAM: + case MONO_CLASS_POINTER: + case MONO_CLASS_GC_FILLER: + return NULL; + default: + g_assert_not_reached (); + } +} + +/* + * LOCKING: assumes the loader lock is held + */ +void +mono_class_set_metadata_update_info (MonoClass *klass, MonoClassMetadataUpdateInfo *value) +{ + switch (m_class_get_class_kind (klass)) { + case MONO_CLASS_GTD: + g_assertf (0, "%s: EnC metadata update info on generic types is not supported", __func__); + break; + case MONO_CLASS_DEF: + set_pointer_property (klass, PROP_METADATA_UPDATE_INFO, value); + return; + case MONO_CLASS_GINST: + case MONO_CLASS_GPARAM: + case MONO_CLASS_POINTER: + case MONO_CLASS_GC_FILLER: + g_assert_not_reached (); + break; + default: + g_assert_not_reached (); + } +} + +gboolean +mono_class_has_metadata_update_info (MonoClass *klass) +{ + switch (m_class_get_class_kind (klass)) { + case MONO_CLASS_GTD: + return FALSE; + case MONO_CLASS_DEF: + return get_pointer_property (klass, PROP_METADATA_UPDATE_INFO) != NULL; + case MONO_CLASS_GINST: + case MONO_CLASS_GPARAM: + case MONO_CLASS_POINTER: + case MONO_CLASS_GC_FILLER: + return FALSE; + default: + g_assert_not_reached (); + } +} + + #ifdef MONO_CLASS_DEF_PRIVATE #define MONO_CLASS_GETTER(funcname, rettype, optref, argtype, fieldname) rettype funcname (argtype *klass) { return optref klass-> fieldname ; } #define MONO_CLASS_OFFSET(funcname, argtype, fieldname) intptr_t funcname (void) { return MONO_STRUCT_OFFSET (argtype, fieldname); } diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 6164476ba9a91..750dcff22d70b 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -434,7 +434,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError error_init (error); /* FIXME: metadata-update - this function needs extensive work */ - if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > table_info_get_rows (tt)) { + if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || mono_metadata_table_bounds_check (image, MONO_TABLE_TYPEDEF, tidx)) { mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token); return NULL; } @@ -614,27 +614,33 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError /* * Compute the field and method lists */ - int first_field_idx; - first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1; - mono_class_set_first_field_idx (klass, first_field_idx); - int first_method_idx; - first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1; - mono_class_set_first_method_idx (klass, first_method_idx); - - if (table_info_get_rows (tt) > tidx){ - mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE); - field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1; - method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1; - } else { - field_last = table_info_get_rows (&image->tables [MONO_TABLE_FIELD]); - method_last = table_info_get_rows (&image->tables [MONO_TABLE_METHOD]); - } + /* + * EnC metadata-update: new classes are added with method and field indices set to 0, new + * methods are added using the EnCLog AddMethod or AddField functions that will be added to + * MonoClassMetadataUpdateInfo + */ + if (G_LIKELY (cols [MONO_TYPEDEF_FIELD_LIST] != 0 || cols [MONO_TYPEDEF_METHOD_LIST] != 0)) { + int first_field_idx; + first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1; + mono_class_set_first_field_idx (klass, first_field_idx); + int first_method_idx; + first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1; + mono_class_set_first_method_idx (klass, first_method_idx); + if (table_info_get_rows (tt) > tidx) { + mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE); + field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1; + method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1; + } else { + field_last = table_info_get_rows (&image->tables [MONO_TABLE_FIELD]); + method_last = table_info_get_rows (&image->tables [MONO_TABLE_METHOD]); + } - if (cols [MONO_TYPEDEF_FIELD_LIST] && - cols [MONO_TYPEDEF_FIELD_LIST] <= table_info_get_rows (&image->tables [MONO_TABLE_FIELD])) - mono_class_set_field_count (klass, field_last - first_field_idx); - if (cols [MONO_TYPEDEF_METHOD_LIST] <= table_info_get_rows (&image->tables [MONO_TABLE_METHOD])) - mono_class_set_method_count (klass, method_last - first_method_idx); + if (cols [MONO_TYPEDEF_FIELD_LIST] && + cols [MONO_TYPEDEF_FIELD_LIST] <= table_info_get_rows (&image->tables [MONO_TABLE_FIELD])) + mono_class_set_field_count (klass, field_last - first_field_idx); + if (cols [MONO_TYPEDEF_METHOD_LIST] <= table_info_get_rows (&image->tables [MONO_TABLE_METHOD])) + mono_class_set_method_count (klass, method_last - first_method_idx); + } /* reserve space to store vector pointer in arrays */ if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) { @@ -4080,16 +4086,3 @@ mono_classes_init (void) mono_counters_register ("MonoClass size", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size); } - -void -m_field_set_parent (MonoClassField *field, MonoClass *klass) -{ - uintptr_t old_flags = m_field_get_meta_flags (field); - field->parent_and_flags = ((uintptr_t)klass) | old_flags; -} - -void -m_field_set_meta_flags (MonoClassField *field, unsigned int flags) -{ - field->parent_and_flags |= (field->parent_and_flags & ~MONO_CLASS_FIELD_META_FLAG_MASK) | flags; -} diff --git a/src/mono/mono/metadata/class-inlines.h b/src/mono/mono/metadata/class-inlines.h index a9aa3c992a541..e45350a8bc4aa 100644 --- a/src/mono/mono/metadata/class-inlines.h +++ b/src/mono/mono/metadata/class-inlines.h @@ -253,4 +253,18 @@ m_method_is_wrapper (MonoMethod *method) return method->wrapper_type != 0; } + +static inline void +m_field_set_parent (MonoClassField *field, MonoClass *klass) +{ + uintptr_t old_flags = m_field_get_meta_flags (field); + field->parent_and_flags = ((uintptr_t)klass) | old_flags; +} + +static inline void +m_field_set_meta_flags (MonoClassField *field, unsigned int flags) +{ + field->parent_and_flags |= (field->parent_and_flags & ~MONO_CLASS_FIELD_META_FLAG_MASK) | flags; +} + #endif diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 01104274c1f3b..4a7992875bf68 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -1231,7 +1231,7 @@ mono_class_get_generic_container (MonoClass *klass); gpointer mono_class_alloc (MonoClass *klass, int size); -gpointer +MONO_COMPONENT_API gpointer mono_class_alloc0 (MonoClass *klass, int size); #define mono_class_alloc0(klass, size) (g_cast (mono_class_alloc0 ((klass), (size)))) @@ -1455,6 +1455,18 @@ mono_class_set_dim_conflicts (MonoClass *klass, GSList *conflicts); GSList* mono_class_get_dim_conflicts (MonoClass *klass); +/* opaque struct of class specific hot reload info */ +typedef struct _MonoClassMetadataUpdateInfo MonoClassMetadataUpdateInfo; + +MONO_COMPONENT_API gboolean +mono_class_has_metadata_update_info (MonoClass *klass); + +MONO_COMPONENT_API MonoClassMetadataUpdateInfo * +mono_class_get_metadata_update_info (MonoClass *klass); + +MONO_COMPONENT_API void +mono_class_set_metadata_update_info (MonoClass *klass, MonoClassMetadataUpdateInfo *value); + MONO_COMPONENT_API MonoMethod * mono_class_get_method_from_name_checked (MonoClass *klass, const char *name, int param_count, int flags, MonoError *error); @@ -1492,7 +1504,7 @@ mono_class_get_default_finalize_method (void); const char * mono_field_get_rva (MonoClassField *field, int swizzle); -void +MONO_COMPONENT_API void mono_field_resolve_type (MonoClassField *field, MonoError *error); gboolean @@ -1575,12 +1587,6 @@ m_field_get_meta_flags (MonoClassField *field) return (unsigned int)(field->parent_and_flags & MONO_CLASS_FIELD_META_FLAG_MASK); } -void -m_field_set_parent (MonoClassField *field, MonoClass *klass); - -void -m_field_set_meta_flags (MonoClassField *field, unsigned int flags); - static inline gboolean m_field_get_offset (MonoClassField *field) { diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index 04af2642f252d..895a654cbfeaa 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -2401,6 +2402,10 @@ mono_class_get_field_idx (MonoClass *klass, int idx) return &klass_fields [idx - first_field_idx]; } } + if (G_UNLIKELY (m_class_get_image (klass)->has_updates && mono_class_has_metadata_update_info (klass))) { + uint32_t token = mono_metadata_make_token (MONO_TABLE_FIELD, idx + 1); + return mono_metadata_update_get_field (klass, token); + } } klass = m_class_get_parent (klass); } @@ -5715,6 +5720,14 @@ mono_find_method_in_metadata (MonoClass *klass, const char *name, int param_coun } } + if (G_UNLIKELY (!res && klass_image->has_updates)) { + if (mono_class_has_metadata_update_info (klass)) { + ERROR_DECL (error); + res = mono_metadata_update_find_method_by_name (klass, name, param_count, flags, error); + mono_error_cleanup (error); + } + } + return res; } @@ -5777,7 +5790,8 @@ mono_class_get_method_from_name_checked (MonoClass *klass, const char *name, FIXME we should better report this error to the caller */ MonoMethod **klass_methods = m_class_get_methods (klass); - if (!klass_methods) + gboolean has_updates = m_class_get_image (klass)->has_updates; + if (!klass_methods && !has_updates) return NULL; int mcount = mono_class_get_method_count (klass); for (i = 0; i < mcount; ++i) { @@ -5791,6 +5805,9 @@ mono_class_get_method_from_name_checked (MonoClass *klass, const char *name, break; } } + if (G_UNLIKELY (!res && has_updates && mono_class_has_metadata_update_info (klass))) { + res = mono_metadata_update_find_method_by_name (klass, name, param_count, flags, error); + } } else { res = mono_find_method_in_metadata (klass, name, param_count, flags); @@ -6417,11 +6434,18 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) MonoImage *image = m_class_get_image (klass); MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL; MonoType *ftype; - int field_idx = field - m_class_get_fields (klass); + int field_idx; + + if (G_UNLIKELY (m_field_is_from_update (field))) { + field_idx = -1; + } else { + field_idx = field - m_class_get_fields (klass); + } error_init (error); if (gtd) { + g_assert (field_idx != -1); MonoClassField *gfield = &m_class_get_fields (gtd) [field_idx]; MonoType *gtype = mono_field_get_type_checked (gfield, error); if (!is_ok (error)) { @@ -6440,7 +6464,13 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) const char *sig; guint32 cols [MONO_FIELD_SIZE]; MonoGenericContainer *container = NULL; - int idx = mono_class_get_first_field_idx (klass) + field_idx; + int idx; + + if (G_UNLIKELY (m_field_is_from_update (field))) { + idx = mono_metadata_update_get_field_idx (field) - 1; + } else { + idx = mono_class_get_first_field_idx (klass) + field_idx; + } /*FIXME, in theory we do not lazy load SRE fields*/ g_assert (!image_is_dynamic (image)); diff --git a/src/mono/mono/metadata/custom-attrs.c b/src/mono/mono/metadata/custom-attrs.c index 580a51b497d37..59a3ce25983e1 100644 --- a/src/mono/mono/metadata/custom-attrs.c +++ b/src/mono/mono/metadata/custom-attrs.c @@ -25,6 +25,7 @@ #include "mono/metadata/tabledefs.h" #include "mono/metadata/tokentype.h" #include "mono/metadata/icall-decl.h" +#include "mono/metadata/metadata-update.h" #include "mono/utils/checked-build.h" #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a)) @@ -150,6 +151,8 @@ free_param_data (MonoMethodSignature *sig, void **params) { */ static guint32 find_field_index (MonoClass *klass, MonoClassField *field) { + if (G_UNLIKELY (m_field_is_from_update (field))) + return mono_metadata_update_get_field_idx (field); int fcount = mono_class_get_field_count (klass); MonoClassField *klass_fields = m_class_get_fields (klass); int index = field - klass_fields; @@ -1626,8 +1629,6 @@ mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ig error_init (error); ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE]; - /* FIXME: metadata-update */ - int rows = table_info_get_rows (ca); i = mono_metadata_custom_attrs_from_index (image, idx); if (!i) @@ -1635,9 +1636,17 @@ mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ig i --; // initial size chosen arbitrarily, but default is 16 which is rather small attr_array = g_array_sized_new (TRUE, TRUE, sizeof (guint32), 128); - while (i < rows) { - if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx) - break; + while (!mono_metadata_table_bounds_check (image, MONO_TABLE_CUSTOMATTRIBUTE, i + 1)) { + if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx) { + if (G_LIKELY (!image->has_updates)) { + break; + } else { + // if there are updates, the new custom attributes are not sorted, + // so we have to go until the end. + ++i; + continue; + } + } attr_array = g_array_append_val (attr_array, i); ++i; } diff --git a/src/mono/mono/metadata/loader-internals.h b/src/mono/mono/metadata/loader-internals.h index bc79d38d4eb5b..772c2dc875ebb 100644 --- a/src/mono/mono/metadata/loader-internals.h +++ b/src/mono/mono/metadata/loader-internals.h @@ -356,6 +356,18 @@ mono_mem_manager_get_generic (MonoImage **images, int nimages); MonoMemoryManager* mono_mem_manager_merge (MonoMemoryManager *mm1, MonoMemoryManager *mm2); +static inline GSList* +g_slist_prepend_mem_manager (MonoMemoryManager *memory_manager, GSList *list, gpointer data) +{ + GSList *new_list; + + new_list = (GSList *) mono_mem_manager_alloc (memory_manager, sizeof (GSList)); + new_list->data = data; + new_list->next = list; + + return new_list; +} + G_END_DECLS #endif diff --git a/src/mono/mono/metadata/metadata-update.c b/src/mono/mono/metadata/metadata-update.c index 800ffb9f04727..e24823ead81f3 100644 --- a/src/mono/mono/metadata/metadata-update.c +++ b/src/mono/mono/metadata/metadata-update.c @@ -12,6 +12,7 @@ #include "mono/metadata/metadata-update.h" #include "mono/metadata/components.h" +#include "mono/metadata/class-internals.h" #include "mono/component/hot_reload.h" gboolean @@ -147,3 +148,37 @@ mono_metadata_table_num_rows_slow (MonoImage *base_image, int table_index) { return mono_component_hot_reload()->table_num_rows_slow (base_image, table_index); } + +void* +mono_metadata_update_metadata_linear_search (MonoImage *base_image, MonoTableInfo *base_table, const void *key, BinarySearchComparer comparer) +{ + return mono_component_hot_reload()->metadata_linear_search (base_image, base_table, key, comparer); +} + +/* + * Returns the (1-based) table row index of the fielddef of the given field + * (which must have m_field_is_from_update set). + */ +uint32_t +mono_metadata_update_get_field_idx (MonoClassField *field) +{ + return mono_component_hot_reload()->get_field_idx (field); +} + +MonoClassField * +mono_metadata_update_get_field (MonoClass *klass, uint32_t fielddef_token) +{ + return mono_component_hot_reload()->get_field (klass, fielddef_token); +} + +gpointer +mono_metadata_update_get_static_field_addr (MonoClassField *field) +{ + return mono_component_hot_reload()->get_static_field_addr (field); +} + +MonoMethod * +mono_metadata_update_find_method_by_name (MonoClass *klass, const char *name, int param_count, int flags, MonoError *error) +{ + return mono_component_hot_reload()->find_method_by_name (klass, name, param_count, flags, error); +} diff --git a/src/mono/mono/metadata/metadata-update.h b/src/mono/mono/metadata/metadata-update.h index 15d0d51e10f4a..ee999a4f0a10f 100644 --- a/src/mono/mono/metadata/metadata-update.h +++ b/src/mono/mono/metadata/metadata-update.h @@ -6,6 +6,7 @@ #define __MONO_METADATA_UPDATE_H__ #include "mono/utils/mono-forward.h" +#include "mono/utils/bsearch.h" #include "mono/metadata/loader-internals.h" #include "mono/metadata/metadata-internals.h" @@ -57,4 +58,19 @@ mono_metadata_update_table_bounds_check (MonoImage *base_image, int table_index, gboolean mono_metadata_update_delta_heap_lookup (MonoImage *base_image, MetadataHeapGetterFunc get_heap, uint32_t orig_index, MonoImage **image_out, uint32_t *index_out); +void* +mono_metadata_update_metadata_linear_search (MonoImage *base_image, MonoTableInfo *base_table, const void *key, BinarySearchComparer comparer); + +MonoMethod* +mono_metadata_update_find_method_by_name (MonoClass *klass, const char *name, int param_count, int flags, MonoError *error); + +uint32_t +mono_metadata_update_get_field_idx (MonoClassField *field); + +MonoClassField * +mono_metadata_update_get_field (MonoClass *klass, uint32_t fielddef_token); + +gpointer +mono_metadata_update_get_static_field_addr (MonoClassField *field); + #endif /*__MONO_METADATA_UPDATE_H__*/ diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 04a43f5e0076f..8aa7a921ab48c 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -4801,7 +4801,12 @@ mono_metadata_typedef_from_field (MonoImage *meta, guint32 index) if (meta->uncompressed_metadata) loc.idx = search_ptr_table (meta, MONO_TABLE_FIELD_POINTER, loc.idx); - /* FIXME: metadata-update */ + /* if it's not in the base image, look in the hot reload table */ + gboolean added = (loc.idx > table_info_get_rows (&meta->tables [MONO_TABLE_FIELD])); + if (added) { + uint32_t res = mono_component_hot_reload()->field_parent (meta, loc.idx); + return res; /* 0 if not found, otherwise 1-based */ + } if (!mono_binary_search (&loc, tdef->base, table_info_get_rows (tdef), tdef->row_size, typedef_locator)) return 0; @@ -4974,18 +4979,22 @@ mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index) MonoTableInfo *tdef = &meta->tables [MONO_TABLE_NESTEDCLASS]; locator_t loc; - if (!tdef->base) + if (!tdef->base && !meta->has_updates) return 0; loc.idx = mono_metadata_token_index (index); loc.col_idx = MONO_NESTED_CLASS_NESTED; loc.t = tdef; - /* FIXME: metadata-update */ - - if (!mono_binary_search (&loc, tdef->base, table_info_get_rows (tdef), tdef->row_size, table_locator)) + gboolean found = tdef->base && mono_binary_search (&loc, tdef->base, table_info_get_rows (tdef), tdef->row_size, table_locator) != NULL; + if (!found && !meta->has_updates) return 0; + if (G_UNLIKELY (meta->has_updates)) { + if (!found && !mono_metadata_update_metadata_linear_search (meta, tdef, &loc, table_locator)) + return 0; + } + /* loc_result is 0..1, needs to be mapped to table index (that is +1) */ return mono_metadata_decode_row_col (tdef, loc.result, MONO_NESTED_CLASS_ENCLOSING) | MONO_TOKEN_TYPE_DEF; } @@ -5077,19 +5086,24 @@ mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index) MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CUSTOMATTRIBUTE]; locator_t loc; - if (!tdef->base) + if (!tdef->base && !meta->has_updates) return 0; loc.idx = index; loc.col_idx = MONO_CUSTOM_ATTR_PARENT; loc.t = tdef; - /* FIXME: metadata-update */ /* FIXME: Index translation */ - if (!mono_binary_search (&loc, tdef->base, table_info_get_rows (tdef), tdef->row_size, table_locator)) + gboolean found = tdef->base && mono_binary_search (&loc, tdef->base, table_info_get_rows (tdef), tdef->row_size, table_locator) != NULL; + if (!found && !meta->has_updates) return 0; + if (G_UNLIKELY (meta->has_updates)) { + if (!found && !mono_metadata_update_metadata_linear_search (meta, tdef, &loc, table_locator)) + return 0; + } + /* Find the first entry by searching backwards */ while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_CUSTOM_ATTR_PARENT) == index)) loc.result --; diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 6c6d089ee2122..c1c4d939df2a1 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -1666,7 +1666,7 @@ mono_class_set_ref_info (MonoClass *klass, MonoObjectHandle obj); void mono_class_free_ref_info (MonoClass *klass); -MonoObject * +MONO_COMPONENT_API MonoObject * mono_object_new_pinned (MonoClass *klass, MonoError *error); MonoObjectHandle diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index 284e15b1ade8e..55afb98f2f194 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -2854,6 +2855,9 @@ mono_static_field_get_addr (MonoVTable *vt, MonoClassField *field) g_assert (field->type->attrs & FIELD_ATTRIBUTE_STATIC); if (field->offset == -1) { + if (G_UNLIKELY (m_field_is_from_update (field))) { + return mono_metadata_update_get_static_field_addr (field); + } /* Special static */ ERROR_DECL (error); gpointer addr = mono_special_static_field_get_offset (field, error); diff --git a/src/mono/mono/utils/mono-error-internals.h b/src/mono/mono/utils/mono-error-internals.h index a26558689ae1c..f43727dde76bf 100644 --- a/src/mono/mono/utils/mono-error-internals.h +++ b/src/mono/mono/utils/mono-error-internals.h @@ -202,6 +202,7 @@ mono_error_set_generic_error (MonoError *error, const char * name_space, const c void mono_error_set_execution_engine (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3); +MONO_COMPONENT_API void mono_error_set_not_implemented (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3); From 93cb3559a17aca424e3ce1206a71496da2c34b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Honza=20Rame=C5=A1?= Date: Wed, 19 Jan 2022 01:12:18 +0100 Subject: [PATCH 028/308] Reduce allocations in code generated by Logging generators (#61162) (#62011) --- .../gen/LoggerMessageGenerator.Emitter.cs | 14 +++++++++++++- .../Baselines/.editorconfig | 4 ++++ .../Baselines/TestWithDefaultValues.generated.txt | 4 +++- .../TestWithDynamicLogLevel.generated.txt | 4 +++- .../TestWithMoreThan6Params.generated.txt | 6 +++++- 5 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/.editorconfig diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Emitter.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Emitter.cs index 53dd062b5d4b4..69f87fdcd48f6 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Emitter.cs @@ -16,10 +16,18 @@ internal class Emitter private const int MaxLoggerMessageDefineArguments = 6; private const int DefaultStringBuilderCapacity = 1024; + private static readonly string s_generatedTypeSummary = + " " + + "This API supports the logging infrastructure and is not intended to be used directly from your code. " + + "It is subject to change in the future. " + + ""; private static readonly string s_generatedCodeAttribute = $"global::System.CodeDom.Compiler.GeneratedCodeAttribute(" + $"\"{typeof(Emitter).Assembly.GetName().Name}\", " + $"\"{typeof(Emitter).Assembly.GetName().Version}\")"; + private static readonly string s_editorBrowsableAttribute = + "global::System.ComponentModel.EditorBrowsableAttribute(" + + "global::System.ComponentModel.EditorBrowsableState.Never)"; private readonly StringBuilder _builder = new StringBuilder(DefaultStringBuilderCapacity); private bool _needEnumerationHelper; @@ -127,7 +135,9 @@ namespace {lc.Namespace} private void GenStruct(LoggerMethod lm, string nestedIndentation) { _builder.AppendLine($@" + {nestedIndentation}/// {s_generatedTypeSummary} {nestedIndentation}[{s_generatedCodeAttribute}] + {nestedIndentation}[{s_editorBrowsableAttribute}] {nestedIndentation}private readonly struct __{lm.Name}Struct : global::System.Collections.Generic.IReadOnlyList> {nestedIndentation}{{"); GenFields(lm, nestedIndentation); @@ -156,7 +166,7 @@ private void GenStruct(LoggerMethod lm, string nestedIndentation) {nestedIndentation}}} "); _builder.Append($@" - {nestedIndentation}public static string Format(__{lm.Name}Struct state, global::System.Exception? ex) => state.ToString(); + {nestedIndentation}public static readonly global::System.Func<__{lm.Name}Struct, global::System.Exception?, string> Format = (state, ex) => state.ToString(); {nestedIndentation}public int Count => {lm.TemplateParameters.Count + 1}; @@ -489,7 +499,9 @@ private void GenEnumerationHelper() if (_needEnumerationHelper) { _builder.Append($@" +/// {s_generatedTypeSummary} [{s_generatedCodeAttribute}] +[{s_editorBrowsableAttribute}] internal static class __LoggerMessageGenerator {{ public static string Enumerate(global::System.Collections.IEnumerable? enumerable) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/.editorconfig b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/.editorconfig new file mode 100644 index 0000000000000..e9356fee5e6d2 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/.editorconfig @@ -0,0 +1,4 @@ +# editorconfig.org + +[*.generated.txt] +insert_final_newline = false diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithDefaultValues.generated.txt b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithDefaultValues.generated.txt index f4747ef679f83..5292db82ac8c8 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithDefaultValues.generated.txt +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithDefaultValues.generated.txt @@ -5,7 +5,9 @@ namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses { partial class TestWithDefaultValues { + /// This API supports the logging infrastructure and is not intended to be used directly from your code. It is subject to change in the future. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] private readonly struct __M0Struct : global::System.Collections.Generic.IReadOnlyList> { @@ -15,7 +17,7 @@ namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses return $""; } - public static string Format(__M0Struct state, global::System.Exception? ex) => state.ToString(); + public static readonly global::System.Func<__M0Struct, global::System.Exception?, string> Format = (state, ex) => state.ToString(); public int Count => 1; diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithDynamicLogLevel.generated.txt b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithDynamicLogLevel.generated.txt index 1d1af4719fe40..6326923544aa9 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithDynamicLogLevel.generated.txt +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithDynamicLogLevel.generated.txt @@ -5,7 +5,9 @@ namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses { partial class TestWithDynamicLogLevel { + /// This API supports the logging infrastructure and is not intended to be used directly from your code. It is subject to change in the future. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] private readonly struct __M9Struct : global::System.Collections.Generic.IReadOnlyList> { @@ -15,7 +17,7 @@ namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses return $"M9"; } - public static string Format(__M9Struct state, global::System.Exception? ex) => state.ToString(); + public static readonly global::System.Func<__M9Struct, global::System.Exception?, string> Format = (state, ex) => state.ToString(); public int Count => 1; diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithMoreThan6Params.generated.txt b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithMoreThan6Params.generated.txt index 3387ec2da1a32..84611c6766f72 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithMoreThan6Params.generated.txt +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithMoreThan6Params.generated.txt @@ -5,7 +5,9 @@ namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses { partial class TestWithMoreThan6Params { + /// This API supports the logging infrastructure and is not intended to be used directly from your code. It is subject to change in the future. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] private readonly struct __Method9Struct : global::System.Collections.Generic.IReadOnlyList> { private readonly global::System.Int32 _p1; @@ -41,7 +43,7 @@ namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses return $"M9 {p1} {p2} {p3} {p4} {p5} {p6} {p7}"; } - public static string Format(__Method9Struct state, global::System.Exception? ex) => state.ToString(); + public static readonly global::System.Func<__Method9Struct, global::System.Exception?, string> Format = (state, ex) => state.ToString(); public int Count => 8; @@ -88,7 +90,9 @@ namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses } } } +/// This API supports the logging infrastructure and is not intended to be used directly from your code. It is subject to change in the future. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] +[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] internal static class __LoggerMessageGenerator { public static string Enumerate(global::System.Collections.IEnumerable? enumerable) From cde93b69b6b099627d3615ec7f54cfb28b25bcde Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Tue, 18 Jan 2022 16:57:51 -0800 Subject: [PATCH 029/308] JIT: yet another OSR stress mode (#62980) Existing OSR stress use existing patchpoint placement logic and alter the policy settings so that OSR methods are created more eagerly. This new version of OSR stress alters the patchpoint placement logic, to add patchpoints to more places. In conjunction with the eager policy stress above this leads to creation and execution of large numbers of OSR methods. Any IL offset in the method with an empty stack (and not in a handler) is fair game for a patchpoint, so this new method randomly adds patchpoints to the starts of blocks when stack empty (future work may extend this to mid-block stack empty points). The new mode is enabled by setting `COMPlus_JitRandomOnStackReplacement` to a non-zero value; this value represents the likelihood of adding a patchpoint at a stack-empty block start, and also factors into the random seed. (Recall this is parsed in hex, so 0x64 == 100 or larger will put a patchpoint at the start of every stack empty block). Various values are interesting because once a method reaches a patchpoint and triggers OSR, the remainder of that method's execution is in the OSR method, so later patchpoints in the original method may never be reached. So some sort of random/selective patchpoint approach (in conjunction with varying policy settings) is needed to ensure that we create an execute as many different OSR variants as possible. This PR also includes a couple of fixes exposed by local testing of this new stress mode: * The OSR prolog may end up empty, which gcencoder doesn't like. Detect this and add a `nop` for the prolog. * If we're importing the `fgEntryBB` during OSR, we don't need to schedule it for re-importation. This happens if we put a patchpoint at IL offset zero. * Update the selective dumping policy `COMPlus_JitDumpAtOSROoffset` to only dump OSR method compilations. A new test leg is added to `jit-experimental` to run with this mode enabled with a probability of 21% (0x15) and quick OSR triggers. Also included: * fix probability calc * remove obsolete assert * osr exposed does not apply to simd * only pad zero-sized OSR prolog if we're reporting generic context * Add ability to have patchpoint at specified offset. * Fix interaction of stress patchpoints and profile instrumentation. We need to force block-based instrumentation if we might have stress patchpoints. --- .../templates/runtimes/run-test-job.yml | 1 + src/coreclr/jit/codegencommon.cpp | 16 ++-- src/coreclr/jit/compiler.cpp | 16 ++-- src/coreclr/jit/fgdiagnostic.cpp | 4 +- src/coreclr/jit/fgprofile.cpp | 17 +++- src/coreclr/jit/importer.cpp | 96 +++++++++++++++---- src/coreclr/jit/jitconfigvalues.h | 6 ++ src/coreclr/jit/lclvars.cpp | 4 +- src/tests/Common/testenvironment.proj | 2 + 9 files changed, 123 insertions(+), 39 deletions(-) diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml index 04399d26a6a22..214b56547b7ac 100644 --- a/eng/pipelines/common/templates/runtimes/run-test-job.yml +++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml @@ -546,6 +546,7 @@ jobs: - jitosr - jitosr_stress - jitosr_pgo + - jitosr_stress_random - jitpartialcompilation - jitpartialcompilation_osr - jitpartialcompilation_osr_pgo diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 7072e4fd66b0a..1c9eda6f63afc 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -6236,15 +6236,9 @@ void CodeGen::genEnregisterOSRArgsAndLocals() // This local was part of the live tier0 state and is enregistered in the // OSR method. Initialize the register from the right frame slot. // - // We currently don't expect to see enregistered multi-reg args in OSR methods, - // as struct promotion is disabled. So any struct arg just uses the location - // on the tier0 frame. - // // If we ever enable promotion we'll need to generalize what follows to copy each // field from the tier0 frame to its OSR home. // - assert(!varDsc->lvIsMultiRegArg); - if (!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex)) { // This arg or local is not live at entry to the OSR method. @@ -7543,6 +7537,16 @@ void CodeGen::genFnProlog() #endif // PROFILING_SUPPORTED + // For OSR we may have a zero-length prolog. That's not supported + // when the method must report a generics context,/ so add a nop if so. + // + if (compiler->opts.IsOSR() && (GetEmitter()->emitGetPrologOffsetEstimate() == 0) && + (compiler->lvaReportParamTypeArg() || compiler->lvaKeepAliveAndReportThis())) + { + JITDUMP("OSR: prolog was zero length and has generic context to report: adding nop to pad prolog.\n"); + instGen(INS_nop); + } + if (!GetInterruptible()) { // The 'real' prolog ends here for non-interruptible methods. diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index b8775857bb659..56701ceb08fad 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -2644,15 +2644,19 @@ void Compiler::compInitOptions(JitFlags* jitFlags) verboseDump = (JitConfig.JitDumpTier0() > 0); } - // Optionally suppress dumping some OSR jit requests. + // Optionally suppress dumping except for a specific OSR jit request. // - if (verboseDump && jitFlags->IsSet(JitFlags::JIT_FLAG_OSR)) - { - const int desiredOffset = JitConfig.JitDumpAtOSROffset(); + const int dumpAtOSROffset = JitConfig.JitDumpAtOSROffset(); - if (desiredOffset != -1) + if (verboseDump && (dumpAtOSROffset != -1)) + { + if (jitFlags->IsSet(JitFlags::JIT_FLAG_OSR)) + { + verboseDump = (((IL_OFFSET)dumpAtOSROffset) == info.compILEntry); + } + else { - verboseDump = (((IL_OFFSET)desiredOffset) == info.compILEntry); + verboseDump = false; } } diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index 3b3a84007fa45..0bc461ebbb949 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -2151,11 +2151,11 @@ void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 * { if (block == fgEntryBB) { - printf("original-entry"); + printf(" original-entry"); } if (block == fgOSREntryBB) { - printf("osr-entry"); + printf(" osr-entry"); } } diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index 27b16ababf96b..34ab390a9b899 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -1721,12 +1721,23 @@ PhaseStatus Compiler::fgPrepareToInstrumentMethod() // jitting on PGO. If we ever implement a broader pattern of deferral -- say deferring // based on static PGO -- we will need to reconsider. // + // Under OSR stress we may add patchpoints even without backedges. So we also + // need to change the PGO instrumetation approach if OSR stress is enabled. + // CLANG_FORMAT_COMMENT_ANCHOR; +#if defined(DEBUG) + const bool mayHaveStressPatchpoints = + (JitConfig.JitOffsetOnStackReplacement() >= 0) || (JitConfig.JitRandomOnStackReplacement() > 0); +#else + const bool mayHaveStressPatchpoints = false; +#endif + + const bool mayHavePatchpoints = + (JitConfig.TC_OnStackReplacement() > 0) && (compHasBackwardJump || mayHaveStressPatchpoints); const bool prejit = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT); - const bool tier0WithPatchpoints = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0) && - (JitConfig.TC_OnStackReplacement() > 0) && compHasBackwardJump; - const bool osrMethod = opts.IsOSR(); + const bool tier0WithPatchpoints = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0) && mayHavePatchpoints; + const bool osrMethod = opts.IsOSR(); const bool useEdgeProfiles = (JitConfig.JitEdgeProfiling() > 0) && !prejit && !tier0WithPatchpoints && !osrMethod; if (useEdgeProfiles) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 64c0eb44c5891..ffdddf2870f06 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -11786,28 +11786,30 @@ void Compiler::impImportBlockCode(BasicBlock* block) #ifdef FEATURE_ON_STACK_REPLACEMENT - // Are there any places in the method where we might add a patchpoint? + // Is OSR enabled? // - if (compHasBackwardJump) + if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0) && (JitConfig.TC_OnStackReplacement() > 0)) { - // Is OSR enabled? + // We don't inline at Tier0, if we do, we may need rethink our approach. + // Could probably support inlines that don't introduce flow. // - if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0) && (JitConfig.TC_OnStackReplacement() > 0)) + assert(!compIsForInlining()); + + // OSR is not yet supported for methods with explicit tail calls. + // + // But we also do not have to switch these methods to be optimized as we should be + // able to avoid getting trapped in Tier0 code by normal call counting. + // So instead, just suppress adding patchpoints. + // + if (!compTailPrefixSeen) { - // OSR is not yet supported for methods with explicit tail calls. - // - // But we also may not switch methods to be optimized as we should be - // able to avoid getting trapped in Tier0 code by normal call counting. - // So instead, just suppress adding patchpoints. + assert(compCanHavePatchpoints()); + + // The normaly policy is only to add patchpoints to the targets of lexically + // backwards branches. // - if (!compTailPrefixSeen) + if (compHasBackwardJump) { - assert(compCanHavePatchpoints()); - - // 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? // if (((block->bbFlags & BBF_BACKWARD_JUMP_TARGET) != 0) && (verCurrentState.esStackDepth == 0)) @@ -11820,12 +11822,64 @@ void Compiler::impImportBlockCode(BasicBlock* block) setMethodHasPatchpoint(); } } + else + { + // Should not see backward branch targets w/o backwards branches + assert((block->bbFlags & BBF_BACKWARD_JUMP_TARGET) == 0); + } } - } - else - { - // Should not see backward branch targets w/o backwards branches - assert((block->bbFlags & BBF_BACKWARD_JUMP_TARGET) == 0); + +#ifdef DEBUG + // As a stress test, we can place patchpoints at the start of any block + // that is a stack empty point and is not within a handler. + // + // Todo: enable for mid-block stack empty points too. + // + const int offsetOSR = JitConfig.JitOffsetOnStackReplacement(); + const int randomOSR = JitConfig.JitRandomOnStackReplacement(); + const bool tryOffsetOSR = offsetOSR >= 0; + const bool tryRandomOSR = randomOSR > 0; + + if ((tryOffsetOSR || tryRandomOSR) && (verCurrentState.esStackDepth == 0) && !block->hasHndIndex() && + ((block->bbFlags & BBF_PATCHPOINT) == 0)) + { + // Block start can have a patchpoint. See if we should add one. + // + bool addPatchpoint = false; + + // Specific offset? + // + if (tryOffsetOSR) + { + if (impCurOpcOffs == (unsigned)offsetOSR) + { + addPatchpoint = true; + } + } + // Random? + // + else + { + // Reuse the random inliner's random state. + // Note m_inlineStrategy is always created, even if we're not inlining. + // + CLRRandom* const random = impInlineRoot()->m_inlineStrategy->GetRandom(randomOSR); + const int randomValue = (int)random->Next(100); + + addPatchpoint = (randomValue < randomOSR); + } + + if (addPatchpoint) + { + block->bbFlags |= BBF_PATCHPOINT; + setMethodHasPatchpoint(); + } + + JITDUMP("\n** %s patchpoint%s added to " FMT_BB " (il offset %u)\n", tryOffsetOSR ? "offset" : "random", + addPatchpoint ? "" : " not", block->bbNum, impCurOpcOffs); + } + +#endif // DEBUG } // Mark stack-empty rare blocks to be considered for partial compilation. diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index 1c8da276c3dc5..4fc4594c6fb2b 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -463,6 +463,12 @@ CONFIG_INTEGER(TC_OnStackReplacement, W("TC_OnStackReplacement"), 0) CONFIG_INTEGER(TC_OnStackReplacement_InitialCounter, W("TC_OnStackReplacement_InitialCounter"), 1000) // Enable partial compilation for Tier0 methods CONFIG_INTEGER(TC_PartialCompilation, W("TC_PartialCompilation"), 0) +#if defined(DEBUG) +// Randomly sprinkle patchpoints. Value is the likelyhood any given stack-empty point becomes a patchpoint. +CONFIG_INTEGER(JitRandomOnStackReplacement, W("JitRandomOnStackReplacement"), 0) +// Place patchpoint at the specified IL offset, if possible. Overrides random placement. +CONFIG_INTEGER(JitOffsetOnStackReplacement, W("JitOffsetOnStackReplacement"), -1) +#endif // debug #if defined(DEBUG) CONFIG_STRING(JitEnableOsrRange, W("JitEnableOsrRange")) // Enable osr for only some methods diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 7b329e0a86a46..eb76cd663f287 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -305,7 +305,9 @@ void Compiler::lvaInitTypeRef() JITDUMP("-- V%02u is OSR exposed\n", varNum); varDsc->lvHasLdAddrOp = 1; - if (varDsc->lvType != TYP_STRUCT) // Why does it apply only to non-structs? + // todo: Why does it apply only to non-structs? + // + if (!varTypeIsStruct(varDsc) && !varTypeIsSIMD(varDsc)) { lvaSetVarAddrExposed(varNum DEBUGARG(AddressExposedReason::OSR_EXPOSED)); } diff --git a/src/tests/Common/testenvironment.proj b/src/tests/Common/testenvironment.proj index c8d6e0d31e59e..aae081a187126 100644 --- a/src/tests/Common/testenvironment.proj +++ b/src/tests/Common/testenvironment.proj @@ -62,6 +62,7 @@ COMPlus_JitEdgeProfiling; COMPlus_JitRandomGuardedDevirtualization; COMPlus_JitRandomEdgeCounts; + COMPlus_JitRandomOnStackReplacement; RunningIlasmRoundTrip @@ -187,6 +188,7 @@ + From 14ebc594b2757e29e1f73742ce37d68f855c0a3c Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 18 Jan 2022 17:36:09 -0800 Subject: [PATCH 030/308] Do not register ACTIVATION_SIGNAL for secondary PAL copies (#63961) Related to #63959 --- src/coreclr/pal/inc/pal.h | 4 +++- src/coreclr/pal/src/exception/signal.cpp | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index bc531d4367174..8f8ab50ed9a52 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -345,6 +345,7 @@ typedef __int64 time_t; #define PAL_INITIALIZE_DEBUGGER_EXCEPTIONS 0x10 #define PAL_INITIALIZE_ENSURE_STACK_SIZE 0x20 #define PAL_INITIALIZE_REGISTER_SIGNALS 0x40 +#define PAL_INITIALIZE_REGISTER_ACTIVATION_SIGNAL 0x80 // PAL_Initialize() flags #define PAL_INITIALIZE (PAL_INITIALIZE_SYNC_THREAD | \ @@ -359,7 +360,8 @@ typedef __int64 time_t; PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER | \ PAL_INITIALIZE_DEBUGGER_EXCEPTIONS | \ PAL_INITIALIZE_ENSURE_STACK_SIZE | \ - PAL_INITIALIZE_REGISTER_SIGNALS) + PAL_INITIALIZE_REGISTER_SIGNALS | \ + PAL_INITIALIZE_REGISTER_ACTIVATION_SIGNAL) typedef DWORD (PALAPI_NOEXPORT *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp index 521150530fa33..58fc78ef357e8 100644 --- a/src/coreclr/pal/src/exception/signal.cpp +++ b/src/coreclr/pal/src/exception/signal.cpp @@ -240,8 +240,11 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags) } #ifdef INJECT_ACTIVATION_SIGNAL - handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation); - g_registered_activation_handler = true; + if (flags & PAL_INITIALIZE_REGISTER_ACTIVATION_SIGNAL) + { + handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation); + g_registered_activation_handler = true; + } #endif return TRUE; From 557901e779a009cf4a51327963727a4d1ded0094 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 18 Jan 2022 20:40:35 -0500 Subject: [PATCH 031/308] Improve auto-atomicity for Regex loops (#63518) * Improve auto-atomicity for Regex loops - As part of recognizing loops that could be made atomic, we currently only look at the node guaranteed to come immediately after it, e.g. in a+b+c+, when analyzing a+ we only look at the b+. That's fine in many cases, but if our expression was instead e.g. a*b*c*, we couldn't make a* atomic because we wouldn't be guaranteed it'd be followed by a b, and we wouldn't look at the subsequent nodes to determine what else might follow. When that situation occurs, we can now walk the tree to find the next node, and repeatedly do so as much as is needed in order to find the next node, enabling us to make all of those loops atomic. - We currently perform the auto-atomicity reduction for single-char loops as part of reducing concatenations. But this means we're performing that transformation at a time when the tree isn't fully formed, which means we can't necessarily reach out of a concatenation to what comes after it and use that to influence the atomicity. It also means we might repeat the analysis unnecessarily multiple times, because it's done as part of parenting a node. We can instead do that optimization as part of the final optimization phase, after the tree is already created. - When we find a lazy loop at the end of an expression, we can treat it as atomic, which means we can lower its max bound to its min bound. - When we encounter a loop (lazy or greedy) at the end of an expression, if it has a max bound of 1 (i.e. it's optional), we can proceed to eliminate ending backtracking with its child regardless of whether the child could be made atomic with the start of the loop, since it won't ever repeat more than once. * Extend auto-atomicity to lazy loops --- .../Text/RegularExpressions/RegexNode.cs | 412 ++++++++++++------ .../tests/Regex.Match.Tests.cs | 12 + .../tests/RegexReductionTests.cs | 26 +- 3 files changed, 306 insertions(+), 144 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index 8f5c0a3039596..0bfb9d4926fbb 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -214,23 +214,33 @@ private void MakeRep(int type, int min, int max) private void MakeLoopAtomic() { - switch (Type) + Debug.Assert(Type is Oneloop or Notoneloop or Setloop); + + // For loops, we simply change the Type to the atomic variant. + // Atomic greedy loops should consume as many values as they can. + Type += Oneloopatomic - Oneloop; + } + + private void MakeLazyAtomic() + { + Debug.Assert(Type is Onelazy or Notonelazy or Setlazy); + + switch (M) { - case Oneloop or Notoneloop or Setloop: - // For loops, we simply change the Type to the atomic variant. - // Atomic greedy loops should consume as many values as they can. - Type += Oneloopatomic - Oneloop; + case 0: + Type = Empty; + Str = null; + Ch = '\0'; break; - case Onelazy or Notonelazy or Setlazy: - // For lazy, we not only change the Type, we also lower the max number of iterations - // to the minimum number of iterations, as they should end up matching as little as possible. - Type += Oneloopatomic - Onelazy; - N = M; + case 1: + Type += One - Onelazy; + M = N = 0; break; default: - Debug.Fail($"Unexpected type: {Type}"); + Type += Oneloopatomic - Onelazy; + N = M; break; } } @@ -362,8 +372,17 @@ internal RegexNode FinalOptimize() Debug.Assert(rootNode.Next is null); Debug.Assert(rootNode.ChildCount() == 1); - if ((Options & RegexOptions.RightToLeft) == 0) // only apply optimization when LTR to avoid needing additional code for the rarer RTL case + // Only apply optimization when LTR to avoid needing additional code for the much rarer RTL case. + // Also only apply these optimizations when not using NonBacktracking, as these optimizations are + // all about avoiding things that are impactful for the backtracking engines but nops for non-backtracking. + if ((Options & (RegexOptions.RightToLeft | RegexOptions.NonBacktracking)) == 0) { + // Optimization: eliminate backtracking for loops. + // For any single-character loop (Oneloop, Notoneloop, Setloop), see if we can automatically convert + // that into its atomic counterpart (Oneloopatomic, Notoneloopatomic, Setloopatomic) based on what + // comes after it in the expression tree. + rootNode.FindAndMakeLoopsAtomic(); + // Optimization: backtracking removal at expression end. // If we find backtracking construct at the end of the regex, we can instead make it non-backtracking, // since nothing would ever backtrack into it anyway. Doing this then makes the construct available @@ -426,19 +445,14 @@ internal RegexNode FinalOptimize() /// private void EliminateEndingBacktracking() { + Debug.Assert((Options & RegexOptions.NonBacktracking) == 0, "NonBacktracking doesn't have backtracking to be eliminated and doesn't support atomic groups."); + if (!StackHelper.TryEnsureSufficientExecutionStack()) { // If we can't recur further, just stop optimizing. return; } - // RegexOptions.NonBacktracking doesn't support atomic groups, so when that option - // is set we don't want to create atomic groups where they weren't explicitly authored. - if ((Options & RegexOptions.NonBacktracking) != 0) - { - return; - } - // Walk the tree starting from the current node. RegexNode node = this; while (true) @@ -446,17 +460,17 @@ private void EliminateEndingBacktracking() switch (node.Type) { // {One/Notone/Set}loops can be upgraded to {One/Notone/Set}loopatomic nodes, e.g. [abc]* => (?>[abc]*). - // And {One/Notone/Set}lazys can similarly be upgraded to be atomic, which really makes them into repeaters - // or even empty nodes. - case Oneloop: - case Notoneloop: - case Setloop: - case Onelazy: - case Notonelazy: - case Setlazy: + case Oneloop or Notoneloop or Setloop: node.MakeLoopAtomic(); break; + // {One/Notone/Set}lazys can similarly be upgraded to be atomic, but in doing so we need to lower their + // max iterations down to their min, as they'll never match more than the min. This effectively makes + // them into a repeater, and we can then downgrade them to a single char or even an empty. + case Onelazy or Notonelazy or Setlazy: + node.MakeLazyAtomic(); + break; + // Just because a particular node is atomic doesn't mean all its descendants are. // Process them as well. case Atomic: @@ -472,7 +486,7 @@ private void EliminateEndingBacktracking() case Capture: case Concatenate: RegexNode existingChild = node.Child(node.ChildCount() - 1); - if ((existingChild.Type == Alternate || existingChild.Type == Loop || existingChild.Type == Lazyloop) && + if ((existingChild.Type is Alternate or Loop or Lazyloop) && (node.Next is null || node.Next.Type != Atomic)) // validate grandparent isn't atomic { var atomic = new RegexNode(Atomic, existingChild.Options); @@ -495,11 +509,27 @@ private void EliminateEndingBacktracking() node = node.Child(0); continue; - // For Loop, we search to see if there's a viable last expression, and iff there - // is we recur into processing it. + // For {Lazy}Loop, we search to see if there's a viable last expression, and iff there + // is we recur into processing it. Also, as with the single-char lazy loops, LazyLoop + // can have its max iteration count dropped to its min iteration count, as there's no + // reason for it to match more than the minimal at the end; that in turn makes it a + // repeater, which results in better code generation. // e.g. (?:abc*)* => (?:ab(?>c*))* + // e.g. (abc*?)+? => (ab){1} + case Lazyloop: + node.N = node.M; + goto case Loop; case Loop: { + if (node.N == 1) + { + // If the loop has a max iteration count of 1 (e.g. it's an optional node), + // there's no possibility for conflict between multiple iterations, so + // we can process it. + node = node.Child(0); + continue; + } + RegexNode? loopDescendent = node.FindLastExpressionInLoopForAutoAtomic(); if (loopDescendent != null) { @@ -651,22 +681,21 @@ private RegexNode ReduceAtomic() switch (child.Type) { // If the child is already atomic, we can just remove the atomic node. - case Oneloopatomic: - case Notoneloopatomic: - case Setloopatomic: + case Oneloopatomic or Notoneloopatomic or Setloopatomic: return child; - // If an atomic subexpression contains only a {one/notone/set}{loop/lazy}, + // If an atomic subexpression contains only a {one/notone/set}loop, // change it to be an {one/notone/set}loopatomic and remove the atomic node. - case Oneloop: - case Notoneloop: - case Setloop: - case Onelazy: - case Notonelazy: - case Setlazy: + case Oneloop or Notoneloop or Setloop: child.MakeLoopAtomic(); return child; + // If an atomic subexpression contains only a {one/notone/set}lazy, + // change it to be an {one/notone/set}loopatomic and remove the atomic node. + case Onelazy or Notonelazy or Setlazy: + child.MakeLazyAtomic(); + return child; + // Alternations have a variety of possible optimizations that can be applied // iff they're atomic. case Alternate: @@ -1447,12 +1476,6 @@ private RegexNode ReduceConcatenation() // and also help to reduce catastrophic backtracking. ReduceConcatenationWithAdjacentLoops(); - // Now convert as many loops as possible to be atomic to avoid unnecessary backtracking. - if ((Options & RegexOptions.RightToLeft) == 0) - { - ReduceConcatenationWithAutoAtomic(); - } - // If the concatenation is now empty, return an empty node, or if it's got a single child, return that child. // Otherwise, return this. return ReplaceNodeIfUnnecessary(Empty); @@ -1658,21 +1681,43 @@ static bool CanCombineCounts(int nodeMin, int nodeMax, int nextMin, int nextMax) /// to {one/notone/set}loopatomic nodes. Such changes avoid potential useless backtracking. /// e.g. A*B (where sets A and B don't overlap) => (?>A*)B. /// - private void ReduceConcatenationWithAutoAtomic() + private void FindAndMakeLoopsAtomic() { - // RegexOptions.NonBacktracking doesn't support atomic groups, so when that option - // is set we don't want to create atomic groups where they weren't explicitly authored. - if ((Options & RegexOptions.NonBacktracking) != 0) + Debug.Assert((Options & RegexOptions.NonBacktracking) == 0, "Atomic groups aren't supported and don't help performance with NonBacktracking"); + + if (!StackHelper.TryEnsureSufficientExecutionStack()) { + // If we're too deep on the stack, give up optimizing further. return; } - Debug.Assert(Type == Concatenate); - Debug.Assert((Options & RegexOptions.RightToLeft) == 0); - Debug.Assert(Children is List); + if ((Options & RegexOptions.RightToLeft) != 0) + { + // RTL is so rare, we don't need to spend additional time/code optimizing for it. + return; + } + // For all node types that have children, recur into each of those children. + int childCount = ChildCount(); + if (childCount != 0) + { + for (int i = 0; i < childCount; i++) + { + Child(i).FindAndMakeLoopsAtomic(); + } + } + + // If this isn't a concatenation, nothing more to do. + if (Type is not Concatenate) + { + return; + } + + // This is a concatenation. Iterate through each pair of nodes in the concatenation seeing whether we can + // make the first node (or its right-most child) atomic based on the second node (or its left-most child). + Debug.Assert(Children is List); var children = (List)Children; - for (int i = 0; i < children.Count - 1; i++) + for (int i = 0; i < childCount - 1; i++) { ProcessNode(children[i], children[i + 1]); @@ -1715,11 +1760,19 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) // If the node can be changed to atomic based on what comes after it, do so. switch (node.Type) { - case Oneloop when CanBeMadeAtomic(node, subsequent): - case Notoneloop when CanBeMadeAtomic(node, subsequent): - case Setloop when CanBeMadeAtomic(node, subsequent): + case Oneloop or Notoneloop or Setloop when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: true): node.MakeLoopAtomic(); break; + + case Onelazy or Notonelazy or Setlazy when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: false): + // allowSubsequentIteration is set to false to avoid dealing with the case where a lazy's max is lowered + // to its min, e.g. `d+?e*?f??` effectively becomes `d`. This also doesn't use MakeLazyAtomic, as that's + // used for applying atomicity to a lazy, which will in turn lower its max iteration count; here, we're + // actually recognizing that there's no difference in outcome whether the node is a setloop, setloopatomic, + // or setlazy, and thus we're best off making it setloopatomic to avoid useless backtracking. + node.Type += Oneloopatomic - Onelazy; + break; + case Alternate: // In the case of alternation, we can't change the alternation node itself // based on what comes after it (at least not with more complicated analysis @@ -1749,7 +1802,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) { RegexNode node = this; - Debug.Assert(node.Type == Loop); + Debug.Assert(node.Type is Loop or Lazyloop); // Start by looking at the loop's sole child. node = node.Child(0); @@ -1770,7 +1823,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) { int concatCount = node.ChildCount(); RegexNode lastConcatChild = node.Child(concatCount - 1); - if (CanBeMadeAtomic(lastConcatChild, node.Child(0))) + if (CanBeMadeAtomic(lastConcatChild, node.Child(0), allowSubsequentIteration: false)) { return lastConcatChild; } @@ -1849,7 +1902,7 @@ private RegexNode ReduceTestgroup() /// Determines whether node can be switched to an atomic loop. Subsequent is the node /// immediately after 'node'. /// - private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent) + private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool allowSubsequentIteration) { if (!StackHelper.TryEnsureSufficientExecutionStack()) { @@ -1857,102 +1910,185 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent) return false; } - // Skip the successor down to the closest node that's guaranteed to follow it. - while (subsequent.ChildCount() > 0) + // In most case, we'll simply check the node against whatever subsequent is. However, in case + // subsequent ends up being a loop with a min bound of 0, we'll also need to evaluate the node + // against whatever comes after subsequent. In that case, we'll walk the tree to find the + // next subsequent, and we'll loop around against to perform the comparison again. + while (true) { - Debug.Assert(subsequent.Type != Group); - switch (subsequent.Type) + // Skip the successor down to the closest node that's guaranteed to follow it. + while (subsequent.ChildCount() > 0) { - case Concatenate: - case Capture: - case Atomic: - case Require when (subsequent.Options & RegexOptions.RightToLeft) == 0: // only lookaheads, not lookbehinds (represented as RTL Require nodes) - case Loop or Lazyloop when subsequent.M > 0: - subsequent = subsequent.Child(0); - continue; - } + Debug.Assert(subsequent.Type != Group); + switch (subsequent.Type) + { + case Concatenate: + case Capture: + case Atomic: + case Require when (subsequent.Options & RegexOptions.RightToLeft) == 0: // only lookaheads, not lookbehinds (represented as RTL Require nodes) + case Loop or Lazyloop when subsequent.M > 0: + subsequent = subsequent.Child(0); + continue; + } - break; - } + break; + } - // If the two nodes don't agree on options in any way, don't try to optimize them. - if (node.Options != subsequent.Options) - { - return false; - } + // If the two nodes don't agree on options in any way, don't try to optimize them. + if (node.Options != subsequent.Options) + { + return false; + } - // If the successor is an alternation, all of its children need to be evaluated, since any of them - // could come after this node. If any of them fail the optimization, then the whole node fails. - if (subsequent.Type == Alternate) - { - int childCount = subsequent.ChildCount(); - for (int i = 0; i < childCount; i++) + // If the successor is an alternation, all of its children need to be evaluated, since any of them + // could come after this node. If any of them fail the optimization, then the whole node fails. + if (subsequent.Type == Alternate) { - if (!CanBeMadeAtomic(node, subsequent.Child(i))) + int childCount = subsequent.ChildCount(); + for (int i = 0; i < childCount; i++) { - return false; + if (!CanBeMadeAtomic(node, subsequent.Child(i), allowSubsequentIteration)) + { + return false; + } } + + return true; } - return true; - } + // If this node is a {one/notone/set}loop, see if it overlaps with its successor in the concatenation. + // If it doesn't, then we can upgrade it to being a {one/notone/set}loopatomic. + // Doing so avoids unnecessary backtracking. + switch (node.Type) + { + case Oneloop or Onelazy: + switch (subsequent.Type) + { + case One when node.Ch != subsequent.Ch: + case Notone when node.Ch == subsequent.Ch: + case Set when !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch != subsequent.Ch: + case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: + case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + case Multi when node.Ch != subsequent.Str![0]: + case End: + case EndZ or Eol when node.Ch != '\n': + case Boundary when RegexCharClass.IsBoundaryWordChar(node.Ch): + case NonBoundary when !RegexCharClass.IsBoundaryWordChar(node.Ch): + case ECMABoundary when RegexCharClass.IsECMAWordChar(node.Ch): + case NonECMABoundary when !RegexCharClass.IsECMAWordChar(node.Ch): + return true; + + case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && node.Ch != subsequent.Ch: + case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: + case Setlazy or Setloop or Setloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. + break; - // If this node is a {one/notone/set}loop, see if it overlaps with its successor in the concatenation. - // If it doesn't, then we can upgrade it to being a {one/notone/set}loopatomic. - // Doing so avoids unnecessary backtracking. - switch (node.Type) - { - case Oneloop: - switch (subsequent.Type) - { - case One when node.Ch != subsequent.Ch: - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch != subsequent.Ch: - case Notone when node.Ch == subsequent.Ch: - case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: - case Multi when node.Ch != subsequent.Str![0]: - case Set when !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): - case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): - case End: - case EndZ or Eol when node.Ch != '\n': - case Boundary when RegexCharClass.IsBoundaryWordChar(node.Ch): - case NonBoundary when !RegexCharClass.IsBoundaryWordChar(node.Ch): - case ECMABoundary when RegexCharClass.IsECMAWordChar(node.Ch): - case NonECMABoundary when !RegexCharClass.IsECMAWordChar(node.Ch): - return true; - } - break; + default: + return false; + } + break; - case Notoneloop: - switch (subsequent.Type) - { - case One when node.Ch == subsequent.Ch: - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: - case Multi when node.Ch == subsequent.Str![0]: - case End: - return true; - } - break; + case Notoneloop or Notonelazy: + switch (subsequent.Type) + { + case One when node.Ch == subsequent.Ch: + case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: + case Multi when node.Ch == subsequent.Str![0]: + case End: + return true; + + case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: + // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. + break; - case Setloop: - switch (subsequent.Type) + default: + return false; + } + break; + + case Setloop or Setlazy: + switch (subsequent.Type) + { + case One when !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case Set when !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + case Multi when !RegexCharClass.CharInClass(subsequent.Str![0], node.Str!): + case End: + case EndZ or Eol when !RegexCharClass.CharInClass('\n', node.Str!): + case Boundary when node.Str == RegexCharClass.WordClass || node.Str == RegexCharClass.DigitClass: + case NonBoundary when node.Str == RegexCharClass.NotWordClass || node.Str == RegexCharClass.NotDigitClass: + case ECMABoundary when node.Str == RegexCharClass.ECMAWordClass || node.Str == RegexCharClass.ECMADigitClass: + case NonECMABoundary when node.Str == RegexCharClass.NotECMAWordClass || node.Str == RegexCharClass.NotDigitClass: + return true; + + case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case Setlazy or Setloop or Setloopatomic when subsequent.M == 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. + break; + + default: + return false; + } + break; + + default: + return false; + } + + // We only get here if the node could be made atomic based on subsequent but subsequent has a lower bound of zero + // and thus we need to move subsequent to be the next node in sequence and loop around to try again. + Debug.Assert(subsequent.Type is Oneloop or Oneloopatomic or Onelazy or Notoneloop or Notoneloopatomic or Notonelazy or Setloop or Setloopatomic or Setlazy); + Debug.Assert(subsequent.M == 0); + if (!allowSubsequentIteration) + { + return false; + } + + // To be conservative, we only walk up through a very limited set of constructs (even though we may have walked + // down through more, like loops), looking for the next concatenation that we're not at the end of, at + // which point subsequent becomes whatever node is next in that concatenation. + while (true) + { + RegexNode? parent = subsequent.Next; + switch (parent?.Type) { - case One when !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Multi when !RegexCharClass.CharInClass(subsequent.Str![0], node.Str!): - case Set when !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): - case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): - case End: - case EndZ or Eol when !RegexCharClass.CharInClass('\n', node.Str!): - case Boundary when node.Str == RegexCharClass.WordClass || node.Str == RegexCharClass.DigitClass: - case NonBoundary when node.Str == RegexCharClass.NotWordClass || node.Str == RegexCharClass.NotDigitClass: - case ECMABoundary when node.Str == RegexCharClass.ECMAWordClass || node.Str == RegexCharClass.ECMADigitClass: - case NonECMABoundary when node.Str == RegexCharClass.NotECMAWordClass || node.Str == RegexCharClass.NotDigitClass: + case Atomic: + case Alternate: + case Capture: + subsequent = parent; + continue; + + case Concatenate: + var peers = (List)parent.Children!; + int currentIndex = peers.IndexOf(subsequent); + Debug.Assert(currentIndex >= 0, "Node should have been in its parent's child list"); + if (currentIndex + 1 == peers.Count) + { + subsequent = parent; + continue; + } + else + { + subsequent = peers[currentIndex + 1]; + break; + } + + case null: + // If we hit the root, we're at the end of the expression, at which point nothing could backtrack + // in and we can declare success. return true; + + default: + // Anything else, we don't know what to do, so we have to assume it could conflict with the loop. + return false; } + break; + } } - - return false; } /// Computes a min bound on the required length of any string that could possibly match. diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs index b010a53c035e2..d49fec910110f 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs @@ -1020,6 +1020,18 @@ public static IEnumerable Match_Advanced_TestData() new CaptureData(string.Empty, 1, 0) } }; + yield return new object[] + { + engine, + "(d+?)(e*?)(f+)", "dddeeefff", RegexOptions.None, 0, 9, + new CaptureData[] + { + new CaptureData("dddeeefff", 0, 9), + new CaptureData("ddd", 0, 3), + new CaptureData("eee", 3, 3), + new CaptureData("fff", 6, 3), + } + }; // Noncapturing group : Actual - "(a+)(?:b*)(ccc)" yield return new object[] diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs index c3cd830fbb7b2..4781b959cf772 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs @@ -378,12 +378,26 @@ private static int GetMinRequiredLength(Regex r) [InlineData("(?(\\w)\\d)", "(?(\\w)\\d|)")] // Auto-atomicity [InlineData("a*b", "(?>a*)b")] - [InlineData("a*b+", "(?>a*)b+")] - [InlineData("a*b{3,4}", "(?>a*)b{3,4}")] + [InlineData("a*b+", "(?>a*)(?>b+)")] + [InlineData("a*b*", "(?>a*)(?>b*)")] + [InlineData("a*b+c*", "(?>a*)(?>b+)(?>c*)")] + [InlineData("a*b*c*", "(?>a*)(?>b*)(?>c*)")] + [InlineData("a*b*c*|d*[ef]*", "(?>a*)(?>b*)(?>c*)|(?>d*)(?>[ef]*)")] + [InlineData("(a*)(b*)(c*)", "((?>a*))((?>b*))((?>c*))")] + [InlineData("a*b{3,4}", "(?>a*)(?>b{3,4})")] + [InlineData("[ab]*[^a]*", "[ab]*(?>[^a]*)")] + [InlineData("[aa]*[^a]*", "(?>a*)(?>[^a]*)")] + [InlineData("a??", "")] + [InlineData("(abc*?)", "(ab)")] + [InlineData("a{1,3}?", "a{1,4}?")] + [InlineData("a{2,3}?", "a{2}")] + [InlineData("bc(a){1,3}?", "bc(a){1,2}?")] + [InlineData("c{3,}?|f{2,}?", "c{3}|f{2}")] + [InlineData("[a-z]*[\x0000-\xFFFF]+", "[a-z]*(?>[\x0000-\xFFFF]+)")] [InlineData("a+b", "(?>a+)b")] [InlineData("a?b", "(?>a?)b")] [InlineData("[^\n]*\n", "(?>[^\n]*)\n")] - [InlineData("[^\n]*\n+", "(?>[^\n]*)\n+")] + [InlineData("[^\n]*\n+", "(?>[^\n]*)(?>\n+)")] [InlineData("(a+)b", "((?>a+))b")] [InlineData("a*(?:bcd|efg)", "(?>a*)(?:bcd|efg)")] [InlineData("\\w*\\b", "(?>\\w*)\\b")] @@ -392,8 +406,8 @@ private static int GetMinRequiredLength(Regex r) [InlineData("(?:a[ce]*|b*)g", "(?:a(?>[ce]*)|(?>b*))g")] [InlineData("(?:a[ce]*|b*)c", "(?:a[ce]*|(?>b*))c")] [InlineData("apple|(?:orange|pear)|grape", "apple|orange|pear|grape")] - [InlineData("(?>(?>(?>(?:abc)*)))", "(?:abc)*")] - [InlineData("(?:w*)+", "(?>w*)+")] + [InlineData("(?:abc)*", "(?>(?>(?>(?:abc)*)))")] + [InlineData("(?:w*)+", "(?>(?>w*)+)")] [InlineData("(?:w*)+\\.", "(?>w*)+\\.")] [InlineData("(a[bcd]e*)*fg", "(a[bcd](?>e*))*fg")] [InlineData("(\\w[bcd]\\s*)*fg", "(\\w[bcd](?>\\s*))*fg")] @@ -461,7 +475,7 @@ public void PatternsReduceIdentically(string pattern1, string pattern2) [InlineData("(?i:abcd)|abcd", "abcd|abcd")] [InlineData("abcd|(?i:abcd)", "abcd|abcd")] // Not applying auto-atomicity - [InlineData("a*b*", "(?>a*)b*")] + [InlineData(@"(a*|b*)\w*", @"((?>a*)|(?>b*))\w*")] [InlineData("[ab]*[^a]", "(?>[ab]*)[^a]")] [InlineData("[ab]*[^a]*", "(?>[ab]*)[^a]*")] [InlineData("[ab]*[^a]*?", "(?>[ab]*)[^a]*?")] From 546c23804538ee751e4bb419942bc0170c3e5e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 19 Jan 2022 10:58:17 +0900 Subject: [PATCH 032/308] Improve ILLink.targets integration (#63914) Runtime side of https://github.com/dotnet/sdk/pull/23470 (depends on that getting merged). Skip touching the IL Linker semaphore that tricks the target into not running. --- .../Microsoft.NETCore.Native.Publish.targets | 2 ++ .../BuildIntegration/Microsoft.NETCore.Native.targets | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets index 67efba61efde9..18258d4288b01 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets @@ -54,6 +54,8 @@ + + diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index 501384a4c0c6c..1a3b4a2f740b4 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -31,6 +31,7 @@ The .NET Foundation licenses this file to you under the MIT license. false true + false @@ -39,7 +40,7 @@ The .NET Foundation licenses this file to you under the MIT license. true true - true + true copyused @@ -304,8 +305,8 @@ The .NET Foundation licenses this file to you under the MIT license. - - + + From b7d8f5ecfa7bceb8069448951c7fabd65bcf26a0 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 18 Jan 2022 18:39:37 -0800 Subject: [PATCH 033/308] Fix Failing Globalization Test on OSX (#63971) --- .../tests/NumberFormatInfo/NumberFormatInfoData.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs index ee007af28b6d0..36ff2977b807d 100644 --- a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs +++ b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs @@ -65,7 +65,11 @@ internal static int[] GetCurrencyNegativePatterns(string localeName) return PlatformDetection.IsNlsGlobalization ? new int[] { 12 } : new int[] { 9 }; case "es-BO": - return (PlatformDetection.IsNlsGlobalization && PlatformDetection.WindowsVersion < 10) ? new int[] { 14 } : new int[] { 1 }; + return (PlatformDetection.IsNlsGlobalization && PlatformDetection.WindowsVersion < 10) ? + new int[] { 14 } : + // Mac OSX used to return 1 which is the format "-$n". OSX Version 12 (Monterey) started + // to return a different value 12 "$ -n". + PlatformDetection.IsOSX ? new int[] { 1, 12 } : new int[] { 1 }; case "fr-CA": return PlatformDetection.IsNlsGlobalization ? new int[] { 15 } : new int[] { 8, 15 }; From da72791c37480532e647e8f69aff3f2b7eef6049 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 18 Jan 2022 18:59:04 -0800 Subject: [PATCH 034/308] Fix System.Reflection.Metadata version in ILVerification nuget package metadata (#63965) Fixes #63944 --- .../Microsoft.ILVerification/Microsoft.ILVerification.pkgproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/.nuget/Microsoft.ILVerification/Microsoft.ILVerification.pkgproj b/src/coreclr/.nuget/Microsoft.ILVerification/Microsoft.ILVerification.pkgproj index db820d395a125..685f941510195 100644 --- a/src/coreclr/.nuget/Microsoft.ILVerification/Microsoft.ILVerification.pkgproj +++ b/src/coreclr/.nuget/Microsoft.ILVerification/Microsoft.ILVerification.pkgproj @@ -15,7 +15,7 @@ lib\netstandard2.0\ILVerification.dll - 1.8.1 + $(SystemReflectionMetadataVersion) netstandard2.0 Build,Analyzers From 454ac0a6e7584e1c02677d459d20dae5df61fb47 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 18 Jan 2022 22:15:32 -0500 Subject: [PATCH 035/308] Revert "Improve auto-atomicity for Regex loops (#63518)" (#63984) This reverts commit 557901e779a009cf4a51327963727a4d1ded0094. --- .../Text/RegularExpressions/RegexNode.cs | 412 ++++++------------ .../tests/Regex.Match.Tests.cs | 12 - .../tests/RegexReductionTests.cs | 26 +- 3 files changed, 144 insertions(+), 306 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index 0bfb9d4926fbb..8f5c0a3039596 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -214,33 +214,23 @@ private void MakeRep(int type, int min, int max) private void MakeLoopAtomic() { - Debug.Assert(Type is Oneloop or Notoneloop or Setloop); - - // For loops, we simply change the Type to the atomic variant. - // Atomic greedy loops should consume as many values as they can. - Type += Oneloopatomic - Oneloop; - } - - private void MakeLazyAtomic() - { - Debug.Assert(Type is Onelazy or Notonelazy or Setlazy); - - switch (M) + switch (Type) { - case 0: - Type = Empty; - Str = null; - Ch = '\0'; + case Oneloop or Notoneloop or Setloop: + // For loops, we simply change the Type to the atomic variant. + // Atomic greedy loops should consume as many values as they can. + Type += Oneloopatomic - Oneloop; break; - case 1: - Type += One - Onelazy; - M = N = 0; + case Onelazy or Notonelazy or Setlazy: + // For lazy, we not only change the Type, we also lower the max number of iterations + // to the minimum number of iterations, as they should end up matching as little as possible. + Type += Oneloopatomic - Onelazy; + N = M; break; default: - Type += Oneloopatomic - Onelazy; - N = M; + Debug.Fail($"Unexpected type: {Type}"); break; } } @@ -372,17 +362,8 @@ internal RegexNode FinalOptimize() Debug.Assert(rootNode.Next is null); Debug.Assert(rootNode.ChildCount() == 1); - // Only apply optimization when LTR to avoid needing additional code for the much rarer RTL case. - // Also only apply these optimizations when not using NonBacktracking, as these optimizations are - // all about avoiding things that are impactful for the backtracking engines but nops for non-backtracking. - if ((Options & (RegexOptions.RightToLeft | RegexOptions.NonBacktracking)) == 0) + if ((Options & RegexOptions.RightToLeft) == 0) // only apply optimization when LTR to avoid needing additional code for the rarer RTL case { - // Optimization: eliminate backtracking for loops. - // For any single-character loop (Oneloop, Notoneloop, Setloop), see if we can automatically convert - // that into its atomic counterpart (Oneloopatomic, Notoneloopatomic, Setloopatomic) based on what - // comes after it in the expression tree. - rootNode.FindAndMakeLoopsAtomic(); - // Optimization: backtracking removal at expression end. // If we find backtracking construct at the end of the regex, we can instead make it non-backtracking, // since nothing would ever backtrack into it anyway. Doing this then makes the construct available @@ -445,14 +426,19 @@ internal RegexNode FinalOptimize() /// private void EliminateEndingBacktracking() { - Debug.Assert((Options & RegexOptions.NonBacktracking) == 0, "NonBacktracking doesn't have backtracking to be eliminated and doesn't support atomic groups."); - if (!StackHelper.TryEnsureSufficientExecutionStack()) { // If we can't recur further, just stop optimizing. return; } + // RegexOptions.NonBacktracking doesn't support atomic groups, so when that option + // is set we don't want to create atomic groups where they weren't explicitly authored. + if ((Options & RegexOptions.NonBacktracking) != 0) + { + return; + } + // Walk the tree starting from the current node. RegexNode node = this; while (true) @@ -460,17 +446,17 @@ private void EliminateEndingBacktracking() switch (node.Type) { // {One/Notone/Set}loops can be upgraded to {One/Notone/Set}loopatomic nodes, e.g. [abc]* => (?>[abc]*). - case Oneloop or Notoneloop or Setloop: + // And {One/Notone/Set}lazys can similarly be upgraded to be atomic, which really makes them into repeaters + // or even empty nodes. + case Oneloop: + case Notoneloop: + case Setloop: + case Onelazy: + case Notonelazy: + case Setlazy: node.MakeLoopAtomic(); break; - // {One/Notone/Set}lazys can similarly be upgraded to be atomic, but in doing so we need to lower their - // max iterations down to their min, as they'll never match more than the min. This effectively makes - // them into a repeater, and we can then downgrade them to a single char or even an empty. - case Onelazy or Notonelazy or Setlazy: - node.MakeLazyAtomic(); - break; - // Just because a particular node is atomic doesn't mean all its descendants are. // Process them as well. case Atomic: @@ -486,7 +472,7 @@ private void EliminateEndingBacktracking() case Capture: case Concatenate: RegexNode existingChild = node.Child(node.ChildCount() - 1); - if ((existingChild.Type is Alternate or Loop or Lazyloop) && + if ((existingChild.Type == Alternate || existingChild.Type == Loop || existingChild.Type == Lazyloop) && (node.Next is null || node.Next.Type != Atomic)) // validate grandparent isn't atomic { var atomic = new RegexNode(Atomic, existingChild.Options); @@ -509,27 +495,11 @@ private void EliminateEndingBacktracking() node = node.Child(0); continue; - // For {Lazy}Loop, we search to see if there's a viable last expression, and iff there - // is we recur into processing it. Also, as with the single-char lazy loops, LazyLoop - // can have its max iteration count dropped to its min iteration count, as there's no - // reason for it to match more than the minimal at the end; that in turn makes it a - // repeater, which results in better code generation. + // For Loop, we search to see if there's a viable last expression, and iff there + // is we recur into processing it. // e.g. (?:abc*)* => (?:ab(?>c*))* - // e.g. (abc*?)+? => (ab){1} - case Lazyloop: - node.N = node.M; - goto case Loop; case Loop: { - if (node.N == 1) - { - // If the loop has a max iteration count of 1 (e.g. it's an optional node), - // there's no possibility for conflict between multiple iterations, so - // we can process it. - node = node.Child(0); - continue; - } - RegexNode? loopDescendent = node.FindLastExpressionInLoopForAutoAtomic(); if (loopDescendent != null) { @@ -681,21 +651,22 @@ private RegexNode ReduceAtomic() switch (child.Type) { // If the child is already atomic, we can just remove the atomic node. - case Oneloopatomic or Notoneloopatomic or Setloopatomic: + case Oneloopatomic: + case Notoneloopatomic: + case Setloopatomic: return child; - // If an atomic subexpression contains only a {one/notone/set}loop, + // If an atomic subexpression contains only a {one/notone/set}{loop/lazy}, // change it to be an {one/notone/set}loopatomic and remove the atomic node. - case Oneloop or Notoneloop or Setloop: + case Oneloop: + case Notoneloop: + case Setloop: + case Onelazy: + case Notonelazy: + case Setlazy: child.MakeLoopAtomic(); return child; - // If an atomic subexpression contains only a {one/notone/set}lazy, - // change it to be an {one/notone/set}loopatomic and remove the atomic node. - case Onelazy or Notonelazy or Setlazy: - child.MakeLazyAtomic(); - return child; - // Alternations have a variety of possible optimizations that can be applied // iff they're atomic. case Alternate: @@ -1476,6 +1447,12 @@ private RegexNode ReduceConcatenation() // and also help to reduce catastrophic backtracking. ReduceConcatenationWithAdjacentLoops(); + // Now convert as many loops as possible to be atomic to avoid unnecessary backtracking. + if ((Options & RegexOptions.RightToLeft) == 0) + { + ReduceConcatenationWithAutoAtomic(); + } + // If the concatenation is now empty, return an empty node, or if it's got a single child, return that child. // Otherwise, return this. return ReplaceNodeIfUnnecessary(Empty); @@ -1681,43 +1658,21 @@ static bool CanCombineCounts(int nodeMin, int nodeMax, int nextMin, int nextMax) /// to {one/notone/set}loopatomic nodes. Such changes avoid potential useless backtracking. /// e.g. A*B (where sets A and B don't overlap) => (?>A*)B. /// - private void FindAndMakeLoopsAtomic() + private void ReduceConcatenationWithAutoAtomic() { - Debug.Assert((Options & RegexOptions.NonBacktracking) == 0, "Atomic groups aren't supported and don't help performance with NonBacktracking"); - - if (!StackHelper.TryEnsureSufficientExecutionStack()) - { - // If we're too deep on the stack, give up optimizing further. - return; - } - - if ((Options & RegexOptions.RightToLeft) != 0) - { - // RTL is so rare, we don't need to spend additional time/code optimizing for it. - return; - } - - // For all node types that have children, recur into each of those children. - int childCount = ChildCount(); - if (childCount != 0) - { - for (int i = 0; i < childCount; i++) - { - Child(i).FindAndMakeLoopsAtomic(); - } - } - - // If this isn't a concatenation, nothing more to do. - if (Type is not Concatenate) + // RegexOptions.NonBacktracking doesn't support atomic groups, so when that option + // is set we don't want to create atomic groups where they weren't explicitly authored. + if ((Options & RegexOptions.NonBacktracking) != 0) { return; } - // This is a concatenation. Iterate through each pair of nodes in the concatenation seeing whether we can - // make the first node (or its right-most child) atomic based on the second node (or its left-most child). + Debug.Assert(Type == Concatenate); + Debug.Assert((Options & RegexOptions.RightToLeft) == 0); Debug.Assert(Children is List); + var children = (List)Children; - for (int i = 0; i < childCount - 1; i++) + for (int i = 0; i < children.Count - 1; i++) { ProcessNode(children[i], children[i + 1]); @@ -1760,19 +1715,11 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) // If the node can be changed to atomic based on what comes after it, do so. switch (node.Type) { - case Oneloop or Notoneloop or Setloop when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: true): + case Oneloop when CanBeMadeAtomic(node, subsequent): + case Notoneloop when CanBeMadeAtomic(node, subsequent): + case Setloop when CanBeMadeAtomic(node, subsequent): node.MakeLoopAtomic(); break; - - case Onelazy or Notonelazy or Setlazy when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: false): - // allowSubsequentIteration is set to false to avoid dealing with the case where a lazy's max is lowered - // to its min, e.g. `d+?e*?f??` effectively becomes `d`. This also doesn't use MakeLazyAtomic, as that's - // used for applying atomicity to a lazy, which will in turn lower its max iteration count; here, we're - // actually recognizing that there's no difference in outcome whether the node is a setloop, setloopatomic, - // or setlazy, and thus we're best off making it setloopatomic to avoid useless backtracking. - node.Type += Oneloopatomic - Onelazy; - break; - case Alternate: // In the case of alternation, we can't change the alternation node itself // based on what comes after it (at least not with more complicated analysis @@ -1802,7 +1749,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) { RegexNode node = this; - Debug.Assert(node.Type is Loop or Lazyloop); + Debug.Assert(node.Type == Loop); // Start by looking at the loop's sole child. node = node.Child(0); @@ -1823,7 +1770,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) { int concatCount = node.ChildCount(); RegexNode lastConcatChild = node.Child(concatCount - 1); - if (CanBeMadeAtomic(lastConcatChild, node.Child(0), allowSubsequentIteration: false)) + if (CanBeMadeAtomic(lastConcatChild, node.Child(0))) { return lastConcatChild; } @@ -1902,7 +1849,7 @@ private RegexNode ReduceTestgroup() /// Determines whether node can be switched to an atomic loop. Subsequent is the node /// immediately after 'node'. /// - private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool allowSubsequentIteration) + private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent) { if (!StackHelper.TryEnsureSufficientExecutionStack()) { @@ -1910,185 +1857,102 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a return false; } - // In most case, we'll simply check the node against whatever subsequent is. However, in case - // subsequent ends up being a loop with a min bound of 0, we'll also need to evaluate the node - // against whatever comes after subsequent. In that case, we'll walk the tree to find the - // next subsequent, and we'll loop around against to perform the comparison again. - while (true) + // Skip the successor down to the closest node that's guaranteed to follow it. + while (subsequent.ChildCount() > 0) { - // Skip the successor down to the closest node that's guaranteed to follow it. - while (subsequent.ChildCount() > 0) - { - Debug.Assert(subsequent.Type != Group); - switch (subsequent.Type) - { - case Concatenate: - case Capture: - case Atomic: - case Require when (subsequent.Options & RegexOptions.RightToLeft) == 0: // only lookaheads, not lookbehinds (represented as RTL Require nodes) - case Loop or Lazyloop when subsequent.M > 0: - subsequent = subsequent.Child(0); - continue; - } - - break; - } - - // If the two nodes don't agree on options in any way, don't try to optimize them. - if (node.Options != subsequent.Options) + Debug.Assert(subsequent.Type != Group); + switch (subsequent.Type) { - return false; + case Concatenate: + case Capture: + case Atomic: + case Require when (subsequent.Options & RegexOptions.RightToLeft) == 0: // only lookaheads, not lookbehinds (represented as RTL Require nodes) + case Loop or Lazyloop when subsequent.M > 0: + subsequent = subsequent.Child(0); + continue; } - // If the successor is an alternation, all of its children need to be evaluated, since any of them - // could come after this node. If any of them fail the optimization, then the whole node fails. - if (subsequent.Type == Alternate) - { - int childCount = subsequent.ChildCount(); - for (int i = 0; i < childCount; i++) - { - if (!CanBeMadeAtomic(node, subsequent.Child(i), allowSubsequentIteration)) - { - return false; - } - } + break; + } - return true; - } + // If the two nodes don't agree on options in any way, don't try to optimize them. + if (node.Options != subsequent.Options) + { + return false; + } - // If this node is a {one/notone/set}loop, see if it overlaps with its successor in the concatenation. - // If it doesn't, then we can upgrade it to being a {one/notone/set}loopatomic. - // Doing so avoids unnecessary backtracking. - switch (node.Type) + // If the successor is an alternation, all of its children need to be evaluated, since any of them + // could come after this node. If any of them fail the optimization, then the whole node fails. + if (subsequent.Type == Alternate) + { + int childCount = subsequent.ChildCount(); + for (int i = 0; i < childCount; i++) { - case Oneloop or Onelazy: - switch (subsequent.Type) - { - case One when node.Ch != subsequent.Ch: - case Notone when node.Ch == subsequent.Ch: - case Set when !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch != subsequent.Ch: - case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: - case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): - case Multi when node.Ch != subsequent.Str![0]: - case End: - case EndZ or Eol when node.Ch != '\n': - case Boundary when RegexCharClass.IsBoundaryWordChar(node.Ch): - case NonBoundary when !RegexCharClass.IsBoundaryWordChar(node.Ch): - case ECMABoundary when RegexCharClass.IsECMAWordChar(node.Ch): - case NonECMABoundary when !RegexCharClass.IsECMAWordChar(node.Ch): - return true; - - case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && node.Ch != subsequent.Ch: - case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: - case Setlazy or Setloop or Setloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): - // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. - break; - - default: - return false; - } - break; - - case Notoneloop or Notonelazy: - switch (subsequent.Type) - { - case One when node.Ch == subsequent.Ch: - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: - case Multi when node.Ch == subsequent.Str![0]: - case End: - return true; - - case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: - // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. - break; - - default: - return false; - } - break; - - case Setloop or Setlazy: - switch (subsequent.Type) - { - case One when !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Set when !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): - case Multi when !RegexCharClass.CharInClass(subsequent.Str![0], node.Str!): - case End: - case EndZ or Eol when !RegexCharClass.CharInClass('\n', node.Str!): - case Boundary when node.Str == RegexCharClass.WordClass || node.Str == RegexCharClass.DigitClass: - case NonBoundary when node.Str == RegexCharClass.NotWordClass || node.Str == RegexCharClass.NotDigitClass: - case ECMABoundary when node.Str == RegexCharClass.ECMAWordClass || node.Str == RegexCharClass.ECMADigitClass: - case NonECMABoundary when node.Str == RegexCharClass.NotECMAWordClass || node.Str == RegexCharClass.NotDigitClass: - return true; - - case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Setlazy or Setloop or Setloopatomic when subsequent.M == 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): - // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. - break; - - default: - return false; - } - break; - - default: + if (!CanBeMadeAtomic(node, subsequent.Child(i))) + { return false; + } } - // We only get here if the node could be made atomic based on subsequent but subsequent has a lower bound of zero - // and thus we need to move subsequent to be the next node in sequence and loop around to try again. - Debug.Assert(subsequent.Type is Oneloop or Oneloopatomic or Onelazy or Notoneloop or Notoneloopatomic or Notonelazy or Setloop or Setloopatomic or Setlazy); - Debug.Assert(subsequent.M == 0); - if (!allowSubsequentIteration) - { - return false; - } + return true; + } - // To be conservative, we only walk up through a very limited set of constructs (even though we may have walked - // down through more, like loops), looking for the next concatenation that we're not at the end of, at - // which point subsequent becomes whatever node is next in that concatenation. - while (true) - { - RegexNode? parent = subsequent.Next; - switch (parent?.Type) + // If this node is a {one/notone/set}loop, see if it overlaps with its successor in the concatenation. + // If it doesn't, then we can upgrade it to being a {one/notone/set}loopatomic. + // Doing so avoids unnecessary backtracking. + switch (node.Type) + { + case Oneloop: + switch (subsequent.Type) { - case Atomic: - case Alternate: - case Capture: - subsequent = parent; - continue; - - case Concatenate: - var peers = (List)parent.Children!; - int currentIndex = peers.IndexOf(subsequent); - Debug.Assert(currentIndex >= 0, "Node should have been in its parent's child list"); - if (currentIndex + 1 == peers.Count) - { - subsequent = parent; - continue; - } - else - { - subsequent = peers[currentIndex + 1]; - break; - } - - case null: - // If we hit the root, we're at the end of the expression, at which point nothing could backtrack - // in and we can declare success. + case One when node.Ch != subsequent.Ch: + case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch != subsequent.Ch: + case Notone when node.Ch == subsequent.Ch: + case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: + case Multi when node.Ch != subsequent.Str![0]: + case Set when !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + case End: + case EndZ or Eol when node.Ch != '\n': + case Boundary when RegexCharClass.IsBoundaryWordChar(node.Ch): + case NonBoundary when !RegexCharClass.IsBoundaryWordChar(node.Ch): + case ECMABoundary when RegexCharClass.IsECMAWordChar(node.Ch): + case NonECMABoundary when !RegexCharClass.IsECMAWordChar(node.Ch): return true; + } + break; - default: - // Anything else, we don't know what to do, so we have to assume it could conflict with the loop. - return false; + case Notoneloop: + switch (subsequent.Type) + { + case One when node.Ch == subsequent.Ch: + case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: + case Multi when node.Ch == subsequent.Str![0]: + case End: + return true; } + break; + case Setloop: + switch (subsequent.Type) + { + case One when !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case Multi when !RegexCharClass.CharInClass(subsequent.Str![0], node.Str!): + case Set when !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + case End: + case EndZ or Eol when !RegexCharClass.CharInClass('\n', node.Str!): + case Boundary when node.Str == RegexCharClass.WordClass || node.Str == RegexCharClass.DigitClass: + case NonBoundary when node.Str == RegexCharClass.NotWordClass || node.Str == RegexCharClass.NotDigitClass: + case ECMABoundary when node.Str == RegexCharClass.ECMAWordClass || node.Str == RegexCharClass.ECMADigitClass: + case NonECMABoundary when node.Str == RegexCharClass.NotECMAWordClass || node.Str == RegexCharClass.NotDigitClass: + return true; + } break; - } } + + return false; } /// Computes a min bound on the required length of any string that could possibly match. diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs index d49fec910110f..b010a53c035e2 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs @@ -1020,18 +1020,6 @@ public static IEnumerable Match_Advanced_TestData() new CaptureData(string.Empty, 1, 0) } }; - yield return new object[] - { - engine, - "(d+?)(e*?)(f+)", "dddeeefff", RegexOptions.None, 0, 9, - new CaptureData[] - { - new CaptureData("dddeeefff", 0, 9), - new CaptureData("ddd", 0, 3), - new CaptureData("eee", 3, 3), - new CaptureData("fff", 6, 3), - } - }; // Noncapturing group : Actual - "(a+)(?:b*)(ccc)" yield return new object[] diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs index 4781b959cf772..c3cd830fbb7b2 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs @@ -378,26 +378,12 @@ private static int GetMinRequiredLength(Regex r) [InlineData("(?(\\w)\\d)", "(?(\\w)\\d|)")] // Auto-atomicity [InlineData("a*b", "(?>a*)b")] - [InlineData("a*b+", "(?>a*)(?>b+)")] - [InlineData("a*b*", "(?>a*)(?>b*)")] - [InlineData("a*b+c*", "(?>a*)(?>b+)(?>c*)")] - [InlineData("a*b*c*", "(?>a*)(?>b*)(?>c*)")] - [InlineData("a*b*c*|d*[ef]*", "(?>a*)(?>b*)(?>c*)|(?>d*)(?>[ef]*)")] - [InlineData("(a*)(b*)(c*)", "((?>a*))((?>b*))((?>c*))")] - [InlineData("a*b{3,4}", "(?>a*)(?>b{3,4})")] - [InlineData("[ab]*[^a]*", "[ab]*(?>[^a]*)")] - [InlineData("[aa]*[^a]*", "(?>a*)(?>[^a]*)")] - [InlineData("a??", "")] - [InlineData("(abc*?)", "(ab)")] - [InlineData("a{1,3}?", "a{1,4}?")] - [InlineData("a{2,3}?", "a{2}")] - [InlineData("bc(a){1,3}?", "bc(a){1,2}?")] - [InlineData("c{3,}?|f{2,}?", "c{3}|f{2}")] - [InlineData("[a-z]*[\x0000-\xFFFF]+", "[a-z]*(?>[\x0000-\xFFFF]+)")] + [InlineData("a*b+", "(?>a*)b+")] + [InlineData("a*b{3,4}", "(?>a*)b{3,4}")] [InlineData("a+b", "(?>a+)b")] [InlineData("a?b", "(?>a?)b")] [InlineData("[^\n]*\n", "(?>[^\n]*)\n")] - [InlineData("[^\n]*\n+", "(?>[^\n]*)(?>\n+)")] + [InlineData("[^\n]*\n+", "(?>[^\n]*)\n+")] [InlineData("(a+)b", "((?>a+))b")] [InlineData("a*(?:bcd|efg)", "(?>a*)(?:bcd|efg)")] [InlineData("\\w*\\b", "(?>\\w*)\\b")] @@ -406,8 +392,8 @@ private static int GetMinRequiredLength(Regex r) [InlineData("(?:a[ce]*|b*)g", "(?:a(?>[ce]*)|(?>b*))g")] [InlineData("(?:a[ce]*|b*)c", "(?:a[ce]*|(?>b*))c")] [InlineData("apple|(?:orange|pear)|grape", "apple|orange|pear|grape")] - [InlineData("(?:abc)*", "(?>(?>(?>(?:abc)*)))")] - [InlineData("(?:w*)+", "(?>(?>w*)+)")] + [InlineData("(?>(?>(?>(?:abc)*)))", "(?:abc)*")] + [InlineData("(?:w*)+", "(?>w*)+")] [InlineData("(?:w*)+\\.", "(?>w*)+\\.")] [InlineData("(a[bcd]e*)*fg", "(a[bcd](?>e*))*fg")] [InlineData("(\\w[bcd]\\s*)*fg", "(\\w[bcd](?>\\s*))*fg")] @@ -475,7 +461,7 @@ public void PatternsReduceIdentically(string pattern1, string pattern2) [InlineData("(?i:abcd)|abcd", "abcd|abcd")] [InlineData("abcd|(?i:abcd)", "abcd|abcd")] // Not applying auto-atomicity - [InlineData(@"(a*|b*)\w*", @"((?>a*)|(?>b*))\w*")] + [InlineData("a*b*", "(?>a*)b*")] [InlineData("[ab]*[^a]", "(?>[ab]*)[^a]")] [InlineData("[ab]*[^a]*", "(?>[ab]*)[^a]*")] [InlineData("[ab]*[^a]*?", "(?>[ab]*)[^a]*?")] From fc3875f14f310cdce716df30a94feb43db79a28a Mon Sep 17 00:00:00 2001 From: Jose Perez Rodriguez Date: Tue, 18 Jan 2022 19:47:09 -0800 Subject: [PATCH 036/308] Fix case where we incorrectly select a prefix as a FindFirstChar optimization when the pattern includdes an alternation that could lead to different prefixes. (#63976) --- .../RegularExpressions/RegexPrefixAnalyzer.cs | 49 ------------------- .../tests/Regex.Match.Tests.cs | 6 +++ 2 files changed, 6 insertions(+), 49 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs index 7b762188411b4..ceabbef99af6c 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs @@ -79,55 +79,6 @@ static bool Process(RegexNode node, ref ValueStringBuilder vsb) return !rtl; } - // Alternation: find a string that's a shared prefix of all branches - case RegexNode.Alternate: - { - int childCount = node.ChildCount(); - - // Store the initial branch into the target builder - int initialLength = vsb.Length; - bool keepExploring = Process(node.Child(0), ref vsb); - int addedLength = vsb.Length - initialLength; - - // Then explore the rest of the branches, finding the length - // a prefix they all share in common with the initial branch. - if (addedLength != 0) - { - var alternateSb = new ValueStringBuilder(64); - - // Process each branch. If we reach a point where we've proven there's - // no overlap, we can bail early. - for (int i = 1; i < childCount && addedLength != 0; i++) - { - alternateSb.Length = 0; - - // Process the branch. We want to keep exploring after this alternation, - // but we can't if either this branch doesn't allow for it or if the prefix - // supplied by this branch doesn't entirely match all the previous ones. - keepExploring &= Process(node.Child(i), ref alternateSb); - keepExploring &= alternateSb.Length == addedLength; - - addedLength = Math.Min(addedLength, alternateSb.Length); - for (int j = 0; j < addedLength; j++) - { - if (vsb[initialLength + j] != alternateSb[j]) - { - addedLength = j; - keepExploring = false; - break; - } - } - } - - alternateSb.Dispose(); - - // Then cull back on what was added based on the other branches. - vsb.Length = initialLength + addedLength; - } - - return !rtl && keepExploring; - } - // One character case RegexNode.One when (node.Options & RegexOptions.IgnoreCase) == 0: vsb.Append(node.Ch); diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs index b010a53c035e2..7f60d62db6dbc 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs @@ -200,6 +200,12 @@ public static IEnumerable Match_MemberData() yield return (@"((\d{2,3}?)){2}", "1234", RegexOptions.None, 0, 4, true, "1234"); yield return (@"(abc\d{2,3}?){2}", "abc123abc4567", RegexOptions.None, 0, 12, true, "abc123abc45"); + // Testing selected FindOptimizations finds the right prefix + yield return (@"(^|a+)bc", " aabc", RegexOptions.None, 0, 5, true, "aabc"); + yield return (@"(^|($|a+))bc", " aabc", RegexOptions.None, 0, 5, true, "aabc"); + yield return (@"yz(^|a+)bc", " yzaabc", RegexOptions.None, 0, 7, true, "yzaabc"); + yield return (@"(^a|a$) bc", "a bc", RegexOptions.None, 0, 4, true, "a bc"); + if (!RegexHelpers.IsNonBacktracking(engine)) { // Back references not support with NonBacktracking From 0b307c95286a4f468fbb627a66515054ff18dc87 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Wed, 19 Jan 2022 07:25:12 +0200 Subject: [PATCH 037/308] Add managed implementation of Math/MathF.Abs (#63881) * Add managed implementation of Math/MathF.Abs * Cleanup trailing whitespaces in changeset * Delete unused _copysignf macro --- .../src/System/Math.CoreCLR.cs | 8 --- .../classlibnative/float/floatdouble.cpp | 9 --- .../classlibnative/float/floatsingle.cpp | 21 ------ src/coreclr/classlibnative/inc/floatdouble.h | 1 - src/coreclr/classlibnative/inc/floatsingle.h | 1 - .../src/System/Math.CoreRT.cs | 12 ---- .../src/System/Runtime/RuntimeImports.cs | 12 ---- src/coreclr/vm/ecalllist.h | 2 - .../System.Private.CoreLib/src/System/Math.cs | 24 ++++++- .../src/System/Math.Mono.cs | 6 -- src/mono/mono/metadata/icall-decl.h | 2 - src/mono/mono/metadata/icall-def-netcore.h | 4 +- src/mono/mono/metadata/sysmath.c | 50 ++++++-------- src/mono/mono/mini/interp/interp.c | 24 ++++--- src/mono/mono/mini/interp/mintops.def | 2 - src/mono/mono/mini/interp/transform.c | 66 +++++++++---------- 16 files changed, 85 insertions(+), 159 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs index c86aa1b2e62bf..a619dc4b1ca79 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Math.CoreCLR.cs @@ -16,14 +16,6 @@ namespace System { public static partial class Math { - [Intrinsic] - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern double Abs(double value); - - [Intrinsic] - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern float Abs(float value); - [Intrinsic] [MethodImpl(MethodImplOptions.InternalCall)] public static extern double Acos(double d); diff --git a/src/coreclr/classlibnative/float/floatdouble.cpp b/src/coreclr/classlibnative/float/floatdouble.cpp index 67aceb60ea13e..d20b772eb2207 100644 --- a/src/coreclr/classlibnative/float/floatdouble.cpp +++ b/src/coreclr/classlibnative/float/floatdouble.cpp @@ -42,15 +42,6 @@ #pragma float_control(precise, off) #endif -/*=====================================Abs====================================== -** -==============================================================================*/ -FCIMPL1_V(double, COMDouble::Abs, double x) - FCALL_CONTRACT; - - return fabs(x); -FCIMPLEND - /*=====================================Acos===================================== ** ==============================================================================*/ diff --git a/src/coreclr/classlibnative/float/floatsingle.cpp b/src/coreclr/classlibnative/float/floatsingle.cpp index 965998fbaa2ba..1694fd78cb846 100644 --- a/src/coreclr/classlibnative/float/floatsingle.cpp +++ b/src/coreclr/classlibnative/float/floatsingle.cpp @@ -8,18 +8,6 @@ #include "floatsingle.h" -// Windows x86 and Windows ARM/ARM64 may not define _isnanf() or _copysignf() but they do -// define _isnan() and _copysign(). We will redirect the macros to these other functions if -// the macro is not defined for the platform. This has the side effect of a possible implicit -// upcasting for arguments passed in and an explicit downcasting for the _copysign() call. -#if (defined(TARGET_X86) || defined(TARGET_ARM) || defined(TARGET_ARM64)) && !defined(TARGET_UNIX) - -#if !defined(_copysignf) -#define _copysignf (float)_copysign -#endif - -#endif - // The default compilation mode is /fp:precise, which disables floating-point intrinsics. This // default compilation mode has previously caused performance regressions in floating-point code. // We enable /fp:fast semantics for the majority of the math functions, as it will speed up performance @@ -40,15 +28,6 @@ #pragma float_control(precise, off) #endif -/*=====================================Abs===================================== -** -==============================================================================*/ -FCIMPL1_V(float, COMSingle::Abs, float x) - FCALL_CONTRACT; - - return fabsf(x); -FCIMPLEND - /*=====================================Acos===================================== ** ==============================================================================*/ diff --git a/src/coreclr/classlibnative/inc/floatdouble.h b/src/coreclr/classlibnative/inc/floatdouble.h index 9163349127ca1..43fecbd47431f 100644 --- a/src/coreclr/classlibnative/inc/floatdouble.h +++ b/src/coreclr/classlibnative/inc/floatdouble.h @@ -9,7 +9,6 @@ class COMDouble { public: - FCDECL1_V(static double, Abs, double x); FCDECL1_V(static double, Acos, double x); FCDECL1_V(static double, Acosh, double x); FCDECL1_V(static double, Asin, double x); diff --git a/src/coreclr/classlibnative/inc/floatsingle.h b/src/coreclr/classlibnative/inc/floatsingle.h index 09a0512b230db..765032ce6371e 100644 --- a/src/coreclr/classlibnative/inc/floatsingle.h +++ b/src/coreclr/classlibnative/inc/floatsingle.h @@ -9,7 +9,6 @@ class COMSingle { public: - FCDECL1_V(static float, Abs, float x); FCDECL1_V(static float, Acos, float x); FCDECL1_V(static float, Acosh, float x); FCDECL1_V(static float, Asin, float x); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.CoreRT.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.CoreRT.cs index 8a53e1588b83d..15b629dbee219 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.CoreRT.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Math.CoreRT.cs @@ -16,18 +16,6 @@ namespace System { public static partial class Math { - [Intrinsic] - public static float Abs(float value) - { - return RuntimeImports.fabsf(value); - } - - [Intrinsic] - public static double Abs(double value) - { - return RuntimeImports.fabs(value); - } - [Intrinsic] public static double Acos(double d) { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index 304f7073e7ec3..a7edbf10d819a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -679,18 +679,6 @@ internal struct ConservativelyReportedRegionDesc [RuntimeImport(RuntimeLibrary, "RhpMemoryBarrier")] internal static extern void MemoryBarrier(); - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "fabs")] - internal static extern double fabs(double x); - - [Intrinsic] - internal static float fabsf(float x) - { - // fabsf is not a real export for some architectures - return (float)fabs(x); - } - [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "acos")] diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index be7a6826854f0..f3ada145b6839 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -322,8 +322,6 @@ FCFuncStart(gDelegateFuncs) FCFuncEnd() FCFuncStart(gMathFuncs) - FCFuncElementSig("Abs", &gsig_SM_Dbl_RetDbl, COMDouble::Abs) - FCFuncElementSig("Abs", &gsig_SM_Flt_RetFlt, COMSingle::Abs) FCFuncElement("Acos", COMDouble::Acos) FCFuncElement("Acosh", COMDouble::Acosh) FCFuncElement("Asin", COMDouble::Asin) diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index f242b825fb170..a929322173585 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -49,9 +49,9 @@ public static partial class Math private const double SCALEB_C3 = 9007199254740992; // 0x1p53 - private const int ILogB_NaN = 0x7fffffff; + private const int ILogB_NaN = 0x7FFFFFFF; - private const int ILogB_Zero = (-1 - 0x7fffffff); + private const int ILogB_Zero = (-1 - 0x7FFFFFFF); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Abs(short value) @@ -133,6 +133,26 @@ public static decimal Abs(decimal value) return decimal.Abs(value); } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Abs(double value) + { + const ulong mask = 0x7FFFFFFFFFFFFFFF; + ulong raw = BitConverter.DoubleToUInt64Bits(value); + + return BitConverter.UInt64BitsToDouble(raw & mask); + } + + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Abs(float value) + { + const uint mask = 0x7FFFFFFF; + uint raw = BitConverter.SingleToUInt32Bits(value); + + return BitConverter.UInt32BitsToSingle(raw & mask); + } + [DoesNotReturn] [StackTraceHidden] private static void ThrowAbsOverflow() diff --git a/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs index b2bf6baadd57c..eb0024f983e64 100644 --- a/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Math.Mono.cs @@ -7,12 +7,6 @@ namespace System { public partial class Math { - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern double Abs(double value); - - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern float Abs(float value); - [MethodImpl(MethodImplOptions.InternalCall)] public static extern double Acos(double d); diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h index d99cf1cee6c32..5b75710e6456a 100644 --- a/src/mono/mono/metadata/icall-decl.h +++ b/src/mono/mono/metadata/icall-decl.h @@ -68,7 +68,6 @@ ICALL_EXPORT void ves_icall_System_ArgIterator_Setup (MonoArgIterator*, char*, c ICALL_EXPORT MonoType* ves_icall_System_ArgIterator_IntGetNextArgType (MonoArgIterator*); ICALL_EXPORT void ves_icall_System_ArgIterator_IntGetNextArg (MonoArgIterator*, MonoTypedRef*); ICALL_EXPORT void ves_icall_System_ArgIterator_IntGetNextArgWithType (MonoArgIterator*, MonoTypedRef*, MonoType*); -ICALL_EXPORT double ves_icall_System_Math_Abs_double (double); ICALL_EXPORT double ves_icall_System_Math_Acos (double); ICALL_EXPORT double ves_icall_System_Math_Acosh (double); ICALL_EXPORT double ves_icall_System_Math_Asin (double); @@ -116,7 +115,6 @@ ICALL_EXPORT float ves_icall_System_MathF_Sinh (float); ICALL_EXPORT float ves_icall_System_MathF_Sqrt (float); ICALL_EXPORT float ves_icall_System_MathF_Tan (float); ICALL_EXPORT float ves_icall_System_MathF_Tanh (float); -ICALL_EXPORT float ves_icall_System_Math_Abs_single (float); ICALL_EXPORT double ves_icall_System_Math_Log2 (double); ICALL_EXPORT double ves_icall_System_Math_FusedMultiplyAdd (double, double, double); ICALL_EXPORT float ves_icall_System_MathF_Log2 (float); diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index 3dde98a274d3d..45c65207a0849 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -108,9 +108,7 @@ ICALL_TYPE(STREAM, "System.IO.Stream", STREAM_1) HANDLES(STREAM_1, "HasOverriddenBeginEndRead", ves_icall_System_IO_Stream_HasOverriddenBeginEndRead, MonoBoolean, 1, (MonoObject)) HANDLES(STREAM_2, "HasOverriddenBeginEndWrite", ves_icall_System_IO_Stream_HasOverriddenBeginEndWrite, MonoBoolean, 1, (MonoObject)) -ICALL_TYPE(MATH, "System.Math", MATH_19) -NOHANDLES(ICALL(MATH_19, "Abs(double)", ves_icall_System_Math_Abs_double)) -NOHANDLES(ICALL(MATH_20, "Abs(single)", ves_icall_System_Math_Abs_single)) +ICALL_TYPE(MATH, "System.Math", MATH_1) NOHANDLES(ICALL(MATH_1, "Acos", ves_icall_System_Math_Acos)) NOHANDLES(ICALL(MATH_1a, "Acosh", ves_icall_System_Math_Acosh)) NOHANDLES(ICALL(MATH_2, "Asin", ves_icall_System_Math_Asin)) diff --git a/src/mono/mono/metadata/sysmath.c b/src/mono/mono/metadata/sysmath.c index e8fef9f8e08e9..ec25a20fc0025 100644 --- a/src/mono/mono/metadata/sysmath.c +++ b/src/mono/mono/metadata/sysmath.c @@ -1,6 +1,6 @@ /** * \file - * these are based on bob smith's csharp routines + * these are based on bob smith's csharp routines * * Author: * Mono Project (http://www.mono-project.com) @@ -55,49 +55,49 @@ ves_icall_System_Math_ModF (gdouble x, gdouble *d) return modf (x, d); } -gdouble +gdouble ves_icall_System_Math_Sin (gdouble x) { return sin (x); } -gdouble +gdouble ves_icall_System_Math_Cos (gdouble x) { return cos (x); } -gdouble +gdouble ves_icall_System_Math_Cbrt (gdouble x) { return cbrt (x); } -gdouble +gdouble ves_icall_System_Math_Tan (gdouble x) { return tan (x); } -gdouble +gdouble ves_icall_System_Math_Sinh (gdouble x) { return sinh (x); } -gdouble +gdouble ves_icall_System_Math_Cosh (gdouble x) { return cosh (x); } -gdouble +gdouble ves_icall_System_Math_Tanh (gdouble x) { return tanh (x); } -gdouble +gdouble ves_icall_System_Math_Acos (gdouble x) { return acos (x); @@ -109,78 +109,66 @@ ves_icall_System_Math_Acosh (gdouble x) return acosh (x); } -gdouble +gdouble ves_icall_System_Math_Asin (gdouble x) { return asin (x); } -gdouble +gdouble ves_icall_System_Math_Asinh (gdouble x) { return asinh (x); } -gdouble +gdouble ves_icall_System_Math_Atan (gdouble x) { return atan (x); } -gdouble +gdouble ves_icall_System_Math_Atan2 (gdouble y, gdouble x) { return atan2 (y, x); } -gdouble +gdouble ves_icall_System_Math_Atanh (gdouble x) { return atanh (x); } -gdouble +gdouble ves_icall_System_Math_Exp (gdouble x) { return exp (x); } -gdouble +gdouble ves_icall_System_Math_Log (gdouble x) { return log (x); } -gdouble +gdouble ves_icall_System_Math_Log10 (gdouble x) { return log10 (x); } -gdouble +gdouble ves_icall_System_Math_Pow (gdouble x, gdouble y) { return pow (x, y); } -gdouble +gdouble ves_icall_System_Math_Sqrt (gdouble x) { return sqrt (x); } -gdouble -ves_icall_System_Math_Abs_double (gdouble v) -{ - return fabs (v); -} - -float -ves_icall_System_Math_Abs_single (float v) -{ - return fabsf (v); -} - gdouble ves_icall_System_Math_Ceiling (gdouble v) { diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index e5aef94c5c6ee..099c70695c138 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1930,7 +1930,7 @@ dump_args (InterpFrame *inv) GString *str = g_string_new (""); int i; MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method); - + if (signature->param_count == 0 && !signature->hasthis) return g_string_free (str, FALSE); @@ -3232,7 +3232,7 @@ static long opcode_counts[MINT_LASTOP]; #define COUNT_OP(op) opcode_counts[op]++ #else -#define COUNT_OP(op) +#define COUNT_OP(op) #endif #if DEBUG_INTERP @@ -3478,7 +3478,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs #endif main_loop: /* - * using while (ip < end) may result in a 15% performance drop, + * using while (ip < end) may result in a 15% performance drop, * but it may be useful for debug */ while (1) { @@ -3559,7 +3559,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_LDC_I4_8) LDC(8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_S) + MINT_IN_CASE(MINT_LDC_I4_S) LOCAL_VAR (ip [1], gint32) = (short)ip [2]; ip += 3; MINT_IN_BREAK; @@ -3584,7 +3584,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ip += 4; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LDC_R8) + MINT_IN_CASE(MINT_LDC_R8) LOCAL_VAR (ip [1], gint64) = READ64 (ip + 2); /* note union usage */ ip += 6; MINT_IN_BREAK; @@ -3720,7 +3720,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs call_args_offset = ip [3]; if (need_unbox) { - MonoObject *this_arg = LOCAL_VAR (call_args_offset, MonoObject*); + MonoObject *this_arg = LOCAL_VAR (call_args_offset, MonoObject*); LOCAL_VAR (call_args_offset, gpointer) = mono_object_unbox_internal (this_arg); } ip += 4; @@ -6450,8 +6450,8 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; ip += short_offset ? (gint16)*(ip + 1) : (gint32)READ32 (ip + 1); MINT_IN_BREAK; } - MINT_IN_CASE(MINT_ICALL_V_V) - MINT_IN_CASE(MINT_ICALL_P_V) + MINT_IN_CASE(MINT_ICALL_V_V) + MINT_IN_CASE(MINT_ICALL_P_V) MINT_IN_CASE(MINT_ICALL_PP_V) MINT_IN_CASE(MINT_ICALL_PPP_V) MINT_IN_CASE(MINT_ICALL_PPPP_V) @@ -6476,7 +6476,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; CHECK_RESUME_STATE (context); ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_MONO_LDPTR) + MINT_IN_CASE(MINT_MONO_LDPTR) LOCAL_VAR (ip [1], gpointer) = frame->imethod->data_items [ip [2]]; ip += 3; MINT_IN_BREAK; @@ -6912,12 +6912,12 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_BREAK; } MINT_IN_CASE(MINT_MONO_RETHROW) { - /* + /* * need to clarify what this should actually do: * * Takes an exception from the stack and rethrows it. * This is useful for wrappers that don't want to have to - * use CEE_THROW and lose the exception stacktrace. + * use CEE_THROW and lose the exception stacktrace. */ MonoException *exc = LOCAL_VAR (ip [1], MonoException*); @@ -6950,7 +6950,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; LOCAL_VAR (ip [1], double) = mathfunc (LOCAL_VAR (ip [2], double), LOCAL_VAR (ip [3], double)); \ ip += 4; - MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK; MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK; MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK; MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK; @@ -6990,7 +6989,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; #define MATH_BINOPF(mathfunc) \ LOCAL_VAR (ip [1], float) = mathfunc (LOCAL_VAR (ip [2], float), LOCAL_VAR (ip [3], float)); \ ip += 4; - MINT_IN_CASE(MINT_ABSF) MATH_UNOPF(fabsf); MINT_IN_BREAK; MINT_IN_CASE(MINT_ASINF) MATH_UNOPF(asinf); MINT_IN_BREAK; MINT_IN_CASE(MINT_ASINHF) MATH_UNOPF(asinhf); MINT_IN_BREAK; MINT_IN_CASE(MINT_ACOSF) MATH_UNOPF(acosf); MINT_IN_BREAK; diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 52b2c4bb1522c..59f909b24b365 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -708,7 +708,6 @@ OPDEF(MINT_LD_DELEGATE_METHOD_PTR, "ld_delegate_method_ptr", 3, 1, 1, MintOpNoAr // Math intrinsics // double -OPDEF(MINT_ABS, "abs", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_ASIN, "asin", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_ASINH, "asinh", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_ACOS, "acos", 3, 1, 1, MintOpNoArgs) @@ -735,7 +734,6 @@ OPDEF(MINT_TAN, "tan", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_TANH, "tanh", 3, 1, 1, MintOpNoArgs) // float. These must be kept in the same order as their double counterpart -OPDEF(MINT_ABSF, "absf", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_ASINF, "asinf", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_ASINHF, "asinhf", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_ACOSF, "acosf", 3, 1, 1, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 8679774a33876..a5d57007d885f 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -778,7 +778,7 @@ init_bb_stack_state (TransformData *td, InterpBasicBlock *bb) } } -static void +static void handle_branch (TransformData *td, int long_op, int offset) { int target = td->ip + offset - td->il_code; @@ -806,7 +806,7 @@ handle_branch (TransformData *td, int long_op, int offset) td->last_ins->info.target_bb = target_bb; } -static void +static void one_arg_branch(TransformData *td, int mint_op, int offset, int inst_size) { int type = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type; @@ -835,7 +835,7 @@ interp_add_conv (TransformData *td, StackInfo *sp, InterpInst *prev_ins, int typ interp_ins_set_dreg (new_inst, sp->local); } -static void +static void two_arg_branch(TransformData *td, int mint_op, int offset, int inst_size) { int type1 = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type; @@ -854,7 +854,7 @@ two_arg_branch(TransformData *td, int mint_op, int offset, int inst_size) } else if (type1 == STACK_TYPE_R8 && type2 == STACK_TYPE_R4) { interp_add_conv (td, td->sp - 2, td->last_ins, STACK_TYPE_R8, MINT_CONV_R8_R4); } else if (type1 != type2) { - g_warning("%s.%s: branch type mismatch %d %d", + g_warning("%s.%s: branch type mismatch %d %d", m_class_get_name (td->method->klass), td->method->name, td->sp [-1].type, td->sp [-2].type); } @@ -910,7 +910,7 @@ binary_arith_op(TransformData *td, int mint_op) if (type2 == STACK_TYPE_MP) type2 = STACK_TYPE_I; if (type1 != type2) { - g_warning("%s.%s: %04x arith type mismatch %s %d %d", + g_warning("%s.%s: %04x arith type mismatch %s %d %d", m_class_get_name (td->method->klass), td->method->name, td->ip - td->il_code, mono_interp_opname (mint_op), type1, type2); } @@ -929,7 +929,7 @@ shift_op(TransformData *td, int mint_op) int op = mint_op + td->sp [-2].type - STACK_TYPE_I4; CHECK_STACK(td, 2); if (td->sp [-1].type != STACK_TYPE_I4) { - g_warning("%s.%s: shift type mismatch %d", + g_warning("%s.%s: shift type mismatch %d", m_class_get_name (td->method->klass), td->method->name, td->sp [-2].type); } @@ -940,7 +940,7 @@ shift_op(TransformData *td, int mint_op) interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } -static int +static int can_store (int st_value, int vt_value) { if (st_value == STACK_TYPE_O || st_value == STACK_TYPE_MP) @@ -967,7 +967,7 @@ get_arg_type_exact (TransformData *td, int n, int *mt) return type; } -static void +static void load_arg(TransformData *td, int n) { gint32 size = 0; @@ -1006,12 +1006,12 @@ load_arg(TransformData *td, int n) } interp_add_ins (td, get_mov_for_type (mt, TRUE)); interp_ins_set_sreg (td->last_ins, n); - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); if (mt == MINT_TYPE_VT) td->last_ins->data [0] = size; } -static void +static void store_arg(TransformData *td, int n) { gint32 size = 0; @@ -1060,7 +1060,7 @@ load_local (TransformData *td, int local) td->last_ins->data [0] = size; } -static void +static void store_local (TransformData *td, int local) { int mt = td->locals [local].mt; @@ -1070,7 +1070,7 @@ store_local (TransformData *td, int local) interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_I4); #endif if (!can_store(td->sp [-1].type, stack_type [mt])) { - g_warning("%s.%s: Store local stack type mismatch %d %d", + g_warning("%s.%s: Store local stack type mismatch %d %d", m_class_get_name (td->method->klass), td->method->name, stack_type [mt], td->sp [-1].type); } @@ -2180,9 +2180,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas if (csignature->param_count == 1 && csignature->params [0]->type == param_type) { // unops if (tm [0] == 'A') { - if (strcmp (tm, "Abs") == 0) { - *op = MINT_ABS; - } else if (strcmp (tm, "Asin") == 0){ + if (strcmp (tm, "Asin") == 0){ *op = MINT_ASIN; } else if (strcmp (tm, "Asinh") == 0){ *op = MINT_ASINH; @@ -2245,7 +2243,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas } if (*op != -1 && is_float) { - *op = *op + (MINT_ABSF - MINT_ABS); + *op = *op + (MINT_ASINF - MINT_ASIN); } } else if (in_corlib && !strcmp (klass_name_space, "System") && (!strcmp (klass_name, "Span`1") || !strcmp (klass_name, "ReadOnlySpan`1"))) { if (!strcmp (tm, "get_Item")) { @@ -2830,7 +2828,7 @@ interp_inline_method (TransformData *td, MonoMethod *target_method, MonoMethodHe gboolean ret; unsigned int prev_max_stack_height, prev_locals_size; int prev_n_data_items; - int i; + int i; int prev_sp_offset; int prev_aggressive_inlining; MonoGenericContext *generic_context = NULL; @@ -3293,7 +3291,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target CHECK_STACK (td, csignature->param_count + csignature->hasthis); if (tailcall && !td->gen_sdb_seq_points && !calli && op == -1 && - (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 && + (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 && (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0 && !(target_method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING)) { (void)mono_class_vtable_checked (target_method->klass, error); @@ -3332,7 +3330,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target int in_offset = td->ip - td->il_code; if (interp_ip_in_cbb (td, in_offset + 5)) - ++td->ip; /* gobble the CEE_RET if it isn't branched to */ + ++td->ip; /* gobble the CEE_RET if it isn't branched to */ td->ip += 5; return TRUE; } @@ -3438,7 +3436,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target else g_error ("Unsupported opcode"); } - + if (op == MINT_LDLEN) { #ifdef MONO_BIG_ARRAYS SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I8); @@ -4658,7 +4656,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, } switch (*td->ip) { - case CEE_NOP: + case CEE_NOP: /* lose it */ emitted_funccall_seq_point = FALSE; ++td->ip; @@ -4828,7 +4826,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_ins_set_dreg (td->last_ins, td->sp [-1].local); ++td->ip; break; - case CEE_LDC_I4_S: + case CEE_LDC_I4_S: interp_add_ins (td, MINT_LDC_I4_S); td->last_ins->data [0] = ((gint8 *) td->ip) [1]; push_simple_type (td, STACK_TYPE_I4); @@ -4933,7 +4931,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, last_seq_point->flags |= INTERP_INST_FLAG_SEQ_POINT_NESTED_CALL; } else - emitted_funccall_seq_point = TRUE; + emitted_funccall_seq_point = TRUE; } last_seq_point = interp_add_ins (td, MINT_SDB_SEQ_POINT); // This seq point is actually associated with the instruction following the call @@ -5397,7 +5395,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, } ++td->ip; break; - case CEE_CONV_I: + case CEE_CONV_I: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R8: @@ -5871,7 +5869,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_UNBOX: CHECK_STACK (td, 1); token = read32 (td->ip + 1); - + if (method->wrapper_type != MONO_WRAPPER_NONE) klass = (MonoClass *)mono_method_get_wrapper_data (method, token); else { @@ -6948,7 +6946,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_LD_DELEGATE_METHOD_PTR); interp_ins_set_sreg (td->last_ins, td->sp [0].local); push_simple_type (td, STACK_TYPE_I); - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); break; case CEE_MONO_CALLI_EXTRA_ARG: { int saved_local = td->sp [-1].local; @@ -7081,7 +7079,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, td->sp--; interp_ins_set_sreg (td->last_ins, td->sp [0].local); klass = (MonoClass *)mono_method_get_wrapper_data (method, token); - + /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/ if (td->sp > td->stack) @@ -7184,7 +7182,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, * to take into account the number of prefix bytes (usually the * throw point is just (ip - n_prefix_bytes). */ - case CEE_PREFIX1: + case CEE_PREFIX1: ++td->ip; switch (*td->ip) { case CEE_ARGLIST: @@ -7333,7 +7331,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, td->ip += 5; break; } - + int index = get_data_item_index (td, mono_interp_get_imethod (m, error)); goto_if_nok (error, exit); if (*td->ip == CEE_LDVIRTFTN) { @@ -7426,7 +7424,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, #if SIZEOF_VOID_P == 8 if (td->sp [-1].type == STACK_TYPE_I8) interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_MOV_8); -#endif +#endif interp_add_ins (td, MINT_LOCALLOC); if (td->sp != td->stack + 1) g_warning("CEE_LOCALLOC: stack not empty"); @@ -7542,7 +7540,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5); #endif size = mono_type_size (m_class_get_byval_arg (szclass), &align); - } + } interp_add_ins (td, MINT_LDC_I4); WRITE32_INS (td->last_ins, 0, &size); push_simple_type (td, STACK_TYPE_I4); @@ -9133,7 +9131,7 @@ static void initialize_global_var_cb (TransformData *td, int var, gpointer data) { initialize_global_var (td, var, (int)(gsize)data); -} +} static void initialize_global_vars (TransformData *td) @@ -9552,7 +9550,7 @@ interp_fix_localloc_ret (TransformData *td) g_assert (td->has_localloc); for (InterpBasicBlock *bb = td->entry_bb; bb != NULL; bb = bb->next_bb) { InterpInst *ins = bb->first_ins; - while (ins) { + while (ins) { if (ins->opcode >= MINT_RET && ins->opcode <= MINT_RET_VT) ins->opcode += MINT_RET_LOCALLOC - MINT_RET; ins = ins->next; @@ -9806,7 +9804,7 @@ tiered_patcher (MiniTieredPatchPointContext *ctx, gpointer patchsite) #endif -void +void mono_interp_transform_init (void) { mono_os_mutex_init_recursive(&calc_section); From 3104ed8a3579746eaadb6280acc4fae1ae0df6ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 19 Jan 2022 15:00:52 +0900 Subject: [PATCH 038/308] Fix up warnings from delegate thunks (#63980) If we hit a p/invoke with a `System.Delegate` in a delegate marshalling stub, blame the delegate type, not the compiler-generated method. Apparently we marshal System.Delegate in MsQuick interop. --- .../IL/Stubs/DelegateMarshallingMethodThunk.cs | 8 ++++++++ .../Compiler/UsageBasedInteropStubManager.cs | 14 +++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/DelegateMarshallingMethodThunk.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/DelegateMarshallingMethodThunk.cs index 276f7dc4a42fc..5b09863069020 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/DelegateMarshallingMethodThunk.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/DelegateMarshallingMethodThunk.cs @@ -27,6 +27,14 @@ public partial class DelegateMarshallingMethodThunk : ILStubMethod private readonly MethodDesc _invokeMethod; private MethodSignature _signature; // signature of the native callable marshalling stub + public MethodDesc InvokeMethod + { + get + { + return _invokeMethod; + } + } + public DelegateMarshallingMethodThunkKind Kind { get; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedInteropStubManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedInteropStubManager.cs index a1e931e172539..fe42b62526b77 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedInteropStubManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedInteropStubManager.cs @@ -61,11 +61,23 @@ private void AddParameterMarshallingDependencies(ref DependencyList dependencies if ((type.IsWellKnownType(WellKnownType.MulticastDelegate) || type == context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType)) { + // If we hit this p/invoke as part of delegate marshalling (i.e. this is a delegate + // that has another delegate in the signature), blame the delegate type, not the marshalling thunk. + // This should ideally warn from the use site (e.g. where GetDelegateForFunctionPointer + // is called) but it's currently hard to get a warning from those spots and this guarantees + // we won't miss a spot (e.g. a p/invoke that has a delegate and that delegate contains + // a System.Delegate parameter). + MethodDesc reportedMethod = method; + if (reportedMethod is Internal.IL.Stubs.DelegateMarshallingMethodThunk delegateThunkMethod) + { + reportedMethod = delegateThunkMethod.InvokeMethod; + } + var message = new DiagnosticString(DiagnosticId.CorrectnessOfAbstractDelegatesCannotBeGuaranteed).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(method)); _logger.LogWarning( message, (int)DiagnosticId.CorrectnessOfAbstractDelegatesCannotBeGuaranteed, - method, + reportedMethod, MessageSubCategory.AotAnalysis); } From c66e3c49b59e0894ed3e7c41b0e78dcda22528ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 19 Jan 2022 15:01:43 +0900 Subject: [PATCH 039/308] Add support for libraries testing with NativeAOT (#63781) This adds support for running libraries tests with NativeAOT. It reuses the single file xunit runner since we cannot `LoadFrom` the tests on NativeAOT. The strategy is the same as for single file testing: do a publish. To do the NativeAOT publish, we include the Microsoft.DotNet.ILCompiler.targets. --- eng/liveBuilds.targets | 3 ++ eng/testing/default.rd.xml | 81 ++++++++++++++++++++++++++++ eng/testing/tests.props | 1 + eng/testing/tests.singlefile.targets | 26 ++++++++- src/libraries/externals.csproj | 5 +- src/libraries/tests.proj | 10 +++- 6 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 eng/testing/default.rd.xml diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index bc2e7e5dff9a0..aab934c42ae6b 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -24,6 +24,9 @@ $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'sharedFramework')) $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'crossgen2')) + $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'ilc')) + $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'aotsdk')) + $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'build')) $([MSBuild]::NormalizeDirectory('$(MonoArtifactsPath)', 'cross', $(TargetOS.ToLowerInvariant())-$(TargetArchitecture.ToLowerInvariant()))) diff --git a/eng/testing/default.rd.xml b/eng/testing/default.rd.xml new file mode 100644 index 0000000000000..c0aaef61d2519 --- /dev/null +++ b/eng/testing/default.rd.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eng/testing/tests.props b/eng/testing/tests.props index 86c661d4bb281..3025ab6233504 100644 --- a/eng/testing/tests.props +++ b/eng/testing/tests.props @@ -7,6 +7,7 @@ $(TestDependsOn);GenerateRunScript;RunTests true $(MSBuildThisFileDirectory)ILLinkDescriptors\ + true diff --git a/eng/testing/tests.singlefile.targets b/eng/testing/tests.singlefile.targets index 85ee6deb32db3..e6783add3640a 100644 --- a/eng/testing/tests.singlefile.targets +++ b/eng/testing/tests.singlefile.targets @@ -12,7 +12,7 @@ chmod +rwx $(AssemblyName) && ./$(AssemblyName) - + true true true @@ -20,6 +20,30 @@ $(SingleFileHostSourcePath).exe + + $(CoreCLRILCompilerDir) + $(CoreCLRILCompilerDir)netstandard/ILCompiler.Build.Tasks.dll + $(CoreCLRAotSdkDir) + $(NetCoreAppCurrentTestHostSharedFrameworkPath) + $(NoWarn);IL3050;IL3052;IL3055;IL1005 + false + + + true + + + + + + + + + + + + + + diff --git a/src/libraries/externals.csproj b/src/libraries/externals.csproj index 969ed9603a2cd..54ef0d14897c6 100644 --- a/src/libraries/externals.csproj +++ b/src/libraries/externals.csproj @@ -26,7 +26,8 @@ + AfterTargets="AfterResolveReferences" + Condition="'$(TestNativeAot)' != 'true'"> true @@ -75,7 +76,7 @@ + Condition="'$(RuntimeFlavor)' != 'Mono' and '$(TestNativeAot)' != 'true'"> diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index c560a65102156..d9391e0ec2c9d 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -343,13 +343,21 @@ Roslyn4.0.Tests.csproj" /> - + + + + + + + + + From 00e13f5482ea1156e6b37ea5d242d7f27befb8d3 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 19 Jan 2022 08:42:07 +0100 Subject: [PATCH 040/308] Add tests for creating memory mapped files from non-seekable files (#63927) --- .../System/IO/FileCleanupTestBase.cs | 28 ++++++++++ .../tests/File/ReadWriteAllBytes.cs | 2 +- .../tests/File/ReadWriteAllBytesAsync.cs | 2 +- .../FileStreamConformanceTests.Windows.cs | 2 +- .../FileStream/FileStreamConformanceTests.cs | 2 +- .../tests/FileSystemTest.cs | 25 --------- .../MemoryMappedFile.CreateFromFile.Tests.cs | 52 +++++++++++++++++++ .../tests/MemoryMappedFilesTestsBase.Unix.cs | 3 ++ .../MemoryMappedFilesTestsBase.Windows.cs | 7 ++- 9 files changed, 90 insertions(+), 33 deletions(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs b/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs index 4f9b32add6f0d..bc53138d8be13 100644 --- a/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs +++ b/src/libraries/Common/tests/TestUtilities/System/IO/FileCleanupTestBase.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Threading; +using System.Text; namespace System.IO { @@ -134,6 +135,33 @@ protected string GetTestFileName(int? index = null, [CallerMemberName] string me return testFileName; } + protected static string GetNamedPipeServerStreamName() + { + if (PlatformDetection.IsInAppContainer) + { + return @"LOCAL\" + Guid.NewGuid().ToString("N"); + } + + if (PlatformDetection.IsWindows) + { + return Guid.NewGuid().ToString("N"); + } + + const int MinUdsPathLength = 104; // required min is 92, but every platform we currently target is at least 104 + const int MinAvailableForSufficientRandomness = 5; // we want enough randomness in the name to avoid conflicts between concurrent tests + string prefix = Path.Combine(Path.GetTempPath(), "CoreFxPipe_"); + int availableLength = MinUdsPathLength - prefix.Length - 1; // 1 - for possible null terminator + Assert.True(availableLength >= MinAvailableForSufficientRandomness, $"UDS prefix {prefix} length {prefix.Length} is too long"); + + StringBuilder sb = new(availableLength); + Random random = new Random(); + for (int i = 0; i < availableLength; i++) + { + sb.Append((char)('a' + random.Next(0, 26))); + } + return sb.ToString(); + } + private string GenerateTestFileName(int? index, string memberName, int lineNumber) => string.Format( index.HasValue ? "{0}_{1}_{2}_{3}" : "{0}_{1}_{3}", diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs index 26dd666d06916..4d3a96c80665a 100644 --- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs +++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs @@ -166,7 +166,7 @@ public void ProcFs_NotEmpty(string path) [ActiveIssue("https://github.com/dotnet/runtime/issues/60427")] public async Task ReadAllBytes_NonSeekableFileStream_InWindows() { - string pipeName = FileSystemTest.GetNamedPipeServerStreamName(); + string pipeName = GetNamedPipeServerStreamName(); string pipePath = Path.GetFullPath($@"\\.\pipe\{pipeName}"); var namedPipeWriterStream = new NamedPipeServerStream(pipeName, PipeDirection.Out); diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs index c4f147cbb8009..c6fbb37880b95 100644 --- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs +++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs @@ -177,7 +177,7 @@ public async Task ProcFs_NotEmpty(string path) [PlatformSpecific(TestPlatforms.Windows)] // DOS device paths (\\.\ and \\?\) are a Windows concept public async Task ReadAllBytesAsync_NonSeekableFileStream_InWindows() { - string pipeName = FileSystemTest.GetNamedPipeServerStreamName(); + string pipeName = GetNamedPipeServerStreamName(); string pipePath = Path.GetFullPath($@"\\.\pipe\{pipeName}"); var namedPipeWriterStream = new NamedPipeServerStream(pipeName, PipeDirection.Out); diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/FileStreamConformanceTests.Windows.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/FileStreamConformanceTests.Windows.cs index 6e694e4347369..044343f91a9f6 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileStream/FileStreamConformanceTests.Windows.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileStream/FileStreamConformanceTests.Windows.cs @@ -19,7 +19,7 @@ public class UnseekableDeviceFileStreamConnectedConformanceTests : ConnectedStre { protected override async Task CreateConnectedStreamsAsync() { - string pipeName = FileSystemTest.GetNamedPipeServerStreamName(); + string pipeName = GetNamedPipeServerStreamName(); string pipePath = Path.GetFullPath($@"\\.\pipe\{pipeName}"); var server = new NamedPipeServerStream(pipeName, PipeDirection.In); diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/FileStreamConformanceTests.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/FileStreamConformanceTests.cs index d1fd4fe764f4d..d9d36053a8e11 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileStream/FileStreamConformanceTests.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileStream/FileStreamConformanceTests.cs @@ -252,7 +252,7 @@ public class NamedPipeFileStreamConnectedConformanceTests : ConnectedStreamConfo { protected override async Task CreateConnectedStreamsAsync() { - string name = FileSystemTest.GetNamedPipeServerStreamName(); + string name = GetNamedPipeServerStreamName(); var server = new NamedPipeServerStream(name, PipeDirection.In); var client = new NamedPipeClientStream(".", name, PipeDirection.Out); diff --git a/src/libraries/System.IO.FileSystem/tests/FileSystemTest.cs b/src/libraries/System.IO.FileSystem/tests/FileSystemTest.cs index afc49d5244ece..53251552104f6 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileSystemTest.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileSystemTest.cs @@ -55,31 +55,6 @@ public static TheoryData TrailingSeparators } } - public static string GetNamedPipeServerStreamName() - { - if (PlatformDetection.IsInAppContainer) - { - return @"LOCAL\" + Guid.NewGuid().ToString("N"); - } - - if (PlatformDetection.IsWindows) - { - return Guid.NewGuid().ToString("N"); - } - - const int MinUdsPathLength = 104; // required min is 92, but every platform we currently target is at least 104 - const int MinAvailableForSufficientRandomness = 5; // we want enough randomness in the name to avoid conflicts between concurrent tests - string prefix = Path.Combine(Path.GetTempPath(), "CoreFxPipe_"); - int availableLength = MinUdsPathLength - prefix.Length - 1; // 1 - for possible null terminator - Assert.True(availableLength >= MinAvailableForSufficientRandomness, $"UDS prefix {prefix} length {prefix.Length} is too long"); - - return string.Create(availableLength, 0, (span, _) => - { - for (int i = 0; i < span.Length; i++) - span[i] = (char)('a' + Random.Shared.Next(0, 26)); - }); - } - /// /// Do a test action against read only file system (for Unix). /// diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFile.CreateFromFile.Tests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFile.CreateFromFile.Tests.cs index 824f9b9fd17e3..c9feabeae25de 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFile.CreateFromFile.Tests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFile.CreateFromFile.Tests.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using Microsoft.DotNet.XUnitExtensions; using Xunit; +using System.IO.Pipes; +using System.Threading.Tasks; namespace System.IO.MemoryMappedFiles.Tests { @@ -968,5 +970,55 @@ public void MapHandleMatchesFileStreamHandle() } } } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [SkipOnPlatform(TestPlatforms.Browser, "mkfifo is not supported on WASM")] + public async Task OpeningMemoryMappedFileFromFileStreamThatWrapsPipeThrowsNotSupportedException(long capacity) + { + (string pipePath, NamedPipeServerStream? serverStream) = CreatePipe(); + using FileStream clientStream = new (pipePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None); + + if (serverStream is not null) + { + await serverStream.WaitForConnectionAsync(); + } + + Assert.Throws(() => MemoryMappedFile.CreateFromFile(clientStream, null, capacity, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, false)); + + serverStream?.Dispose(); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [SkipOnPlatform(TestPlatforms.Browser, "mkfifo is not supported on WASM")] + public void OpeningMemoryMappedFileFromPipePathThrowsNotSupportedException(long capacity) + { + (string pipePath, NamedPipeServerStream? serverStream) = CreatePipe(); + + Assert.Throws(() => MemoryMappedFile.CreateFromFile(pipePath, FileMode.Open, null, capacity, MemoryMappedFileAccess.ReadWrite)); + + serverStream?.Dispose(); + } + + private (string pipePath, NamedPipeServerStream? serverStream) CreatePipe() + { + if (OperatingSystem.IsWindows()) + { + string pipeName = GetNamedPipeServerStreamName(); + string pipePath = Path.GetFullPath($@"\\.\pipe\{pipeName}"); + + return (pipePath, new NamedPipeServerStream(pipeName, PipeDirection.InOut)); + } + else + { + string fifoPath = GetTestFilePath(); + Assert.Equal(0, mkfifo(fifoPath, 438 /* 666 in octal */ )); + + return (fifoPath, null); + } + } } } diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFilesTestsBase.Unix.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFilesTestsBase.Unix.cs index 670aa4d70aa0d..8024754a921da 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFilesTestsBase.Unix.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFilesTestsBase.Unix.cs @@ -34,6 +34,9 @@ public abstract partial class MemoryMappedFilesTestBase : FileCleanupTestBase [DllImport("libc", SetLastError = true)] private static extern int sysconf(int name); + [DllImport("libc", SetLastError = true)] + protected static extern int mkfifo(string path, int mode); + /// Asserts that the handle's inheritability matches the specified value. protected static void AssertInheritability(SafeHandle handle, HandleInheritability inheritability) { diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFilesTestsBase.Windows.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFilesTestsBase.Windows.cs index 9473abe2e0529..2460c15fd5985 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFilesTestsBase.Windows.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFilesTestsBase.Windows.cs @@ -43,10 +43,9 @@ private struct SYSTEM_INFO internal short wProcessorRevision; } - protected static int geteuid() - { - throw new PlatformNotSupportedException(); - } + protected static int geteuid() => throw new PlatformNotSupportedException(); + + protected static int mkfifo(string path, int mode) => throw new PlatformNotSupportedException(); /// Asserts that the handle's inheritability matches the specified value. protected static void AssertInheritability(SafeHandle handle, HandleInheritability inheritability) From ea2a98163327022e6cefb6a424de4cb4e9618277 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:55:35 +0100 Subject: [PATCH 041/308] [wasm][debugger] Added support for StepThroughAttribute (#63679) * Hidden methods and step through methods behave the same way. * Perpared flow for setting JustMyCode in the future. * Tests for JustMyCode setting before debug launch. * Transformed into dynamic JustMyCode change flow. * JustMyCode disabled, first 3 cases solved. * Finished behavior for JMC disabled (with 1 difference). * JMC enabled: stepIn np bp + stepIn bp + resume bp. * Functional version (with minor deviations from expected behavior). * Refactoring. --- .../debugger/BrowserDebugProxy/DebugStore.cs | 8 +- .../BrowserDebugProxy/DevToolsHelper.cs | 2 + .../debugger/BrowserDebugProxy/MonoProxy.cs | 83 +++++++++-- .../DebuggerTestSuite/BreakpointTests.cs | 131 +++++++++++++++++- .../DebuggerTestSuite/DebuggerTestBase.cs | 8 ++ .../debugger/DebuggerTestSuite/MiscTests.cs | 2 +- .../tests/debugger-test/debugger-test.cs | 20 +++ 7 files changed, 234 insertions(+), 20 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index 7860aef3772e8..e37f75191c511 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -333,6 +333,7 @@ internal class MethodInfo public bool IsStatic() => (methodDef.Attributes & MethodAttributes.Static) != 0; public int IsAsync { get; set; } public bool IsHiddenFromDebugger { get; } + public bool HasStepThroughAttribute { get; } public TypeInfo TypeInfo { get; } public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type, MetadataReader asmMetadataReader, MetadataReader pdbMetadataReader) @@ -379,7 +380,12 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, var name = asmMetadataReader.GetString(asmMetadataReader.GetTypeReference((TypeReferenceHandle)container).Name); if (name == "DebuggerHiddenAttribute") { - this.IsHiddenFromDebugger = true; + IsHiddenFromDebugger = true; + break; + } + if (name == "DebuggerStepThroughAttribute") + { + HasStepThroughAttribute = true; break; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index e17c3d2bccc4f..af1cead1c9593 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -312,6 +312,8 @@ public ExecutionContext(MonoSDBHelper sdbAgent, int id, object auxData) public TaskCompletionSource ready; public bool IsRuntimeReady => ready != null && ready.Task.IsCompleted; public bool IsSkippingHiddenMethod { get; set; } + public bool IsSteppingThroughMethod { get; set; } + public bool IsResumedAfterBp { get; set; } public int ThreadId { get; set; } public int Id { get; set; } public object AuxData { get; set; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 13979ad0f4968..33d1dc4c59d98 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -26,6 +26,7 @@ internal class MonoProxy : DevToolsProxy private const string sPauseOnCaught = "pause_on_caught"; // index of the runtime in a same JS page/process public int RuntimeId { get; private init; } + public bool JustMyCode { get; private set; } public MonoProxy(ILoggerFactory loggerFactory, IList urlSymbolServerList, int runtimeId = 0) : base(loggerFactory) { @@ -573,10 +574,33 @@ protected override async Task AcceptCommand(MessageId id, string method, J return true; } } + case "DotnetDebugger.justMyCode": + { + try + { + SetJustMyCode(id, args, token); + } + catch (Exception) + { + SendResponse(id, + Result.Exception(new ArgumentException( + $"DotnetDebugger.justMyCode got incorrect argument ({args})")), + token); + } + return true; + } } return false; } + private void SetJustMyCode(MessageId id, JObject args, CancellationToken token) + { + var isEnabled = args["enabled"]?.Value(); + if (isEnabled == null) + throw new ArgumentException(); + JustMyCode = isEnabled.Value; + SendResponse(id, Result.OkFromObject(new { justMyCodeEnabled = JustMyCode }), token); + } private async Task CallOnFunction(MessageId id, JObject args, CancellationToken token) { var context = GetContext(id); @@ -813,24 +837,44 @@ private async Task SendCallStack(SessionId sessionId, ExecutionContext con DebugStore store = await LoadStore(sessionId, token); var method = await context.SdbAgent.GetMethodInfo(methodId, token); - if (context.IsSkippingHiddenMethod == true) + var shouldReturn = await SkipMethod( + isSkippable: context.IsSkippingHiddenMethod, + shouldBeSkipped: event_kind != EventKind.UserBreak, + StepKind.Over); + context.IsSkippingHiddenMethod = false; + if (shouldReturn) + return true; + + shouldReturn = await SkipMethod( + isSkippable: context.IsSteppingThroughMethod, + shouldBeSkipped: event_kind != EventKind.UserBreak && event_kind != EventKind.Breakpoint, + StepKind.Over); + context.IsSteppingThroughMethod = false; + if (shouldReturn) + return true; + + if (j == 0 && (method?.Info.HasStepThroughAttribute == true || method?.Info.IsHiddenFromDebugger == true)) { - context.IsSkippingHiddenMethod = false; - if (event_kind != EventKind.UserBreak) + if (method.Info.IsHiddenFromDebugger) { - await context.SdbAgent.Step(context.ThreadId, StepKind.Over, token); - await SendCommand(sessionId, "Debugger.resume", new JObject(), token); - return true; + if (event_kind == EventKind.Step) + context.IsSkippingHiddenMethod = true; + if (await SkipMethod(isSkippable: true, shouldBeSkipped: true, StepKind.Out)) + return true; } - } - if (j == 0 && method?.Info.IsHiddenFromDebugger == true) - { - if (event_kind == EventKind.Step) - context.IsSkippingHiddenMethod = true; - await context.SdbAgent.Step(context.ThreadId, StepKind.Out, token); - await SendCommand(sessionId, "Debugger.resume", new JObject(), token); - return true; + if (event_kind == EventKind.Step || + (JustMyCode && (event_kind == EventKind.Breakpoint || event_kind == EventKind.UserBreak))) + { + if (context.IsResumedAfterBp) + context.IsResumedAfterBp = false; + else if (event_kind != EventKind.UserBreak) + context.IsSteppingThroughMethod = true; + if (await SkipMethod(isSkippable: true, shouldBeSkipped: true, StepKind.Out)) + return true; + } + if (event_kind == EventKind.Breakpoint) + context.IsResumedAfterBp = true; } SourceLocation location = method?.Info.GetLocationByIl(il_pos); @@ -910,6 +954,17 @@ private async Task SendCallStack(SessionId sessionId, ExecutionContext con SendEvent(sessionId, "Debugger.paused", o, token); return true; + + async Task SkipMethod(bool isSkippable, bool shouldBeSkipped, StepKind stepKind) + { + if (isSkippable && shouldBeSkipped) + { + await context.SdbAgent.Step(context.ThreadId, stepKind, token); + await SendCommand(sessionId, "Debugger.resume", new JObject(), token); + return true; + } + return false; + } } private async Task OnReceiveDebuggerAgentEvent(SessionId sessionId, JObject args, CancellationToken token) { diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs index 2644e8f754040..01f526e8c78db 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs @@ -668,7 +668,7 @@ await EvaluateAndCheck( [Fact] - public async Task DebuggerAttributeNoStopInDebuggerHidden() + public async Task DebuggerHiddenNoStopOnBp() { var bp_hidden = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "HiddenMethod", 1); var bp_visible = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "VisibleMethod", 1); @@ -683,7 +683,7 @@ await EvaluateAndCheck( } [Fact] - public async Task DebuggerAttributeStopOnDebuggerHiddenCallWithDebuggerBreakCall() + public async Task DebuggerHiddenStopOnUserBp() { var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunDebuggerBreak", 0); var init_location = await EvaluateAndCheck( @@ -708,6 +708,131 @@ await SendCommandAndCheck(null, "Debugger.resume", "VisibleMethodDebuggerBreak"); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task StepThroughAttributeStepInNoBp(bool justMyCodeEnabled) + { + var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 1); + if (justMyCodeEnabled) + await SetJustMyCode(true); + + var init_location = await EvaluateAndCheck( + "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerAttribute:RunStepThrough'); }, 1);", + "dotnet://debugger-test.dll/debugger-test.cs", + bp_init.Value["locations"][0]["lineNumber"].Value(), + bp_init.Value["locations"][0]["columnNumber"].Value(), + "RunStepThrough" + ); + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", 868, 8, "RunStepThrough"); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task StepThroughAttributeStepInWithBp(bool justMyCodeEnabled) + { + var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 1); + var bp1_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "NotStopOnJustMyCode", 1); + var bp2_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "NotStopOnJustMyCode", 3); + + var init_location = await EvaluateAndCheck( + "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerAttribute:RunStepThrough'); }, 1);", + "dotnet://debugger-test.dll/debugger-test.cs", + bp_init.Value["locations"][0]["lineNumber"].Value(), + bp_init.Value["locations"][0]["columnNumber"].Value(), + "RunStepThrough" + ); + + if (justMyCodeEnabled) + { + await SetJustMyCode(true); + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", 868, 8, "RunStepThrough"); + } + else + { + var line1 = bp1_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + var line2 = bp2_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + var line3 = 867; + var step_throgh_fun = "NotStopOnJustMyCode"; + var outer_fun = "RunStepThrough"; + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line1, 8, step_throgh_fun); + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line2, 8, step_throgh_fun); + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line3, 8, outer_fun); + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task StepThroughAttributeResumeWithBp(bool justMyCodeEnabled) + { + var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 1); + var bp1_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "NotStopOnJustMyCode", 1); + var bp_outside_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 2); + + var init_location = await EvaluateAndCheck( + "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerAttribute:RunStepThrough'); }, 1);", + "dotnet://debugger-test.dll/debugger-test.cs", + bp_init.Value["locations"][0]["lineNumber"].Value(), + bp_init.Value["locations"][0]["columnNumber"].Value(), + "RunStepThrough" + ); + + if (justMyCodeEnabled) + await SetJustMyCode(true); + else + { + var line1 = bp1_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + var function_name1 = "NotStopOnJustMyCode"; + await SendCommandAndCheck(null, "Debugger.resume", "dotnet://debugger-test.dll/debugger-test.cs", line1, 8, function_name1); + } + + var line2 = bp_outside_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + var function_name2 = "RunStepThrough"; + await SendCommandAndCheck(null, "Debugger.resume", "dotnet://debugger-test.dll/debugger-test.cs", line2, 8, function_name2); + } + + [Theory] + [InlineData(false, "Debugger.resume")] + [InlineData(false, "Debugger.stepInto")] + [InlineData(true, "Debugger.stepInto")] + [InlineData(true, "Debugger.resume")] + public async Task StepThroughAttributeWithUserBp(bool justMyCodeEnabled, string debuggingFunction) + { + var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 2); + var bp_outside_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 3); + + var init_location = await EvaluateAndCheck( + "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerAttribute:RunStepThrough'); }, 1);", + "dotnet://debugger-test.dll/debugger-test.cs", + bp_init.Value["locations"][0]["lineNumber"].Value(), + bp_init.Value["locations"][0]["columnNumber"].Value(), + "RunStepThrough" + ); + + int line1, line2; + string function_name1, function_name2; + + if (justMyCodeEnabled) + { + await SetJustMyCode(true); + line1 = bp_outside_decorated_fun.Value["locations"][0]["lineNumber"].Value() - 1; + function_name1 = "RunStepThrough"; + line2 = bp_outside_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + function_name2 = "RunStepThrough"; + } + else + { + line1 = 862; + function_name1 = "NotStopOnJustMyCodeUserBp"; + line2 = bp_outside_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + function_name2 = "RunStepThrough"; + } + await SendCommandAndCheck(null, debuggingFunction, "dotnet://debugger-test.dll/debugger-test.cs", line1, 8, function_name1); + await SendCommandAndCheck(null, debuggingFunction, "dotnet://debugger-test.dll/debugger-test.cs", line2, 4, function_name2); + } + [Fact] public async Task CreateGoodBreakpointAndHitGoToWasmPageWithoutAssetsComeBackAndHitAgain() { @@ -776,7 +901,5 @@ await EvaluateAndCheck( } ); } - - } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index 5660e8c55011b..d49a2331e2a11 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -1237,6 +1237,14 @@ internal async Task LoadAssemblyAndTestHotReload(string asm_file, strin await cli.SendCommand("Runtime.evaluate", run_method, token); return await insp.WaitFor(Inspector.PAUSE); } + + internal async Task SetJustMyCode(bool enabled) + { + var req = JObject.FromObject(new { enabled = enabled }); + var res = await cli.SendCommand("DotnetDebugger.justMyCode", req, token); + Assert.True(res.IsOk); + Assert.Equal(res.Value["justMyCodeEnabled"], enabled); + } } class DotnetObjectId diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs index bb61841cdd1f7..9bb227f43f409 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs @@ -913,7 +913,7 @@ public async Task InspectLocalsUsingClassFromLibraryUsingDebugTypeFull() await EvaluateAndCheck( "window.setTimeout(function() {" + expression + "; }, 1);", - "dotnet://debugger-test.dll/debugger-test.cs", 860, 8, + "dotnet://debugger-test.dll/debugger-test.cs", 880, 8, "CallToEvaluateLocal", wait_for_event_fn: async (pause_location) => { diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 98b9cb00dc401..49c811faaa317 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -848,6 +848,26 @@ public static void RunDebuggerBreak() HiddenMethodDebuggerBreak(); VisibleMethodDebuggerBreak(); } + + [System.Diagnostics.DebuggerStepThroughAttribute] + public static void NotStopOnJustMyCode() + { + var a = 0; + currentCount++; + var b = 1; + } + + [System.Diagnostics.DebuggerStepThroughAttribute] + public static void NotStopOnJustMyCodeUserBp() + { + System.Diagnostics.Debugger.Break(); + } + + public static void RunStepThrough() + { + NotStopOnJustMyCode(); + NotStopOnJustMyCodeUserBp(); + } } public class DebugTypeFull From b68cf65634bb0d6a1a7e588568959cdc33a0322c Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 19 Jan 2022 08:58:20 +0100 Subject: [PATCH 042/308] Reading beyond EOF should return 0 for FILE_FLAG_NO_BUFFERING (#63625) * move Length to SafeFileHandle, so it's cached value can be reused in more places --- .../tests/RandomAccess/NoBuffering.Windows.cs | 41 ++++++++++++++----- .../Win32/SafeHandles/SafeFileHandle.Unix.cs | 11 +++++ .../SafeHandles/SafeFileHandle.Windows.cs | 39 +++++++++++++++++- .../src/System/IO/File.cs | 4 +- .../src/System/IO/RandomAccess.Unix.cs | 7 ---- .../src/System/IO/RandomAccess.Windows.cs | 30 +++++++------- .../src/System/IO/RandomAccess.cs | 3 +- .../IO/Strategies/OSFileStreamStrategy.cs | 37 ++--------------- 8 files changed, 102 insertions(+), 70 deletions(-) diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/NoBuffering.Windows.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/NoBuffering.Windows.cs index ef60a9f223fb2..83b4c87bb64f5 100644 --- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/NoBuffering.Windows.cs +++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/NoBuffering.Windows.cs @@ -38,15 +38,6 @@ public async Task ReadUsingSingleBuffer(bool asyncOperation, bool asyncHandle) int current = 0; int total = 0; - // From https://docs.microsoft.com/en-us/windows/win32/fileio/file-buffering: - // "File access sizes, including the optional file offset in the OVERLAPPED structure, - // if specified, must be for a number of bytes that is an integer multiple of the volume sector size." - // So if buffer and physical sector size is 4096 and the file size is 4097: - // the read from offset=0 reads 4096 bytes - // the read from offset=4096 reads 1 byte - // the read from offset=4097 THROWS (Invalid argument, offset is not a multiple of sector size!) - // That is why we stop at the first incomplete read (the next one would throw). - // It's possible to get 0 if we are lucky and file size is a multiple of physical sector size. do { current = asyncOperation @@ -57,7 +48,7 @@ public async Task ReadUsingSingleBuffer(bool asyncOperation, bool asyncHandle) total += current; } - while (current == buffer.Memory.Length); + while (current != 0); Assert.Equal(fileSize, total); } @@ -222,6 +213,36 @@ public async Task ReadWriteAsyncUsingEmptyBuffers() await RandomAccess.WriteAsync(handle, Array.Empty>(), 0); } + [Theory] + [MemberData(nameof(AllAsyncSyncCombinations))] + public async Task ReadShouldReturnZeroForEndOfFile(bool asyncOperation, bool asyncHandle) + { + int fileSize = Environment.SystemPageSize + 1; // it MUST NOT be a multiple of it (https://github.com/dotnet/runtime/issues/62851) + string filePath = GetTestFilePath(); + byte[] expected = RandomNumberGenerator.GetBytes(fileSize); + File.WriteAllBytes(filePath, expected); + + using FileStream fileStream = new (filePath, FileMode.Open, FileAccess.Read, FileShare.None, 0, GetFileOptions(asyncHandle)); + using SectorAlignedMemory buffer = SectorAlignedMemory.Allocate(Environment.SystemPageSize); + + int current = 0; + int total = 0; + + do + { + current = asyncOperation + ? await fileStream.ReadAsync(buffer.Memory) + : fileStream.Read(buffer.GetSpan()); + + Assert.True(expected.AsSpan(total, current).SequenceEqual(buffer.GetSpan().Slice(0, current))); + + total += current; + } + while (current != 0); + + Assert.Equal(fileSize, total); + } + // when using FileOptions.Asynchronous we are testing Scatter&Gather APIs on Windows (FILE_FLAG_OVERLAPPED requirement) private static FileOptions GetFileOptions(bool asyncHandle) => (asyncHandle ? FileOptions.Asynchronous : FileOptions.None) | NoBuffering; } diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs index 32e242e0d8e4c..6bfd650a0d2fc 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs @@ -57,6 +57,10 @@ internal bool SupportsRandomAccess internal void EnsureThreadPoolBindingInitialized() { /* nop */ } + internal bool LengthCanBeCached => false; + + internal bool HasCachedFileLength => false; + private static SafeFileHandle Open(string path, Interop.Sys.OpenFlags flags, int mode, Func? createOpenException) { @@ -504,6 +508,13 @@ private bool GetCanSeek() return canSeek == NullableBool.True; } + internal long GetFileLength() + { + int result = Interop.Sys.FStat(this, out Interop.Sys.FileStatus status); + FileStreamHelpers.CheckFileCall(result, Path); + return status.Size; + } + private enum NullableBool { Undefined = 0, diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs index 3352f0194e73b..a4ecc686513cb 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; using System.IO; -using System.IO.Strategies; using System.Runtime.InteropServices; using System.Threading; @@ -13,6 +12,8 @@ namespace Microsoft.Win32.SafeHandles public sealed partial class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid { internal const FileOptions NoBuffering = (FileOptions)0x20000000; + private long _length = -1; // negative means that hasn't been fetched. + private bool _lengthCanBeCached; // file has been opened for reading and not shared for writing. private volatile FileOptions _fileOptions = (FileOptions)(-1); private volatile int _fileType = -1; @@ -22,10 +23,16 @@ public SafeFileHandle() : base(true) public bool IsAsync => (GetFileOptions() & FileOptions.Asynchronous) != 0; + internal bool IsNoBuffering => (GetFileOptions() & NoBuffering) != 0; + internal bool CanSeek => !IsClosed && GetFileType() == Interop.Kernel32.FileTypes.FILE_TYPE_DISK; internal ThreadPoolBoundHandle? ThreadPoolBinding { get; set; } + internal bool LengthCanBeCached => _lengthCanBeCached; + + internal bool HasCachedFileLength => _lengthCanBeCached && _length >= 0; + internal static unsafe SafeFileHandle Open(string fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, long preallocationSize) { using (DisableMediaInsertionPrompt.Create()) @@ -103,6 +110,7 @@ private static unsafe SafeFileHandle CreateFile(string fullPath, FileMode mode, fileHandle._path = fullPath; fileHandle._fileOptions = options; + fileHandle._lengthCanBeCached = (share & FileShare.Write) == 0 && (access & FileAccess.Write) == 0; return fileHandle; } @@ -252,5 +260,34 @@ internal int GetFileType() return fileType; } + + internal unsafe long GetFileLength() + { + if (!_lengthCanBeCached) + { + return GetFileLengthCore(); + } + + // On Windows, when the file is locked for writes we can cache file length + // in memory and avoid subsequent native calls which are expensive. + if (_length < 0) + { + _length = GetFileLengthCore(); + } + + return _length; + + long GetFileLengthCore() + { + Interop.Kernel32.FILE_STANDARD_INFO info; + + if (!Interop.Kernel32.GetFileInformationByHandleEx(this, Interop.Kernel32.FileStandardInfo, &info, (uint)sizeof(Interop.Kernel32.FILE_STANDARD_INFO))) + { + throw Win32Marshal.GetExceptionForLastWin32Error(Path); + } + + return info.EndOfFile; + } + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/File.cs b/src/libraries/System.Private.CoreLib/src/System/IO/File.cs index aa0bb62be57dc..2b4c61f1eb0ba 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/File.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/File.cs @@ -256,7 +256,7 @@ public static byte[] ReadAllBytes(string path) using (SafeFileHandle sfh = OpenHandle(path, FileMode.Open, FileAccess.Read, FileShare.Read, options)) { long fileLength = 0; - if (sfh.CanSeek && (fileLength = RandomAccess.GetFileLength(sfh)) > Array.MaxLength) + if (sfh.CanSeek && (fileLength = sfh.GetFileLength()) > Array.MaxLength) { throw new IOException(SR.IO_FileTooLong2GB); } @@ -530,7 +530,7 @@ private static async Task InternalReadAllTextAsync(string path, Encoding SafeFileHandle sfh = OpenHandle(path, FileMode.Open, FileAccess.Read, FileShare.Read, options); long fileLength = 0L; - if (sfh.CanSeek && (fileLength = RandomAccess.GetFileLength(sfh)) > Array.MaxLength) + if (sfh.CanSeek && (fileLength = sfh.GetFileLength()) > Array.MaxLength) { sfh.Dispose(); return Task.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException(SR.IO_FileTooLong2GB))); diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs index d922e89c13de5..d9739e3082dfd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs @@ -19,13 +19,6 @@ public static partial class RandomAccess // that get stackalloced in the Linux kernel. private const int IovStackThreshold = 8; - internal static long GetFileLength(SafeFileHandle handle) - { - int result = Interop.Sys.FStat(handle, out Interop.Sys.FileStatus status); - FileStreamHelpers.CheckFileCall(result, handle.Path); - return status.Size; - } - internal static unsafe int ReadAtOffset(SafeFileHandle handle, Span buffer, long fileOffset) { fixed (byte* bufPtr = &MemoryMarshal.GetReference(buffer)) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs index 348b0bf4f15a5..4e79f02de4081 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs @@ -18,18 +18,6 @@ public static partial class RandomAccess { private static readonly IOCompletionCallback s_callback = AllocateCallback(); - internal static unsafe long GetFileLength(SafeFileHandle handle) - { - Interop.Kernel32.FILE_STANDARD_INFO info; - - if (!Interop.Kernel32.GetFileInformationByHandleEx(handle, Interop.Kernel32.FileStandardInfo, &info, (uint)sizeof(Interop.Kernel32.FILE_STANDARD_INFO))) - { - throw Win32Marshal.GetExceptionForLastWin32Error(handle.Path); - } - - return info.EndOfFile; - } - internal static unsafe int ReadAtOffset(SafeFileHandle handle, Span buffer, long fileOffset) { if (handle.IsAsync) @@ -53,8 +41,8 @@ internal static unsafe int ReadAtOffset(SafeFileHandle handle, Span buffer // "If lpOverlapped is not NULL, then when a synchronous read operation reaches the end of a file, // ReadFile returns FALSE and GetLastError returns ERROR_HANDLE_EOF" return numBytesRead; - case Interop.Errors.ERROR_BROKEN_PIPE: - // For pipes, ERROR_BROKEN_PIPE is the normal end of the pipe. + case Interop.Errors.ERROR_BROKEN_PIPE: // For pipes, ERROR_BROKEN_PIPE is the normal end of the pipe. + case Interop.Errors.ERROR_INVALID_PARAMETER when IsEndOfFileForNoBuffering(handle, fileOffset): return 0; default: throw Win32Marshal.GetExceptionForWin32Error(errorCode, handle.Path); @@ -100,6 +88,7 @@ private static unsafe int ReadSyncUsingAsyncHandle(SafeFileHandle handle, Span fileHandle.IsNoBuffering && fileHandle.CanSeek && fileOffset >= fileHandle.GetFileLength(); + // We need to store the reference count (see the comment in FreeNativeOverlappedIfItIsSafe) and an EventHandle to signal the completion. // We could keep these two things separate, but since ManualResetEvent is sealed and we want to avoid any extra allocations, this type has been created. // It's basically ManualResetEvent with reference count. diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.cs index 04b59ae472a76..5c4ede7ff408b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO.Strategies; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.Win32.SafeHandles; @@ -25,7 +24,7 @@ public static long GetLength(SafeFileHandle handle) { ValidateInput(handle, fileOffset: 0); - return GetFileLength(handle); + return handle.GetFileLength(); } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs index 0386dfa78d563..662945c0941e9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using System.Threading.Tasks.Sources; using Microsoft.Win32.SafeHandles; namespace System.IO.Strategies @@ -16,9 +15,7 @@ internal abstract class OSFileStreamStrategy : FileStreamStrategy private readonly FileAccess _access; // What file was opened for. protected long _filePosition; - private long _length = -1; // negative means that hasn't been fetched. private long _appendStart; // When appending, prevent overwriting file. - private bool _lengthCanBeCached; // SafeFileHandle hasn't been exposed, file has been opened for reading and not shared for writing. internal OSFileStreamStrategy(SafeFileHandle handle, FileAccess access) { @@ -45,7 +42,6 @@ internal OSFileStreamStrategy(string path, FileMode mode, FileAccess access, Fil string fullPath = Path.GetFullPath(path); _access = access; - _lengthCanBeCached = (share & FileShare.Write) == 0 && (access & FileAccess.Write) == 0; _fileHandle = SafeFileHandle.Open(fullPath, mode, access, share, options, preallocationSize); @@ -78,34 +74,13 @@ internal OSFileStreamStrategy(string path, FileMode mode, FileAccess access, Fil public sealed override bool CanWrite => !_fileHandle.IsClosed && (_access & FileAccess.Write) != 0; - public unsafe sealed override long Length - { - get - { - if (!LengthCachingSupported) - { - return RandomAccess.GetFileLength(_fileHandle); - } - - // On Windows, when the file is locked for writes we can cache file length - // in memory and avoid subsequent native calls which are expensive. - - if (_length < 0) - { - _length = RandomAccess.GetFileLength(_fileHandle); - } - - return _length; - } - } + public unsafe sealed override long Length => _fileHandle.GetFileLength(); // in case of concurrent incomplete reads, there can be multiple threads trying to update the position // at the same time. That is why we are using Interlocked here. internal void OnIncompleteOperation(int expectedBytesTransferred, int actualBytesTransferred) => Interlocked.Add(ref _filePosition, actualBytesTransferred - expectedBytesTransferred); - private bool LengthCachingSupported => OperatingSystem.IsWindows() && _lengthCanBeCached; - /// Gets or sets the position within the current stream public sealed override long Position { @@ -129,9 +104,6 @@ internal sealed override SafeFileHandle SafeFileHandle FileStreamHelpers.Seek(_fileHandle, _filePosition, SeekOrigin.Begin); } - _lengthCanBeCached = false; - _length = -1; // invalidate cached length - return _fileHandle; } } @@ -224,10 +196,7 @@ protected unsafe void SetLengthCore(long value) Debug.Assert(value >= 0, "value >= 0"); FileStreamHelpers.SetFileLength(_fileHandle, value); - if (LengthCachingSupported) - { - _length = value; - } + Debug.Assert(!_fileHandle.LengthCanBeCached, "If length can be cached (file opened for reading, not shared for writing), it should be impossible to modify file length"); if (_filePosition > value) { @@ -314,7 +283,7 @@ public sealed override ValueTask ReadAsync(Memory destination, Cancel return RandomAccess.ReadAtOffsetAsync(_fileHandle, destination, fileOffset: -1, cancellationToken); } - if (LengthCachingSupported && _length >= 0 && Volatile.Read(ref _filePosition) >= _length) + if (_fileHandle.HasCachedFileLength && Volatile.Read(ref _filePosition) >= _fileHandle.GetFileLength()) { // We know for sure that the file length can be safely cached and it has already been obtained. // If we have reached EOF we just return here and avoid a sys-call. From a354bb152f4e505d53034c3538f971ad4c2f18ac Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 19 Jan 2022 04:10:27 -0500 Subject: [PATCH 043/308] Address follow-up feedback to CachedCompletedInt32Task (#63968) --- .../Tasks/CachedCompletedInt32Task.cs | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/CachedCompletedInt32Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/CachedCompletedInt32Task.cs index 911c2676b4531..080253a37dc5a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/CachedCompletedInt32Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/CachedCompletedInt32Task.cs @@ -15,29 +15,22 @@ internal struct CachedCompletedInt32Task { private Task? _task; - /// - /// Gets a completed whose result is . - /// - /// - /// This method will try to return an already cached task if available. - /// - /// The task's result. + /// Gets a completed whose result is . + /// This method will try to return an already cached task if available. + /// The result value for which a is needed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Task GetTask(int result) { - Task? task; -#pragma warning disable CA1849 // Call async methods when in an async method - if ((task = _task) is not null && task.Result == result) -#pragma warning restore CA1849 // Call async methods when in an async method + if (_task is Task task) { - Debug.Assert(task.IsCompletedSuccessfully, - "Expected that a stored last task completed successfully"); - return task; - } - else - { - return _task = Task.FromResult(result); + Debug.Assert(task.IsCompletedSuccessfully, "Expected that a stored last task completed successfully"); + if (task.Result == result) + { + return task; + } } + + return _task = Task.FromResult(result); } } } From 313baef638104ed64f93e077c84547421884c91b Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 19 Jan 2022 13:16:28 +0300 Subject: [PATCH 044/308] JIT: Fix repeatable failure for max CALLSITE_DEPTH (#63966) --- src/coreclr/jit/fginline.cpp | 4 +++- .../JitBlue/Runtime_63942/Runtime_63942.cs | 13 ++++++++++++ .../Runtime_63942/Runtime_63942.csproj | 21 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_63942/Runtime_63942.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_63942/Runtime_63942.csproj diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index aaf40cefbfd13..53566eb17de7b 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -47,7 +47,9 @@ unsigned Compiler::fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo) // This inline candidate has the same IL code buffer as an already // inlined method does. inlineResult->NoteFatal(InlineObservation::CALLSITE_IS_RECURSIVE); - break; + + // No need to note CALLSITE_DEPTH we're already rejecting this candidate + return depth; } if (depth > InlineStrategy::IMPLEMENTATION_MAX_INLINE_DEPTH) diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_63942/Runtime_63942.cs b/src/tests/JIT/Regression/JitBlue/Runtime_63942/Runtime_63942.cs new file mode 100644 index 0000000000000..a4abd8fd4bf63 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_63942/Runtime_63942.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. + +// Found by Antigen + +public class Runtime_63942 +{ + public static int Main() + { + var _ = 3.14.ToString(); + return 100; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_63942/Runtime_63942.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_63942/Runtime_63942.csproj new file mode 100644 index 0000000000000..9756f0815d4d6 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_63942/Runtime_63942.csproj @@ -0,0 +1,21 @@ + + + Exe + True + + + + + + + \ No newline at end of file From eeaee44e6fe4425db044967e025255e6a12c97a9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 19 Jan 2022 11:20:02 +0100 Subject: [PATCH 045/308] [main] Update dependencies from dotnet/runtime dotnet/arcade dotnet/xharness dotnet/icu dotnet/roslyn-analyzers dotnet/llvm-project (#63737) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dotnet-maestro[bot] Co-authored-by: Alexander Köplinger --- .config/dotnet-tools.json | 2 +- eng/Version.Details.xml | 160 +++--- eng/Versions.props | 70 +-- eng/common/cross/toolchain.cmake | 11 +- eng/common/post-build/publish-using-darc.ps1 | 28 +- .../channels/generic-internal-channel.yml | 190 ------- .../channels/generic-public-channel.yml | 192 ------- .../templates/post-build/post-build.yml | 538 ++++-------------- eng/common/templates/steps/source-build.yml | 2 +- global.json | 10 +- 10 files changed, 240 insertions(+), 963 deletions(-) delete mode 100644 eng/common/templates/post-build/channels/generic-internal-channel.yml delete mode 100644 eng/common/templates/post-build/channels/generic-public-channel.yml diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 015825df43d7a..0e5219042b700 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "1.0.0-prerelease.22062.1", + "version": "1.0.0-prerelease.22067.1", "commands": [ "xharness" ] diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f2f65abdb43a3..a8d298b5be9c8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/icu - aae7d341a8ee7841ed0cb1cf298ab17fe04c187b + 4170ccfbbcada3e22aa4428a84524fabef006e38 https://github.com/dotnet/msquic @@ -50,77 +50,77 @@ - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 https://github.com/microsoft/vstest @@ -170,89 +170,89 @@ https://github.com/dotnet/runtime-assets a597df23119faf540d95cebab14b82f084c47384 - + https://github.com/dotnet/llvm-project - 662aff66999c435aec09c58643e9fd703eadc3e0 + 79a6d232058e2c2f1d9e833355b72f07fe342a3b - + https://github.com/dotnet/llvm-project - 662aff66999c435aec09c58643e9fd703eadc3e0 + 79a6d232058e2c2f1d9e833355b72f07fe342a3b - + https://github.com/dotnet/llvm-project - 662aff66999c435aec09c58643e9fd703eadc3e0 + 79a6d232058e2c2f1d9e833355b72f07fe342a3b - + https://github.com/dotnet/llvm-project - 662aff66999c435aec09c58643e9fd703eadc3e0 + 79a6d232058e2c2f1d9e833355b72f07fe342a3b - + https://github.com/dotnet/llvm-project - 662aff66999c435aec09c58643e9fd703eadc3e0 + 79a6d232058e2c2f1d9e833355b72f07fe342a3b - + https://github.com/dotnet/llvm-project - 662aff66999c435aec09c58643e9fd703eadc3e0 + 79a6d232058e2c2f1d9e833355b72f07fe342a3b - + https://github.com/dotnet/llvm-project - 662aff66999c435aec09c58643e9fd703eadc3e0 + 79a6d232058e2c2f1d9e833355b72f07fe342a3b - + https://github.com/dotnet/llvm-project - 662aff66999c435aec09c58643e9fd703eadc3e0 + 79a6d232058e2c2f1d9e833355b72f07fe342a3b - + https://github.com/dotnet/runtime - a2af6294767b4a3f4c2ce787c5dda2abeeda7a00 + ae2f60c950cc021921fce83c796cbcb5ff96c658 - + https://github.com/dotnet/runtime - a2af6294767b4a3f4c2ce787c5dda2abeeda7a00 + ae2f60c950cc021921fce83c796cbcb5ff96c658 - + https://github.com/dotnet/runtime - a2af6294767b4a3f4c2ce787c5dda2abeeda7a00 + ae2f60c950cc021921fce83c796cbcb5ff96c658 - + https://github.com/dotnet/runtime - a2af6294767b4a3f4c2ce787c5dda2abeeda7a00 + ae2f60c950cc021921fce83c796cbcb5ff96c658 - + https://github.com/dotnet/runtime - a2af6294767b4a3f4c2ce787c5dda2abeeda7a00 + ae2f60c950cc021921fce83c796cbcb5ff96c658 - + https://github.com/dotnet/runtime - a2af6294767b4a3f4c2ce787c5dda2abeeda7a00 + ae2f60c950cc021921fce83c796cbcb5ff96c658 - + https://github.com/dotnet/runtime - a2af6294767b4a3f4c2ce787c5dda2abeeda7a00 + ae2f60c950cc021921fce83c796cbcb5ff96c658 - + https://github.com/dotnet/runtime - a2af6294767b4a3f4c2ce787c5dda2abeeda7a00 + ae2f60c950cc021921fce83c796cbcb5ff96c658 https://github.com/dotnet/linker e485816b48273d03bd6266a64dad9bea97f861d5 - + https://github.com/dotnet/xharness - d33e67a6c2cc5fe415917c6f9bd17046a929dcc0 + 3060cda4543b80824a9238bcd176bb1a5af72044 - + https://github.com/dotnet/xharness - d33e67a6c2cc5fe415917c6f9bd17046a929dcc0 + 3060cda4543b80824a9238bcd176bb1a5af72044 - + https://github.com/dotnet/xharness - d33e67a6c2cc5fe415917c6f9bd17046a929dcc0 + 3060cda4543b80824a9238bcd176bb1a5af72044 - + https://github.com/dotnet/arcade - 34bc5b1611e13bd0ee6a9f38ab8524d2ee489be5 + 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -278,9 +278,9 @@ https://github.com/dotnet/runtime-assets a597df23119faf540d95cebab14b82f084c47384 - + https://github.com/dotnet/roslyn-analyzers - e101c379c6e3c7011562ee3af3e3de066da0048f + 6c43d213c426cf64c78eb1e9e38e4b9ec6454181 https://github.com/dotnet/sdk diff --git a/eng/Versions.props b/eng/Versions.props index ceff6ee674bc4..b0db712120a28 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -50,34 +50,34 @@ 3.3.2 4.0.1 4.0.1 - 7.0.0-preview1.21613.1 + 7.0.0-preview1.22067.1 2.0.0-alpha.1.21525.11 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 2.5.1-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 - 7.0.0-beta.22056.6 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 2.5.1-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 + 7.0.0-beta.22068.3 6.0.0-preview.1.102 - 7.0.0-alpha.1.22059.2 - 7.0.0-alpha.1.22059.2 - 7.0.0-alpha.1.22059.2 + 7.0.0-alpha.1.22066.4 + 7.0.0-alpha.1.22066.4 + 7.0.0-alpha.1.22066.4 3.1.0 - 7.0.0-alpha.1.22059.2 + 7.0.0-alpha.1.22066.4 1.0.0-alpha.1.22060.1 1.0.0-alpha.1.22060.1 1.0.0-alpha.1.22060.1 @@ -120,11 +120,11 @@ 5.0.0 5.0.0 4.9.0-rc2.21473.1 - 7.0.0-alpha.1.22059.2 - 7.0.0-alpha.1.22059.2 + 7.0.0-alpha.1.22066.4 + 7.0.0-alpha.1.22066.4 4.5.4 4.5.0 - 7.0.0-alpha.1.22059.2 + 7.0.0-alpha.1.22066.4 7.0.0-beta.22060.1 7.0.0-beta.22060.1 @@ -160,9 +160,9 @@ 1.0.1-prerelease-00006 16.9.0-preview-20201201-01 - 1.0.0-prerelease.22062.1 - 1.0.0-prerelease.22062.1 - 1.0.0-prerelease.22062.1 + 1.0.0-prerelease.22067.1 + 1.0.0-prerelease.22067.1 + 1.0.0-prerelease.22067.1 1.0.2-alpha.0.22060.2 2.4.2-pre.9 2.4.2 @@ -179,18 +179,18 @@ 7.0.100-1.22063.2 $(MicrosoftNETILLinkTasksVersion) - 7.0.0-alpha.1.22060.1 + 7.0.0-alpha.1.22067.1 7.0.0-alpha.1.21529.3 - 11.1.0-alpha.1.21615.1 - 11.1.0-alpha.1.21615.1 - 11.1.0-alpha.1.21615.1 - 11.1.0-alpha.1.21615.1 - 11.1.0-alpha.1.21615.1 - 11.1.0-alpha.1.21615.1 - 11.1.0-alpha.1.21615.1 - 11.1.0-alpha.1.21615.1 + 11.1.0-alpha.1.22067.2 + 11.1.0-alpha.1.22067.2 + 11.1.0-alpha.1.22067.2 + 11.1.0-alpha.1.22067.2 + 11.1.0-alpha.1.22067.2 + 11.1.0-alpha.1.22067.2 + 11.1.0-alpha.1.22067.2 + 11.1.0-alpha.1.22067.2 7.0.0-alpha.1.21601.1 $(MicrosoftNETWorkloadEmscriptenManifest70100Version) diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index f7878dddd3921..fba2afda438b6 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -37,6 +37,13 @@ elseif(TARGET_ARCH_NAME STREQUAL "arm") if(TIZEN) set(TIZEN_TOOLCHAIN "armv7hl-tizen-linux-gnueabihf/9.2.0") endif() +elseif(TARGET_ARCH_NAME STREQUAL "armv6") + set(CMAKE_SYSTEM_PROCESSOR armv6l) + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf) + set(TOOLCHAIN "armv6-alpine-linux-musleabihf") + else() + set(TOOLCHAIN "arm-linux-gnueabihf") + endif() elseif(TARGET_ARCH_NAME STREQUAL "arm64") set(CMAKE_SYSTEM_PROCESSOR aarch64) if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-alpine-linux-musl) @@ -60,7 +67,7 @@ elseif (ILLUMOS) set(CMAKE_SYSTEM_PROCESSOR "x86_64") set(TOOLCHAIN "x86_64-illumos") else() - message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, arm64, s390x and x86 are supported!") + message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, armv6, arm64, s390x and x86 are supported!") endif() if(DEFINED ENV{TOOLCHAIN}) @@ -194,7 +201,7 @@ endif() # Specify compile options -if((TARGET_ARCH_NAME MATCHES "^(arm|armel|arm64|s390x)$" AND NOT ANDROID) OR ILLUMOS) +if((TARGET_ARCH_NAME MATCHES "^(arm|armv6|armel|arm64|s390x)$" AND NOT ANDROID) OR ILLUMOS) set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN}) diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1 index 2427ca6b6aec7..8508397d77640 100644 --- a/eng/common/post-build/publish-using-darc.ps1 +++ b/eng/common/post-build/publish-using-darc.ps1 @@ -5,13 +5,8 @@ param( [Parameter(Mandatory=$true)][string] $MaestroToken, [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com', [Parameter(Mandatory=$true)][string] $WaitPublishingFinish, - [Parameter(Mandatory=$false)][string] $EnableSourceLinkValidation, - [Parameter(Mandatory=$false)][string] $EnableSigningValidation, - [Parameter(Mandatory=$false)][string] $EnableNugetValidation, - [Parameter(Mandatory=$false)][string] $PublishInstallersAndChecksums, [Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters, - [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters, - [Parameter(Mandatory=$false)][string] $SigningValidationAdditionalParameters + [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters ) try { @@ -35,27 +30,6 @@ try { $optionalParams.Add("--no-wait") | Out-Null } - if ("false" -ne $PublishInstallersAndChecksums) { - $optionalParams.Add("--publish-installers-and-checksums") | Out-Null - } - - if ("true" -eq $EnableNugetValidation) { - $optionalParams.Add("--validate-nuget") | Out-Null - } - - if ("true" -eq $EnableSourceLinkValidation) { - $optionalParams.Add("--validate-sourcelinkchecksums") | Out-Null - } - - if ("true" -eq $EnableSigningValidation) { - $optionalParams.Add("--validate-signingchecksums") | Out-Null - - if ("" -ne $SigningValidationAdditionalParameters) { - $optionalParams.Add("--signing-validation-parameters") | Out-Null - $optionalParams.Add($SigningValidationAdditionalParameters) | Out-Null - } - } - & $darc add-build-to-channel ` --id $buildId ` --publishing-infra-version $PublishingInfraVersion ` diff --git a/eng/common/templates/post-build/channels/generic-internal-channel.yml b/eng/common/templates/post-build/channels/generic-internal-channel.yml deleted file mode 100644 index 8990dfc8c87cc..0000000000000 --- a/eng/common/templates/post-build/channels/generic-internal-channel.yml +++ /dev/null @@ -1,190 +0,0 @@ -parameters: - BARBuildId: '' - PromoteToChannelIds: '' - artifactsPublishingAdditionalParameters: '' - dependsOn: - - Validate - publishInstallersAndChecksums: true - symbolPublishingAdditionalParameters: '' - stageName: '' - channelName: '' - channelId: '' - transportFeed: '' - shippingFeed: '' - symbolsFeed: '' - -stages: -- stage: ${{ parameters.stageName }} - dependsOn: ${{ parameters.dependsOn }} - variables: - - template: ../common-variables.yml - displayName: ${{ parameters.channelName }} Publishing - jobs: - - template: ../setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - job: publish_symbols - displayName: Symbol Publishing - dependsOn: setupMaestroVars - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) - variables: - - group: DotNet-Symbol-Server-Pats - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - pool: - vmImage: 'windows-2019' - steps: - - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." - displayName: Warn about v2 Arcade Publishing Usage - - # This is necessary whenever we want to publish/restore to an AzDO private feed - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: DownloadBuildArtifacts@0 - displayName: Download Build Assets - continueOnError: true - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: 'specific' - itemPattern: | - PdbArtifacts/** - BlobArtifacts/** - downloadPath: '$(Build.ArtifactStagingDirectory)' - checkDownloadedFiles: true - - # This is necessary whenever we want to publish/restore to an AzDO private feed - # Since sdk-task.ps1 tries to restore packages we need to do this authentication here - # otherwise it'll complain about accessing a private feed. - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: PowerShell@2 - displayName: Enable cross-org publishing - inputs: - filePath: eng\common\enable-cross-org-publishing.ps1 - arguments: -token $(dn-bot-dnceng-artifact-feeds-rw) - - - task: PowerShell@2 - displayName: Publish - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet - /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat) - /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat) - /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/' - /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' - /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' - /p:Configuration=Release - /p:PublishToMSDL=false - ${{ parameters.symbolPublishingAdditionalParameters }} - - - template: ../../steps/publish-logs.yml - parameters: - StageLabel: '${{ parameters.stageName }}' - JobLabel: 'SymbolPublishing' - - - job: publish_assets - displayName: Publish Assets - dependsOn: setupMaestroVars - timeoutInMinutes: 120 - variables: - - name: BARBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - - name: IsStableBuild - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ] - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) - pool: - vmImage: 'windows-2019' - steps: - - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." - displayName: Warn about v2 Arcade Publishing Usage - - - task: DownloadBuildArtifacts@0 - displayName: Download Build Assets - continueOnError: true - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: 'specific' - itemPattern: | - PackageArtifacts/** - BlobArtifacts/** - AssetManifests/** - downloadPath: '$(Build.ArtifactStagingDirectory)' - checkDownloadedFiles: true - - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - - # This is necessary whenever we want to publish/restore to an AzDO private feed - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: PowerShell@2 - displayName: Enable cross-org publishing - inputs: - filePath: eng\common\enable-cross-org-publishing.ps1 - arguments: -token $(dn-bot-dnceng-artifact-feeds-rw) - - - task: PowerShell@2 - displayName: Publish Assets - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet - /p:PublishingInfraVersion=2 - /p:IsStableBuild=$(IsStableBuild) - /p:IsInternalBuild=$(IsInternalBuild) - /p:RepositoryName=$(Build.Repository.Name) - /p:CommitSha=$(Build.SourceVersion) - /p:NugetPath=$(NuGetExeToolPath) - /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-universal-packages-rw)' - /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' - /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' - /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' - /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' - /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' - /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/' - /p:Configuration=Release - /p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }} - /p:ChecksumsTargetStaticFeed=$(InternalChecksumsBlobFeedUrl) - /p:ChecksumsAzureAccountKey=$(InternalChecksumsBlobFeedKey) - /p:InstallersTargetStaticFeed=$(InternalInstallersBlobFeedUrl) - /p:InstallersAzureAccountKey=$(InternalInstallersBlobFeedKey) - /p:AzureDevOpsStaticShippingFeed='${{ parameters.shippingFeed }}' - /p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:AzureDevOpsStaticTransportFeed='${{ parameters.transportFeed }}' - /p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:AzureDevOpsStaticSymbolsFeed='${{ parameters.symbolsFeed }}' - /p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:PublishToMSDL=false - ${{ parameters.artifactsPublishingAdditionalParameters }} - - - template: ../../steps/publish-logs.yml - parameters: - StageLabel: '${{ parameters.stageName }}' - JobLabel: 'AssetsPublishing' - - - template: ../../steps/add-build-to-channel.yml - parameters: - ChannelId: ${{ parameters.channelId }} diff --git a/eng/common/templates/post-build/channels/generic-public-channel.yml b/eng/common/templates/post-build/channels/generic-public-channel.yml deleted file mode 100644 index 3220c6a4f92ff..0000000000000 --- a/eng/common/templates/post-build/channels/generic-public-channel.yml +++ /dev/null @@ -1,192 +0,0 @@ -parameters: - BARBuildId: '' - PromoteToChannelIds: '' - artifactsPublishingAdditionalParameters: '' - dependsOn: - - Validate - publishInstallersAndChecksums: true - symbolPublishingAdditionalParameters: '' - stageName: '' - channelName: '' - channelId: '' - transportFeed: '' - shippingFeed: '' - symbolsFeed: '' - # If the channel name is empty, no links will be generated - akaMSChannelName: '' - -stages: -- stage: ${{ parameters.stageName }} - dependsOn: ${{ parameters.dependsOn }} - variables: - - template: ../common-variables.yml - displayName: ${{ parameters.channelName }} Publishing - jobs: - - template: ../setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - job: publish_symbols - displayName: Symbol Publishing - dependsOn: setupMaestroVars - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) - variables: - - group: DotNet-Symbol-Server-Pats - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - pool: - vmImage: 'windows-2019' - steps: - - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." - displayName: Warn about v2 Arcade Publishing Usage - - - task: DownloadBuildArtifacts@0 - displayName: Download Build Assets - continueOnError: true - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: 'specific' - itemPattern: | - PdbArtifacts/** - BlobArtifacts/** - downloadPath: '$(Build.ArtifactStagingDirectory)' - checkDownloadedFiles: true - - # This is necessary whenever we want to publish/restore to an AzDO private feed - # Since sdk-task.ps1 tries to restore packages we need to do this authentication here - # otherwise it'll complain about accessing a private feed. - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: PowerShell@2 - displayName: Enable cross-org publishing - inputs: - filePath: eng\common\enable-cross-org-publishing.ps1 - arguments: -token $(dn-bot-dnceng-artifact-feeds-rw) - - - task: PowerShell@2 - displayName: Publish - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet - /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat) - /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat) - /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/' - /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' - /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' - /p:Configuration=Release - ${{ parameters.symbolPublishingAdditionalParameters }} - - - template: ../../steps/publish-logs.yml - parameters: - StageLabel: '${{ parameters.stageName }}' - JobLabel: 'SymbolPublishing' - - - job: publish_assets - displayName: Publish Assets - dependsOn: setupMaestroVars - timeoutInMinutes: 120 - variables: - - name: BARBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - - name: IsStableBuild - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ] - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - - name: ArtifactsCategory - value: ${{ coalesce(variables._DotNetArtifactsCategory, '.NETCore') }} - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) - pool: - vmImage: 'windows-2019' - steps: - - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." - displayName: Warn about v2 Arcade Publishing Usage - - - task: DownloadBuildArtifacts@0 - displayName: Download Build Assets - continueOnError: true - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: 'specific' - itemPattern: | - PackageArtifacts/** - BlobArtifacts/** - AssetManifests/** - downloadPath: '$(Build.ArtifactStagingDirectory)' - checkDownloadedFiles: true - - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - - # This is necessary whenever we want to publish/restore to an AzDO private feed - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: PowerShell@2 - displayName: Enable cross-org publishing - inputs: - filePath: eng\common\enable-cross-org-publishing.ps1 - arguments: -token $(dn-bot-dnceng-artifact-feeds-rw) - - - task: PowerShell@2 - displayName: Publish Assets - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet - /p:PublishingInfraVersion=2 - /p:ArtifactsCategory=$(ArtifactsCategory) - /p:IsStableBuild=$(IsStableBuild) - /p:IsInternalBuild=$(IsInternalBuild) - /p:RepositoryName=$(Build.Repository.Name) - /p:CommitSha=$(Build.SourceVersion) - /p:NugetPath=$(NuGetExeToolPath) - /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-universal-packages-rw)' - /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' - /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' - /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' - /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' - /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' - /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/' - /p:Configuration=Release - /p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }} - /p:InstallersTargetStaticFeed=$(InstallersBlobFeedUrl) - /p:InstallersAzureAccountKey=$(dotnetcli-storage-key) - /p:ChecksumsTargetStaticFeed=$(ChecksumsBlobFeedUrl) - /p:ChecksumsAzureAccountKey=$(dotnetclichecksums-storage-key) - /p:AzureDevOpsStaticShippingFeed='${{ parameters.shippingFeed }}' - /p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:AzureDevOpsStaticTransportFeed='${{ parameters.transportFeed }}' - /p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:AzureDevOpsStaticSymbolsFeed='${{ parameters.symbolsFeed }}' - /p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:LatestLinkShortUrlPrefix=dotnet/'${{ parameters.akaMSChannelName }}' - /p:AkaMSClientId=$(akams-client-id) - /p:AkaMSClientSecret=$(akams-client-secret) - ${{ parameters.artifactsPublishingAdditionalParameters }} - - - template: ../../steps/publish-logs.yml - parameters: - StageLabel: '${{ parameters.stageName }}' - JobLabel: 'AssetsPublishing' - - - template: ../../steps/add-build-to-channel.yml - parameters: - ChannelId: ${{ parameters.channelId }} diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index 4f79cf0f33703..8985b429c8543 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -1,71 +1,89 @@ parameters: - # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST. - # Publishing V2 accepts optionally outlining the publishing stages - default is inline. - # Publishing V3 DOES NOT accept inlining the publishing stages. - publishingInfraVersion: 2 - # When set to true the publishing templates from the repo will be used - # otherwise Darc add-build-to-channel will be used to trigger the promotion pipeline - inline: true - - # Only used if inline==false. When set to true will stall the current build until - # the Promotion Pipeline build finishes. Otherwise, the current build will continue - # execution concurrently with the promotion build. - waitPublishingFinish: true - - BARBuildId: '' - PromoteToChannelIds: '' - - enableSourceLinkValidation: false - enableSigningValidation: true - enableSymbolValidation: false - enableNugetValidation: true - publishInstallersAndChecksums: true - SDLValidationParameters: - enable: false - continueOnError: false - params: '' - artifactNames: '' - downloadArtifacts: true + # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST. + # Publishing V1 is no longer supported + # Publishing V2 is no longer supported + # Publishing V3 is the default + - name: publishingInfraVersion + displayName: Which version of publishing should be used to promote the build definition? + type: number + default: 3 + values: + - 3 + + - name: BARBuildId + displayName: BAR Build Id + type: number + default: 0 + + - name: PromoteToChannelIds + displayName: Channel to promote BARBuildId to + type: string + default: '' + + - name: enableSourceLinkValidation + displayName: Enable SourceLink validation + type: boolean + default: false + + - name: enableSigningValidation + displayName: Enable signing validation + type: boolean + default: true + + - name: enableSymbolValidation + displayName: Enable symbol validation + type: boolean + default: false + + - name: enableNugetValidation + displayName: Enable NuGet validation + type: boolean + default: true + + - name: publishInstallersAndChecksums + displayName: Publish installers and checksums + type: boolean + default: true + + - name: SDLValidationParameters + type: object + default: + enable: false + continueOnError: false + params: '' + artifactNames: '' + downloadArtifacts: true # These parameters let the user customize the call to sdk-task.ps1 for publishing # symbols & general artifacts as well as for signing validation - symbolPublishingAdditionalParameters: '' - artifactsPublishingAdditionalParameters: '' - signingValidationAdditionalParameters: '' + - name: symbolPublishingAdditionalParameters + displayName: Symbol publishing additional parameters + type: string + default: '' + + - name: artifactsPublishingAdditionalParameters + displayName: Artifact publishing additional parameters + type: string + default: '' + + - name: signingValidationAdditionalParameters + displayName: Signing validation additional parameters + type: string + default: '' # Which stages should finish execution before post-build stages start - validateDependsOn: - - build - publishDependsOn: - - Validate + - name: validateDependsOn + type: object + default: + - build - # Channel ID's instantiated in this file. - # When adding a new channel implementation the call to `check-channel-consistency.ps1` - # needs to be updated with the new channel ID - NetEngLatestChannelId: 2 - NetEngValidationChannelId: 9 - NetDev5ChannelId: 131 - NetDev6ChannelId: 1296 - GeneralTestingChannelId: 529 - NETCoreToolingDevChannelId: 548 - NETCoreToolingReleaseChannelId: 549 - NETInternalToolingChannelId: 551 - NETCoreExperimentalChannelId: 562 - NetEngServicesIntChannelId: 678 - NetEngServicesProdChannelId: 679 - NetCoreSDK313xxChannelId: 759 - NetCoreSDK313xxInternalChannelId: 760 - NetCoreSDK314xxChannelId: 921 - NetCoreSDK314xxInternalChannelId: 922 - VS166ChannelId: 1010 - VS167ChannelId: 1011 - VS168ChannelId: 1154 - VSMasterChannelId: 1012 - VS169ChannelId: 1473 - VS1610ChannelId: 1692 + - name: publishDependsOn + type: object + default: + - Validate stages: -- ${{ if or(and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')), eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: +- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - stage: Validate dependsOn: ${{ parameters.validateDependsOn }} displayName: Validate Build Assets @@ -77,23 +95,6 @@ stages: BARBuildId: ${{ parameters.BARBuildId }} PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - ${{ if and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')) }}: - - job: - displayName: Post-build Checks - dependsOn: setupMaestroVars - variables: - - name: TargetChannels - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'] ] - pool: - vmImage: 'windows-2019' - steps: - - task: PowerShell@2 - displayName: Maestro Channels Consistency - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/check-channel-consistency.ps1 - arguments: -PromoteToChannels "$(TargetChannels)" - -AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.NetDev6ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.NetCoreSDK313xxChannelId}},${{parameters.NetCoreSDK313xxInternalChannelId}},${{parameters.NetCoreSDK314xxChannelId}},${{parameters.NetCoreSDK314xxInternalChannelId}},${{parameters.VS166ChannelId}},${{parameters.VS167ChannelId}},${{parameters.VS168ChannelId}},${{parameters.VSMasterChannelId}},${{parameters.VS169ChannelId}},${{parameters.VS1610ChannelId}} - - job: displayName: NuGet Validation dependsOn: setupMaestroVars @@ -229,361 +230,38 @@ stages: artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }} downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }} -- ${{ if or(ge(parameters.publishingInfraVersion, 3), eq(parameters.inline, 'false')) }}: - - stage: publish_using_darc - ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - dependsOn: ${{ parameters.publishDependsOn }} - ${{ if and(ne(parameters.enableNugetValidation, 'true'), ne(parameters.enableSigningValidation, 'true'), ne(parameters.enableSourceLinkValidation, 'true'), ne(parameters.SDLValidationParameters.enable, 'true')) }}: - dependsOn: ${{ parameters.validateDependsOn }} - displayName: Publish using Darc - variables: - - template: common-variables.yml - jobs: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - job: - displayName: Publish Using Darc - dependsOn: setupMaestroVars - timeoutInMinutes: 120 - variables: - - name: BARBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - pool: - vmImage: 'windows-2019' - steps: - - task: PowerShell@2 - displayName: Publish Using Darc - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) - -PublishingInfraVersion ${{ parameters.PublishingInfraVersion }} - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' - -WaitPublishingFinish ${{ parameters.waitPublishingFinish }} - -PublishInstallersAndChecksums ${{ parameters.publishInstallersAndChecksums }} - -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' - -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' - -- ${{ if and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')) }}: - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NetCore_Dev5_Publish' - channelName: '.NET 5 Dev' - akaMSChannelName: 'net5/dev' - channelId: ${{ parameters.NetDev5ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NetCore_Dev6_Publish' - channelName: '.NET 6 Dev' - akaMSChannelName: 'net6/dev' - channelId: ${{ parameters.NetDev6ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml +- stage: publish_using_darc + ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: + dependsOn: ${{ parameters.publishDependsOn }} + ${{ if and(ne(parameters.enableNugetValidation, 'true'), ne(parameters.enableSigningValidation, 'true'), ne(parameters.enableSourceLinkValidation, 'true'), ne(parameters.SDLValidationParameters.enable, 'true')) }}: + dependsOn: ${{ parameters.validateDependsOn }} + displayName: Publish using Darc + variables: + - template: common-variables.yml + jobs: + - template: setup-maestro-vars.yml parameters: BARBuildId: ${{ parameters.BARBuildId }} PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net_Eng_Latest_Publish' - channelName: '.NET Eng - Latest' - akaMSChannelName: 'eng/daily' - channelId: ${{ parameters.NetEngLatestChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json' - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net_Eng_Validation_Publish' - channelName: '.NET Eng - Validation' - akaMSChannelName: 'eng/validation' - channelId: ${{ parameters.NetEngValidationChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'General_Testing_Publish' - channelName: 'General Testing' - akaMSChannelName: 'generaltesting' - channelId: ${{ parameters.GeneralTestingChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_Tooling_Dev_Publishing' - channelName: '.NET Core Tooling Dev' - channelId: ${{ parameters.NETCoreToolingDevChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_Tooling_Release_Publishing' - channelName: '.NET Core Tooling Release' - channelId: ${{ parameters.NETCoreToolingReleaseChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NET_Internal_Tooling_Publishing' - channelName: '.NET Internal Tooling' - channelId: ${{ parameters.NETInternalToolingChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_Experimental_Publishing' - channelName: '.NET Core Experimental' - channelId: ${{ parameters.NETCoreExperimentalChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net_Eng_Services_Int_Publish' - channelName: '.NET Eng Services - Int' - channelId: ${{ parameters.NetEngServicesIntChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net_Eng_Services_Prod_Publish' - channelName: '.NET Eng Services - Prod' - channelId: ${{ parameters.NetEngServicesProdChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_SDK_314xx_Publishing' - channelName: '.NET Core SDK 3.1.4xx' - channelId: ${{ parameters.NetCoreSDK314xxChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_SDK_314xx_Internal_Publishing' - channelName: '.NET Core SDK 3.1.4xx Internal' - channelId: ${{ parameters.NetCoreSDK314xxInternalChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_SDK_313xx_Publishing' - channelName: '.NET Core SDK 3.1.3xx' - channelId: ${{ parameters.NetCoreSDK313xxChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_SDK_313xx_Internal_Publishing' - channelName: '.NET Core SDK 3.1.3xx Internal' - channelId: ${{ parameters.NetCoreSDK313xxInternalChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS16_6_Publishing' - channelName: 'VS 16.6' - channelId: ${{ parameters.VS166ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS16_7_Publishing' - channelName: 'VS 16.7' - channelId: ${{ parameters.VS167ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS16_8_Publishing' - channelName: 'VS 16.8' - channelId: ${{ parameters.VS168ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS_Master_Publishing' - channelName: 'VS Master' - channelId: ${{ parameters.VSMasterChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS_16_9_Publishing' - channelName: 'VS 16.9' - channelId: ${{ parameters.VS169ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS_16_10_Publishing' - channelName: 'VS 16.10' - channelId: ${{ parameters.VS1610ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' + - job: + displayName: Publish Using Darc + dependsOn: setupMaestroVars + timeoutInMinutes: 120 + variables: + - name: BARBuildId + value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] + pool: + vmImage: 'windows-2019' + steps: + - task: PowerShell@2 + displayName: Publish Using Darc + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + arguments: -BuildId $(BARBuildId) + -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} + -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -MaestroToken '$(MaestroApiAccessToken)' + -WaitPublishingFinish true + -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' + -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' \ No newline at end of file diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml index ba40dc82f1411..d85d6d07d5c7b 100644 --- a/eng/common/templates/steps/source-build.yml +++ b/eng/common/templates/steps/source-build.yml @@ -23,7 +23,7 @@ steps: # In addition, add an msbuild argument to copy the WIP from the repo to the target build location. # This is because SetupNuGetSources.sh will alter the current NuGet.config file, and we need to preserve those # changes. - $internalRestoreArgs= + internalRestoreArgs= if [ '$(dn-bot-dnceng-artifact-feeds-rw)' != '$''(dn-bot-dnceng-artifact-feeds-rw)' ]; then # Temporarily work around https://github.com/dotnet/arcade/issues/7709 chmod +x $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh diff --git a/global.json b/global.json index f191cfdd2e352..6e753c749b04a 100644 --- a/global.json +++ b/global.json @@ -12,12 +12,12 @@ "python3": "3.7.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.22056.6", - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22056.6", - "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22056.6", - "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.22056.6", + "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.22068.3", + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22068.3", + "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22068.3", + "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.22068.3", "Microsoft.Build.NoTargets": "3.1.0", "Microsoft.Build.Traversal": "3.0.23", - "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.22059.2" + "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.22066.4" } } From a25536f790258fe68240feff864713e8d20b418c Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 19 Jan 2022 06:52:15 -0500 Subject: [PATCH 046/308] Improve auto-atomicity for Regex loops (#63986) - As part of recognizing loops that could be made atomic, we currently only look at the node guaranteed to come immediately after it, e.g. in a+b+c+, when analyzing a+ we only look at the b+. That's fine in many cases, but if our expression was instead e.g. a*b*c*, we couldn't make a* atomic because we wouldn't be guaranteed it'd be followed by a b, and we wouldn't look at the subsequent nodes to determine what else might follow. When that situation occurs, we can now walk the tree to find the next node, and repeatedly do so as much as is needed in order to find the next node, enabling us to make all of those loops atomic. - We currently perform the auto-atomicity reduction for single-char loops as part of reducing concatenations. But this means we're performing that transformation at a time when the tree isn't fully formed, which means we can't necessarily reach out of a concatenation to what comes after it and use that to influence the atomicity. It also means we might repeat the analysis unnecessarily multiple times, because it's done as part of parenting a node. We can instead do that optimization as part of the final optimization phase, after the tree is already created. - When we find a lazy loop at the end of an expression, we can treat it as atomic, which means we can lower its max bound to its min bound. - When we encounter a loop (lazy or greedy) at the end of an expression, if it has a max bound of 1 (i.e. it's optional), we can proceed to eliminate ending backtracking with its child regardless of whether the child could be made atomic with the start of the loop, since it won't ever repeat more than once. --- .../Text/RegularExpressions/RegexNode.cs | 351 ++++++++++++------ .../tests/Regex.Match.Tests.cs | 12 + .../tests/RegexReductionTests.cs | 26 +- 3 files changed, 268 insertions(+), 121 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index 8f5c0a3039596..2f70cbd778177 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -227,6 +227,12 @@ private void MakeLoopAtomic() // to the minimum number of iterations, as they should end up matching as little as possible. Type += Oneloopatomic - Onelazy; N = M; + if (N == 0) + { + Type = Empty; + Str = null; + Ch = '\0'; + } break; default: @@ -362,8 +368,17 @@ internal RegexNode FinalOptimize() Debug.Assert(rootNode.Next is null); Debug.Assert(rootNode.ChildCount() == 1); - if ((Options & RegexOptions.RightToLeft) == 0) // only apply optimization when LTR to avoid needing additional code for the rarer RTL case + // Only apply optimization when LTR to avoid needing additional code for the much rarer RTL case. + // Also only apply these optimizations when not using NonBacktracking, as these optimizations are + // all about avoiding things that are impactful for the backtracking engines but nops for non-backtracking. + if ((Options & (RegexOptions.RightToLeft | RegexOptions.NonBacktracking)) == 0) { + // Optimization: eliminate backtracking for loops. + // For any single-character loop (Oneloop, Notoneloop, Setloop), see if we can automatically convert + // that into its atomic counterpart (Oneloopatomic, Notoneloopatomic, Setloopatomic) based on what + // comes after it in the expression tree. + rootNode.FindAndMakeLoopsAtomic(); + // Optimization: backtracking removal at expression end. // If we find backtracking construct at the end of the regex, we can instead make it non-backtracking, // since nothing would ever backtrack into it anyway. Doing this then makes the construct available @@ -426,19 +441,14 @@ internal RegexNode FinalOptimize() /// private void EliminateEndingBacktracking() { + Debug.Assert((Options & RegexOptions.NonBacktracking) == 0, "NonBacktracking doesn't have backtracking to be eliminated and doesn't support atomic groups."); + if (!StackHelper.TryEnsureSufficientExecutionStack()) { // If we can't recur further, just stop optimizing. return; } - // RegexOptions.NonBacktracking doesn't support atomic groups, so when that option - // is set we don't want to create atomic groups where they weren't explicitly authored. - if ((Options & RegexOptions.NonBacktracking) != 0) - { - return; - } - // Walk the tree starting from the current node. RegexNode node = this; while (true) @@ -448,12 +458,8 @@ private void EliminateEndingBacktracking() // {One/Notone/Set}loops can be upgraded to {One/Notone/Set}loopatomic nodes, e.g. [abc]* => (?>[abc]*). // And {One/Notone/Set}lazys can similarly be upgraded to be atomic, which really makes them into repeaters // or even empty nodes. - case Oneloop: - case Notoneloop: - case Setloop: - case Onelazy: - case Notonelazy: - case Setlazy: + case Oneloop or Notoneloop or Setloop: + case Onelazy or Notonelazy or Setlazy: node.MakeLoopAtomic(); break; @@ -472,7 +478,7 @@ private void EliminateEndingBacktracking() case Capture: case Concatenate: RegexNode existingChild = node.Child(node.ChildCount() - 1); - if ((existingChild.Type == Alternate || existingChild.Type == Loop || existingChild.Type == Lazyloop) && + if ((existingChild.Type is Alternate or Loop or Lazyloop) && (node.Next is null || node.Next.Type != Atomic)) // validate grandparent isn't atomic { var atomic = new RegexNode(Atomic, existingChild.Options); @@ -495,11 +501,27 @@ private void EliminateEndingBacktracking() node = node.Child(0); continue; - // For Loop, we search to see if there's a viable last expression, and iff there - // is we recur into processing it. + // For {Lazy}Loop, we search to see if there's a viable last expression, and iff there + // is we recur into processing it. Also, as with the single-char lazy loops, LazyLoop + // can have its max iteration count dropped to its min iteration count, as there's no + // reason for it to match more than the minimal at the end; that in turn makes it a + // repeater, which results in better code generation. // e.g. (?:abc*)* => (?:ab(?>c*))* + // e.g. (abc*?)+? => (ab){1} + case Lazyloop: + node.N = node.M; + goto case Loop; case Loop: { + if (node.N == 1) + { + // If the loop has a max iteration count of 1 (e.g. it's an optional node), + // there's no possibility for conflict between multiple iterations, so + // we can process it. + node = node.Child(0); + continue; + } + RegexNode? loopDescendent = node.FindLastExpressionInLoopForAutoAtomic(); if (loopDescendent != null) { @@ -1447,12 +1469,6 @@ private RegexNode ReduceConcatenation() // and also help to reduce catastrophic backtracking. ReduceConcatenationWithAdjacentLoops(); - // Now convert as many loops as possible to be atomic to avoid unnecessary backtracking. - if ((Options & RegexOptions.RightToLeft) == 0) - { - ReduceConcatenationWithAutoAtomic(); - } - // If the concatenation is now empty, return an empty node, or if it's got a single child, return that child. // Otherwise, return this. return ReplaceNodeIfUnnecessary(Empty); @@ -1658,21 +1674,43 @@ static bool CanCombineCounts(int nodeMin, int nodeMax, int nextMin, int nextMax) /// to {one/notone/set}loopatomic nodes. Such changes avoid potential useless backtracking. /// e.g. A*B (where sets A and B don't overlap) => (?>A*)B. /// - private void ReduceConcatenationWithAutoAtomic() + private void FindAndMakeLoopsAtomic() { - // RegexOptions.NonBacktracking doesn't support atomic groups, so when that option - // is set we don't want to create atomic groups where they weren't explicitly authored. - if ((Options & RegexOptions.NonBacktracking) != 0) + Debug.Assert((Options & RegexOptions.NonBacktracking) == 0, "Atomic groups aren't supported and don't help performance with NonBacktracking"); + + if (!StackHelper.TryEnsureSufficientExecutionStack()) { + // If we're too deep on the stack, give up optimizing further. return; } - Debug.Assert(Type == Concatenate); - Debug.Assert((Options & RegexOptions.RightToLeft) == 0); - Debug.Assert(Children is List); + if ((Options & RegexOptions.RightToLeft) != 0) + { + // RTL is so rare, we don't need to spend additional time/code optimizing for it. + return; + } + // For all node types that have children, recur into each of those children. + int childCount = ChildCount(); + if (childCount != 0) + { + for (int i = 0; i < childCount; i++) + { + Child(i).FindAndMakeLoopsAtomic(); + } + } + + // If this isn't a concatenation, nothing more to do. + if (Type is not Concatenate) + { + return; + } + + // This is a concatenation. Iterate through each pair of nodes in the concatenation seeing whether we can + // make the first node (or its right-most child) atomic based on the second node (or its left-most child). + Debug.Assert(Children is List); var children = (List)Children; - for (int i = 0; i < children.Count - 1; i++) + for (int i = 0; i < childCount - 1; i++) { ProcessNode(children[i], children[i + 1]); @@ -1715,9 +1753,9 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) // If the node can be changed to atomic based on what comes after it, do so. switch (node.Type) { - case Oneloop when CanBeMadeAtomic(node, subsequent): - case Notoneloop when CanBeMadeAtomic(node, subsequent): - case Setloop when CanBeMadeAtomic(node, subsequent): + case Oneloop when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: true): + case Notoneloop when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: true): + case Setloop when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: true): node.MakeLoopAtomic(); break; case Alternate: @@ -1749,7 +1787,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) { RegexNode node = this; - Debug.Assert(node.Type == Loop); + Debug.Assert(node.Type is Loop or Lazyloop); // Start by looking at the loop's sole child. node = node.Child(0); @@ -1770,7 +1808,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) { int concatCount = node.ChildCount(); RegexNode lastConcatChild = node.Child(concatCount - 1); - if (CanBeMadeAtomic(lastConcatChild, node.Child(0))) + if (CanBeMadeAtomic(lastConcatChild, node.Child(0), allowSubsequentIteration: false)) { return lastConcatChild; } @@ -1849,7 +1887,7 @@ private RegexNode ReduceTestgroup() /// Determines whether node can be switched to an atomic loop. Subsequent is the node /// immediately after 'node'. /// - private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent) + private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool allowSubsequentIteration) { if (!StackHelper.TryEnsureSufficientExecutionStack()) { @@ -1857,102 +1895,185 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent) return false; } - // Skip the successor down to the closest node that's guaranteed to follow it. - while (subsequent.ChildCount() > 0) + // In most case, we'll simply check the node against whatever subsequent is. However, in case + // subsequent ends up being a loop with a min bound of 0, we'll also need to evaluate the node + // against whatever comes after subsequent. In that case, we'll walk the tree to find the + // next subsequent, and we'll loop around against to perform the comparison again. + while (true) { - Debug.Assert(subsequent.Type != Group); - switch (subsequent.Type) + // Skip the successor down to the closest node that's guaranteed to follow it. + while (subsequent.ChildCount() > 0) { - case Concatenate: - case Capture: - case Atomic: - case Require when (subsequent.Options & RegexOptions.RightToLeft) == 0: // only lookaheads, not lookbehinds (represented as RTL Require nodes) - case Loop or Lazyloop when subsequent.M > 0: - subsequent = subsequent.Child(0); - continue; - } + Debug.Assert(subsequent.Type != Group); + switch (subsequent.Type) + { + case Concatenate: + case Capture: + case Atomic: + case Require when (subsequent.Options & RegexOptions.RightToLeft) == 0: // only lookaheads, not lookbehinds (represented as RTL Require nodes) + case Loop or Lazyloop when subsequent.M > 0: + subsequent = subsequent.Child(0); + continue; + } - break; - } + break; + } - // If the two nodes don't agree on options in any way, don't try to optimize them. - if (node.Options != subsequent.Options) - { - return false; - } + // If the two nodes don't agree on options in any way, don't try to optimize them. + if (node.Options != subsequent.Options) + { + return false; + } - // If the successor is an alternation, all of its children need to be evaluated, since any of them - // could come after this node. If any of them fail the optimization, then the whole node fails. - if (subsequent.Type == Alternate) - { - int childCount = subsequent.ChildCount(); - for (int i = 0; i < childCount; i++) + // If the successor is an alternation, all of its children need to be evaluated, since any of them + // could come after this node. If any of them fail the optimization, then the whole node fails. + if (subsequent.Type == Alternate) { - if (!CanBeMadeAtomic(node, subsequent.Child(i))) + int childCount = subsequent.ChildCount(); + for (int i = 0; i < childCount; i++) { - return false; + if (!CanBeMadeAtomic(node, subsequent.Child(i), allowSubsequentIteration)) + { + return false; + } } + + return true; } - return true; - } + // If this node is a {one/notone/set}loop, see if it overlaps with its successor in the concatenation. + // If it doesn't, then we can upgrade it to being a {one/notone/set}loopatomic. + // Doing so avoids unnecessary backtracking. + switch (node.Type) + { + case Oneloop: + switch (subsequent.Type) + { + case One when node.Ch != subsequent.Ch: + case Notone when node.Ch == subsequent.Ch: + case Set when !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch != subsequent.Ch: + case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: + case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + case Multi when node.Ch != subsequent.Str![0]: + case End: + case EndZ or Eol when node.Ch != '\n': + case Boundary when RegexCharClass.IsBoundaryWordChar(node.Ch): + case NonBoundary when !RegexCharClass.IsBoundaryWordChar(node.Ch): + case ECMABoundary when RegexCharClass.IsECMAWordChar(node.Ch): + case NonECMABoundary when !RegexCharClass.IsECMAWordChar(node.Ch): + return true; + + case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && node.Ch != subsequent.Ch: + case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: + case Setlazy or Setloop or Setloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. + break; - // If this node is a {one/notone/set}loop, see if it overlaps with its successor in the concatenation. - // If it doesn't, then we can upgrade it to being a {one/notone/set}loopatomic. - // Doing so avoids unnecessary backtracking. - switch (node.Type) - { - case Oneloop: - switch (subsequent.Type) - { - case One when node.Ch != subsequent.Ch: - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch != subsequent.Ch: - case Notone when node.Ch == subsequent.Ch: - case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: - case Multi when node.Ch != subsequent.Str![0]: - case Set when !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): - case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): - case End: - case EndZ or Eol when node.Ch != '\n': - case Boundary when RegexCharClass.IsBoundaryWordChar(node.Ch): - case NonBoundary when !RegexCharClass.IsBoundaryWordChar(node.Ch): - case ECMABoundary when RegexCharClass.IsECMAWordChar(node.Ch): - case NonECMABoundary when !RegexCharClass.IsECMAWordChar(node.Ch): - return true; - } - break; + default: + return false; + } + break; - case Notoneloop: - switch (subsequent.Type) - { - case One when node.Ch == subsequent.Ch: - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: - case Multi when node.Ch == subsequent.Str![0]: - case End: - return true; - } - break; + case Notoneloop: + switch (subsequent.Type) + { + case One when node.Ch == subsequent.Ch: + case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: + case Multi when node.Ch == subsequent.Str![0]: + case End: + return true; + + case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: + // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. + break; - case Setloop: - switch (subsequent.Type) + default: + return false; + } + break; + + case Setloop: + switch (subsequent.Type) + { + case One when !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case Set when !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + case Multi when !RegexCharClass.CharInClass(subsequent.Str![0], node.Str!): + case End: + case EndZ or Eol when !RegexCharClass.CharInClass('\n', node.Str!): + case Boundary when node.Str == RegexCharClass.WordClass || node.Str == RegexCharClass.DigitClass: + case NonBoundary when node.Str == RegexCharClass.NotWordClass || node.Str == RegexCharClass.NotDigitClass: + case ECMABoundary when node.Str == RegexCharClass.ECMAWordClass || node.Str == RegexCharClass.ECMADigitClass: + case NonECMABoundary when node.Str == RegexCharClass.NotECMAWordClass || node.Str == RegexCharClass.NotDigitClass: + return true; + + case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case Setlazy or Setloop or Setloopatomic when subsequent.M == 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. + break; + + default: + return false; + } + break; + + default: + return false; + } + + // We only get here if the node could be made atomic based on subsequent but subsequent has a lower bound of zero + // and thus we need to move subsequent to be the next node in sequence and loop around to try again. + Debug.Assert(subsequent.Type is Oneloop or Oneloopatomic or Onelazy or Notoneloop or Notoneloopatomic or Notonelazy or Setloop or Setloopatomic or Setlazy); + Debug.Assert(subsequent.M == 0); + if (!allowSubsequentIteration) + { + return false; + } + + // To be conservative, we only walk up through a very limited set of constructs (even though we may have walked + // down through more, like loops), looking for the next concatenation that we're not at the end of, at + // which point subsequent becomes whatever node is next in that concatenation. + while (true) + { + RegexNode? parent = subsequent.Next; + switch (parent?.Type) { - case One when !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Multi when !RegexCharClass.CharInClass(subsequent.Str![0], node.Str!): - case Set when !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): - case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): - case End: - case EndZ or Eol when !RegexCharClass.CharInClass('\n', node.Str!): - case Boundary when node.Str == RegexCharClass.WordClass || node.Str == RegexCharClass.DigitClass: - case NonBoundary when node.Str == RegexCharClass.NotWordClass || node.Str == RegexCharClass.NotDigitClass: - case ECMABoundary when node.Str == RegexCharClass.ECMAWordClass || node.Str == RegexCharClass.ECMADigitClass: - case NonECMABoundary when node.Str == RegexCharClass.NotECMAWordClass || node.Str == RegexCharClass.NotDigitClass: + case Atomic: + case Alternate: + case Capture: + subsequent = parent; + continue; + + case Concatenate: + var peers = (List)parent.Children!; + int currentIndex = peers.IndexOf(subsequent); + Debug.Assert(currentIndex >= 0, "Node should have been in its parent's child list"); + if (currentIndex + 1 == peers.Count) + { + subsequent = parent; + continue; + } + else + { + subsequent = peers[currentIndex + 1]; + break; + } + + case null: + // If we hit the root, we're at the end of the expression, at which point nothing could backtrack + // in and we can declare success. return true; + + default: + // Anything else, we don't know what to do, so we have to assume it could conflict with the loop. + return false; } + break; + } } - - return false; } /// Computes a min bound on the required length of any string that could possibly match. diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs index 7f60d62db6dbc..a8a98aafa29d7 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs @@ -1026,6 +1026,18 @@ public static IEnumerable Match_Advanced_TestData() new CaptureData(string.Empty, 1, 0) } }; + yield return new object[] + { + engine, + "(d+?)(e*?)(f+)", "dddeeefff", RegexOptions.None, 0, 9, + new CaptureData[] + { + new CaptureData("dddeeefff", 0, 9), + new CaptureData("ddd", 0, 3), + new CaptureData("eee", 3, 3), + new CaptureData("fff", 6, 3), + } + }; // Noncapturing group : Actual - "(a+)(?:b*)(ccc)" yield return new object[] diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs index c3cd830fbb7b2..4781b959cf772 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs @@ -378,12 +378,26 @@ private static int GetMinRequiredLength(Regex r) [InlineData("(?(\\w)\\d)", "(?(\\w)\\d|)")] // Auto-atomicity [InlineData("a*b", "(?>a*)b")] - [InlineData("a*b+", "(?>a*)b+")] - [InlineData("a*b{3,4}", "(?>a*)b{3,4}")] + [InlineData("a*b+", "(?>a*)(?>b+)")] + [InlineData("a*b*", "(?>a*)(?>b*)")] + [InlineData("a*b+c*", "(?>a*)(?>b+)(?>c*)")] + [InlineData("a*b*c*", "(?>a*)(?>b*)(?>c*)")] + [InlineData("a*b*c*|d*[ef]*", "(?>a*)(?>b*)(?>c*)|(?>d*)(?>[ef]*)")] + [InlineData("(a*)(b*)(c*)", "((?>a*))((?>b*))((?>c*))")] + [InlineData("a*b{3,4}", "(?>a*)(?>b{3,4})")] + [InlineData("[ab]*[^a]*", "[ab]*(?>[^a]*)")] + [InlineData("[aa]*[^a]*", "(?>a*)(?>[^a]*)")] + [InlineData("a??", "")] + [InlineData("(abc*?)", "(ab)")] + [InlineData("a{1,3}?", "a{1,4}?")] + [InlineData("a{2,3}?", "a{2}")] + [InlineData("bc(a){1,3}?", "bc(a){1,2}?")] + [InlineData("c{3,}?|f{2,}?", "c{3}|f{2}")] + [InlineData("[a-z]*[\x0000-\xFFFF]+", "[a-z]*(?>[\x0000-\xFFFF]+)")] [InlineData("a+b", "(?>a+)b")] [InlineData("a?b", "(?>a?)b")] [InlineData("[^\n]*\n", "(?>[^\n]*)\n")] - [InlineData("[^\n]*\n+", "(?>[^\n]*)\n+")] + [InlineData("[^\n]*\n+", "(?>[^\n]*)(?>\n+)")] [InlineData("(a+)b", "((?>a+))b")] [InlineData("a*(?:bcd|efg)", "(?>a*)(?:bcd|efg)")] [InlineData("\\w*\\b", "(?>\\w*)\\b")] @@ -392,8 +406,8 @@ private static int GetMinRequiredLength(Regex r) [InlineData("(?:a[ce]*|b*)g", "(?:a(?>[ce]*)|(?>b*))g")] [InlineData("(?:a[ce]*|b*)c", "(?:a[ce]*|(?>b*))c")] [InlineData("apple|(?:orange|pear)|grape", "apple|orange|pear|grape")] - [InlineData("(?>(?>(?>(?:abc)*)))", "(?:abc)*")] - [InlineData("(?:w*)+", "(?>w*)+")] + [InlineData("(?:abc)*", "(?>(?>(?>(?:abc)*)))")] + [InlineData("(?:w*)+", "(?>(?>w*)+)")] [InlineData("(?:w*)+\\.", "(?>w*)+\\.")] [InlineData("(a[bcd]e*)*fg", "(a[bcd](?>e*))*fg")] [InlineData("(\\w[bcd]\\s*)*fg", "(\\w[bcd](?>\\s*))*fg")] @@ -461,7 +475,7 @@ public void PatternsReduceIdentically(string pattern1, string pattern2) [InlineData("(?i:abcd)|abcd", "abcd|abcd")] [InlineData("abcd|(?i:abcd)", "abcd|abcd")] // Not applying auto-atomicity - [InlineData("a*b*", "(?>a*)b*")] + [InlineData(@"(a*|b*)\w*", @"((?>a*)|(?>b*))\w*")] [InlineData("[ab]*[^a]", "(?>[ab]*)[^a]")] [InlineData("[ab]*[^a]*", "(?>[ab]*)[^a]*")] [InlineData("[ab]*[^a]*?", "(?>[ab]*)[^a]*?")] From 777c353c767c588824a489ad39238fef01c80f4e Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 19 Jan 2022 06:53:24 -0500 Subject: [PATCH 047/308] Extend regex switch alternation optimization to IgnoreCase (#63756) IgnoreCase now results in producing sets (e.g. an 'a' becomes '[Aa]') but the source generator's optimization that produces a switch statements for alternations with non-overlapping branches doesn't yet understand such sets. This augments that logic to fix that. --- .../gen/RegexGenerator.Emitter.cs | 95 +++++++++++++++---- .../Text/RegularExpressions/RegexCharClass.cs | 5 +- .../Text/RegularExpressions/RegexNode.cs | 15 +-- .../tests/Regex.Match.Tests.cs | 33 ++++++- 4 files changed, 118 insertions(+), 30 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index 396cf1bef784b..d3b724985d2c1 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -916,24 +916,69 @@ void EmitAlternation(RegexNode node) } } + // Detect whether every branch begins with one or more unique characters. + const int SetCharsSize = 5; // arbitrary limit (for IgnoreCase, we want this to be at least 3 to handle the vast majority of values) + Span setChars = stackalloc char[SetCharsSize]; if (useSwitchedBranches) { + // Iterate through every branch, seeing if we can easily find a starting One, Multi, or small Set. + // If we can, extract its starting char (or multiple in the case of a set), validate that all such + // starting characters are unique relative to all the branches. var seenChars = new HashSet(); - for (int i = 0; i < childCount; i++) + for (int i = 0; i < childCount && useSwitchedBranches; i++) { - if (node.Child(i).FindBranchOneOrMultiStart() is not RegexNode oneOrMulti || - !seenChars.Add(oneOrMulti.FirstCharOfOneOrMulti())) + // If it's not a One, Multi, or Set, we can't apply this optimization. + // If it's IgnoreCase (and wasn't reduced to a non-IgnoreCase set), also ignore it to keep the logic simple. + if (node.Child(i).FindBranchOneMultiOrSetStart() is not RegexNode oneMultiOrSet || + (oneMultiOrSet.Options & RegexOptions.IgnoreCase) != 0) // TODO: https://github.com/dotnet/runtime/issues/61048 { useSwitchedBranches = false; break; } + + // If it's a One or a Multi, get the first character and add it to the set. + // If it was already in the set, we can't apply this optimization. + if (oneMultiOrSet.Type is RegexNode.One or RegexNode.Multi) + { + if (!seenChars.Add(oneMultiOrSet.FirstCharOfOneOrMulti())) + { + useSwitchedBranches = false; + break; + } + } + else + { + // The branch begins with a set. Make sure it's a set of only a few characters + // and get them. If we can't, we can't apply this optimization. + Debug.Assert(oneMultiOrSet.Type is RegexNode.Set); + int numChars; + if (RegexCharClass.IsNegated(oneMultiOrSet.Str!) || + (numChars = RegexCharClass.GetSetChars(oneMultiOrSet.Str!, setChars)) == 0) + { + useSwitchedBranches = false; + break; + } + + // Check to make sure each of the chars is unique relative to all other branches examined. + foreach (char c in setChars.Slice(0, numChars)) + { + if (!seenChars.Add(c)) + { + useSwitchedBranches = false; + break; + } + } + } } } if (useSwitchedBranches) { // Note: This optimization does not exist with RegexOptions.Compiled. Here we rely on the - // C# compiler to lower the C# switch statement with appropriate optimizations. + // C# compiler to lower the C# switch statement with appropriate optimizations. In some + // cases there are enough branches that the compiler will emit a jump table. In others + // it'll optimize the order of checks in order to minimize the total number in the worst + // case. In any case, we get easier to read and reason about C#. EmitSwitchedBranches(); } else @@ -950,8 +995,9 @@ void EmitSwitchedBranches() writer.WriteLine(); // Emit a switch statement on the first char of each branch. - using (EmitBlock(writer, $"switch ({ToLowerIfNeeded(hasTextInfo, options, $"{sliceSpan}[{sliceStaticPos++}]", IsCaseInsensitive(node))})")) + using (EmitBlock(writer, $"switch ({sliceSpan}[{sliceStaticPos++}])")) { + Span setChars = stackalloc char[SetCharsSize]; // needs to be same size as detection check in caller int startingSliceStaticPos = sliceStaticPos; // Emit a case for each branch. @@ -960,13 +1006,23 @@ void EmitSwitchedBranches() sliceStaticPos = startingSliceStaticPos; RegexNode child = node.Child(i); - Debug.Assert(child.Type is RegexNode.One or RegexNode.Multi or RegexNode.Concatenate, DescribeNode(child, rm.Code)); - Debug.Assert(child.Type is not RegexNode.Concatenate || (child.ChildCount() >= 2 && child.Child(0).Type is RegexNode.One or RegexNode.Multi)); + Debug.Assert(child.Type is RegexNode.One or RegexNode.Multi or RegexNode.Set or RegexNode.Concatenate, DescribeNode(child, rm.Code)); + Debug.Assert(child.Type is not RegexNode.Concatenate || (child.ChildCount() >= 2 && child.Child(0).Type is RegexNode.One or RegexNode.Multi or RegexNode.Set)); - RegexNode? childStart = child.FindBranchOneOrMultiStart(); - Debug.Assert(childStart is not null, DescribeNode(child, rm.Code)); + RegexNode? childStart = child.FindBranchOneMultiOrSetStart(); + Debug.Assert(childStart is not null, "Unexpectedly couldn't find the branch starting node."); + Debug.Assert((childStart.Options & RegexOptions.IgnoreCase) == 0, "Expected only to find non-IgnoreCase branch starts"); - writer.WriteLine($"case {Literal(childStart.FirstCharOfOneOrMulti())}:"); + if (childStart.Type is RegexNode.Set) + { + int numChars = RegexCharClass.GetSetChars(childStart.Str!, setChars); + Debug.Assert(numChars != 0); + writer.WriteLine($"case {string.Join(" or ", setChars.Slice(0, numChars).ToArray().Select(c => Literal(c)))}:"); + } + else + { + writer.WriteLine($"case {Literal(childStart.FirstCharOfOneOrMulti())}:"); + } writer.Indent++; // Emit the code for the branch, without the first character that was already matched in the switch. @@ -974,6 +1030,7 @@ void EmitSwitchedBranches() { case RegexNode.Multi: EmitNode(CloneMultiWithoutFirstChar(child)); + writer.WriteLine(); break; case RegexNode.Concatenate: @@ -988,16 +1045,17 @@ void EmitSwitchedBranches() newConcat.AddChild(child.Child(j)); } EmitNode(newConcat.Reduce()); + writer.WriteLine(); break; - static RegexNode CloneMultiWithoutFirstChar(RegexNode node) - { - Debug.Assert(node.Type is RegexNode.Multi); - Debug.Assert(node.Str!.Length >= 2); - return node.Str!.Length == 2 ? - new RegexNode(RegexNode.One, node.Options, node.Str![1]) : - new RegexNode(RegexNode.Multi, node.Options, node.Str!.Substring(1)); - } + static RegexNode CloneMultiWithoutFirstChar(RegexNode node) + { + Debug.Assert(node.Type is RegexNode.Multi); + Debug.Assert(node.Str!.Length >= 2); + return node.Str!.Length == 2 ? + new RegexNode(RegexNode.One, node.Options, node.Str![1]) : + new RegexNode(RegexNode.Multi, node.Options, node.Str!.Substring(1)); + } } // This is only ever used for atomic alternations, so we can simply reset the doneLabel @@ -1009,7 +1067,6 @@ static RegexNode CloneMultiWithoutFirstChar(RegexNode node) // Before jumping to the end, we need to zero out sliceStaticPos, so that no // matter what the value is after the branch, whatever follows the alternate // will see the same sliceStaticPos. - writer.WriteLine(); TransferSliceStaticPosToPos(); writer.WriteLine($"break;"); writer.WriteLine(); diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs index 98957dfb408df..d52e2889786f7 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs @@ -716,9 +716,8 @@ public static bool TryGetSingleRange(string set, out char lowInclusive, out char /// public static int GetSetChars(string set, Span chars) { - // If the set is negated, it's likely to contain a large number of characters, - // so we don't even try. We also get the characters by enumerating the set - // portion, so we validate that it's set up to enable that, e.g. no categories. + // We get the characters by enumerating the set portion, so we validate that it's + // set up to enable that, e.g. no categories. if (!CanEasilyEnumerateSetContents(set)) { return 0; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index 2f70cbd778177..ba7f0cc64eb7f 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -1386,14 +1386,15 @@ static void ProcessOneOrMulti(RegexNode node, ReadOnlySpan startingSpan) /// public RegexNode? FindBranchOneOrMultiStart() { - RegexNode branch = this; - - if (branch.Type == Concatenate) - { - branch = branch.Child(0); - } + RegexNode branch = Type == Concatenate ? Child(0) : this; + return branch.Type is One or Multi ? branch : null; + } - return branch.Type == One || branch.Type == Multi ? branch : null; + /// Same as but also for Sets. + public RegexNode? FindBranchOneMultiOrSetStart() + { + RegexNode branch = Type == Concatenate ? Child(0) : this; + return branch.Type is One or Multi or Set ? branch : null; } /// Gets the character that begins a One or Multi. diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs index a8a98aafa29d7..8fd3ea6e32231 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs @@ -424,6 +424,38 @@ public static IEnumerable Match_MemberData() } // Alternation construct + foreach (string input in new[] { "abc", "def" }) + { + string upper = input.ToUpperInvariant(); + + // Two branches + yield return (@"abc|def", input, RegexOptions.None, 0, input.Length, true, input); + yield return (@"abc|def", upper, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant, 0, input.Length, true, upper); + yield return (@"abc|def", upper, RegexOptions.None, 0, input.Length, false, ""); + + // Three branches + yield return (@"abc|agh|def", input, RegexOptions.None, 0, input.Length, true, input); + yield return (@"abc|agh|def", upper, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant, 0, input.Length, true, upper); + yield return (@"abc|agh|def", upper, RegexOptions.None, 0, input.Length, false, ""); + + // Four branches + yield return (@"abc|agh|def|aij", input, RegexOptions.None, 0, input.Length, true, input); + yield return (@"abc|agh|def|aij", upper, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant, 0, input.Length, true, upper); + yield return (@"abc|agh|def|aij", upper, RegexOptions.None, 0, input.Length, false, ""); + + // Four branches (containing various other constructs) + if (!RegexHelpers.IsNonBacktracking(engine)) + { + yield return (@"abc|(agh)|(?=def)def|(?:(?(aij)aij|(?!)))", input, RegexOptions.None, 0, input.Length, true, input); + yield return (@"abc|(agh)|(?=def)def|(?:(?(aij)aij|(?!)))", upper, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant, 0, input.Length, true, upper); + yield return (@"abc|(agh)|(?=def)def|(?:(?(aij)aij|(?!)))", upper, RegexOptions.None, 0, input.Length, false, ""); + } + + // Sets in various positions in each branch + yield return (@"a\wc|\wgh|de\w", input, RegexOptions.None, 0, input.Length, true, input); + yield return (@"a\wc|\wgh|de\w", upper, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant, 0, input.Length, true, upper); + yield return (@"a\wc|\wgh|de\w", upper, RegexOptions.None, 0, input.Length, false, ""); + } yield return ("[^a-z0-9]etag|[^a-z0-9]digest", "this string has .digest as a substring", RegexOptions.None, 16, 7, true, ".digest"); if (!RegexHelpers.IsNonBacktracking(engine)) { @@ -446,7 +478,6 @@ public static IEnumerable Match_MemberData() yield return ("(?>(?:a|ab|abc|abcd))d", "abcd", RegexOptions.None, 0, 4, false, string.Empty); yield return ("(?>(?:a|ab|abc|abcd))d", "abcd", RegexOptions.RightToLeft, 0, 4, true, "abcd"); } - yield return ("[^a-z0-9]etag|[^a-z0-9]digest", "this string has .digest as a substring", RegexOptions.None, 16, 7, true, ".digest"); // No Negation yield return ("[abcd-[abcd]]+", "abcxyzABCXYZ`!@#$%^&*()_-+= \t\n", RegexOptions.None, 0, 30, false, string.Empty); From 6e4dfbfe2db42c9c67f1094dd65ec683c44e3457 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 19 Jan 2022 06:53:36 -0500 Subject: [PATCH 048/308] Improve reductions for Regex empty / nothing nodes (#63695) --- .../Text/RegularExpressions/RegexNode.cs | 119 +++++++++++++----- .../tests/RegexReductionTests.cs | 8 ++ 2 files changed, 93 insertions(+), 34 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index ba7f0cc64eb7f..6ce2b946d1727 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -597,6 +597,7 @@ internal RegexNode Reduce() => Group => ReduceGroup(), Loop or Lazyloop => ReduceLoops(), Prevent => ReducePrevent(), + Require => ReduceRequire(), Set or Setloop or Setloopatomic or Setlazy => ReduceSet(), Testgroup => ReduceTestgroup(), Testref => ReduceTestref(), @@ -607,17 +608,14 @@ internal RegexNode Reduce() => /// /// Simple optimization for a concatenation or alternation: /// - if the node has only one child, use it instead - /// - if the node has zero children, turn it into an empty with the specified empty type + /// - if the node has zero children, turn it into an empty with Nothing for an alternation or Empty for a concatenation /// - private RegexNode ReplaceNodeIfUnnecessary(int emptyTypeIfNoChildren) + private RegexNode ReplaceNodeIfUnnecessary() { - Debug.Assert( - (Type == Alternate && emptyTypeIfNoChildren == Nothing) || - (Type == Concatenate && emptyTypeIfNoChildren == Empty)); - + Debug.Assert(Type is Alternate or Concatenate); return ChildCount() switch { - 0 => new RegexNode(emptyTypeIfNoChildren, Options), + 0 => new RegexNode(Type == Alternate ? Nothing : Empty, Options), 1 => Child(0), _ => this, }; @@ -672,6 +670,12 @@ private RegexNode ReduceAtomic() switch (child.Type) { + // If the child is empty/nothing, there's nothing to be made atomic so the Atomic + // node can simply be removed. + case Empty: + case Nothing: + return child; + // If the child is already atomic, we can just remove the atomic node. case Oneloopatomic: case Notoneloopatomic: @@ -971,9 +975,19 @@ private RegexNode ReduceAlternation() default: ReduceSingleLetterAndNestedAlternations(); - RegexNode node = ReplaceNodeIfUnnecessary(Nothing); - node = ExtractCommonPrefixText(node); - node = ExtractCommonPrefixOneNotoneSet(node); + RegexNode node = ReplaceNodeIfUnnecessary(); + if (node.Type == Alternate) + { + node = ExtractCommonPrefixText(node); + if (node.Type == Alternate) + { + node = ExtractCommonPrefixOneNotoneSet(node); + if (node.Type == Alternate) + { + node = RemoveRedundantEmptiesAndNothings(node); + } + } + } return node; } @@ -1103,11 +1117,7 @@ void ReduceSingleLetterAndNestedAlternations() // e.g. \w12|\d34|\d56|\w78|\w90 => \w12|\d(?:34|56)|\w(?:78|90) static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) { - if (alternation.Type != Alternate) - { - return alternation; - } - + Debug.Assert(alternation.Type == Alternate); Debug.Assert(alternation.Children is List { Count: >= 2 }); var children = (List)alternation.Children; @@ -1193,9 +1203,45 @@ static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) children.RemoveRange(startingIndex + 1, endingIndex - startingIndex - 1); } - // If we've reduced this alternation to just a single branch, return it. - // Otherwise, return the alternation. - return alternation.ChildCount() == 1 ? alternation.Child(0) : alternation; + return alternation.ReplaceNodeIfUnnecessary(); + } + + // Removes unnecessary Empty and Nothing nodes from the alternation. A Nothing will never + // match, so it can be removed entirely, and an Empty can be removed if there's a previous + // Empty in the alternation: it's an extreme case of just having a repeated branch in an + // alternation, and while we don't check for all duplicates, checking for empty is easy. + static RegexNode RemoveRedundantEmptiesAndNothings(RegexNode node) + { + Debug.Assert(node.Type == Alternate); + Debug.Assert(node.ChildCount() >= 2); + var children = (List)node.Children!; + + int i = 0, j = 0; + bool seenEmpty = false; + while (i < children.Count) + { + RegexNode child = children[i]; + switch (child.Type) + { + case Empty when !seenEmpty: + seenEmpty = true; + goto default; + + case Empty: + case Nothing: + i++; + break; + + default: + children[j] = children[i]; + i++; + j++; + break; + } + } + + children.RemoveRange(j, children.Count - j); + return node.ReplaceNodeIfUnnecessary(); } // Analyzes all the branches of the alternation for text that's identical at the beginning @@ -1209,11 +1255,7 @@ static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) // e.g. abc|ade => a(?bc|de) static RegexNode ExtractCommonPrefixText(RegexNode alternation) { - if (alternation.Type != Alternate) - { - return alternation; - } - + Debug.Assert(alternation.Type == Alternate); Debug.Assert(alternation.Children is List { Count: >= 2 }); var children = (List)alternation.Children; @@ -1309,20 +1351,11 @@ static RegexNode ExtractCommonPrefixText(RegexNode alternation) new RegexNode(One, startingNodeOptions, startingSpan[0]) : new RegexNode(Multi, startingNodeOptions, startingSpan.ToString()); var newAlternate = new RegexNode(Alternate, startingNodeOptions); - bool seenEmpty = false; for (int i = startingIndex; i < endingIndex; i++) { RegexNode branch = children[i]; ProcessOneOrMulti(branch.Type == Concatenate ? branch.Child(0) : branch, startingSpan); branch = branch.Reduce(); - if (branch.Type == Empty) - { - if (seenEmpty) - { - continue; - } - seenEmpty = true; - } newAlternate.AddChild(branch); // Remove the starting text from the one or multi node. This may end up changing @@ -1472,7 +1505,7 @@ private RegexNode ReduceConcatenation() // If the concatenation is now empty, return an empty node, or if it's got a single child, return that child. // Otherwise, return this. - return ReplaceNodeIfUnnecessary(Empty); + return ReplaceNodeIfUnnecessary(); } /// @@ -1819,13 +1852,31 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) return null; } + /// Optimizations for positive lookaheads/behinds. + private RegexNode ReduceRequire() + { + Debug.Assert(Type == Require); + Debug.Assert(ChildCount() == 1); + + // A positive lookaround wrapped around an empty is a nop, and can just + // be made into an empty. A developer typically doesn't write this, but + // rather it evolves due to optimizations resulting in empty. + if (Child(0).Type == Empty) + { + Type = Empty; + Children = null; + } + + return this; + } + /// Optimizations for negative lookaheads/behinds. private RegexNode ReducePrevent() { Debug.Assert(Type == Prevent); Debug.Assert(ChildCount() == 1); - // A negative lookahead/lookbehind wrapped around an empty child, i.e. (?!), is + // A negative lookaround wrapped around an empty child, i.e. (?!), is // sometimes used as a way to insert a guaranteed no-match into the expression. // We can reduce it to simply Nothing. if (Child(0).Type == Empty) diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs index 4781b959cf772..37a0fdb7c21ac 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs @@ -343,6 +343,9 @@ private static int GetMinRequiredLength(Regex r) [InlineData("(?:a{1,2}){4}", "a{4,8}")] // Nested atomic [InlineData("(?>(?>(?>(?>abc*))))", "(?>ab(?>c*))")] + [InlineData("(?>(?>(?>(?>))))", "")] + [InlineData("(?>(?>(?>(?>(?!)))))", "(?!)")] + [InlineData("(?=(?>))", "")] // Alternation reduction [InlineData("a|b", "[ab]")] [InlineData("a|b|c|d|e|g|h|z", "[a-eghz]")] @@ -366,6 +369,11 @@ private static int GetMinRequiredLength(Regex r) [InlineData("hello there|hello again|hello|hello|hello|hello", "hello(?> there| again|)")] [InlineData("hello there|hello again|hello|hello|hello|hello|hello world", "hello(?> there| again|| world)")] [InlineData("hello there|hello again|hello|hello|hello|hello|hello world|hello", "hello(?> there| again|| world)")] + [InlineData("ab|cd|||ef", "ab|cd||ef")] + [InlineData("|ab|cd|e||f", "|ab|cd|ef")] + [InlineData("ab|cd|||||||||||ef", "ab|cd||ef")] + [InlineData("ab|cd|||||||||||e||f|||", "ab|cd||ef")] + [InlineData("ab|cd|(?!)|ef", "ab|cd|ef")] [InlineData("abcd(?:(?i:e)|(?i:f))", "abcd(?i:[ef])")] [InlineData("(?i:abcde)|(?i:abcdf)", "(?i:abcd[ef])")] [InlineData("xyz(?:(?i:abcde)|(?i:abcdf))", "xyz(?i:abcd[ef])")] From a5292a6b54ca743efe2e5b6776864efb7c7702a5 Mon Sep 17 00:00:00 2001 From: Olivier Giniaux Date: Wed, 19 Jan 2022 12:56:54 +0100 Subject: [PATCH 049/308] Fix profiling objectsallocatedbyclass (#63814) * Add test for ObjectsAllocatedByClass profiler callbacks * Fix ObjectsAllocatedByClass profiler callbacks based on wrong flag * Fix wrong args in test log Co-authored-by: Olivier Giniaux --- src/coreclr/vm/proftoeeinterfaceimpl.cpp | 2 +- .../profiler/native/gcprofiler/gcprofiler.cpp | 18 ++++++++++++++++++ .../profiler/native/gcprofiler/gcprofiler.h | 3 +++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp index 749fa73126b08..50e57f8144eef 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -1274,7 +1274,7 @@ bool AllocByClassHelper(Object * pBO, void * pv) _ASSERTE(pv != NULL); { - BEGIN_PROFILER_CALLBACK(CORProfilerTrackAllocations()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC()); // Pass along the call g_profControlBlock.AllocByClass( (ObjectID) pBO, diff --git a/src/tests/profiler/native/gcprofiler/gcprofiler.cpp b/src/tests/profiler/native/gcprofiler/gcprofiler.cpp index 42666a2d8eac8..ed6312cd89c46 100644 --- a/src/tests/profiler/native/gcprofiler/gcprofiler.cpp +++ b/src/tests/profiler/native/gcprofiler/gcprofiler.cpp @@ -37,6 +37,10 @@ HRESULT GCProfiler::Shutdown() { printf("GCProfiler::Shutdown: FAIL: Expected GarbageCollectionFinished to be called\n"); } + else if (_allocatedByClassCalls == 0) + { + printf("GCProfiler::Shutdown: FAIL: Expected ObjectsAllocatedByClass to be called\n"); + } else if (_pohObjectsSeenRootReferences == 0 || _pohObjectsSeenObjectReferences == 0) { printf("GCProfiler::Shutdown: FAIL: no POH objects seen. root references=%d object references=%d\n", @@ -86,6 +90,20 @@ HRESULT GCProfiler::GarbageCollectionFinished() return S_OK; } +HRESULT GCProfiler::ObjectsAllocatedByClass(ULONG cClassCount, ClassID classIds[], ULONG cObjects[]) +{ + SHUTDOWNGUARD(); + + _allocatedByClassCalls++; + if (_gcStarts != _allocatedByClassCalls) + { + _failures++; + printf("GCProfiler::ObjectsAllocatedByClass: FAIL: Expected ObjectsAllocatedByClass Calls == GCStart. AllocatedByClassCalls=%d, GCStart=%d\n", (int)_allocatedByClassCalls, (int)_gcStarts); + } + + return S_OK; +} + HRESULT GCProfiler::ObjectReferences(ObjectID objectId, ClassID classId, ULONG cObjectRefs, ObjectID objectRefIds[]) { SHUTDOWNGUARD(); diff --git a/src/tests/profiler/native/gcprofiler/gcprofiler.h b/src/tests/profiler/native/gcprofiler/gcprofiler.h index ab519f6f53399..eebdb06853f7a 100644 --- a/src/tests/profiler/native/gcprofiler/gcprofiler.h +++ b/src/tests/profiler/native/gcprofiler/gcprofiler.h @@ -16,6 +16,7 @@ class GCProfiler : public Profiler GCProfiler() : Profiler(), _gcStarts(0), _gcFinishes(0), + _allocatedByClassCalls(0), _failures(0), _pohObjectsSeenRootReferences(0), _pohObjectsSeenObjectReferences(0), @@ -28,12 +29,14 @@ class GCProfiler : public Profiler virtual HRESULT STDMETHODCALLTYPE Shutdown(); virtual HRESULT STDMETHODCALLTYPE GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason); virtual HRESULT STDMETHODCALLTYPE GarbageCollectionFinished(); + virtual HRESULT STDMETHODCALLTYPE ObjectsAllocatedByClass(ULONG cClassCount, ClassID classIds[], ULONG cObjects[]); virtual HRESULT STDMETHODCALLTYPE ObjectReferences(ObjectID objectId, ClassID classId, ULONG cObjectRefs, ObjectID objectRefIds[]); virtual HRESULT STDMETHODCALLTYPE RootReferences(ULONG cRootRefs, ObjectID rootRefIds[]); private: std::atomic _gcStarts; std::atomic _gcFinishes; + std::atomic _allocatedByClassCalls; std::atomic _failures; std::atomic _pohObjectsSeenRootReferences; std::atomic _pohObjectsSeenObjectReferences; From e54df94bc9a5e1e064835be817d3e9ac773e1d9a Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Wed, 19 Jan 2022 11:59:34 +0000 Subject: [PATCH 050/308] Replace "needs more info" label with "needs-author-action" (#63899) --- .github/fabricbot.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/fabricbot.json b/.github/fabricbot.json index c885e48256630..723e3f5c493f2 100644 --- a/.github/fabricbot.json +++ b/.github/fabricbot.json @@ -996,7 +996,7 @@ "subCapability": "IssueCommentResponder", "version": "1.0", "config": { - "taskName": "Replace `needs more info` label with `needs further triage` label when the author comments on an issue", + "taskName": "Replace `needs-author-action` label with `needs further triage` label when the author comments on an issue", "conditions": { "operator": "and", "operands": [ @@ -1017,7 +1017,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs more info" + "label": "needs-author-action" } }, { @@ -1036,7 +1036,7 @@ { "name": "removeLabel", "parameters": { - "label": "needs more info" + "label": "needs-author-action" } } ], @@ -1575,7 +1575,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs more info" + "label": "needs-author-action" } }, { @@ -5416,7 +5416,7 @@ { "name": "labelAdded", "parameters": { - "label": "needs more info" + "label": "needs-author-action" } } ] @@ -5426,12 +5426,12 @@ "issues", "project_card" ], - "taskName": "Needs more info notification", + "taskName": "Needs-author-action notification", "actions": [ { "name": "addReply", "parameters": { - "comment": "This issue has been marked `needs more info` since it may be missing important information. Please refer to our [contribution guidelines](https://github.com/dotnet/runtime/blob/main/CONTRIBUTING.md#writing-a-good-bug-report) for tips on how to report issues effectively." + "comment": "This issue has been marked `needs-author-action` since it may be missing important information. Please refer to our [contribution guidelines](https://github.com/dotnet/runtime/blob/main/CONTRIBUTING.md#writing-a-good-bug-report) for tips on how to report issues effectively." } } ] @@ -5951,7 +5951,7 @@ { "name": "labelAdded", "parameters": { - "label": "needs more info" + "label": "needs-author-action" } }, { @@ -6668,7 +6668,7 @@ { "name": "labelAdded", "parameters": { - "label": "needs more info" + "label": "needs-author-action" } }, { @@ -7352,7 +7352,7 @@ { "name": "labelAdded", "parameters": { - "label": "needs more info" + "label": "needs-author-action" } }, { From 34794bc5f2bcdbaa9057bb07b8764e2bb6a411a2 Mon Sep 17 00:00:00 2001 From: Krzysztof Wicher Date: Wed, 19 Jan 2022 13:45:01 +0100 Subject: [PATCH 051/308] Enable System.Text.Json tests on netfx (#63803) * Enable System.Text.Json tests on netfx * use NETFRAMEWORK define * disable another two test cases after rebase * disable last test case which repros only on CI for me * add p2p only on netfx --- docs/coding-guidelines/project-guidelines.md | 2 +- .../tests/Common/PropertyVisibilityTests.cs | 1 + .../ContextClasses.cs | 3 +-- .../JsonSerializerContextTests.cs | 1 + .../MetadataAndSerializationContextTests.cs | 2 ++ .../MetadataContextTests.cs | 3 +++ .../MixedModeContextTests.cs | 2 ++ .../Serialization/PropertyVisibilityTests.cs | 4 ++++ .../SerializationContextTests.cs | 4 ++++ .../System.Text.Json.SourceGeneration.Tests.targets | 13 ++++++++++++- .../CompilationHelper.cs | 6 +++++- .../JsonSourceGeneratorTests.cs | 2 ++ ...em.Text.Json.SourceGeneration.Unit.Tests.targets | 6 +++++- 13 files changed, 43 insertions(+), 6 deletions(-) diff --git a/docs/coding-guidelines/project-guidelines.md b/docs/coding-guidelines/project-guidelines.md index 5f27836900e25..2e3e47dec4724 100644 --- a/docs/coding-guidelines/project-guidelines.md +++ b/docs/coding-guidelines/project-guidelines.md @@ -52,7 +52,7 @@ Pure netstandard configuration: All supported targets with unique windows/unix build for netcoreapp: ``` - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetFrameworkCurrent) + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetFrameworkMinimum) ``` diff --git a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs index 8c0f57b422a55..302923a104c28 100644 --- a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs @@ -1227,6 +1227,7 @@ public async Task JsonIgnoreAttribute_UnsupportedCollection() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63802", TargetFrameworkMonikers.NetFramework)] public async Task JsonIgnoreAttribute_UnsupportedBigInteger() { string json = @"{""MyBigInteger"":1}"; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs index c01499f7fef3e..75ada92a87303 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Reflection; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; @@ -11,7 +10,7 @@ namespace System.Text.Json.SourceGeneration.Tests public interface ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode { get; } - public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; + public bool IsIncludeFieldsEnabled { get; } public JsonTypeInfo Location { get; } public JsonTypeInfo NumberTypes { get; } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs index 7bc91507d9ad5..fd735e182d5fe 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs @@ -21,6 +21,7 @@ public static void VariousNestingAndVisibilityLevelsAreSupported() } [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63802", TargetFrameworkMonikers.NetFramework)] public static void Converters_AndTypeInfoCreator_NotRooted_WhenMetadataNotPresent() { RemoteExecutor.Invoke( diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs index 57abdf04808a0..a8eeee6f8768b 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; +using System.Reflection; using Xunit; namespace System.Text.Json.SourceGeneration.Tests @@ -44,6 +45,7 @@ namespace System.Text.Json.SourceGeneration.Tests internal partial class MetadataAndSerializationContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Default; + public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } public sealed class MetadataAndSerializationContextTests : RealWorldContextTests diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs index d0c3023b41ae9..89c5035700bea 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; +using System.Reflection; using Xunit; namespace System.Text.Json.SourceGeneration.Tests @@ -43,6 +44,7 @@ namespace System.Text.Json.SourceGeneration.Tests internal partial class MetadataWithPerTypeAttributeContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Metadata; + public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } public sealed class MetadataWithPerTypeAttributeContextTests : RealWorldContextTests @@ -127,6 +129,7 @@ public override void EnsureFastPathGeneratedAsExpected() internal partial class MetadataContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Metadata; + public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } [JsonConverter(typeof(JsonStringEnumConverter))] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs index d547551569935..51e9e23b80d7b 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; +using System.Reflection; using Xunit; namespace System.Text.Json.SourceGeneration.Tests @@ -44,6 +45,7 @@ namespace System.Text.Json.SourceGeneration.Tests internal partial class MixedModeContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Metadata | JsonSourceGenerationMode.Serialization; + public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } public sealed class MixedModeContextTests : RealWorldContextTests diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs index a698165e3f967..1c80d9046a7c4 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs @@ -249,10 +249,12 @@ public override async Task HonorJsonPropertyName_PrivateSetter() [JsonSerializable(typeof(ClassWithNewSlotAttributedDecimalProperty))] [JsonSerializable(typeof(ClassWithNewSlotDecimalProperty))] [JsonSerializable(typeof(LargeStructWithValueAndReferenceTypes))] +#if !NETFRAMEWORK [JsonSerializable(typeof(ClassWithUnsupportedBigInteger))] [JsonSerializable(typeof(WrapperForClassWithUnsupportedBigInteger))] [JsonSerializable(typeof(ClassWithIgnoredUnsupportedBigInteger))] [JsonSerializable(typeof(WrapperForClassWithIgnoredUnsupportedBigInteger))] +#endif [JsonSerializable(typeof(ClassWithThingsToIgnore))] [JsonSerializable(typeof(ClassWithMixedPropertyAccessors_PropertyAttributes))] [JsonSerializable(typeof(ClassWithPropertyPolicyConflictWhichThrows))] @@ -422,10 +424,12 @@ public override async Task JsonIgnoreCondition_WhenWritingNull_OnValueType_Fail_ [JsonSerializable(typeof(ClassWithNewSlotAttributedDecimalProperty))] [JsonSerializable(typeof(ClassWithNewSlotDecimalProperty))] [JsonSerializable(typeof(LargeStructWithValueAndReferenceTypes))] +#if !NETFRAMEWORK [JsonSerializable(typeof(ClassWithUnsupportedBigInteger))] [JsonSerializable(typeof(WrapperForClassWithUnsupportedBigInteger))] [JsonSerializable(typeof(ClassWithIgnoredUnsupportedBigInteger))] [JsonSerializable(typeof(WrapperForClassWithIgnoredUnsupportedBigInteger))] +#endif [JsonSerializable(typeof(ClassWithThingsToIgnore))] [JsonSerializable(typeof(ClassWithMixedPropertyAccessors_PropertyAttributes))] [JsonSerializable(typeof(ClassWithPropertyPolicyConflictWhichThrows))] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs index b51ba070be188..f955070f74cb5 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; +using System.Reflection; using Xunit; namespace System.Text.Json.SourceGeneration.Tests @@ -44,6 +45,7 @@ namespace System.Text.Json.SourceGeneration.Tests internal partial class SerializationContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Serialization; + public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } [JsonSerializable(typeof(Location), GenerationMode = JsonSourceGenerationMode.Serialization)] @@ -83,6 +85,7 @@ internal partial class SerializationContext : JsonSerializerContext, ITestContex internal partial class SerializationWithPerTypeAttributeContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Serialization; + public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } [JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, IncludeFields = true)] @@ -123,6 +126,7 @@ internal partial class SerializationWithPerTypeAttributeContext : JsonSerializer internal partial class SerializationContextWithCamelCase : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Serialization; + public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } public class SerializationContextTests : RealWorldContextTests diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets index 2f977168e8043..16f8d544794b8 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets @@ -1,6 +1,6 @@ - $(NetCoreAppCurrent);$(NetFrameworkCurrent) + $(NetCoreAppCurrent);$(NetFrameworkMinimum) true true @@ -86,6 +86,17 @@ + + + + + + + + + + + diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs index 485a79cd333cd..4381422afb7f4 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.CodeDom.Compiler; using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; @@ -31,6 +32,7 @@ public static Compilation CreateCompilation( // Bypass System.Runtime error. Assembly systemRuntimeAssembly = Assembly.Load("System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); Assembly systemCollectionsAssembly = Assembly.Load("System.Collections, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); + // Needed on netfx string systemRuntimeAssemblyPath = systemRuntimeAssembly.Location; string systemCollectionsAssemblyPath = systemCollectionsAssembly.Location; @@ -38,9 +40,11 @@ public static Compilation CreateCompilation( MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location), MetadataReference.CreateFromFile(typeof(Type).Assembly.Location), - MetadataReference.CreateFromFile(typeof(KeyValuePair).Assembly.Location), + MetadataReference.CreateFromFile(typeof(KeyValuePair<,>).Assembly.Location), MetadataReference.CreateFromFile(typeof(ContractNamespaceAttribute).Assembly.Location), MetadataReference.CreateFromFile(typeof(JavaScriptEncoder).Assembly.Location), + MetadataReference.CreateFromFile(typeof(GeneratedCodeAttribute).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ReadOnlySpan<>).Assembly.Location), MetadataReference.CreateFromFile(systemRuntimeAssemblyPath), MetadataReference.CreateFromFile(systemCollectionsAssemblyPath), }; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs index f8c0a34e57c80..f1d5b1973fd6c 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs @@ -450,6 +450,7 @@ public void UsePrivates() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63802", TargetFrameworkMonikers.NetFramework)] public void Record() { // Compile the referenced assembly first. @@ -511,6 +512,7 @@ public record AppRecord(int Id) } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63802", TargetFrameworkMonikers.NetFramework)] public void RecordInExternalAssembly() { // Compile the referenced assembly first. diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets index da4a8b8d65997..08f362de05e7a 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets @@ -1,6 +1,6 @@ - $(NetCoreAppCurrent);$(NetFrameworkCurrent) + $(NetCoreAppCurrent);$(NetFrameworkMinimum) true @@ -17,6 +17,10 @@ + + + + From b042bc3043f3f7f475f5bd6e8f58df2952dd9250 Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Wed, 19 Jan 2022 14:15:57 +0100 Subject: [PATCH 052/308] Avoid allocating byte array when setting ALPN list on Linux (#63674) * Avoid allocating byte array when setting ALPN list * Code review feedback * Apply suggestions from code review Co-authored-by: Stephen Toub * Slice the stackalloc'd buffer to correct length Co-authored-by: Miha Zupan * Code review fixes Co-authored-by: Stephen Toub Co-authored-by: Miha Zupan --- .../Interop.Ssl.cs | 45 ++++++++++++------- .../System/Net/Security/SslStreamPal.Unix.cs | 5 --- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs index c01b829cd189d..379ab7586ed38 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Net.Security; using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using Microsoft.Win32.SafeHandles; @@ -47,7 +48,7 @@ internal static partial class Ssl internal static partial void SslSetAcceptState(SafeSslHandle ssl); [GeneratedDllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslSetAlpnProtos")] - internal static partial int SslSetAlpnProtos(SafeSslHandle ssl, IntPtr protos, int len); + internal static unsafe partial int SslSetAlpnProtos(SafeSslHandle ssl, byte* protos, int len); [GeneratedDllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslGetVersion")] internal static partial IntPtr SslGetVersion(SafeSslHandle ssl); @@ -168,16 +169,7 @@ internal static class Capabilities internal static readonly bool Tls13Supported = Tls13SupportedImpl() != 0; } - internal static unsafe int SslSetAlpnProtos(SafeSslHandle ssl, List protocols) - { - byte[] buffer = ConvertAlpnProtocolListToByteArray(protocols); - fixed (byte* b = buffer) - { - return SslSetAlpnProtos(ssl, (IntPtr)b, buffer.Length); - } - } - - internal static byte[] ConvertAlpnProtocolListToByteArray(List applicationProtocols) + internal static int GetAlpnProtocolListSerializedLength(List applicationProtocols) { int protocolSize = 0; foreach (SslApplicationProtocol protocol in applicationProtocols) @@ -190,16 +182,37 @@ internal static byte[] ConvertAlpnProtocolListToByteArray(List applicationProtocols, Span buffer) + { + Debug.Assert(GetAlpnProtocolListSerializedLength(applicationProtocols) == buffer.Length, + "GetAlpnProtocolListSerializedSize(applicationProtocols) == buffer.Length"); + + int offset = 0; foreach (SslApplicationProtocol protocol in applicationProtocols) { - buffer[offset++] = (byte)(protocol.Protocol.Length); - protocol.Protocol.Span.CopyTo(buffer.AsSpan(offset)); + buffer[offset++] = (byte)protocol.Protocol.Length; + protocol.Protocol.Span.CopyTo(buffer.Slice(offset)); offset += protocol.Protocol.Length; } + } + + internal static unsafe int SslSetAlpnProtos(SafeSslHandle ssl, List applicationProtocols) + { + int length = GetAlpnProtocolListSerializedLength(applicationProtocols); + Span buffer = length <= 256 ? stackalloc byte[256].Slice(0, length) : new byte[length]; + SerializeAlpnProtocolList(applicationProtocols, buffer); + return SslSetAlpnProtos(ssl, buffer); + } - return buffer; + internal static unsafe int SslSetAlpnProtos(SafeSslHandle ssl, Span serializedProtocols) + { + fixed (byte* pBuffer = &MemoryMarshal.GetReference(serializedProtocols)) + { + return SslSetAlpnProtos(ssl, pBuffer, serializedProtocols.Length); + } } [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslAddExtraChainCert")] diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs index f4c4c5424e18e..63c4efc1edb65 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs @@ -139,11 +139,6 @@ public static void QueryContextConnectionInfo(SafeDeleteSslContext securityConte connectionInfo = new SslConnectionInfo(securityContext.SslContext); } - public static byte[] ConvertAlpnProtocolListToByteArray(List applicationProtocols) - { - return Interop.Ssl.ConvertAlpnProtocolListToByteArray(applicationProtocols); - } - private static SecurityStatusPal HandshakeInternal(SafeFreeCredentials credential, ref SafeDeleteSslContext? context, ReadOnlySpan inputBuffer, ref byte[]? outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { From 8fe0467efd29d952fc2afbf302c1d8a1bb3b2fa5 Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Wed, 19 Jan 2022 16:55:40 +0300 Subject: [PATCH 053/308] Take MacCatalyst into account in EnvironmentTests.WorkingSet_Valid test (#63995) Follow-up on https://github.com/dotnet/runtime/pull/63934 --- .../System.Runtime.Extensions/tests/System/EnvironmentTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs index 5d2bf2785491f..8c6fc1a78d47b 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs @@ -236,7 +236,7 @@ public void Version_Valid() [Fact] public void WorkingSet_Valid() { - if (PlatformDetection.IsBrowser || PlatformDetection.IsiOS || PlatformDetection.IstvOS) + if (PlatformDetection.IsBrowser || (PlatformDetection.IsiOS && !PlatformDetection.IsMacCatalyst) || PlatformDetection.IstvOS) Assert.Equal(0, Environment.WorkingSet); else Assert.True(Environment.WorkingSet > 0, "Expected positive WorkingSet value"); From 31f20c54ad56946a506d705261a5445930b56d29 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 19 Jan 2022 09:57:04 -0500 Subject: [PATCH 054/308] Improve auto-atomicity for conditionals (#63299) - Allow for automatically making loops that end conditional branches be atomic - Allow for using a following expression conditional to make a prior loop atomic - Allow conditionals to influence the computed minimum length --- .../Text/RegularExpressions/RegexNode.cs | 77 ++++++++++++++----- .../tests/RegexReductionTests.cs | 38 +++++++++ 2 files changed, 94 insertions(+), 21 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index 6ce2b946d1727..121b9d1e4225b 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -441,11 +441,12 @@ internal RegexNode FinalOptimize() /// private void EliminateEndingBacktracking() { - Debug.Assert((Options & RegexOptions.NonBacktracking) == 0, "NonBacktracking doesn't have backtracking to be eliminated and doesn't support atomic groups."); - - if (!StackHelper.TryEnsureSufficientExecutionStack()) + if (!StackHelper.TryEnsureSufficientExecutionStack() || + (Options & (RegexOptions.RightToLeft | RegexOptions.NonBacktracking)) != 0) { // If we can't recur further, just stop optimizing. + // We haven't done the work to validate this is correct for RTL. + // And NonBacktracking doesn't support atomic groups and doesn't have backtracking to be eliminated. return; } @@ -470,7 +471,7 @@ private void EliminateEndingBacktracking() continue; // For Capture and Concatenate, we just recur into their last child (only child in the case - // of Capture). However, if the child is Alternate, Loop, and Lazyloop, we can also make the + // of Capture). However, if the child is an alternation or loop, we can also make the // node itself atomic by wrapping it in an Atomic node. Since we later check to see whether a // node is atomic based on its parent or grandparent, we don't bother wrapping such a node in // an Atomic one if its grandparent is already Atomic. @@ -478,7 +479,7 @@ private void EliminateEndingBacktracking() case Capture: case Concatenate: RegexNode existingChild = node.Child(node.ChildCount() - 1); - if ((existingChild.Type is Alternate or Loop or Lazyloop) && + if ((existingChild.Type is Alternate or Testref or Testgroup or Loop or Lazyloop) && (node.Next is null || node.Next.Type != Atomic)) // validate grandparent isn't atomic { var atomic = new RegexNode(Atomic, existingChild.Options); @@ -489,17 +490,25 @@ private void EliminateEndingBacktracking() continue; // For alternate, we can recur into each branch separately. We use this iteration for the first branch. + // Conditionals are just like alternations in this regard. // e.g. abc*|def* => ab(?>c*)|de(?>f*) case Alternate: + case Testref: + case Testgroup: { int branches = node.ChildCount(); for (int i = 1; i < branches; i++) { node.Child(i).EliminateEndingBacktracking(); } + + if (node.Type != Testgroup) // ReduceTestgroup will have already applied ending backtracking removal + { + node = node.Child(0); + continue; + } } - node = node.Child(0); - continue; + break; // For {Lazy}Loop, we search to see if there's a viable last expression, and iff there // is we recur into processing it. Also, as with the single-char lazy loops, LazyLoop @@ -1793,15 +1802,19 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) node.MakeLoopAtomic(); break; case Alternate: + case Testref: + case Testgroup: // In the case of alternation, we can't change the alternation node itself // based on what comes after it (at least not with more complicated analysis // that factors in all branches together), but we can look at each individual // branch, and analyze ending loops in each branch individually to see if they // can be made atomic. Then if we do end up backtracking into the alternation, - // we at least won't need to backtrack into that loop. + // we at least won't need to backtrack into that loop. The same is true for + // conditionals, though we don't want to process the condition expression + // itself, as it's already considered atomic and handled as part of ReduceTestgroup. { int alternateBranches = node.ChildCount(); - for (int b = 0; b < alternateBranches; b++) + for (int b = node.Type == Testgroup ? 1 : 0; b < alternateBranches; b++) { ProcessNode(node.Child(b), subsequent); } @@ -1858,6 +1871,11 @@ private RegexNode ReduceRequire() Debug.Assert(Type == Require); Debug.Assert(ChildCount() == 1); + // A positive lookaround is a zero-width atomic assertion. + // As it's atomic, nothing will backtrack into it, and we can + // eliminate any ending backtracking from it. + EliminateEndingBacktracking(); + // A positive lookaround wrapped around an empty is a nop, and can just // be made into an empty. A developer typically doesn't write this, but // rather it evolves due to optimizations resulting in empty. @@ -1932,6 +1950,11 @@ private RegexNode ReduceTestgroup() ReplaceChild(0, condition.Child(0)); } + // We can also eliminate any ending backtracking in the condition, as the condition + // is considered to be a positive lookahead, which is an atomic zero-width assertion. + condition = Child(0); + condition.EliminateEndingBacktracking(); + return this; } @@ -1954,7 +1977,8 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a while (true) { // Skip the successor down to the closest node that's guaranteed to follow it. - while (subsequent.ChildCount() > 0) + int childCount; + while ((childCount = subsequent.ChildCount()) > 0) { Debug.Assert(subsequent.Type != Group); switch (subsequent.Type) @@ -1972,6 +1996,7 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a } // If the two nodes don't agree on options in any way, don't try to optimize them. + // TODO: Remove this once https://github.com/dotnet/runtime/issues/61048 is implemented. if (node.Options != subsequent.Options) { return false; @@ -1979,18 +2004,22 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a // If the successor is an alternation, all of its children need to be evaluated, since any of them // could come after this node. If any of them fail the optimization, then the whole node fails. - if (subsequent.Type == Alternate) + // This applies to expression conditionals as well, as long as they have both a yes and a no branch (if there's + // only a yes branch, we'd need to also check whatever comes after the conditional). It doesn't apply to + // backreference conditionals, as the condition itself is unknown statically and could overlap with the + // loop being considered for atomicity. + switch (subsequent.Type) { - int childCount = subsequent.ChildCount(); - for (int i = 0; i < childCount; i++) - { - if (!CanBeMadeAtomic(node, subsequent.Child(i), allowSubsequentIteration)) + case Alternate: + case Testgroup when childCount == 3: // condition, yes, and no branch + for (int i = 0; i < childCount; i++) { - return false; + if (!CanBeMadeAtomic(node, subsequent.Child(i), allowSubsequentIteration)) + { + return false; + } } - } - - return true; + return true; } // If this node is a {one/notone/set}loop, see if it overlaps with its successor in the concatenation. @@ -2183,6 +2212,14 @@ public int ComputeMinLength() return min; } + case Testref: + // Minimum of its yes and no branches. The backreference doesn't add to the length. + return Math.Min(Child(0).ComputeMinLength(), Child(1).ComputeMinLength()); + + case Testgroup: + // Minimum of its yes and no branches. The condition is a zero-width assertion. + return Math.Min(Child(1).ComputeMinLength(), Child(2).ComputeMinLength()); + case Concatenate: // The sum of all of the concatenation's children. { @@ -2225,8 +2262,6 @@ public int ComputeMinLength() // a different structure, as they can't be added as part of a concatenation, since they overlap // with what comes after. case Ref: - case Testgroup: - case Testref: // Constructs requiring data at runtime from the matching pattern can't influence min length. return 0; diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs index 37a0fdb7c21ac..38cf72a3f5238 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs @@ -384,6 +384,18 @@ private static int GetMinRequiredLength(Regex r) [InlineData("(?(a)a)", "(?(a)a|)")] [InlineData("(?(abc)def)", "(?(abc)def|)")] [InlineData("(?(\\w)\\d)", "(?(\\w)\\d|)")] + // Loops inside alternation constructs + [InlineData("(abc*|def)ghi", "(ab(?>c*)|def)ghi")] + [InlineData("(abc|def*)ghi", "(abc|de(?>f*))ghi")] + [InlineData("(abc*|def*)ghi", "(ab(?>c*)|de(?>f*))ghi")] + [InlineData("(abc*|def*)", "(ab(?>c*)|de(?>f*))")] + [InlineData("(?(\\w)abc*|def*)ghi", "(?(\\w)ab(?>c*)|de(?>f*))ghi")] + [InlineData("(?(\\w)abc*|def*)", "(?(\\w)ab(?>c*)|de(?>f*))")] + [InlineData("(?(xyz*)abc|def)", "(?(xy(?>z*))abc|def)")] + [InlineData("(?(xyz*)abc|def)\\w", "(?(xy(?>z*))abc|def)\\w")] + // Loops followed by alternation constructs + [InlineData("a*(bcd|efg)", "(?>a*)(bcd|efg)")] + [InlineData("a*(?(xyz)bcd|efg)", "(?>a*)(?(xyz)bcd|efg)")] // Auto-atomicity [InlineData("a*b", "(?>a*)b")] [InlineData("a*b+", "(?>a*)(?>b+)")] @@ -499,6 +511,18 @@ public void PatternsReduceIdentically(string pattern1, string pattern2) [InlineData("(w+)+", "((?>w+))+")] [InlineData("(w{1,2})+", "((?>w{1,2}))+")] [InlineData("(?:ab|cd|ae)f", "(?>ab|cd|ae)f")] + // Loops inside alternation constructs + [InlineData("(abc*|def)chi", "(ab(?>c*)|def)chi")] + [InlineData("(abc|def*)fhi", "(abc|de(?>f*))fhi")] + [InlineData("(abc*|def*)\\whi", "(ab(?>c*)|de(?>f*))\\whi")] + [InlineData("(?(\\w)abc*|def*)\\whi", "(?(\\w)ab(?>c*)|de(?>f*))\\whi")] + // Loops followed by alternation constructs + [InlineData("a*(bcd|afg)", "(?>a*)(bcd|afg)")] + [InlineData("(a*)(?(1)bcd|efg)", "((?>a*))(?(1)bcd|efg)")] + [InlineData("a*(?(abc)bcd|efg)", "(?>a*)(?(abc)bcd|efg)")] + [InlineData("a*(?(xyz)acd|efg)", "(?>a*)(?(xyz)acd|efg)")] + [InlineData("a*(?(xyz)bcd|afg)", "(?>a*)(?(xyz)bcd|afg)")] + [InlineData("a*(?(xyz)bcd)", "(?>a*)(?(xyz)bcd)")] public void PatternsReduceDifferently(string pattern1, string pattern2) { string result1 = GetRegexCodes(new Regex(pattern1)); @@ -545,6 +569,20 @@ public void PatternsReduceDifferently(string pattern1, string pattern2) [InlineData(@"(YZ+|(WX+|(UV+|(ST+|(QR+|(OP+|(MN+|(KL+|(IJ+|(GH+|(EF+|(CD+|(AB+|(89+|(67+|(45+|(23+|(01+|(yz+|(wx+|(uv+|(st+|(qr+|(op+|(mn+|(kl+|(ij+|(gh+|(ef+|(de+|(a|bc+)))))))))))))))))))))))))))))))", 1)] [InlineData(@"a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(a(ab|cd+)|ef+)|gh+)|ij+)|kl+)|mn+)|op+)|qr+)|st+)|uv+)|wx+)|yz+)|01+)|23+)|45+)|67+)|89+)|AB+)|CD+)|EF+)|GH+)|IJ+)|KL+)|MN+)|OP+)|QR+)|ST+)|UV+)|WX+)|YZ+)", 3)] [InlineData(@"(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((a)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))", 1)] + [InlineData(@"(?(\d)\d{3}|\d)", 1)] + [InlineData(@"(?(\d{7})\d{3}|\d{2})", 2)] + [InlineData(@"(?(\d{7})\d{2}|\d{3})", 2)] + [InlineData(@"(?(\d)\d{3}|\d{2})", 2)] + [InlineData(@"(?(\d)|\d{2})", 0)] + [InlineData(@"(?(\d)\d{3})", 0)] + [InlineData(@"(abc)(?(1)\d{3}|\d{2})", 5)] + [InlineData(@"(abc)(?(1)\d{2}|\d{3})", 5)] + [InlineData(@"(abc)(?(1)|\d{2})", 3)] + [InlineData(@"(abc)(?(1)\d{3})", 3)] + [InlineData(@"(abc|)", 0)] + [InlineData(@"(|abc)", 0)] + [InlineData(@"(?(x)abc|)", 0)] + [InlineData(@"(?(x)|abc)", 0)] public void MinRequiredLengthIsCorrect(string pattern, int expectedLength) { var r = new Regex(pattern); From a8c1408084714a7db13db7eb5cae10b209d9c096 Mon Sep 17 00:00:00 2001 From: TobiasLaving <95348503+TobiasLaving@users.noreply.github.com> Date: Wed, 19 Jan 2022 16:04:02 +0100 Subject: [PATCH 055/308] Update runtime.json with manjaro information (#63338) Without specifying runtime on manjaro we cannot run the projects. FYI: Manjaro has a "ID_LIKE" param in os_release that has arch as input. Perhaps that would be another way forward. --- .../src/runtime.compatibility.json | 20 +++++++++++++++++++ .../src/runtime.json | 11 ++++++++++ .../src/runtimeGroups.props | 5 +++++ 3 files changed, 36 insertions(+) diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json index cbc3d322a87a9..25a7780058844 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json +++ b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json @@ -4328,6 +4328,26 @@ "any", "base" ], + "manjaro": [ + "manjaro", + "arch", + "linux", + "unix", + "any", + "base" + ], + "manjaro-x64": [ + "manjaro-x64", + "manjaro", + "arch-x64", + "arch", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], "ol": [ "ol", "rhel", diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json index b2070efde5b7c..f8c398707e0bb 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json +++ b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json @@ -1758,6 +1758,17 @@ "maccatalyst.14-x64" ] }, + "manjaro": { + "#import": [ + "arch" + ] + }, + "manjaro-x64": { + "#import": [ + "manjaro", + "arch-x64" + ] + }, "ol": { "#import": [ "rhel" diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props b/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props index b66931b24edf8..d1613c4345b31 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props +++ b/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props @@ -31,6 +31,11 @@ x64 + + arch + x64 + + any wasm From 8604989022950ef38f94b9150043b31d81f061a5 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Wed, 19 Jan 2022 17:49:39 +0200 Subject: [PATCH 056/308] [Group 5] Enable nullable annotations for `Microsoft.Extensions.Configuration.Json` (#63694) * Nullable enable --- .../ref/Microsoft.Extensions.Configuration.Json.cs | 4 ++-- .../ref/Microsoft.Extensions.Configuration.Json.csproj | 1 + .../src/JsonConfigurationExtensions.cs | 4 ++-- .../src/JsonConfigurationFileParser.cs | 6 +++--- .../src/Microsoft.Extensions.Configuration.Json.csproj | 1 + 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/ref/Microsoft.Extensions.Configuration.Json.cs b/src/libraries/Microsoft.Extensions.Configuration.Json/ref/Microsoft.Extensions.Configuration.Json.cs index b844fec6f2f7a..556870c199dcf 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/ref/Microsoft.Extensions.Configuration.Json.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/ref/Microsoft.Extensions.Configuration.Json.cs @@ -8,8 +8,8 @@ namespace Microsoft.Extensions.Configuration { public static partial class JsonConfigurationExtensions { - public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddJsonFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, Microsoft.Extensions.FileProviders.IFileProvider provider, string path, bool optional, bool reloadOnChange) { throw null; } - public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddJsonFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, System.Action configureSource) { throw null; } + public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddJsonFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, Microsoft.Extensions.FileProviders.IFileProvider? provider, string path, bool optional, bool reloadOnChange) { throw null; } + public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddJsonFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, System.Action? configureSource) { throw null; } public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddJsonFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string path) { throw null; } public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddJsonFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string path, bool optional) { throw null; } public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddJsonFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) { throw null; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/ref/Microsoft.Extensions.Configuration.Json.csproj b/src/libraries/Microsoft.Extensions.Configuration.Json/ref/Microsoft.Extensions.Configuration.Json.csproj index 195538be004ea..d6c79dcac206b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/ref/Microsoft.Extensions.Configuration.Json.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/ref/Microsoft.Extensions.Configuration.Json.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) + enable diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationExtensions.cs index e5cc31af1289e..bf3a83cbad455 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationExtensions.cs @@ -62,7 +62,7 @@ public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder build /// Whether the file is optional. /// Whether the configuration should be reloaded if the file changes. /// The . - public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) + public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, IFileProvider? provider, string path, bool optional, bool reloadOnChange) { if (builder == null) { @@ -89,7 +89,7 @@ public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder build /// The to add to. /// Configures the source. /// The . - public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, Action configureSource) + public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, Action? configureSource) => builder.Add(configureSource); /// diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationFileParser.cs b/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationFileParser.cs index 2104b66ea66c4..077ead2b51108 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationFileParser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationFileParser.cs @@ -13,13 +13,13 @@ internal sealed class JsonConfigurationFileParser { private JsonConfigurationFileParser() { } - private readonly Dictionary _data = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _data = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Stack _paths = new Stack(); - public static IDictionary Parse(Stream input) + public static IDictionary Parse(Stream input) => new JsonConfigurationFileParser().ParseStream(input); - private IDictionary ParseStream(Stream input) + private IDictionary ParseStream(Stream input) { var jsonDocumentOptions = new JsonDocumentOptions { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/src/Microsoft.Extensions.Configuration.Json.csproj b/src/libraries/Microsoft.Extensions.Configuration.Json/src/Microsoft.Extensions.Configuration.Json.csproj index ad2b4ea3c1f82..61be4beedfb22 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/src/Microsoft.Extensions.Configuration.Json.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/src/Microsoft.Extensions.Configuration.Json.csproj @@ -2,6 +2,7 @@ $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.1;netstandard2.0;$(NetFrameworkMinimum) + enable true true From df049b9a23c5182bf7f26f224b69bf1f47f9dc2f Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Wed, 19 Jan 2022 09:26:30 -0700 Subject: [PATCH 057/308] Disable 2 SMTP tests on checked runtime (#63947) --- .../System.Net.Mail/tests/Functional/SmtpClientTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs index bd0fb5298432d..ecdbdede4315d 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs @@ -341,7 +341,7 @@ public void TestZeroTimeout() [InlineData("howdydoo")] [InlineData("")] [InlineData(null)] - [SkipOnCoreClr("System.Net.Tests are flaky and/or long running: https://github.com/dotnet/runtime/issues/131", RuntimeConfiguration.Checked)] + [SkipOnCoreClr("System.Net.Tests are flaky and/or long running: https://github.com/dotnet/runtime/issues/131", ~RuntimeConfiguration.Release)] [ActiveIssue("https://github.com/dotnet/runtime/issues/131", TestRuntimes.Mono)] // System.Net.Tests are flaky and/or long running public async Task TestMailDeliveryAsync(string body) { @@ -360,7 +360,7 @@ public async Task TestMailDeliveryAsync(string body) [Fact] [PlatformSpecific(TestPlatforms.Windows)] // NTLM support required, see https://github.com/dotnet/runtime/issues/25827 - [SkipOnCoreClr("System.Net.Tests are flaky and/or long running: https://github.com/dotnet/runtime/issues/131", RuntimeConfiguration.Checked)] + [SkipOnCoreClr("System.Net.Tests are flaky and/or long running: https://github.com/dotnet/runtime/issues/131", ~RuntimeConfiguration.Release)] [ActiveIssue("https://github.com/dotnet/runtime/issues/131", TestRuntimes.Mono)] // System.Net.Tests are flaky and/or long running public async Task TestCredentialsCopyInAsyncContext() { From bbbfba31b61a2299c434172f709716325c073ef8 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 19 Jan 2022 12:27:25 -0500 Subject: [PATCH 058/308] Use IndexOf in StringBuilder.Replace(char, char) (#63913) --- .../src/System/Text/StringBuilder.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs index 5957628a6ac84..1f58c7185f6c6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs @@ -2063,13 +2063,16 @@ public StringBuilder Replace(char oldChar, char newChar, int startIndex, int cou { int curInChunk = Math.Max(startIndexInChunk, 0); int endInChunk = Math.Min(chunk.m_ChunkLength, endIndexInChunk); - while (curInChunk < endInChunk) + + Span span = chunk.m_ChunkChars.AsSpan(curInChunk, endInChunk - curInChunk); + int i; + while ((i = span.IndexOf(oldChar)) >= 0) { - if (chunk.m_ChunkChars[curInChunk] == oldChar) - chunk.m_ChunkChars[curInChunk] = newChar; - curInChunk++; + span[i] = newChar; + span = span.Slice(i + 1); } } + if (startIndexInChunk >= 0) { break; From 12f434db114e629854e7d5eb966e07d24e243712 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Wed, 19 Jan 2022 20:42:27 +0200 Subject: [PATCH 059/308] Fix for Werror=use-after-free in PAL (#63954) * Fix for Werror=use-after-free in PAL * Delete Local{Alloc,Free} * Delete LMEM_* macros * Delete PAL_dladdr --- .../dlls/mscordac/mscordac_unixexports.src | 2 - src/coreclr/inc/bbsweep.h | 4 - src/coreclr/inc/holder.h | 9 +- src/coreclr/pal/inc/pal.h | 22 +---- src/coreclr/pal/src/CMakeLists.txt | 2 - src/coreclr/pal/src/include/pal/modulename.h | 35 ------- src/coreclr/pal/src/loader/module.cpp | 12 ++- src/coreclr/pal/src/loader/modulename.cpp | 68 -------------- src/coreclr/pal/src/memory/local.cpp | 93 ------------------- src/coreclr/pal/src/misc/fmtmessage.cpp | 14 +-- src/coreclr/pal/tests/palsuite/CMakeLists.txt | 3 - .../pal/tests/palsuite/compilableTests.txt | 3 - .../LocalAlloc/test1/LocalAlloc.cpp | 48 ---------- .../LocalFree/test1/LocalFree.cpp | 48 ---------- .../LocalFree/test2/LocalFree.cpp | 38 -------- .../FormatMessageW/test6/test.cpp | 20 ++-- .../pal/tests/palsuite/paltestlist.txt | 3 - 17 files changed, 35 insertions(+), 389 deletions(-) delete mode 100644 src/coreclr/pal/src/include/pal/modulename.h delete mode 100644 src/coreclr/pal/src/loader/modulename.cpp delete mode 100644 src/coreclr/pal/src/memory/local.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/LocalAlloc.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/LocalFree.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/LocalFree.cpp diff --git a/src/coreclr/dlls/mscordac/mscordac_unixexports.src b/src/coreclr/dlls/mscordac/mscordac_unixexports.src index a518b2dca2c8c..334d1b90c9308 100644 --- a/src/coreclr/dlls/mscordac/mscordac_unixexports.src +++ b/src/coreclr/dlls/mscordac/mscordac_unixexports.src @@ -139,8 +139,6 @@ nativeStringResourceTable_mscorrc #LoadLibraryA #LoadLibraryW #LoadLibraryExW -#LocalAlloc -#LocalFree #MapViewOfFile #MapViewOfFileEx #MoveFileExW diff --git a/src/coreclr/inc/bbsweep.h b/src/coreclr/inc/bbsweep.h index eda1e11d2f2e1..4e3636681e4e4 100644 --- a/src/coreclr/inc/bbsweep.h +++ b/src/coreclr/inc/bbsweep.h @@ -31,11 +31,9 @@ #pragma push_macro("SetEvent") #pragma push_macro("ResetEvent") #pragma push_macro("ReleaseSemaphore") -#pragma push_macro("LocalFree") #undef SetEvent #undef ResetEvent #undef ReleaseSemaphore -#undef LocalFree // MAX_COUNT is the maximal number of runtime processes that can run at a given time #define MAX_COUNT 20 @@ -299,7 +297,6 @@ class BBSweep if (pSD) delete [] ((char *) pSD); if (pAdminSid) FreeSid(pAdminSid); if (hToken) CloseHandle(hToken); - if (pACL) LocalFree(pACL); if (buffer) delete [] ((char *) buffer); #endif } @@ -416,7 +413,6 @@ class BBSweep HANDLE hBBSweepThread; // a handle to the CLR sweeper thread (that calls watch for sweep events) }; -#pragma pop_macro("LocalFree") #pragma pop_macro("ReleaseSemaphore") #pragma pop_macro("ResetEvent") #pragma pop_macro("SetEvent") diff --git a/src/coreclr/inc/holder.h b/src/coreclr/inc/holder.h index 448610634a612..4ec7b106cc0e8 100644 --- a/src/coreclr/inc/holder.h +++ b/src/coreclr/inc/holder.h @@ -1152,7 +1152,14 @@ FORCEINLINE void HolderFreeLibrary(HMODULE h) { FreeLibrary(h); } typedef Wrapper, HolderFreeLibrary, NULL> HModuleHolder; template FORCEINLINE -void DoLocalFree(T* pMem) { (LocalFree)((HLOCAL)pMem); } +void DoLocalFree(T* pMem) +{ +#ifdef HOST_WINDOWS + (LocalFree)((void*)pMem); +#else + (free)((void*)pMem); +#endif +} template using LocalAllocHolder = SpecializedWrapper<_TYPE, DoLocalFree<_TYPE>>; diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index 8f8ab50ed9a52..db22c68fde053 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -2844,24 +2844,6 @@ VirtualQuery( #define FillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) #define ZeroMemory(Destination,Length) memset((Destination),0,(Length)) -#define LMEM_FIXED 0x0000 -#define LMEM_MOVEABLE 0x0002 -#define LMEM_ZEROINIT 0x0040 -#define LPTR (LMEM_FIXED | LMEM_ZEROINIT) - -PALIMPORT -HLOCAL -PALAPI -LocalAlloc( - IN UINT uFlags, - IN SIZE_T uBytes); - -PALIMPORT -HLOCAL -PALAPI -LocalFree( - IN HLOCAL hMem); - PALIMPORT BOOL PALAPI @@ -3263,8 +3245,8 @@ FORCEINLINE void PAL_ArmInterlockedOperationBarrier() Function: InterlockedAdd -The InterlockedAdd function adds the value of the specified variable -with another specified value. The function prevents more than one thread +The InterlockedAdd function adds the value of the specified variable +with another specified value. The function prevents more than one thread from using the same variable simultaneously. Parameters diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt index afab5e6518455..a9beb759b892f 100644 --- a/src/coreclr/pal/src/CMakeLists.txt +++ b/src/coreclr/pal/src/CMakeLists.txt @@ -143,14 +143,12 @@ set(SOURCES init/pal.cpp init/sxs.cpp loader/module.cpp - loader/modulename.cpp locale/unicode.cpp locale/unicodedata.cpp locale/utf8.cpp map/common.cpp map/map.cpp map/virtual.cpp - memory/local.cpp misc/cgroup.cpp misc/dbgmsg.cpp misc/environ.cpp diff --git a/src/coreclr/pal/src/include/pal/modulename.h b/src/coreclr/pal/src/include/pal/modulename.h deleted file mode 100644 index 87d54b77a5b95..0000000000000 --- a/src/coreclr/pal/src/include/pal/modulename.h +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*++ - - - -Module Name: - - include/pal/modulename.h - -Abstract: - Header file for functions to get the name of a module - -Revision History: - - - ---*/ - -#ifndef _PAL_MODULENAME_H_ -#define _PAL_MODULENAME_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif // __cplusplus - -const char *PAL_dladdr(LPVOID ProcAddress); - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif /*_PAL_MODULENAME_H_*/ diff --git a/src/coreclr/pal/src/loader/module.cpp b/src/coreclr/pal/src/loader/module.cpp index e792f75a2b22e..2a559b56e2bef 100644 --- a/src/coreclr/pal/src/loader/module.cpp +++ b/src/coreclr/pal/src/loader/module.cpp @@ -30,7 +30,6 @@ SET_DEFAULT_DEBUG_CHANNEL(LOADER); // some headers have code with asserts, so do #include "pal/file.h" #include "pal/utils.h" #include "pal/init.h" -#include "pal/modulename.h" #include "pal/environ.h" #include "pal/virtual.h" #include "pal/map.hpp" @@ -342,9 +341,10 @@ GetProcAddress( /* if we don't know the module's full name yet, this is our chance to obtain it */ if (!module->lib_name && module->dl_handle) { - const char* libName = PAL_dladdr((LPVOID)ProcAddress); - if (libName) + Dl_info dl_info; + if (dladdr((LPVOID)ProcAddress, &dl_info) != 0) { + const char* libName = dl_info.dli_fname; module->lib_name = UTIL_MBToWC_Alloc(libName, -1); if (nullptr == module->lib_name) { @@ -356,6 +356,10 @@ GetProcAddress( module, libName); } } + else + { + TRACE("GetProcAddress: dladdr() call failed!\n"); + } } } else @@ -925,7 +929,7 @@ struct CopyModuleDataParam int result; }; -void handle_image_range(uint8_t* source_start, size_t size, struct CopyModuleDataParam* param) +void handle_image_range(uint8_t* source_start, size_t size, struct CopyModuleDataParam* param) { uint8_t* source_end = source_start + size; if (param->destination_buffer_start != NULL) diff --git a/src/coreclr/pal/src/loader/modulename.cpp b/src/coreclr/pal/src/loader/modulename.cpp deleted file mode 100644 index 40c1c6de5c3d6..0000000000000 --- a/src/coreclr/pal/src/loader/modulename.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*++ - - - -Module Name: - - modulename.cpp - -Abstract: - - Implementation of internal functions to get module names - - - ---*/ - -#include "pal/thread.hpp" -#include "pal/malloc.hpp" -#include "pal/palinternal.h" -#include "pal/dbgmsg.h" -#include "pal/modulename.h" - -#include - -using namespace CorUnix; - -SET_DEFAULT_DEBUG_CHANNEL(LOADER); - -/*++ - PAL_dladdr - - Internal wrapper for dladder used only to get module name - -Parameters: - LPVOID ProcAddress: a pointer to a function in a shared library - -Return value: - Pointer to string with the fullpath to the shared library containing - ProcAddress. - - NULL if error occurred. - -Notes: - The string returned by this function is owned by the OS. - If you need to keep it, strdup() it, because it is unknown how long - this ptr will point at the string you want (over the lifetime of - the system running) It is only safe to use it immediately after calling - this function. ---*/ -const char *PAL_dladdr(LPVOID ProcAddress) -{ - Dl_info dl_info; - if (!dladdr(ProcAddress, &dl_info)) - { - WARN("dladdr() call failed!\n"); - /* If we get an error, return NULL */ - return (NULL); - } - else - { - /* Return the module name */ - return dl_info.dli_fname; - } -} - diff --git a/src/coreclr/pal/src/memory/local.cpp b/src/coreclr/pal/src/memory/local.cpp deleted file mode 100644 index fc62ef428b1e2..0000000000000 --- a/src/coreclr/pal/src/memory/local.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*++ - - - -Module Name: - - local.c - -Abstract: - - Implementation of local memory management functions. - -Revision History: - - - ---*/ - -#include "pal/palinternal.h" -#include "pal/dbgmsg.h" - - -SET_DEFAULT_DEBUG_CHANNEL(MEM); - - -/*++ -Function: - LocalAlloc - -See MSDN doc. ---*/ -HLOCAL -PALAPI -LocalAlloc( - IN UINT uFlags, - IN SIZE_T uBytes) -{ - LPVOID lpRetVal = NULL; - PERF_ENTRY(LocalAlloc); - ENTRY("LocalAlloc (uFlags=%#x, uBytes=%u)\n", uFlags, uBytes); - - if ((uFlags & ~LMEM_ZEROINIT) != 0) - { - ASSERT("Invalid parameter AllocFlags=0x%x\n", uFlags); - SetLastError(ERROR_INVALID_PARAMETER); - goto done; - } - - lpRetVal = PAL_malloc(uBytes); - - if (lpRetVal == NULL) - { - ERROR("Not enough memory\n"); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto done; - } - - if ((uFlags & LMEM_ZEROINIT) != 0) - { - memset(lpRetVal, 0, uBytes); - } - -done: - LOGEXIT( "LocalAlloc returning %p.\n", lpRetVal ); - PERF_EXIT(LocalAlloc); - return (HLOCAL) lpRetVal; -} - -/*++ -Function: - LocalFree - -See MSDN doc. ---*/ -HLOCAL -PALAPI -LocalFree( - IN HLOCAL hMem) -{ - BOOL bRetVal = FALSE; - PERF_ENTRY(LocalFree); - ENTRY("LocalFree (hmem=%p)\n", hMem); - - free(hMem); - bRetVal = TRUE; - - LOGEXIT( "LocalFree returning %p.\n", bRetVal == TRUE ? (HLOCAL)NULL : hMem ); - PERF_EXIT(LocalFree); - return bRetVal == TRUE ? (HLOCAL)NULL : hMem; -} diff --git a/src/coreclr/pal/src/misc/fmtmessage.cpp b/src/coreclr/pal/src/misc/fmtmessage.cpp index 81502bfc7722e..e9d87d19c4a08 100644 --- a/src/coreclr/pal/src/misc/fmtmessage.cpp +++ b/src/coreclr/pal/src/misc/fmtmessage.cpp @@ -63,7 +63,7 @@ static LPWSTR FMTMSG_GetMessageString( DWORD dwErrCode ) allocChars = MAX_ERROR_STRING_LENGTH + 1; } - LPWSTR lpRetVal = (LPWSTR)LocalAlloc(LMEM_FIXED, allocChars * sizeof(WCHAR)); + LPWSTR lpRetVal = (LPWSTR)PAL_malloc(allocChars * sizeof(WCHAR)); if (lpRetVal) { @@ -135,7 +135,7 @@ static INT FMTMSG__watoi( LPWSTR str ) UINT NumOfBytes = 0; \ nSize *= 2; \ NumOfBytes = nSize * sizeof( WCHAR ); \ - lpTemp = static_cast( LocalAlloc( LMEM_FIXED, NumOfBytes ) ); \ + lpTemp = static_cast( PAL_malloc( NumOfBytes ) ); \ TRACE( "Growing the buffer.\n" );\ \ if ( !lpTemp ) \ @@ -149,7 +149,7 @@ static INT FMTMSG__watoi( LPWSTR str ) \ *lpWorkingString = '\0';\ PAL_wcscpy( lpTemp, lpReturnString );\ - LocalFree( lpReturnString ); \ + free( lpReturnString ); \ lpWorkingString = lpReturnString = lpTemp; \ lpWorkingString += nCount; \ } \ @@ -341,7 +341,7 @@ FormatMessageW( /* Parameter processing. */ if ( dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER ) { - TRACE( "Allocated %d TCHARs. Don't forget to call LocalFree to " + TRACE( "Allocated %d TCHARs. Don't forget to call free to " "free the memory when done.\n", nSize ); bIsLocalAlloced = TRUE; } @@ -418,7 +418,7 @@ FormatMessageW( } lpWorkingString = static_cast( - LocalAlloc( LMEM_FIXED, nSize * sizeof( WCHAR ) ) ); + PAL_malloc( nSize * sizeof( WCHAR ) ) ); if ( !lpWorkingString ) { ERROR( "Unable to allocate memory for the working string.\n" ); @@ -675,14 +675,14 @@ FormatMessageW( { TRACE( "Copying the string into the buffer.\n" ); PAL_wcsncpy( lpBuffer, lpReturnString, nCount + 1 ); - LocalFree( lpReturnString ); + free( lpReturnString ); } } else /* Error, something occurred. */ { if ( lpReturnString ) { - LocalFree( lpReturnString ); + free( lpReturnString ); } } LOGEXIT( "FormatMessageW returns %d.\n", nCount ); diff --git a/src/coreclr/pal/tests/palsuite/CMakeLists.txt b/src/coreclr/pal/tests/palsuite/CMakeLists.txt index d7b3faca6b366..f14b2442afa78 100644 --- a/src/coreclr/pal/tests/palsuite/CMakeLists.txt +++ b/src/coreclr/pal/tests/palsuite/CMakeLists.txt @@ -580,9 +580,6 @@ add_executable_clr(paltests # filemapping_memmgt/GetProcAddress/test1/testlib.cpp filemapping_memmgt/GetProcAddress/test2/test2.cpp # filemapping_memmgt/GetProcAddress/test2/testlib.cpp - filemapping_memmgt/LocalAlloc/test1/LocalAlloc.cpp - filemapping_memmgt/LocalFree/test1/LocalFree.cpp - filemapping_memmgt/LocalFree/test2/LocalFree.cpp filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.cpp filemapping_memmgt/MapViewOfFile/test2/MapViewOfFile.cpp filemapping_memmgt/MapViewOfFile/test3/MapViewOfFile.cpp diff --git a/src/coreclr/pal/tests/palsuite/compilableTests.txt b/src/coreclr/pal/tests/palsuite/compilableTests.txt index df727bc277be4..a7e27f9228976 100644 --- a/src/coreclr/pal/tests/palsuite/compilableTests.txt +++ b/src/coreclr/pal/tests/palsuite/compilableTests.txt @@ -486,9 +486,6 @@ filemapping_memmgt/GetModuleFileNameW/test1/paltest_getmodulefilenamew_test1 filemapping_memmgt/GetModuleFileNameW/test2/paltest_getmodulefilenamew_test2 filemapping_memmgt/GetProcAddress/test1/paltest_getprocaddress_test1 filemapping_memmgt/GetProcAddress/test2/paltest_getprocaddress_test2 -filemapping_memmgt/LocalAlloc/test1/paltest_localalloc_test1 -filemapping_memmgt/LocalFree/test1/paltest_localfree_test1 -filemapping_memmgt/LocalFree/test2/paltest_localfree_test2 filemapping_memmgt/MapViewOfFile/test1/paltest_mapviewoffile_test1 filemapping_memmgt/MapViewOfFile/test2/paltest_mapviewoffile_test2 filemapping_memmgt/MapViewOfFile/test3/paltest_mapviewoffile_test3 diff --git a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/LocalAlloc.cpp b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/LocalAlloc.cpp deleted file mode 100644 index 5879ed598071a..0000000000000 --- a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/LocalAlloc.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================= -** -** Source: LocalAlloc.c -** -** Purpose: Positive test the LocalAlloc API. -** Call LocalAlloc with zero as the allocation attribute -** -** -**============================================================*/ -#include - -PALTEST(filemapping_memmgt_LocalAlloc_test1_paltest_localalloc_test1, "filemapping_memmgt/LocalAlloc/test1/paltest_localalloc_test1") -{ - HLOCAL LocalHeap; - HLOCAL FreeHeap; - int err; - const SIZE_T heapSize = 64; - - /*Initialize the PAL environment*/ - err = PAL_Initialize(argc, argv); - if(0 != err) - { - return FAIL; - } - - /*Allocate the specified number of bytes from the heap*/ - /*with allocation attribute: zero which is required by PAL Doc*/ - LocalHeap = LocalAlloc(0, heapSize); - if(!LocalHeap) - { - Fail("\nFailed to call LocalAlloc API, " - "error code=%u\n", GetLastError()); - } - - /*Free the allocated local heap memory*/ - FreeHeap = LocalFree(LocalHeap); - if(FreeHeap) - { - Fail("Failed to call LocalFree API, " - "error code=%u\n", GetLastError()); - } - - PAL_Terminate(); - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/LocalFree.cpp b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/LocalFree.cpp deleted file mode 100644 index 0fcb32d6fc96f..0000000000000 --- a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/LocalFree.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================= -** -** Source: LocalFree.c -** -** Purpose: Positive test the LocalFree API. -** Call LocalFree to free a specified local memory object -** -** -**============================================================*/ -#include - -PALTEST(filemapping_memmgt_LocalFree_test1_paltest_localfree_test1, "filemapping_memmgt/LocalFree/test1/paltest_localfree_test1") -{ - HLOCAL LocalHeap; - HLOCAL FreeHeap; - int err; - const SIZE_T heapSize = 64; - - /*Initialize the PAL environment*/ - err = PAL_Initialize(argc, argv); - if(0 != err) - { - return FAIL; - } - - /*Allocate the specified number of bytes from the heap*/ - /*with zero ad the allocation attribute*/ - LocalHeap = LocalAlloc(0, heapSize); - if(!LocalHeap) - { - Fail("\nFailed to call LocalAlloc API, " - "error code=%u\n", GetLastError()); - } - - /*Free the allocated local heap memory*/ - FreeHeap = LocalFree(LocalHeap); - if(FreeHeap) - { - Fail("Failed to call LocalFree API, " - "error code=%u\n", GetLastError()); - } - - PAL_Terminate(); - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/LocalFree.cpp b/src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/LocalFree.cpp deleted file mode 100644 index 5d66077a2cfd7..0000000000000 --- a/src/coreclr/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/LocalFree.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. - -/*============================================================= -** -** Source: LocalFree.c -** -** Purpose: Positive test the LocalFree API. -** call LocalFree by passing NULL as local memory -** object handle -** -** -**============================================================*/ -#include - -PALTEST(filemapping_memmgt_LocalFree_test2_paltest_localfree_test2, "filemapping_memmgt/LocalFree/test2/paltest_localfree_test2") -{ - HLOCAL FreeHeap; - int err; - - /*Initialize the PAL environment*/ - err = PAL_Initialize(argc, argv); - if(0 != err) - { - return FAIL; - } - - /*call LocalFree by passing NULL as local memory object handle*/ - FreeHeap = LocalFree(NULL); - if(FreeHeap) - { - Fail("Failed to call LocalFree API, " - "error code=%u\n", GetLastError()); - } - - PAL_Terminate(); - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/test.cpp b/src/coreclr/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/test.cpp index b16b0ea27754e..15d94411bb030 100644 --- a/src/coreclr/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/test.cpp +++ b/src/coreclr/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/test.cpp @@ -36,9 +36,9 @@ PALTEST(miscellaneous_FormatMessageW_test6_paltest_formatmessagew_test6, "miscel the error message it extracts is correct, only that it does place some information into the buffer when it is called. */ - + /* - + ERROR_SUCCESS (0L) is normally returned by GetLastError, But, the ERROR_SUCCESS is removed from messages for Unix based Systems To ensure that we have some information into the buffer we are using the message @@ -54,25 +54,25 @@ PALTEST(miscellaneous_FormatMessageW_test6_paltest_formatmessagew_test6, "miscel 0, /* maximum size of message buffer */ NULL /* array of message inserts */ ); - - if(ReturnResult == 0) + + if(ReturnResult == 0) { Fail("ERROR: The return value was 0, which indicates failure. The " "function failed when trying to Format a FROM_SYSTEM message."); } - - if(wcslen(OutBuffer) <= 0) + + if(wcslen(OutBuffer) <= 0) { Fail("ERROR: There are no characters in the buffer, and when the " "FORMAT_MESSAGE_FROM_SYSTEM flag is used with ERROR_FILE_NOT_FOUND error, " "something should be put into the buffer."); } - - LocalFree(OutBuffer); - + + free(OutBuffer); + PAL_Terminate(); return PASS; - + } diff --git a/src/coreclr/pal/tests/palsuite/paltestlist.txt b/src/coreclr/pal/tests/palsuite/paltestlist.txt index 514cd52f1a590..2afdf101d5b68 100644 --- a/src/coreclr/pal/tests/palsuite/paltestlist.txt +++ b/src/coreclr/pal/tests/palsuite/paltestlist.txt @@ -448,9 +448,6 @@ filemapping_memmgt/CreateFileMappingW/test9/paltest_createfilemappingw_test9 filemapping_memmgt/FreeLibrary/test2/paltest_freelibrary_test2 filemapping_memmgt/GetModuleFileNameA/test2/paltest_getmodulefilenamea_test2 filemapping_memmgt/GetModuleFileNameW/test2/paltest_getmodulefilenamew_test2 -filemapping_memmgt/LocalAlloc/test1/paltest_localalloc_test1 -filemapping_memmgt/LocalFree/test1/paltest_localfree_test1 -filemapping_memmgt/LocalFree/test2/paltest_localfree_test2 filemapping_memmgt/MapViewOfFile/test1/paltest_mapviewoffile_test1 filemapping_memmgt/MapViewOfFile/test2/paltest_mapviewoffile_test2 filemapping_memmgt/MapViewOfFile/test3/paltest_mapviewoffile_test3 From 67848f23d51562bd2e54f6490f5aad22f57baffe Mon Sep 17 00:00:00 2001 From: Brennan Date: Wed, 19 Jan 2022 11:01:24 -0800 Subject: [PATCH 060/308] [RateLimiting] Dequeue items when queuing with NewestFirst (#63377) --- .../RateLimiting/ConcurrencyLimiter.cs | 23 ++++- .../RateLimiting/TokenBucketRateLimiter.cs | 23 ++++- .../tests/BaseRateLimiterTests.cs | 14 ++- .../tests/ConcurrencyLimiterTests.cs | 91 ++++++++++++++++- .../tests/TokenBucketRateLimiterTests.cs | 97 ++++++++++++++++++- 5 files changed, 235 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index 4ef7a3b721e4d..74ef7ec9e890b 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -95,10 +95,27 @@ protected override ValueTask WaitAsyncCore(int permitCount, Canc return new ValueTask(lease); } - // Don't queue if queue limit reached - if (_queueCount + permitCount > _options.QueueLimit) + // Avoid integer overflow by using subtraction instead of addition + Debug.Assert(_options.QueueLimit >= _queueCount); + if (_options.QueueLimit - _queueCount < permitCount) { - return new ValueTask(QueueLimitLease); + if (_options.QueueProcessingOrder == QueueProcessingOrder.NewestFirst && permitCount <= _options.QueueLimit) + { + // remove oldest items from queue until there is space for the newest request + do + { + RequestRegistration oldestRequest = _queue.DequeueHead(); + _queueCount -= oldestRequest.Count; + Debug.Assert(_queueCount >= 0); + oldestRequest.Tcs.TrySetResult(FailedLease); + } + while (_options.QueueLimit - _queueCount < permitCount); + } + else + { + // Don't queue if queue limit reached and QueueProcessingOrder is OldestFirst + return new ValueTask(QueueLimitLease); + } } TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index bb1ec82f3fff0..6593d895a6810 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -101,10 +101,27 @@ protected override ValueTask WaitAsyncCore(int tokenCount, Cance return new ValueTask(lease); } - // Don't queue if queue limit reached - if (_queueCount + tokenCount > _options.QueueLimit) + // Avoid integer overflow by using subtraction instead of addition + Debug.Assert(_options.QueueLimit >= _queueCount); + if (_options.QueueLimit - _queueCount < tokenCount) { - return new ValueTask(CreateFailedTokenLease(tokenCount)); + if (_options.QueueProcessingOrder == QueueProcessingOrder.NewestFirst && tokenCount <= _options.QueueLimit) + { + // remove oldest items from queue until there is space for the newest acquisition request + do + { + RequestRegistration oldestRequest = _queue.DequeueHead(); + _queueCount -= oldestRequest.Count; + Debug.Assert(_queueCount >= 0); + oldestRequest.Tcs.TrySetResult(FailedLease); + } + while (_options.QueueLimit - _queueCount < tokenCount); + } + else + { + // Don't queue if queue limit reached and QueueProcessingOrder is OldestFirst + return new ValueTask(CreateFailedTokenLease(tokenCount)); + } } TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); diff --git a/src/libraries/System.Threading.RateLimiting/tests/BaseRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/BaseRateLimiterTests.cs index 9d98a5101a33b..a96dc0ba86e63 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/BaseRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/BaseRateLimiterTests.cs @@ -24,11 +24,23 @@ public abstract class BaseRateLimiterTests public abstract Task CanAcquireResourceAsync_QueuesAndGrabsNewest(); [Fact] - public abstract Task FailsWhenQueuingMoreThanLimit(); + public abstract Task FailsWhenQueuingMoreThanLimit_OldestFirst(); + + [Fact] + public abstract Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst(); + + [Fact] + public abstract Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFirst(); + + [Fact] + public abstract Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimitAndNoAvailability_NewestFirst(); [Fact] public abstract Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAvailable(); + [Fact] + public abstract Task LargeAcquiresAndQueuesDoNotIntegerOverflow(); + [Fact] public abstract void ThrowsWhenAcquiringMoreThanLimit(); diff --git a/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs index 22658e07a5c9c..da041ac938aa2 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/ConcurrencyLimiterTests.cs @@ -94,9 +94,9 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() } [Fact] - public override async Task FailsWhenQueuingMoreThanLimit() + public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() { - var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); using var lease = limiter.Acquire(1); var wait = limiter.WaitAsync(1); @@ -105,11 +105,96 @@ public override async Task FailsWhenQueuingMoreThanLimit() } [Fact] - public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAvailable() + public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() { var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)); var lease = limiter.Acquire(1); var wait = limiter.WaitAsync(1); + Assert.False(wait.IsCompleted); + + var wait2 = limiter.WaitAsync(1); + var lease1 = await wait; + Assert.False(lease1.IsAcquired); + Assert.False(wait2.IsCompleted); + + lease.Dispose(); + + lease = await wait2; + Assert.True(lease.IsAcquired); + } + + [Fact] + public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFirst() + { + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2)); + var lease = limiter.Acquire(2); + Assert.True(lease.IsAcquired); + var wait = limiter.WaitAsync(1); + Assert.False(wait.IsCompleted); + + var wait2 = limiter.WaitAsync(1); + Assert.False(wait2.IsCompleted); + + var wait3 = limiter.WaitAsync(2); + var lease1 = await wait; + var lease2 = await wait2; + Assert.False(lease1.IsAcquired); + Assert.False(lease2.IsAcquired); + Assert.False(wait3.IsCompleted); + + lease.Dispose(); + + lease = await wait3; + Assert.True(lease.IsAcquired); + } + + [Fact] + public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimitAndNoAvailability_NewestFirst() + { + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(2, QueueProcessingOrder.NewestFirst, 1)); + var lease = limiter.Acquire(2); + Assert.True(lease.IsAcquired); + + // Fill queue + var wait = limiter.WaitAsync(1); + Assert.False(wait.IsCompleted); + + var lease1 = await limiter.WaitAsync(2); + Assert.False(lease1.IsAcquired); + + lease.Dispose(); + var lease2 = await wait; + Assert.True(lease2.IsAcquired); + } + + [Fact] + public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() + { + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(int.MaxValue, QueueProcessingOrder.NewestFirst, int.MaxValue)); + var lease = limiter.Acquire(int.MaxValue); + Assert.True(lease.IsAcquired); + + // Fill queue + var wait = limiter.WaitAsync(3); + Assert.False(wait.IsCompleted); + + var wait2 = limiter.WaitAsync(int.MaxValue); + Assert.False(wait2.IsCompleted); + + var lease1 = await wait; + Assert.False(lease1.IsAcquired); + + lease.Dispose(); + var lease2 = await wait2; + Assert.True(lease2.IsAcquired); + } + + [Fact] + public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAvailable() + { + var limiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1)); + var lease = limiter.Acquire(1); + var wait = limiter.WaitAsync(1); var failedLease = await limiter.WaitAsync(1); Assert.False(failedLease.IsAcquired); diff --git a/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs b/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs index edf05bfe15cce..594bb79be22eb 100644 --- a/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs +++ b/src/libraries/System.Threading.RateLimiting/tests/TokenBucketRateLimiterTests.cs @@ -111,9 +111,9 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() } [Fact] - public override async Task FailsWhenQueuingMoreThanLimit() + public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() { - var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, TimeSpan.Zero, 1, autoReplenishment: false)); using var lease = limiter.Acquire(1); var wait = limiter.WaitAsync(1); @@ -125,9 +125,77 @@ public override async Task FailsWhenQueuingMoreThanLimit() } [Fact] - public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAvailable() + public override async Task DropsOldestWhenQueuingMoreThanLimit_NewestFirst() { var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1, + TimeSpan.Zero, 1, autoReplenishment: false)); + var lease = limiter.Acquire(1); + var wait = limiter.WaitAsync(1); + Assert.False(wait.IsCompleted); + + var wait2 = limiter.WaitAsync(1); + var lease1 = await wait; + Assert.False(lease1.IsAcquired); + Assert.False(wait2.IsCompleted); + + limiter.TryReplenish(); + + lease = await wait2; + Assert.True(lease.IsAcquired); + } + + [Fact] + public override async Task DropsMultipleOldestWhenQueuingMoreThanLimit_NewestFirst() + { + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 2, + TimeSpan.Zero, 1, autoReplenishment: false)); + var lease = limiter.Acquire(2); + Assert.True(lease.IsAcquired); + var wait = limiter.WaitAsync(1); + Assert.False(wait.IsCompleted); + + var wait2 = limiter.WaitAsync(1); + Assert.False(wait2.IsCompleted); + + var wait3 = limiter.WaitAsync(2); + var lease1 = await wait; + var lease2 = await wait2; + Assert.False(lease1.IsAcquired); + Assert.False(lease2.IsAcquired); + Assert.False(wait3.IsCompleted); + + limiter.TryReplenish(); + limiter.TryReplenish(); + + lease = await wait3; + Assert.True(lease.IsAcquired); + } + + [Fact] + public override async Task DropsRequestedLeaseIfPermitCountGreaterThanQueueLimitAndNoAvailability_NewestFirst() + { + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(2, QueueProcessingOrder.NewestFirst, 1, + TimeSpan.Zero, 1, autoReplenishment: false)); + var lease = limiter.Acquire(2); + Assert.True(lease.IsAcquired); + + // Fill queue + var wait = limiter.WaitAsync(1); + Assert.False(wait.IsCompleted); + + var lease1 = await limiter.WaitAsync(2); + Assert.False(lease1.IsAcquired); + + limiter.TryReplenish(); + + lease = await wait; + Assert.True(lease.IsAcquired); + } + + [Fact] + public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAvailable() + { + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(1, QueueProcessingOrder.OldestFirst, 1, TimeSpan.Zero, 1, autoReplenishment: false)); var lease = limiter.Acquire(1); var wait = limiter.WaitAsync(1); @@ -147,6 +215,29 @@ public override async Task QueueAvailableAfterQueueLimitHitAndResources_BecomeAv Assert.True(lease.IsAcquired); } + [Fact] + public override async Task LargeAcquiresAndQueuesDoNotIntegerOverflow() + { + var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions(int.MaxValue, QueueProcessingOrder.NewestFirst, int.MaxValue, + TimeSpan.Zero, int.MaxValue, autoReplenishment: false)); + var lease = limiter.Acquire(int.MaxValue); + Assert.True(lease.IsAcquired); + + // Fill queue + var wait = limiter.WaitAsync(3); + Assert.False(wait.IsCompleted); + + var wait2 = limiter.WaitAsync(int.MaxValue); + Assert.False(wait2.IsCompleted); + + var lease1 = await wait; + Assert.False(lease1.IsAcquired); + + limiter.TryReplenish(); + var lease2 = await wait2; + Assert.True(lease2.IsAcquired); + } + [Fact] public override void ThrowsWhenAcquiringMoreThanLimit() { From ded841a690e73c04ebdc86c681893bf9fd372751 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 19 Jan 2022 22:22:49 +0300 Subject: [PATCH 061/308] Don't reuse registers in Debug mode (#63698) Co-authored-by: Bruce Forstall --- src/coreclr/jit/lsra.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 3e7177c48a99a..f1e97f9692d9a 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -2808,7 +2808,7 @@ regNumber LinearScan::allocateReg(Interval* currentInterval, bool wasAssigned = regSelector->foundUnassignedReg() && (assignedInterval != nullptr) && (assignedInterval->physReg == foundReg); unassignPhysReg(availablePhysRegRecord ARM_ARG(currentInterval->registerType)); - if (regSelector->isMatchingConstant()) + if (regSelector->isMatchingConstant() && compiler->opts.OptimizationEnabled()) { assert(assignedInterval->isConstant); refPosition->treeNode->SetReuseRegVal(); From 65db54e2a92a2ef8ba8a75c70990e78f21818e18 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 19 Jan 2022 22:23:45 +0300 Subject: [PATCH 062/308] Add IsKnownConstant jit helper and optimize 'str == ""' with str.StartsWith('c') (#63734) Co-authored-by: Miha Zupan Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> --- src/coreclr/jit/compiler.hpp | 24 ++++- src/coreclr/jit/fgbasic.cpp | 38 ++++--- src/coreclr/jit/gentree.cpp | 3 + src/coreclr/jit/importer.cpp | 82 +++++++++------ src/coreclr/jit/inline.def | 2 + src/coreclr/jit/inlinepolicy.cpp | 22 ++++- src/coreclr/jit/inlinepolicy.h | 4 + src/coreclr/jit/morph.cpp | 41 +++++++- src/coreclr/jit/namedintrinsiclist.h | 1 + .../CompilerServices/RuntimeHelpers.cs | 10 ++ .../src/System/String.Comparison.cs | 21 +++- .../JIT/opt/IsKnownConstant/StringEquals.cs | 99 +++++++++++++++++++ .../opt/IsKnownConstant/StringEquals.csproj | 9 ++ 13 files changed, 305 insertions(+), 51 deletions(-) create mode 100644 src/tests/JIT/opt/IsKnownConstant/StringEquals.cs create mode 100644 src/tests/JIT/opt/IsKnownConstant/StringEquals.csproj diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 937d144d70ead..2379c0e0ac6ac 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -4516,11 +4516,12 @@ inline static bool StructHasNoPromotionFlagSet(DWORD attribs) return ((attribs & CORINFO_FLG_DONT_PROMOTE) != 0); } -/***************************************************************************** - * This node should not be referenced by anyone now. Set its values to garbage - * to catch extra references - */ - +//------------------------------------------------------------------------------ +// DEBUG_DESTROY_NODE: sets value of tree to garbage to catch extra references +// +// Arguments: +// tree: This node should not be referenced by anyone now +// inline void DEBUG_DESTROY_NODE(GenTree* tree) { #ifdef DEBUG @@ -4541,6 +4542,19 @@ inline void DEBUG_DESTROY_NODE(GenTree* tree) #endif } +//------------------------------------------------------------------------------ +// DEBUG_DESTROY_NODE: sets value of trees to garbage to catch extra references +// +// Arguments: +// tree, ...rest: These nodes should not be referenced by anyone now +// +template +void DEBUG_DESTROY_NODE(GenTree* tree, T... rest) +{ + DEBUG_DESTROY_NODE(tree); + DEBUG_DESTROY_NODE(rest...); +} + //------------------------------------------------------------------------------ // lvRefCnt: access reference count for this local var // diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index eb98143713818..6b41c055422b0 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -1113,12 +1113,12 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed { ni = lookupNamedIntrinsic(methodHnd); - bool foldableIntrinsc = false; + bool foldableIntrinsic = false; if (IsMathIntrinsic(ni)) { // Most Math(F) intrinsics have single arguments - foldableIntrinsc = FgStack::IsConstantOrConstArg(pushedStack.Top(), impInlineInfo); + foldableIntrinsic = FgStack::IsConstantOrConstArg(pushedStack.Top(), impInlineInfo); } else { @@ -1131,7 +1131,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed case NI_System_GC_KeepAlive: { pushedStack.PushUnknown(); - foldableIntrinsc = true; + foldableIntrinsic = true; break; } @@ -1145,6 +1145,20 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed break; } + case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: + if (FgStack::IsConstArgument(pushedStack.Top(), impInlineInfo)) + { + compInlineResult->Note(InlineObservation::CALLEE_CONST_ARG_FEEDS_ISCONST); + } + else + { + compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_ISCONST); + } + // RuntimeHelpers.IsKnownConstant is always folded into a const + pushedStack.PushConstant(); + foldableIntrinsic = true; + break; + // These are foldable if the first argument is a constant case NI_System_Type_get_IsValueType: case NI_System_Type_GetTypeFromHandle: @@ -1159,10 +1173,10 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed case NI_Vector128_Create: #endif { - // Top() in order to keep it as is in case of foldableIntrinsc + // Top() in order to keep it as is in case of foldableIntrinsic if (FgStack::IsConstantOrConstArg(pushedStack.Top(), impInlineInfo)) { - foldableIntrinsc = true; + foldableIntrinsic = true; } break; } @@ -1177,7 +1191,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed if (FgStack::IsConstantOrConstArg(pushedStack.Top(0), impInlineInfo) && FgStack::IsConstantOrConstArg(pushedStack.Top(1), impInlineInfo)) { - foldableIntrinsc = true; + foldableIntrinsic = true; pushedStack.PushConstant(); } break; @@ -1186,31 +1200,31 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed case NI_IsSupported_True: case NI_IsSupported_False: { - foldableIntrinsc = true; + foldableIntrinsic = true; pushedStack.PushConstant(); break; } #if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) case NI_Vector128_get_Count: case NI_Vector256_get_Count: - foldableIntrinsc = true; + foldableIntrinsic = true; pushedStack.PushConstant(); // TODO: check if it's a loop condition - we unroll such loops. break; case NI_Vector256_get_Zero: case NI_Vector256_get_AllBitsSet: - foldableIntrinsc = true; + foldableIntrinsic = true; pushedStack.PushUnknown(); break; #elif defined(TARGET_ARM64) && defined(FEATURE_HW_INTRINSICS) case NI_Vector64_get_Count: case NI_Vector128_get_Count: - foldableIntrinsc = true; + foldableIntrinsic = true; pushedStack.PushConstant(); break; case NI_Vector128_get_Zero: case NI_Vector128_get_AllBitsSet: - foldableIntrinsc = true; + foldableIntrinsic = true; pushedStack.PushUnknown(); break; #endif @@ -1222,7 +1236,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed } } - if (foldableIntrinsc) + if (foldableIntrinsic) { compInlineResult->Note(InlineObservation::CALLSITE_FOLDABLE_INTRINSIC); handled = true; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 59c47e4246c7e..ca588f4de9f6b 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -10824,6 +10824,9 @@ void Compiler::gtDispTree(GenTree* tree, case NI_System_Object_GetType: printf(" objGetType"); break; + case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: + printf(" isKnownConst"); + break; default: unreached(); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index ffdddf2870f06..08597695cf2d4 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3879,19 +3879,25 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, return new (this, GT_LABEL) GenTree(GT_LABEL, TYP_I_IMPL); } - if (((ni == NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan) || - (ni == NI_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray)) && - IsTargetAbi(CORINFO_CORERT_ABI)) + switch (ni) { // CreateSpan must be expanded for NativeAOT - mustExpand = true; - } + case NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan: + case NI_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray: + mustExpand |= IsTargetAbi(CORINFO_CORERT_ABI); + break; - if ((ni == NI_System_ByReference_ctor) || (ni == NI_System_ByReference_get_Value) || - (ni == NI_System_Activator_AllocatorOf) || (ni == NI_System_Activator_DefaultConstructorOf) || - (ni == NI_System_Object_MethodTableOf) || (ni == NI_System_EETypePtr_EETypePtrOf)) - { - mustExpand = true; + case NI_System_ByReference_ctor: + case NI_System_ByReference_get_Value: + case NI_System_Activator_AllocatorOf: + case NI_System_Activator_DefaultConstructorOf: + case NI_System_Object_MethodTableOf: + case NI_System_EETypePtr_EETypePtrOf: + mustExpand = true; + break; + + default: + break; } GenTree* retNode = nullptr; @@ -3935,29 +3941,19 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, case NI_System_String_get_Length: { GenTree* op1 = impPopStack().val; - if (opts.OptimizationEnabled()) + if (op1->OperIs(GT_CNS_STR)) { - if (op1->OperIs(GT_CNS_STR)) + // Optimize `ldstr + String::get_Length()` to CNS_INT + // e.g. "Hello".Length => 5 + GenTreeIntCon* iconNode = gtNewStringLiteralLength(op1->AsStrCon()); + if (iconNode != nullptr) { - // Optimize `ldstr + String::get_Length()` to CNS_INT - // e.g. "Hello".Length => 5 - GenTreeIntCon* iconNode = gtNewStringLiteralLength(op1->AsStrCon()); - if (iconNode != nullptr) - { - retNode = iconNode; - break; - } + retNode = iconNode; + break; } - GenTreeArrLen* arrLen = gtNewArrLen(TYP_INT, op1, OFFSETOF__CORINFO_String__stringLen, compCurBB); - op1 = arrLen; - } - else - { - /* Create the expression "*(str_addr + stringLengthOffset)" */ - op1 = gtNewOperNode(GT_ADD, TYP_BYREF, op1, - gtNewIconNode(OFFSETOF__CORINFO_String__stringLen, TYP_I_IMPL)); - op1 = gtNewOperNode(GT_IND, TYP_INT, op1); } + GenTreeArrLen* arrLen = gtNewArrLen(TYP_INT, op1, OFFSETOF__CORINFO_String__stringLen, compCurBB); + op1 = arrLen; // Getting the length of a null string should throw op1->gtFlags |= GTF_EXCEPT; @@ -4007,6 +4003,26 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, break; } + case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: + { + GenTree* op1 = impPopStack().val; + if (op1->OperIsConst()) + { + // op1 is a known constant, replace with 'true'. + retNode = gtNewIconNode(1); + JITDUMP("\nExpanding RuntimeHelpers.IsKnownConstant to true early\n"); + // We can also consider FTN_ADDR and typeof(T) here + } + else + { + // op1 is not a known constant, we'll do the expansion in morph + retNode = new (this, GT_INTRINSIC) GenTreeIntrinsic(TYP_INT, op1, ni, method); + JITDUMP("\nConverting RuntimeHelpers.IsKnownConstant to:\n"); + DISPTREE(retNode); + } + break; + } + case NI_System_Activator_AllocatorOf: case NI_System_Activator_DefaultConstructorOf: case NI_System_Object_MethodTableOf: @@ -4283,7 +4299,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, case NI_System_Threading_Thread_get_ManagedThreadId: { - if (opts.OptimizationEnabled() && impStackTop().val->OperIs(GT_RET_EXPR)) + if (impStackTop().val->OperIs(GT_RET_EXPR)) { GenTreeCall* call = impStackTop().val->AsRetExpr()->gtInlineCandidate->AsCall(); if (call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) @@ -4306,7 +4322,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, case NI_System_Threading_Interlocked_Or: case NI_System_Threading_Interlocked_And: { - if (opts.OptimizationEnabled() && compOpportunisticallyDependsOn(InstructionSet_Atomics)) + if (compOpportunisticallyDependsOn(InstructionSet_Atomics)) { assert(sig->numArgs == 2); GenTree* op2 = impPopStack().val; @@ -5352,6 +5368,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray; } + else if (strcmp(methodName, "IsKnownConstant") == 0) + { + result = NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant; + } } else if (strncmp(namespaceName, "System.Runtime.Intrinsics", 25) == 0) { diff --git a/src/coreclr/jit/inline.def b/src/coreclr/jit/inline.def index a28daf4e980fd..a519471a3caec 100644 --- a/src/coreclr/jit/inline.def +++ b/src/coreclr/jit/inline.def @@ -70,6 +70,8 @@ INLINE_OBSERVATION(ARG_FEEDS_CONSTANT_TEST, bool, "argument feeds constant t INLINE_OBSERVATION(ARG_FEEDS_TEST, bool, "argument feeds test", INFORMATION, CALLEE) INLINE_OBSERVATION(ARG_FEEDS_CAST, int, "argument feeds castclass or isinst", INFORMATION, CALLEE) INLINE_OBSERVATION(ARG_FEEDS_RANGE_CHECK, bool, "argument feeds range check", INFORMATION, CALLEE) +INLINE_OBSERVATION(ARG_FEEDS_ISCONST, bool, "argument feeds IsKnownConstant", INFORMATION, CALLEE) +INLINE_OBSERVATION(CONST_ARG_FEEDS_ISCONST, bool, "const argument feeds IsKnownConstant", INFORMATION, CALLEE) INLINE_OBSERVATION(ARG_STRUCT, int, "arg is a struct passed by value", INFORMATION, CALLEE) INLINE_OBSERVATION(RETURNS_STRUCT, bool, "returns a struct by value", INFORMATION, CALLEE) INLINE_OBSERVATION(ARG_STRUCT_FIELD_ACCESS, int, "ldfld/stfld over arg (struct)", INFORMATION, CALLEE) diff --git a/src/coreclr/jit/inlinepolicy.cpp b/src/coreclr/jit/inlinepolicy.cpp index 1ec47378872d5..0ea9135b82c24 100644 --- a/src/coreclr/jit/inlinepolicy.cpp +++ b/src/coreclr/jit/inlinepolicy.cpp @@ -326,6 +326,14 @@ void DefaultPolicy::NoteBool(InlineObservation obs, bool value) m_ArgFeedsRangeCheck++; break; + case InlineObservation::CALLEE_CONST_ARG_FEEDS_ISCONST: + m_ConstArgFeedsIsKnownConst = true; + break; + + case InlineObservation::CALLEE_ARG_FEEDS_ISCONST: + m_ArgFeedsIsKnownConst = true; + break; + case InlineObservation::CALLEE_UNSUPPORTED_OPCODE: propagate = true; break; @@ -727,6 +735,15 @@ double DefaultPolicy::DetermineMultiplier() JITDUMP("\nInline candidate has arg that feeds range check. Multiplier increased to %g.", multiplier); } + if (m_ConstArgFeedsIsKnownConst || (m_ArgFeedsIsKnownConst && m_IsPrejitRoot)) + { + // if we use RuntimeHelpers.IsKnownConstant we most likely expect our function to be always inlined + // at least in the case of constant arguments. In IsPrejitRoot we don't have callsite info so let's + // assume we have a constant here in order to avoid "baked" noinline + multiplier += 20; + JITDUMP("\nConstant argument feeds RuntimeHelpers.IsKnownConstant. Multiplier increased to %g.", multiplier); + } + if (m_ConstantArgFeedsConstantTest > 0) { multiplier += 3.0; @@ -1371,7 +1388,7 @@ void ExtendedDefaultPolicy::NoteInt(InlineObservation obs, int value) { SetNever(InlineObservation::CALLEE_DOES_NOT_RETURN); } - else if (!m_IsForceInline && !m_HasProfile) + else if (!m_IsForceInline && !m_HasProfile && !m_ConstArgFeedsIsKnownConst && !m_ArgFeedsIsKnownConst) { unsigned bbLimit = (unsigned)JitConfig.JitExtDefaultPolicyMaxBB(); if (m_IsPrejitRoot) @@ -1381,6 +1398,7 @@ void ExtendedDefaultPolicy::NoteInt(InlineObservation obs, int value) bbLimit += 5 + m_Switch * 10; } bbLimit += m_FoldableBranch + m_FoldableSwitch * 10; + if ((unsigned)value > bbLimit) { SetNever(InlineObservation::CALLEE_TOO_MANY_BASIC_BLOCKS); @@ -2638,6 +2656,8 @@ void DiscretionaryPolicy::DumpData(FILE* file) const fprintf(file, ",%u", m_ArgFeedsConstantTest); fprintf(file, ",%u", m_MethodIsMostlyLoadStore ? 1 : 0); fprintf(file, ",%u", m_ArgFeedsRangeCheck); + fprintf(file, ",%u", m_ConstArgFeedsIsKnownConst ? 1 : 0); + fprintf(file, ",%u", m_ArgFeedsIsKnownConst ? 1 : 0); fprintf(file, ",%u", m_ConstantArgFeedsConstantTest); fprintf(file, ",%d", m_CalleeNativeSizeEstimate); fprintf(file, ",%d", m_CallsiteNativeSizeEstimate); diff --git a/src/coreclr/jit/inlinepolicy.h b/src/coreclr/jit/inlinepolicy.h index f5f200e9f5bd7..05e8539982ee8 100644 --- a/src/coreclr/jit/inlinepolicy.h +++ b/src/coreclr/jit/inlinepolicy.h @@ -110,6 +110,8 @@ class DefaultPolicy : public LegalPolicy , m_CallsiteIsInLoop(false) , m_IsNoReturn(false) , m_IsNoReturnKnown(false) + , m_ConstArgFeedsIsKnownConst(false) + , m_ArgFeedsIsKnownConst(false) { // empty } @@ -178,6 +180,8 @@ class DefaultPolicy : public LegalPolicy bool m_CallsiteIsInLoop : 1; bool m_IsNoReturn : 1; bool m_IsNoReturnKnown : 1; + bool m_ConstArgFeedsIsKnownConst : 1; + bool m_ArgFeedsIsKnownConst : 1; }; // ExtendedDefaultPolicy is a slightly more aggressive variant of diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 972cecf7cd2ee..f1210b1741dcc 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -5198,7 +5198,7 @@ GenTree* Compiler::fgMorphArrayIndex(GenTree* tree) asIndex->Arr()->AsStrCon()->gtSconCPX, &length); if ((cnsIndex < length) && (str != nullptr)) { - GenTree* cnsCharNode = gtNewIconNode(str[cnsIndex], elemTyp); + GenTree* cnsCharNode = gtNewIconNode(str[cnsIndex], TYP_INT); INDEBUG(cnsCharNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); return cnsCharNode; } @@ -13224,6 +13224,45 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) } break; + case GT_INTRINSIC: + if (tree->AsIntrinsic()->gtIntrinsicName == + NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant) + { + // Should be expanded by the time it reaches CSE phase + assert(!optValnumCSE_phase); + + JITDUMP("\nExpanding RuntimeHelpers.IsKnownConstant to "); + if (op1->OperIsConst()) + { + // We're lucky to catch a constant here while importer was not + JITDUMP("true\n"); + DEBUG_DESTROY_NODE(tree, op1); + tree = gtNewIconNode(1); + } + else + { + GenTree* op1SideEffects = nullptr; + gtExtractSideEffList(op1, &op1SideEffects, GTF_ALL_EFFECT); + if (op1SideEffects != nullptr) + { + DEBUG_DESTROY_NODE(tree); + // Keep side-effects of op1 + tree = gtNewOperNode(GT_COMMA, TYP_INT, op1SideEffects, gtNewIconNode(0)); + JITDUMP("false with side effects:\n") + DISPTREE(tree); + } + else + { + JITDUMP("false\n"); + DEBUG_DESTROY_NODE(tree, op1); + tree = gtNewIconNode(0); + } + } + INDEBUG(tree->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); + return tree; + } + break; + default: break; } diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 25733a41a9c9e..7b2108d3edd05 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -78,6 +78,7 @@ enum NamedIntrinsic : unsigned short NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan, NI_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray, + NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant, NI_System_String_get_Chars, NI_System_String_get_Length, diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index 8187320ec9768..498055ad6a1c5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -117,5 +117,15 @@ internal static bool IsPrimitiveType(this CorElementType et) /// This method is intended for compiler use rather than use directly in code. T must be one of byte, sbyte, char, short, ushort, int, long, ulong, float, or double. [Intrinsic] public static unsafe ReadOnlySpan CreateSpan(RuntimeFieldHandle fldHandle) => new ReadOnlySpan(GetSpanDataFrom(fldHandle, typeof(T).TypeHandle, out int length), length); + + + // The following intrinsics return true if input is a compile-time constant + // Feel free to add more overloads on demand + + [Intrinsic] + internal static bool IsKnownConstant(string? t) => false; + + [Intrinsic] + internal static bool IsKnownConstant(char t) => false; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs b/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs index 9d068b4da0bc9..6a059351f376a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs @@ -683,6 +683,18 @@ public bool Equals([NotNullWhen(true)] string? value, StringComparison compariso // Determines whether two Strings match. public static bool Equals(string? a, string? b) { + // Transform 'str == ""' to 'str != null && str.Length == 0' if either a or b are jit-time + // constants. Otherwise, these two blocks are eliminated + if (RuntimeHelpers.IsKnownConstant(a) && a != null && a.Length == 0) + { + return b != null && b.Length == 0; + } + + if (RuntimeHelpers.IsKnownConstant(b) && b != null && b.Length == 0) + { + return a != null && a.Length == 0; + } + if (object.ReferenceEquals(a, b)) { return true; @@ -1013,7 +1025,14 @@ public bool StartsWith(string value, bool ignoreCase, CultureInfo? culture) return referenceCulture.CompareInfo.IsPrefix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); } - public bool StartsWith(char value) => Length != 0 && _firstChar == value; + public bool StartsWith(char value) + { + if (RuntimeHelpers.IsKnownConstant(value) && value != '\0') + { + return _firstChar == value; + } + return Length != 0 && _firstChar == value; + } internal static void CheckStringComparison(StringComparison comparisonType) { diff --git a/src/tests/JIT/opt/IsKnownConstant/StringEquals.cs b/src/tests/JIT/opt/IsKnownConstant/StringEquals.cs new file mode 100644 index 0000000000000..4a109ae5d6548 --- /dev/null +++ b/src/tests/JIT/opt/IsKnownConstant/StringEquals.cs @@ -0,0 +1,99 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; + +public class Program +{ + public static int Main() + { + AssertEquals(true, TestEquals1("")); + AssertEquals(false, TestEquals1(null)); + AssertEquals(false, TestEquals1("1")); + + AssertEquals(true, TestEquals2("")); + AssertEquals(false, TestEquals2(null)); + AssertEquals(false, TestEquals2("1")); + + AssertEquals(true, TestEquals3("")); + AssertEquals(false, TestEquals3(null)); + AssertEquals(false, TestEquals3("1")); + + AssertEquals(true, TestEquals4("")); + AssertEquals(false, TestEquals4(null)); + AssertEquals(false, TestEquals4("1")); + + AssertEquals(true, TestEquals5("")); + AssertEquals(false, TestEquals5(null)); + AssertEquals(false, TestEquals5("1")); + + AssertEquals(false, TestEquals6("")); + AssertEquals(true, TestEquals6(null)); + AssertEquals(false, TestEquals6("1")); + + AssertEquals(false, TestEquals7()); + AssertEquals(false, TestEquals8()); + + AssertEquals(true, TestEquals5("")); + AssertEquals(false, TestEquals5(null)); + AssertEquals(false, TestEquals5("1")); + + AssertEquals(true, TestStartWith("c")); + AssertEquals(false, TestStartWith("C")); + AssertThrowsNRE(() => TestStartWith(null)); + + return 100; + } + + private static void AssertEquals(bool expected, bool actual, [CallerLineNumber]int l = 0) + { + if (expected != actual) + throw new InvalidOperationException(); + } + + private static void AssertThrowsNRE(Action a) + { + try + { + a(); + } + catch (NullReferenceException) + { + return; + } + throw new InvalidOperationException(); + } + + private static string NullStr() => null; + private static string EmptyStr() => ""; + private static string NonEmptyStr() => "1"; + + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestEquals1(string str) => str == ""; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestEquals2(string str) => str == string.Empty; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestEquals3(string str) => "" == str; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestEquals4(string str) => string.Empty == str; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestEquals5(string str) => string.Empty == str; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestEquals6(string str) => string.Equals(NullStr(), str); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestEquals7() => string.Equals(NullStr(), EmptyStr()); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestEquals8() => string.Equals(NullStr(), NonEmptyStr()); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestStartWith(string str) => str.StartsWith('c'); +} diff --git a/src/tests/JIT/opt/IsKnownConstant/StringEquals.csproj b/src/tests/JIT/opt/IsKnownConstant/StringEquals.csproj new file mode 100644 index 0000000000000..6946bed81bfd5 --- /dev/null +++ b/src/tests/JIT/opt/IsKnownConstant/StringEquals.csproj @@ -0,0 +1,9 @@ + + + Exe + True + + + + + From ac4c7fb9457a8b0972686b017d82367d7a9bf1ca Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 19 Jan 2022 20:59:01 +0100 Subject: [PATCH 063/308] - mono_wasm_new_external_root for roots on stack (#63997) - temp_malloc helper via linear buffer in js - small refactorings Co-authored-by: Katelyn Gadd --- .../JavaScript/JSObject.References.cs | 6 +- .../InteropServices/JavaScript/Runtime.cs | 206 +++++++++++++----- src/mono/mono/metadata/class-accessors.c | 4 +- src/mono/mono/metadata/object.c | 4 +- src/mono/wasm/build/README.md | 10 + src/mono/wasm/runtime/cs-to-js.ts | 45 +--- src/mono/wasm/runtime/cwraps.ts | 2 +- src/mono/wasm/runtime/debug.ts | 2 +- src/mono/wasm/runtime/dotnet.d.ts | 10 +- src/mono/wasm/runtime/driver.c | 25 ++- src/mono/wasm/runtime/memory.ts | 46 ++-- src/mono/wasm/runtime/method-binding.ts | 4 +- src/mono/wasm/runtime/roots.ts | 96 +++++++- src/mono/wasm/runtime/types.ts | 44 ++++ 14 files changed, 357 insertions(+), 147 deletions(-) diff --git a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSObject.References.cs b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSObject.References.cs index c9b443e9c82ce..d31f1543ce76b 100644 --- a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSObject.References.cs +++ b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSObject.References.cs @@ -48,7 +48,7 @@ internal void AddInFlight() InFlightCounter++; if (InFlightCounter == 1) { - Debug.Assert(InFlight == null); + Debug.Assert(InFlight == null, "InFlight == null"); InFlight = GCHandle.Alloc(this, GCHandleType.Normal); } } @@ -61,12 +61,12 @@ internal void ReleaseInFlight() { lock (this) { - Debug.Assert(InFlightCounter != 0); + Debug.Assert(InFlightCounter != 0, "InFlightCounter != 0"); InFlightCounter--; if (InFlightCounter == 0) { - Debug.Assert(InFlight.HasValue); + Debug.Assert(InFlight.HasValue, "InFlight.HasValue"); InFlight.Value.Free(); InFlight = null; } diff --git a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs index 60f694e2b7cf3..4b5d072e8ac43 100644 --- a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs +++ b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs @@ -49,14 +49,15 @@ private struct IntPtrAndHandle internal IntPtr ptr; [FieldOffset(0)] - internal RuntimeMethodHandle handle; + internal RuntimeMethodHandle methodHandle; [FieldOffset(0)] internal RuntimeTypeHandle typeHandle; } // see src/mono/wasm/driver.c MARSHAL_TYPE_xxx - public enum MarshalType : int { + public enum MarshalType : int + { NULL = 0, INT = 1, FP64 = 2, @@ -90,7 +91,8 @@ public enum MarshalType : int { } // see src/mono/wasm/driver.c MARSHAL_ERROR_xxx - public enum MarshalError : int { + public enum MarshalError : int + { BUFFER_TOO_SMALL = 512, NULL_CLASS_POINTER = 513, NULL_TYPE_POINTER = 514, @@ -98,13 +100,12 @@ public enum MarshalError : int { FIRST = BUFFER_TOO_SMALL } - public static string GetCallSignature(IntPtr methodHandle, object objForRuntimeType) + public static string GetCallSignature(IntPtr _methodHandle, object? objForRuntimeType) { - IntPtrAndHandle tmp = default(IntPtrAndHandle); - tmp.ptr = methodHandle; + var methodHandle = GetMethodHandleFromIntPtr(_methodHandle); - MethodBase? mb = objForRuntimeType == null ? MethodBase.GetMethodFromHandle(tmp.handle) : MethodBase.GetMethodFromHandle(tmp.handle, Type.GetTypeHandle(objForRuntimeType)); - if (mb == null) + MethodBase? mb = objForRuntimeType is null ? MethodBase.GetMethodFromHandle(methodHandle) : MethodBase.GetMethodFromHandle(methodHandle, Type.GetTypeHandle(objForRuntimeType)); + if (mb is null) return string.Empty; ParameterInfo[] parms = mb.GetParameters(); @@ -112,66 +113,163 @@ public static string GetCallSignature(IntPtr methodHandle, object objForRuntimeT if (parmsLength == 0) return string.Empty; - char[] res = new char[parmsLength]; + var result = new char[parmsLength]; + for (int i = 0; i < parmsLength; i++) + { + Type t = parms[i].ParameterType; + var mt = GetMarshalTypeFromType(t); + result[i] = GetCallSignatureCharacterForMarshalType(mt, null); + } + + return new string(result); + } + + private static RuntimeMethodHandle GetMethodHandleFromIntPtr(IntPtr ptr) + { + var temp = new IntPtrAndHandle { ptr = ptr }; + return temp.methodHandle; + } + + private static RuntimeTypeHandle GetTypeHandleFromIntPtr(IntPtr ptr) + { + var temp = new IntPtrAndHandle { ptr = ptr }; + return temp.typeHandle; + } + + internal static MarshalType GetMarshalTypeFromType(Type? type) + { + if (type is null) + return MarshalType.VOID; - for (int c = 0; c < parmsLength; c++) + var typeCode = Type.GetTypeCode(type); + if (type.IsEnum) { - Type t = parms[c].ParameterType; - switch (Type.GetTypeCode(t)) + switch (typeCode) + { + case TypeCode.Int32: + case TypeCode.UInt32: + return MarshalType.ENUM; + case TypeCode.Int64: + case TypeCode.UInt64: + return MarshalType.ENUM64; + default: + throw new JSException($"Unsupported enum underlying type {typeCode}"); + } + } + + switch (typeCode) + { + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + return MarshalType.INT; + case TypeCode.UInt32: + return MarshalType.UINT32; + case TypeCode.Boolean: + return MarshalType.BOOL; + case TypeCode.Int64: + return MarshalType.INT64; + case TypeCode.UInt64: + return MarshalType.UINT64; + case TypeCode.Single: + return MarshalType.FP32; + case TypeCode.Double: + return MarshalType.FP64; + case TypeCode.String: + return MarshalType.STRING; + case TypeCode.Char: + return MarshalType.CHAR; + } + + if (type.IsArray) + { + if (!type.IsSZArray) + throw new JSException("Only single-dimensional arrays with a zero lower bound can be marshaled to JS"); + + var elementType = type.GetElementType(); + switch (Type.GetTypeCode(elementType)) { case TypeCode.Byte: + return MarshalType.ARRAY_UBYTE; case TypeCode.SByte: + return MarshalType.ARRAY_BYTE; case TypeCode.Int16: + return MarshalType.ARRAY_SHORT; case TypeCode.UInt16: + return MarshalType.ARRAY_USHORT; case TypeCode.Int32: + return MarshalType.ARRAY_INT; case TypeCode.UInt32: - case TypeCode.Boolean: - // Enums types have the same code as their underlying numeric types - if (t.IsEnum) - res[c] = 'j'; - else - res[c] = 'i'; - break; - case TypeCode.Int64: - case TypeCode.UInt64: - // Enums types have the same code as their underlying numeric types - if (t.IsEnum) - res[c] = 'k'; - else - res[c] = 'l'; - break; + return MarshalType.ARRAY_UINT; case TypeCode.Single: - res[c] = 'f'; - break; + return MarshalType.ARRAY_FLOAT; case TypeCode.Double: - res[c] = 'd'; - break; - case TypeCode.String: - res[c] = 's'; - break; + return MarshalType.ARRAY_DOUBLE; default: - if (t == typeof(IntPtr)) - { - res[c] = 'i'; - } - else if (t == typeof(Uri)) - { - res[c] = 'u'; - } - else if (t == typeof(SafeHandle)) - { - res[c] = 'h'; - } - else - { - if (t.IsValueType) - throw new NotSupportedException(SR.ValueTypeNotSupported); - res[c] = 'o'; - } - break; + throw new JSException($"Unsupported array element type {elementType}"); } } - return new string(res); + else if (type == typeof(IntPtr)) + return MarshalType.POINTER; + else if (type == typeof(UIntPtr)) + return MarshalType.POINTER; + else if (type == typeof(SafeHandle)) + return MarshalType.SAFEHANDLE; + else if (typeof(Delegate).IsAssignableFrom(type)) + return MarshalType.DELEGATE; + else if ((type == typeof(Task)) || typeof(Task).IsAssignableFrom(type)) + return MarshalType.TASK; + else if (typeof(Uri) == type) + return MarshalType.URI; + else if (type.IsPointer) + return MarshalType.POINTER; + + if (type.IsValueType) + return MarshalType.VT; + else + return MarshalType.OBJECT; + } + + internal static char GetCallSignatureCharacterForMarshalType(MarshalType t, char? defaultValue) + { + switch (t) + { + case MarshalType.BOOL: + case MarshalType.INT: + case MarshalType.UINT32: + case MarshalType.POINTER: + return 'i'; + case MarshalType.UINT64: + case MarshalType.INT64: + return 'l'; + case MarshalType.FP32: + return 'f'; + case MarshalType.FP64: + return 'd'; + case MarshalType.STRING: + return 's'; + case MarshalType.URI: + return 'u'; + case MarshalType.SAFEHANDLE: + return 'h'; + case MarshalType.ENUM: + return 'j'; + case MarshalType.ENUM64: + return 'k'; + case MarshalType.TASK: + case MarshalType.DELEGATE: + case MarshalType.OBJECT: + return 'o'; + case MarshalType.VT: + return 'a'; + default: + if (defaultValue.HasValue) + return defaultValue.Value; + else + throw new JSException($"Unsupported marshal type {t}"); + } } /// diff --git a/src/mono/mono/metadata/class-accessors.c b/src/mono/mono/metadata/class-accessors.c index 609ad55b40494..a9d950d9e0fa0 100644 --- a/src/mono/mono/metadata/class-accessors.c +++ b/src/mono/mono/metadata/class-accessors.c @@ -68,7 +68,9 @@ mono_class_try_get_generic_class (MonoClass *klass) guint32 mono_class_get_flags (MonoClass *klass) { - switch (m_class_get_class_kind (klass)) { + g_assert (klass); + guint32 kind = m_class_get_class_kind (klass); + switch (kind) { case MONO_CLASS_DEF: case MONO_CLASS_GTD: return m_classdef_get_flags ((MonoClassDef*)klass); diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index 55afb98f2f194..d87fade6e6122 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -6795,9 +6795,9 @@ mono_string_is_interned_lookup (MonoStringHandle str, gboolean insert, MonoError #ifdef HOST_WASM /** * mono_string_instance_is_interned: - * Searches the interned string table for the provided string instance. + * Checks to see if the string instance has its interned flag set. * \param str String to probe - * \returns TRUE if the string is interned, FALSE otherwise. + * \returns TRUE if the string instance is interned, FALSE otherwise. */ int mono_string_instance_is_interned (MonoString *str) diff --git a/src/mono/wasm/build/README.md b/src/mono/wasm/build/README.md index faed3d05827f6..c6fb0a8681944 100644 --- a/src/mono/wasm/build/README.md +++ b/src/mono/wasm/build/README.md @@ -132,3 +132,13 @@ them for the new task assembly. - `eng/testing/linker/trimmingTests.targets`, - `src/tests/Common/wasm-test-runner/WasmTestRunner.proj` - `src/tests/Directory.Build.targets` + +## Profiling build performance + +If encountering build performance issues, you can use the rollup `--perf` option and the typescript compiler `--generateCpuProfile` option to get build profile data, like so: + +```../emsdk/node/14.15.5_64bit/bin/npm run rollup --perf -- --perf --environment Configuration:Release,NativeBinDir:./rollup-test-data,ProductVersion:12.3.4``` + +```node node_modules/typescript/lib/tsc.js --generateCpuProfile dotnet-tsc.cpuprofile -p tsconfig.json ``` + +The .cpuprofile file generated by node can be opened in the Performance tab of Chrome or Edge's devtools. \ No newline at end of file diff --git a/src/mono/wasm/runtime/cs-to-js.ts b/src/mono/wasm/runtime/cs-to-js.ts index 2a7646d85973f..de208efe3c93b 100644 --- a/src/mono/wasm/runtime/cs-to-js.ts +++ b/src/mono/wasm/runtime/cs-to-js.ts @@ -3,7 +3,7 @@ import { mono_wasm_new_root, WasmRoot } from "./roots"; import { - GCHandle, JSHandleDisposed, MonoArray, + GCHandle, JSHandleDisposed, MarshalError, MarshalType, MonoArray, MonoArrayNull, MonoObject, MonoObjectNull, MonoString, MonoType, MonoTypeNull } from "./types"; @@ -18,49 +18,6 @@ import { _are_promises_supported, _create_cancelable_promise } from "./cancelabl import { getU32, getI32, getF32, getF64 } from "./memory"; import { Int32Ptr, VoidPtr } from "./types/emscripten"; -// see src/mono/wasm/driver.c MARSHAL_TYPE_xxx and Runtime.cs MarshalType -export enum MarshalType { - NULL = 0, - INT = 1, - FP64 = 2, - STRING = 3, - VT = 4, - DELEGATE = 5, - TASK = 6, - OBJECT = 7, - BOOL = 8, - ENUM = 9, - URI = 22, - SAFEHANDLE = 23, - ARRAY_BYTE = 10, - ARRAY_UBYTE = 11, - ARRAY_UBYTE_C = 12, - ARRAY_SHORT = 13, - ARRAY_USHORT = 14, - ARRAY_INT = 15, - ARRAY_UINT = 16, - ARRAY_FLOAT = 17, - ARRAY_DOUBLE = 18, - FP32 = 24, - UINT32 = 25, - INT64 = 26, - UINT64 = 27, - CHAR = 28, - STRING_INTERNED = 29, - VOID = 30, - ENUM64 = 31, - POINTER = 32 -} - -// see src/mono/wasm/driver.c MARSHAL_ERROR_xxx and Runtime.cs -export enum MarshalError { - BUFFER_TOO_SMALL = 512, - NULL_CLASS_POINTER = 513, - NULL_TYPE_POINTER = 514, - UNSUPPORTED_TYPE = 515, - FIRST = BUFFER_TOO_SMALL -} - const delegate_invoke_symbol = Symbol.for("wasm delegate_invoke"); const delegate_invoke_signature_symbol = Symbol.for("wasm delegate_invoke_signature"); diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts index 98dd8f8e4e9bb..fab4a0e264549 100644 --- a/src/mono/wasm/runtime/cwraps.ts +++ b/src/mono/wasm/runtime/cwraps.ts @@ -97,7 +97,7 @@ export interface t_Cwraps { mono_wasm_find_corlib_type(namespace: string, name: string): MonoType; mono_wasm_assembly_find_type(assembly: MonoAssembly, namespace: string, name: string): MonoType; mono_wasm_assembly_find_method(klass: MonoClass, name: string, args: number): MonoMethod; - mono_wasm_invoke_method(method: MonoMethod, this_arg: MonoObject, params: VoidPtr, out_exc: MonoObject): MonoObject; + mono_wasm_invoke_method(method: MonoMethod, this_arg: MonoObject, params: VoidPtr, out_exc: VoidPtr): MonoObject; mono_wasm_string_get_utf8(str: MonoString): CharPtr; mono_wasm_string_from_utf16(str: CharPtr, len: number): MonoString; mono_wasm_get_obj_type(str: MonoObject): number; diff --git a/src/mono/wasm/runtime/debug.ts b/src/mono/wasm/runtime/debug.ts index 8eb60b46e5478..2aa8f121a55b8 100644 --- a/src/mono/wasm/runtime/debug.ts +++ b/src/mono/wasm/runtime/debug.ts @@ -179,7 +179,7 @@ export function mono_wasm_call_function_on(request: CallRequest): CFOResponse { const fn_args = request.arguments != undefined ? request.arguments.map(a => JSON.stringify(a.value)) : []; - const fn_body_template = `var fn = ${request.functionDeclaration}; return fn.apply(proxy, [${fn_args}]);`; + const fn_body_template = `const fn = ${request.functionDeclaration}; return fn.apply(proxy, [${fn_args}]);`; const fn_defn = new Function("proxy", fn_body_template); const fn_res = fn_defn(proxy); diff --git a/src/mono/wasm/runtime/dotnet.d.ts b/src/mono/wasm/runtime/dotnet.d.ts index 1f18501c18b59..6d210e51ad7cc 100644 --- a/src/mono/wasm/runtime/dotnet.d.ts +++ b/src/mono/wasm/runtime/dotnet.d.ts @@ -100,10 +100,7 @@ declare class WasmRootBuffer { release(): void; toString(): string; } -declare class WasmRoot { - private __buffer; - private __index; - constructor(buffer: WasmRootBuffer, index: number); +interface WasmRoot { get_address(): NativePointer; get_address_32(): number; get(): T; @@ -253,12 +250,13 @@ declare function mono_call_assembly_entry_point(assembly: string, args?: any[], declare function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr; declare type _MemOffset = number | VoidPtr | NativePointer; +declare type _NumberOrPointer = number | VoidPtr | NativePointer | ManagedPointer; declare function setU8(offset: _MemOffset, value: number): void; declare function setU16(offset: _MemOffset, value: number): void; -declare function setU32(offset: _MemOffset, value: number): void; +declare function setU32(offset: _MemOffset, value: _NumberOrPointer): void; declare function setI8(offset: _MemOffset, value: number): void; declare function setI16(offset: _MemOffset, value: number): void; -declare function setI32(offset: _MemOffset, value: number): void; +declare function setI32(offset: _MemOffset, value: _NumberOrPointer): void; declare function setI64(offset: _MemOffset, value: number): void; declare function setF32(offset: _MemOffset, value: number): void; declare function setF64(offset: _MemOffset, value: number): void; diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index dbe9800b9f12d..a84d1d9b0ec04 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -575,7 +575,7 @@ mono_wasm_assembly_load (const char *name) return res; } -EMSCRIPTEN_KEEPALIVE MonoAssembly* +EMSCRIPTEN_KEEPALIVE MonoAssembly* mono_wasm_get_corlib () { return mono_image_get_assembly (mono_get_corlib()); @@ -656,7 +656,7 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly) uint32_t entry = mono_image_get_entry_point (image); if (!entry) return NULL; - + mono_domain_ensure_entry_assembly (root_domain, assembly); method = mono_get_method (image, entry, NULL); @@ -784,7 +784,8 @@ mono_wasm_marshal_type_from_mono_type (int mono_type, MonoClass *klass, MonoType return MARSHAL_TYPE_VOID; case MONO_TYPE_BOOLEAN: return MARSHAL_TYPE_BOOL; - case MONO_TYPE_I: // IntPtr + case MONO_TYPE_I: // IntPtr + case MONO_TYPE_U: // UIntPtr case MONO_TYPE_PTR: return MARSHAL_TYPE_POINTER; case MONO_TYPE_I1: @@ -929,7 +930,7 @@ mono_wasm_try_unbox_primitive_and_get_type (MonoObject *obj, void *result, int r MonoType *type = mono_class_get_type (klass), *original_type = type; if (!type) return MARSHAL_ERROR_NULL_TYPE_POINTER; - + if ((klass == mono_get_string_class ()) && mono_string_instance_is_interned ((MonoString *)obj)) { *resultL = 0; @@ -939,14 +940,14 @@ mono_wasm_try_unbox_primitive_and_get_type (MonoObject *obj, void *result, int r if (mono_class_is_enum (klass)) type = mono_type_get_underlying_type (type); - + if (!type) return MARSHAL_ERROR_NULL_TYPE_POINTER; - + int mono_type = mono_type_get_type (type); - + if (mono_type == MONO_TYPE_GENERICINST) { - // HACK: While the 'any other type' fallback is valid for classes, it will do the + // HACK: While the 'any other type' fallback is valid for classes, it will do the // wrong thing for structs, so we need to make sure the valuetype handler is used if (mono_type_generic_inst_is_valuetype (type)) mono_type = MONO_TYPE_VALUETYPE; @@ -994,7 +995,7 @@ mono_wasm_try_unbox_primitive_and_get_type (MonoObject *obj, void *result, int r break; case MONO_TYPE_VALUETYPE: { - int obj_size = mono_object_get_size (obj), + int obj_size = mono_object_get_size (obj), required_size = (sizeof (int)) + (sizeof (MonoType *)) + obj_size; // Check whether this struct has special-case marshaling @@ -1104,7 +1105,7 @@ mono_wasm_enable_on_demand_gc (int enable) } EMSCRIPTEN_KEEPALIVE MonoString * -mono_wasm_intern_string (MonoString *string) +mono_wasm_intern_string (MonoString *string) { return mono_string_intern (string); } @@ -1156,12 +1157,12 @@ mono_wasm_unbox_rooted (MonoObject *obj) return mono_object_unbox (obj); } -EMSCRIPTEN_KEEPALIVE char * +EMSCRIPTEN_KEEPALIVE char * mono_wasm_get_type_name (MonoType * typePtr) { return mono_type_get_name_full (typePtr, MONO_TYPE_NAME_FORMAT_REFLECTION); } -EMSCRIPTEN_KEEPALIVE char * +EMSCRIPTEN_KEEPALIVE char * mono_wasm_get_type_aqn (MonoType * typePtr) { return mono_type_get_name_full (typePtr, MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED); } diff --git a/src/mono/wasm/runtime/memory.ts b/src/mono/wasm/runtime/memory.ts index e8a89bd11a574..c8760a0c7a994 100644 --- a/src/mono/wasm/runtime/memory.ts +++ b/src/mono/wasm/runtime/memory.ts @@ -1,36 +1,44 @@ import { Module } from "./imports"; -import { VoidPtr, NativePointer } from "./types/emscripten"; +import { VoidPtr, NativePointer, ManagedPointer } from "./types/emscripten"; -const _temp_mallocs: Array | null> = []; +const alloca_stack: Array = []; +const alloca_buffer_size = 32 * 1024; +let alloca_base: VoidPtr, alloca_offset: VoidPtr, alloca_limit: VoidPtr; + +function _ensure_allocated(): void { + if (alloca_base) + return; + alloca_base = Module._malloc(alloca_buffer_size); + alloca_offset = alloca_base; + alloca_limit = (alloca_base + alloca_buffer_size); +} export function temp_malloc(size: number): VoidPtr { - if (!_temp_mallocs || !_temp_mallocs.length) + _ensure_allocated(); + if (!alloca_stack.length) throw new Error("No temp frames have been created at this point"); - const frame = _temp_mallocs[_temp_mallocs.length - 1] || []; - const result = Module._malloc(size); - frame.push(result); - _temp_mallocs[_temp_mallocs.length - 1] = frame; + const result = alloca_offset; + alloca_offset += size; + if (alloca_offset >= alloca_limit) + throw new Error("Out of temp storage space"); return result; } export function _create_temp_frame(): void { - _temp_mallocs.push(null); + _ensure_allocated(); + alloca_stack.push(alloca_offset); } export function _release_temp_frame(): void { - if (!_temp_mallocs.length) + if (!alloca_stack.length) throw new Error("No temp frames have been created at this point"); - const frame = _temp_mallocs.pop(); - if (!frame) - return; - - for (let i = 0, l = frame.length; i < l; i++) - Module._free(frame[i]); + alloca_offset = alloca_stack.pop(); } type _MemOffset = number | VoidPtr | NativePointer; +type _NumberOrPointer = number | VoidPtr | NativePointer | ManagedPointer; export function setU8(offset: _MemOffset, value: number): void { Module.HEAPU8[offset] = value; @@ -40,8 +48,8 @@ export function setU16(offset: _MemOffset, value: number): void { Module.HEAPU16[offset >>> 1] = value; } -export function setU32(offset: _MemOffset, value: number): void { - Module.HEAPU32[offset >>> 2] = value; +export function setU32 (offset: _MemOffset, value: _NumberOrPointer) : void { + Module.HEAPU32[offset >>> 2] = value; } export function setI8(offset: _MemOffset, value: number): void { @@ -52,8 +60,8 @@ export function setI16(offset: _MemOffset, value: number): void { Module.HEAP16[offset >>> 1] = value; } -export function setI32(offset: _MemOffset, value: number): void { - Module.HEAP32[offset >>> 2] = value; +export function setI32 (offset: _MemOffset, value: _NumberOrPointer) : void { + Module.HEAP32[offset >>> 2] = value; } // NOTE: Accepts a number, not a BigInt, so values over Number.MAX_SAFE_INTEGER will be corrupted diff --git a/src/mono/wasm/runtime/method-binding.ts b/src/mono/wasm/runtime/method-binding.ts index 4827766f88c49..04010b20ab72b 100644 --- a/src/mono/wasm/runtime/method-binding.ts +++ b/src/mono/wasm/runtime/method-binding.ts @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. import { WasmRoot, WasmRootBuffer, mono_wasm_new_root } from "./roots"; -import { MonoClass, MonoMethod, MonoObject, coerceNull, VoidPtrNull, MonoType } from "./types"; +import { MonoClass, MonoMethod, MonoObject, coerceNull, VoidPtrNull, MonoType, MarshalType } from "./types"; import { BINDING, Module, runtimeHelpers } from "./imports"; import { js_to_mono_enum, _js_to_mono_obj, _js_to_mono_uri } from "./js-to-cs"; import { js_string_to_mono_string, js_string_to_mono_string_interned } from "./strings"; -import { MarshalType, _unbox_mono_obj_root_with_known_nonprimitive_type } from "./cs-to-js"; +import { _unbox_mono_obj_root_with_known_nonprimitive_type } from "./cs-to-js"; import { _create_temp_frame, getI32, getU32, getF32, getF64, diff --git a/src/mono/wasm/runtime/roots.ts b/src/mono/wasm/runtime/roots.ts index 010732c23a894..2d473fb22ff20 100644 --- a/src/mono/wasm/runtime/roots.ts +++ b/src/mono/wasm/runtime/roots.ts @@ -10,6 +10,7 @@ let _scratch_root_buffer: WasmRootBuffer | null = null; let _scratch_root_free_indices: Int32Array | null = null; let _scratch_root_free_indices_count = 0; const _scratch_root_free_instances: WasmRoot[] = []; +const _external_root_free_instances: WasmExternalRoot[] = []; /** * Allocates a block of memory that can safely contain pointers into the managed heap. @@ -52,6 +53,26 @@ export function mono_wasm_new_root_buffer_from_pointer(offset: VoidPtr, capacity return new WasmRootBuffer(offset, capacity, false, name); } +/** + * Allocates a WasmRoot pointing to a root provided and controlled by external code. Typicaly on managed stack. + * Releasing this root will not de-allocate the root space. You still need to call .release(). + */ +export function mono_wasm_new_external_root(address: VoidPtr): WasmRoot { + let result: WasmExternalRoot; + + if (!address) + throw new Error("address must be a location in the native heap"); + + if (_external_root_free_instances.length > 0) { + result = _external_root_free_instances.pop()!; + result._set_address(address); + } else { + result = new WasmExternalRoot(address); + } + + return result; +} + /** * Allocates temporary storage for a pointer into the managed heap. * Pointers stored here will be visible to the GC, ensuring that the object they point to aren't moved or collected. @@ -68,7 +89,7 @@ export function mono_wasm_new_root(val const index = _mono_wasm_claim_scratch_index(); const buffer = _scratch_root_buffer; - result = new WasmRoot(buffer!, index); + result = new WasmJsOwnedRoot(buffer!, index); } if (value !== undefined) { @@ -239,7 +260,20 @@ export class WasmRootBuffer { } } -export class WasmRoot { +export interface WasmRoot { + get_address(): NativePointer; + get_address_32(): number; + get(): T; + set(value: T): T; + get value(): T; + set value(value: T); + valueOf(): T; + clear(): void; + release(): void; + toString(): string; +} + +class WasmJsOwnedRoot implements WasmRoot { private __buffer: WasmRootBuffer; private __index: number; @@ -301,3 +335,61 @@ export class WasmRoot { return `[root @${this.get_address()}]`; } } + +class WasmExternalRoot implements WasmRoot { + private __external_address: NativePointer = undefined; + private __external_address_32: number = undefined; + + constructor(address: NativePointer) { + this._set_address(address); + } + + _set_address(address: NativePointer): void { + this.__external_address = address; + this.__external_address_32 = address >>> 2; + } + + get_address(): NativePointer { + return this.__external_address; + } + + get_address_32(): number { + return this.__external_address_32; + } + + get(): T { + const result = Module.HEAPU32[this.__external_address_32]; + return result; + } + + set(value: T): T { + Module.HEAPU32[this.__external_address_32] = value; + return value; + } + + get value(): T { + return this.get(); + } + + set value(value: T) { + this.set(value); + } + + valueOf(): T { + return this.get(); + } + + clear(): void { + this.set(0); + } + + release(): void { + const maxPooledInstances = 128; + if (_external_root_free_instances.length < maxPooledInstances) + _external_root_free_instances.push(this); + } + + toString(): string { + return `[external root @${this.get_address()}]`; + } +} \ No newline at end of file diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts index 02b4ce78e803a..b208aeedcd06a 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types.ts @@ -192,4 +192,48 @@ export function assert(condition: unknown, messsage: string): asserts condition if (!condition) { throw new Error(`Assert failed: ${messsage}`); } +} + +// see src/mono/wasm/driver.c MARSHAL_TYPE_xxx and Runtime.cs MarshalType +export enum MarshalType { + NULL = 0, + INT = 1, + FP64 = 2, + STRING = 3, + VT = 4, + DELEGATE = 5, + TASK = 6, + OBJECT = 7, + BOOL = 8, + ENUM = 9, + URI = 22, + SAFEHANDLE = 23, + ARRAY_BYTE = 10, + ARRAY_UBYTE = 11, + ARRAY_UBYTE_C = 12, + ARRAY_SHORT = 13, + ARRAY_USHORT = 14, + ARRAY_INT = 15, + ARRAY_UINT = 16, + ARRAY_FLOAT = 17, + ARRAY_DOUBLE = 18, + FP32 = 24, + UINT32 = 25, + INT64 = 26, + UINT64 = 27, + CHAR = 28, + STRING_INTERNED = 29, + VOID = 30, + ENUM64 = 31, + POINTER = 32, + SPAN_BYTE = 33, +} + +// see src/mono/wasm/driver.c MARSHAL_ERROR_xxx and Runtime.cs +export enum MarshalError { + BUFFER_TOO_SMALL = 512, + NULL_CLASS_POINTER = 513, + NULL_TYPE_POINTER = 514, + UNSUPPORTED_TYPE = 515, + FIRST = BUFFER_TOO_SMALL } \ No newline at end of file From 675c16711007536120fa2ef7b69224e44299d1e3 Mon Sep 17 00:00:00 2001 From: Egor Chesakov Date: Wed, 19 Jan 2022 12:59:49 -0800 Subject: [PATCH 064/308] [Arm64] Don't use D-copies in CopyBlock (#63588) * Increase the maximum number of internal registers allowd per node in src/coreclr/jit/lsra.h * Based on discussion in https://github.com/dotnet/runtime/issues/63453 don't allocate a SIMD register pair if the JIT won't be able to use Q-copies in src/coreclr/jit/lsraarmarch.cpp * Update CodeGen to reflect that Q-copies should be used only when size >= 2 * FP_REGSIZE_BYTES and using of them makes the instruction sequence shorter in src/coreclr/jit/codegenarmarch.cpp * Update comment - we don't use D-copies after that change in src/coreclr/jit/codegenarmarch.cpp --- src/coreclr/jit/codegenarmarch.cpp | 57 ++++++++++-------------------- src/coreclr/jit/lsra.h | 2 +- src/coreclr/jit/lsraarmarch.cpp | 52 ++++++++++++++------------- 3 files changed, 47 insertions(+), 64 deletions(-) diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index 227de58aedc97..66ecbac761cb5 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -2840,8 +2840,8 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) // When both addresses are not 16-byte aligned the CopyBlock instruction sequence starts with padding // str instruction. For example, when both addresses are 8-byte aligned the instruction sequence looks like // - // ldr D_simdReg1, [srcReg, #srcOffset] - // str D_simdReg1, [dstReg, #dstOffset] + // ldr X_intReg1, [srcReg, #srcOffset] + // str X_intReg1, [dstReg, #dstOffset] // ldp Q_simdReg1, Q_simdReg2, [srcReg, #srcOffset+8] // stp Q_simdReg1, Q_simdReg2, [dstReg, #dstOffset+8] // ldp Q_simdReg1, Q_simdReg2, [srcReg, #srcOffset+40] @@ -2853,7 +2853,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) // be profitable). const bool canUse16ByteWideInstrs = isSrcRegAddrAlignmentKnown && isDstRegAddrAlignmentKnown && - (size >= FP_REGSIZE_BYTES) && (srcRegAddrAlignment == dstRegAddrAlignment); + (size >= 2 * FP_REGSIZE_BYTES) && (srcRegAddrAlignment == dstRegAddrAlignment); bool shouldUse16ByteWideInstrs = false; @@ -2876,8 +2876,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) { // In order to use 16-byte instructions the JIT needs to adjust either srcOffset or dstOffset. // The JIT should use 16-byte loads and stores when the resulting sequence (incl. an additional add - // instruction) - // has fewer number of instructions. + // instruction) has fewer number of instructions. if (helper.InstructionCount(FP_REGSIZE_BYTES) + 1 < helper.InstructionCount(REGSIZE_BYTES)) { @@ -2937,51 +2936,31 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) const unsigned intRegCount = node->AvailableTempRegCount(RBM_ALLINT); - switch (intRegCount) + if (intRegCount >= 2) { - case 1: - intReg1 = node->GetSingleTempReg(RBM_ALLINT); - break; - case 2: - intReg1 = node->ExtractTempReg(RBM_ALLINT); - intReg2 = node->GetSingleTempReg(RBM_ALLINT); - break; - default: - break; + intReg1 = node->ExtractTempReg(RBM_ALLINT); + intReg2 = node->ExtractTempReg(RBM_ALLINT); } - - regNumber simdReg1 = REG_NA; - regNumber simdReg2 = REG_NA; - - const unsigned simdRegCount = node->AvailableTempRegCount(RBM_ALLFLOAT); - - switch (simdRegCount) + else if (intRegCount == 1) { - case 1: - simdReg1 = node->GetSingleTempReg(RBM_ALLFLOAT); - break; - case 2: - simdReg1 = node->ExtractTempReg(RBM_ALLFLOAT); - simdReg2 = node->GetSingleTempReg(RBM_ALLFLOAT); - break; - default: - break; + intReg1 = node->GetSingleTempReg(RBM_ALLINT); + intReg2 = rsGetRsvdReg(); + } + else + { + intReg1 = rsGetRsvdReg(); } if (shouldUse16ByteWideInstrs) { + const regNumber simdReg1 = node->ExtractTempReg(RBM_ALLFLOAT); + const regNumber simdReg2 = node->GetSingleTempReg(RBM_ALLFLOAT); + helper.Unroll(FP_REGSIZE_BYTES, intReg1, simdReg1, simdReg2, srcReg, dstReg, GetEmitter()); } else { - if (intReg2 == REG_NA) - { - helper.Unroll(REGSIZE_BYTES, intReg1, simdReg1, simdReg2, srcReg, dstReg, GetEmitter()); - } - else - { - helper.UnrollBaseInstrs(intReg1, intReg2, srcReg, dstReg, GetEmitter()); - } + helper.UnrollBaseInstrs(intReg1, intReg2, srcReg, dstReg, GetEmitter()); } #endif // TARGET_ARM64 diff --git a/src/coreclr/jit/lsra.h b/src/coreclr/jit/lsra.h index 1b549424f0fc4..052c3f93999a3 100644 --- a/src/coreclr/jit/lsra.h +++ b/src/coreclr/jit/lsra.h @@ -1772,7 +1772,7 @@ class LinearScan : public LinearScanInterface // The following keep track of information about internal (temporary register) intervals // during the building of a single node. - static const int MaxInternalCount = 4; + static const int MaxInternalCount = 5; RefPosition* internalDefs[MaxInternalCount]; int internalCount = 0; bool setInternalRegsDelayFree; diff --git a/src/coreclr/jit/lsraarmarch.cpp b/src/coreclr/jit/lsraarmarch.cpp index ef7a2d0440aa4..f85cb81d9e8c3 100644 --- a/src/coreclr/jit/lsraarmarch.cpp +++ b/src/coreclr/jit/lsraarmarch.cpp @@ -694,36 +694,40 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) { buildInternalIntRegisterDefForNode(blkNode); #ifdef TARGET_ARM64 - const bool dstAddrMayNeedReg = dstAddr->isContained(); - const bool srcAddrMayNeedReg = src->OperIs(GT_LCL_VAR, GT_LCL_FLD) || - ((srcAddrOrFill != nullptr) && srcAddrOrFill->isContained()); + const bool canUseLoadStorePairIntRegsInstrs = (size >= 2 * REGSIZE_BYTES); - if (srcAddrMayNeedReg && dstAddrMayNeedReg) + if (canUseLoadStorePairIntRegsInstrs) { - // The following allocates an additional integer register in a case - // when a load instruction and a store instruction cannot be encoded. + // CodeGen can use ldp/stp instructions sequence. buildInternalIntRegisterDefForNode(blkNode); - // In this case, CodeGen will use a SIMD register for copying. - buildInternalFloatRegisterDefForNode(blkNode, internalFloatRegCandidates()); - // And in case of a larger block size, two SIMD registers. - if (size >= 2 * REGSIZE_BYTES) - { - buildInternalFloatRegisterDefForNode(blkNode, internalFloatRegCandidates()); - } } - else if (srcAddrMayNeedReg || dstAddrMayNeedReg) + + const bool isSrcAddrLocal = src->OperIs(GT_LCL_VAR, GT_LCL_FLD) || + ((srcAddrOrFill != nullptr) && srcAddrOrFill->OperIsLocalAddr()); + const bool isDstAddrLocal = dstAddr->OperIsLocalAddr(); + + // CodeGen can use 16-byte SIMD ldp/stp for larger block sizes + // only when both source and destination base address registers have known alignment. + // This is the case, when both registers are either sp or fp. + bool canUse16ByteWideInstrs = isSrcAddrLocal && isDstAddrLocal && (size >= 2 * FP_REGSIZE_BYTES); + + // Note that the SIMD registers allocation is speculative - LSRA doesn't know at this point + // whether CodeGen will use SIMD registers (i.e. if such instruction sequence will be more optimal). + // Therefore, it must allocate an additional integer register anyway. + if (canUse16ByteWideInstrs) { - if (size >= 2 * REGSIZE_BYTES) - { - buildInternalFloatRegisterDefForNode(blkNode, internalFloatRegCandidates()); - buildInternalFloatRegisterDefForNode(blkNode, internalFloatRegCandidates()); - } - else - { - buildInternalIntRegisterDefForNode(blkNode); - } + buildInternalFloatRegisterDefForNode(blkNode, internalFloatRegCandidates()); + buildInternalFloatRegisterDefForNode(blkNode, internalFloatRegCandidates()); } - else if (size >= 2 * REGSIZE_BYTES) + + const bool srcAddrMayNeedReg = + isSrcAddrLocal || ((srcAddrOrFill != nullptr) && srcAddrOrFill->isContained()); + const bool dstAddrMayNeedReg = isDstAddrLocal || dstAddr->isContained(); + + // The following allocates an additional integer register in a case + // when a load instruction and a store instruction cannot be encoded using offset + // from a corresponding base register. + if (srcAddrMayNeedReg && dstAddrMayNeedReg) { buildInternalIntRegisterDefForNode(blkNode); } From 6f8d8b20a0c78dcfc09ea7a43db48a9a4e055e13 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Wed, 19 Jan 2022 16:41:04 -0500 Subject: [PATCH 065/308] Disable hot reload tests for AOT configurations (#64006) --- src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs index beaa4a0e7338b..405afc9f50edb 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateUtil.cs @@ -47,7 +47,7 @@ internal static bool CheckSupportedMonoConfiguration() { // check that interpreter is enabled, and the build has hot reload capabilities enabled. var isInterp = RuntimeFeature.IsDynamicCodeSupported && !RuntimeFeature.IsDynamicCodeCompiled; - return isInterp && HasApplyUpdateCapabilities(); + return isInterp && !PlatformDetection.IsMonoAOT && HasApplyUpdateCapabilities(); } internal static bool HasApplyUpdateCapabilities() From 826e03e4b984d3bb76b2ead5f6ebb847be9c616f Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 19 Jan 2022 14:08:07 -0800 Subject: [PATCH 066/308] Bump Explicit-layout value types with no fields to at minimum 1 byte size. (#63975) --- src/coreclr/vm/methodtablebuilder.cpp | 8 +++ .../Regressions/empty/explicitStruct_empty.cs | 60 +++++++++++++++++++ .../empty/explicitStruct_empty.csproj | 5 ++ 3 files changed, 73 insertions(+) create mode 100644 src/tests/Loader/classloader/explicitlayout/Regressions/empty/explicitStruct_empty.cs create mode 100644 src/tests/Loader/classloader/explicitlayout/Regressions/empty/explicitStruct_empty.csproj diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 694e03cca35f2..68d11affa4351 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -8648,6 +8648,14 @@ MethodTableBuilder::HandleExplicitLayout( BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL); } } + + if (!numInstanceFieldBytes.IsOverflow() && numInstanceFieldBytes.Value() == 0) + { + // If we calculate a 0-byte size here, we should have also calculated a 0-byte size + // in the initial layout algorithm. + _ASSERTE(GetLayoutInfo()->IsZeroSized()); + numInstanceFieldBytes = S_UINT32(1); + } } // The GC requires that all valuetypes containing orefs be sized to a multiple of TARGET_POINTER_SIZE. diff --git a/src/tests/Loader/classloader/explicitlayout/Regressions/empty/explicitStruct_empty.cs b/src/tests/Loader/classloader/explicitlayout/Regressions/empty/explicitStruct_empty.cs new file mode 100644 index 0000000000000..1de3b4442c7fb --- /dev/null +++ b/src/tests/Loader/classloader/explicitlayout/Regressions/empty/explicitStruct_empty.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +[StructLayout(LayoutKind.Explicit)] +public struct S +{ +} + +[StructLayout(LayoutKind.Explicit)] +public struct S2 +{ +} + +[StructLayout(LayoutKind.Explicit)] +public class C +{ +} + +[StructLayout(LayoutKind.Explicit)] +public class C2 +{ +} + +public class Test_explicitStruct_empty +{ + // Mark as no-inlining so any test failures will show the right stack trace even after + // we consolidate test assemblies. + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void EmptyExplicitStructCanBeLoadedAndCreated() + { + S s = new S(); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void EmptyExplicitStructCanBeLoadedAndCreatedThroughReflection() + { + object s = Activator.CreateInstance(Type.GetType("S2")); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void EmptyExplicitClassCanBeLoadedAndCreated() + { + C c = new C(); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void EmptyExplicitClassCanBeLoadedAndCreatedThroughReflection() + { + object c = Activator.CreateInstance(Type.GetType("C2")); + } +} diff --git a/src/tests/Loader/classloader/explicitlayout/Regressions/empty/explicitStruct_empty.csproj b/src/tests/Loader/classloader/explicitlayout/Regressions/empty/explicitStruct_empty.csproj new file mode 100644 index 0000000000000..a304092ec069b --- /dev/null +++ b/src/tests/Loader/classloader/explicitlayout/Regressions/empty/explicitStruct_empty.csproj @@ -0,0 +1,5 @@ + + + + + From 97fec41a752f067f4d6dde170073300e1184693b Mon Sep 17 00:00:00 2001 From: Santiago Fernandez Madero Date: Wed, 19 Jan 2022 14:18:21 -0800 Subject: [PATCH 067/308] Add runtime-extra-platforms pipeline to have matching runtime PR and Rolling builds (#62564) * Add runtime-extended-platforms pipeline to have matching runtime PR and Rolling builds * Fix evaluate changed paths condition for the extra pipeline * PR Feedback and fix condition * Move MacCatalyst back to staging, disable tvOS tests * Disable browser wasm windows legs --- docs/pr-builds.md | 94 +++ docs/pr-guide.md | 63 +- eng/pipelines/common/global-build-job.yml | 9 +- eng/pipelines/common/platform-matrix.yml | 4 +- .../templates/runtimes/run-test-job.yml | 4 +- eng/pipelines/common/variables.yml | 14 +- eng/pipelines/common/xplat-setup.yml | 19 +- .../libraries/helix-queues-setup.yml | 66 +- eng/pipelines/libraries/outerloop-mono.yml | 8 +- eng/pipelines/libraries/outerloop.yml | 18 +- eng/pipelines/libraries/variables.yml | 2 +- eng/pipelines/runtime-community.yml | 4 +- ...manual.yml => runtime-extra-platforms.yml} | 656 ++++++++++-------- eng/pipelines/runtime-staging.yml | 406 +---------- eng/pipelines/runtime.yml | 210 ++---- eng/pipelines/runtimelab.yml | 4 +- .../tests/Vectors/Vector128Tests.cs | 2 + 17 files changed, 608 insertions(+), 975 deletions(-) create mode 100644 docs/pr-builds.md rename eng/pipelines/{runtime-manual.yml => runtime-extra-platforms.yml} (60%) diff --git a/docs/pr-builds.md b/docs/pr-builds.md new file mode 100644 index 0000000000000..1d098b5c1b9da --- /dev/null +++ b/docs/pr-builds.md @@ -0,0 +1,94 @@ +## PR Builds +When submitting a PR to the `dotnet/runtime` repository various builds will run validation in many areas to ensure we keep productivity and quality high. + +The `dotnet/runtime` validation system can become overwhelming as we need to cover a lot of build scenarios and test in all the platforms that we support. In order to try to make this more reliable and spend the least amount of time testing what the PR change need we have various pipelines, required and optional that are covered in this document. + +Most of the repository pipelines use a custom mechanism to evaluate paths based on the changes contained in the PR to try and build/test the least that we can without compromising quality. This is the initial step on every pipeline that depends on this infrastructure, called "Evalute Paths". In this step you can see the result of the evaluation for each subset of the repository. For more details on which subsets we have based on paths see [here](https://github.com/dotnet/runtime/blob/513fe2863ad5ec6dc453d223d4b60f787a0ffa78/eng/pipelines/common/evaluate-default-paths.yml). Also to understand how this mechanism you can read this [comment](https://github.com/dotnet/runtime/blob/513fe2863ad5ec6dc453d223d4b60f787a0ffa78/eng/pipelines/evaluate-changed-paths.sh#L3-L12). + +### Runtime pipeline +This is the "main" pipeline for the runtime product. In this pipeline we include the most critical tests and platforms where we have enough test resources in order to deliver test results in a reasonable amount of time. The tests executed in this pipeline for runtime and libraries are considered innerloop, are the tests that are executed locally when one runs tests locally. + +For mobile platforms and wasm we run some smoke tests that aim to protect the quality of these platforms. We had to move to a smoke test approach given the hardware and time limitations that we encountered and contributors were affected by this with unstability and long wait times for their PRs to finish validation. + +### Runtime-dev-innerloop pipeline +This pipeline is also required, and its intent is to cover a developer innerloop scenarios that could be affected by any change, like running a specific build command or running tests inside Visual Studio, etc. + +### Dotnet-linker-tests +This is also a required pipeline. The purpose of this pipeline is to test that the libraries code is linker friendly. Meaning that when we trim our libraries using the ILLink, we don't have any trimming bugs, like a required method on a specific scenario is trimmed away by accident. + +### Runtime-staging +This pipeline runs on every change, however it behaves a little different than the other pipelines. This pipeline, will not fail if there are test failures, however it will fail if there is a timeout or a build failure. The reason why we fail on build failures is because we want to protect the developer innerloop (building the repository) for this platform. + +The tests will not fail because the intent of this platform is to stage new platforms where the test infrastructure is new and we need to test if we have enough capacity to include that new platform on the "main" runtime pipeline without causing flakiness. Once we analyze data and a platform is stable when running on PRs in this pipeline for at least a weak it can be promoted either to the `runtime-extra-platforms` pipeline or to the `runtime` pipeline. + +### Runtime-extra-platforms +This pipeline does not run by default as it is not required for a PR, but it runs twice a day, and it can also be invoked in specific PRs by commenting `/azp run runtime-extra-platforms` However, this pipeline is still an important part of our testing. + +This pipeline runs innerloop tests on platforms where we don't have enough hardware capacity to run tests (mobile, browser) or on platforms where we believe tests should organically pass based on the coverage we have in the "main" runtime pipeline. For example, in the "main" pipeline we run tests on Ubuntu 21.10 but since we also support Ubuntu 18.04 which is an LTS release, we run tests on Ubuntu 18.04 of this pipeline just to make sure we have healthy tests on those platforms which we are releasing a product for. + +Another concrete scenario would be windows arm64 for libraries tests. Where we don't have enough hardware, but the JIT is the most important piece to test as that is what generates the native code to run on that platform, so we run JIT tests on arm64 in the "main" pipeline, but our libraries tests are only run on the `runtime-extra-platforms` pipeline. + +### Outerloop pipelines +We have various pipelines that their names contain `Outerloop` on them. These pipelines will not run by default on every PR, they can also be invoked using the `/azp run` comment and will run on a daily basis to analyze test results. + +These pipelines will run tests that take very long, that are not very stable (i.e some networking tests), or that modify machine state. Such tests are called `Outerloop` tests rather than `innerloop`. + +## Rerunning Validation + +Validation may fail for several reasons: + +### Option 1: You have a defect in your PR + +* Simply push the fix to your PR branch, and validation will start over. + +### Option 2: There is a flaky test that is not related to your PR + +* Your assumption should be that a failed test indicates a problem in your PR. (If we don't operate this way, chaos ensues.) If the test fails when run again, it is almost surely a failure caused by your PR. However, there are occasions where unrelated failures occur. Here's some ways to know: + * Perhaps you see the same failure in CI results for unrelated active PR's. + * It's a known issue listed in our [big tracking issue](https://github.com/dotnet/runtime/issues/702) or tagged `blocking-clean-ci` [(query here)](https://github.com/dotnet/runtime/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Ablocking-clean-ci+) + * Its otherwise beyond any reasonable doubt that your code changes could not have caused this. + * If the tests pass on rerun, that may suggest it's not related. +* In this situation, you want to re-run but not necessarily rebase on main. + * To rerun just the failed leg(s): + * Click on any leg. Navigate through the Azure DevOps UI, find the "..." button and choose "Retry failed legs" + * Or, on the GitHub Checks tab choose "re-run failed checks". This will not rebase your change. + * To rerun all validation: + * Add a comment `/azp run runtime` + * Or, click on "re-run all checks" in the GitHub Checks tab + * Or, simply close and reopen the PR. +* If you have established that it is an unrelated failure, please ensure we have an active issue for it. See the [unrelated failure](#what-to-do-if-you-determine-the-failure-is-unrelated) section below. +* Whoever merges the PR should be satisfied that the failure is unrelated, is not introduced by the change, and that we are appropriately tracking it. + +### Option 3: The state of the main branch HEAD is bad. + +* This is the very rare case where there was a build break in main, and you got unlucky. Hopefully the break has been fixed, and you want CI to rebase your change and rerun validation. +* To rebase and rerun all validation: + * Add a comment `/azp run runtime` + * Or, click on "re-run all checks" in the GitHub Checks tab + * Or, simply close and reopen the PR. + * Or, ammend your commit with `--amend --no-edit` and force push to your branch. + +### Additional information: + * You can list the available pipelines by adding a comment like `/azp list` or get the available commands by adding a comment like `azp help`. + * In the rare case the license/cla check fails to register a response, it can be rerun by issuing a GET request to `https://cla.dotnetfoundation.org/check/dotnet/runtime?pullRequest={pr_number}`. A successful response may be a redirect to `https://github.com`. + * Reach out to the infrastructure team for assistance on [Teams channel](https://teams.microsoft.com/l/channel/19%3ab27b36ecd10a46398da76b02f0411de7%40thread.skype/Infrastructure?groupId=014ca51d-be57-47fa-9628-a15efcc3c376&tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47) (for corpnet users) or on [Gitter](https://gitter.im/dotnet/community) in other cases. + +## What to do if you determine the failure is unrelated + +If you have determined the failure is definitely not caused by changes in your PR, please do this: + +* Search for an [existing issue](https://github.com/dotnet/runtime/issues). Usually the test method name or (if a crash/hang) the test assembly name are good search parameters. + * If there's an existing issue, add a comment with + * a) the link to the build + * b) the affected configuration (ie `net6.0-windows-Release-x64-Windows.81.Amd64.Open`) + * c) all console output including the error message and stack trace from the Azure DevOps tab (This is necessary as retention policies are in place that recycle old builds.) + * d) if there's a dump file (see Attachments tab in Azure DevOps) include that + * If the issue is already closed, reopen it and update the labels to reflect the current failure state. + * If there's no existing issue, create an issue with the same information listed above. + * Update the original pull request with a comment linking to the new or existing issue. +* In a follow-up Pull Request, disable the failing test(s) with the corresponding issue link tracking the disable. + * Update the tracking issue with the label `disabled-test`. + * For libraries tests add a [`[ActiveIssue(link)]`](https://github.com/dotnet/arcade/blob/master/src/Microsoft.DotNet.XUnitExtensions/src/Attributes/ActiveIssueAttribute.cs) attribute on the test method. You can narrow the disabling down to runtime variant, flavor, and platform. For an example see [File_AppendAllLinesAsync_Encoded](https://github.com/dotnet/runtime/blob/a259ec2e967d502f82163beba6b84da5319c5e08/src/libraries/System.IO.FileSystem/tests/File/AppendAsync.cs#L899) + * For runtime tests found under `src/tests`, please edit [`issues.targets`](https://github.com/dotnet/runtime/blob/main/src/tests/issues.targets). There are several groups for different types of disable (mono vs. coreclr, different platforms, different scenarios). Add the folder containing the test and issue mimicking any of the samples in the file. + +There are plenty of possible bugs, e.g. race conditions, where a failure might highlight a real problem and it won't manifest again on a retry. Therefore these steps should be followed for every iteration of the PR build, e.g. before retrying/rebuilding. \ No newline at end of file diff --git a/docs/pr-guide.md b/docs/pr-guide.md index b250efd6e12dd..eb7dea7a01ba7 100644 --- a/docs/pr-guide.md +++ b/docs/pr-guide.md @@ -24,71 +24,10 @@ Anyone with write access can merge a pull request manually or by setting the [au * The PR has been approved by at least one reviewer and any other objections are addressed. * You can request another review from the original reviewer. -* The PR successfully builds and passes all tests in the Continuous Integration (CI) system. - * Depending on your change, you may need to re-run validation. See [rerunning validation](#rerunning-validation) below. +* The PR successfully builds and passes all tests in the Continuous Integration (CI) system. For more information please read to our [PR Builds](pr-builds.md) doc. Typically, PRs are merged as one commit. It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to bisect them. -## Rerunning Validation - -Validation may fail for several reasons: - -### Option 1: You have a defect in your PR - -* Simply push the fix to your PR branch, and validation will start over. - -### Option 2: There is a flaky test that is not related to your PR - -* Your assumption should be that a failed test indicates a problem in your PR. (If we don't operate this way, chaos ensues.) If the test fails when run again, it is almost surely a failure caused by your PR. However, there are occasions where unrelated failures occur. Here's some ways to know: - * Perhaps you see the same failure in CI results for unrelated active PR's. - * It's a known issue listed in our [big tracking issue](https://github.com/dotnet/runtime/issues/702) or tagged `blocking-clean-ci` [(query here)](https://github.com/dotnet/runtime/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Ablocking-clean-ci+) - * Its otherwise beyond any reasonable doubt that your code changes could not have caused this. - * If the tests pass on rerun, that may suggest it's not related. -* In this situation, you want to re-run but not necessarily rebase on main. - * To rerun just the failed leg(s): - * Click on any leg. Navigate through the Azure DevOps UI, find the "..." button and choose "Retry failed legs" - * Or, on the GitHub Checks tab choose "re-run failed checks". This will not rebase your change. - * To rerun all validation: - * Add a comment `/azp run runtime` - * Or, click on "re-run all checks" in the GitHub Checks tab - * Or, simply close and reopen the PR. -* If you have established that it is an unrelated failure, please ensure we have an active issue for it. See the [unrelated failure](#what-to-do-if-you-determine-the-failure-is-unrelated) section below. -* Whoever merges the PR should be satisfied that the failure is unrelated, is not introduced by the change, and that we are appropriately tracking it. - -### Option 3: The state of the main branch HEAD is bad. - -* This is the very rare case where there was a build break in main, and you got unlucky. Hopefully the break has been fixed, and you want CI to rebase your change and rerun validation. -* To rebase and rerun all validation: - * Add a comment `/azp run runtime` - * Or, click on "re-run all checks" in the GitHub Checks tab - * Or, simply close and reopen the PR. - * Or, ammend your commit with `--amend --no-edit` and force push to your branch. - -### Additional information: - * You can list the available pipelines by adding a comment like `/azp list` or get the available commands by adding a comment like `azp help`. - * In the rare case the license/cla check fails to register a response, it can be rerun by issuing a GET request to `https://cla.dotnetfoundation.org/check/dotnet/runtime?pullRequest={pr_number}`. A successful response may be a redirect to `https://github.com`. - * Reach out to the infrastructure team for assistance on [Teams channel](https://teams.microsoft.com/l/channel/19%3ab27b36ecd10a46398da76b02f0411de7%40thread.skype/Infrastructure?groupId=014ca51d-be57-47fa-9628-a15efcc3c376&tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47) (for corpnet users) or on [Gitter](https://gitter.im/dotnet/community) in other cases. - -## What to do if you determine the failure is unrelated - -If you have determined the failure is definitely not caused by changes in your PR, please do this: - -* Search for an [existing issue](https://github.com/dotnet/runtime/issues). Usually the test method name or (if a crash/hang) the test assembly name are good search parameters. - * If there's an existing issue, add a comment with - * a) the link to the build - * b) the affected configuration (ie `net6.0-windows-Release-x64-Windows.81.Amd64.Open`) - * c) all console output including the error message and stack trace from the Azure DevOps tab (This is necessary as retention policies are in place that recycle old builds.) - * d) if there's a dump file (see Attachments tab in Azure DevOps) include that - * If the issue is already closed, reopen it and update the labels to reflect the current failure state. - * If there's no existing issue, create an issue with the same information listed above. - * Update the original pull request with a comment linking to the new or existing issue. -* In a follow-up Pull Request, disable the failing test(s) with the corresponding issue link tracking the disable. - * Update the tracking issue with the label `disabled-test`. - * For libraries tests add a [`[ActiveIssue(link)]`](https://github.com/dotnet/arcade/blob/master/src/Microsoft.DotNet.XUnitExtensions/src/Attributes/ActiveIssueAttribute.cs) attribute on the test method. You can narrow the disabling down to runtime variant, flavor, and platform. For an example see [File_AppendAllLinesAsync_Encoded](https://github.com/dotnet/runtime/blob/a259ec2e967d502f82163beba6b84da5319c5e08/src/libraries/System.IO.FileSystem/tests/File/AppendAsync.cs#L899) - * For runtime tests found under `src/tests`, please edit [`issues.targets`](https://github.com/dotnet/runtime/blob/main/src/tests/issues.targets). There are several groups for different types of disable (mono vs. coreclr, different platforms, different scenarios). Add the folder containing the test and issue mimicking any of the samples in the file. - -There are plenty of possible bugs, e.g. race conditions, where a failure might highlight a real problem and it won't manifest again on a retry. Therefore these steps should be followed for every iteration of the PR build, e.g. before retrying/rebuilding. - ## Blocking Pull Request Merging If for whatever reason you would like to move your pull request back to an in-progress status to avoid merging it in the current form, you can do that by adding [WIP] prefix to the pull request title. diff --git a/eng/pipelines/common/global-build-job.yml b/eng/pipelines/common/global-build-job.yml index cf30d702dda60..12d56d00e2d64 100644 --- a/eng/pipelines/common/global-build-job.yml +++ b/eng/pipelines/common/global-build-job.yml @@ -3,6 +3,7 @@ parameters: nameSuffix: '' buildArgs: '' archType: '' + hostedOs: '' osGroup: '' osSubgroup: '' container: '' @@ -35,8 +36,12 @@ parameters: jobs: - template: /eng/common/templates/job/job.yml parameters: - name: ${{ format('build_{0}{1}_{2}_{3}_{4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.nameSuffix) }} - displayName: ${{ format('Build {0}{1} {2} {3} {4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.nameSuffix) }} + ${{ if eq(parameters.hostedOs, '') }}: + name: ${{ format('build_{0}{1}_{2}_{3}_{4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.nameSuffix) }} + displayName: ${{ format('Build {0}{1} {2} {3} {4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.nameSuffix) }} + ${{ if ne(parameters.hostedOs, '') }}: + name: ${{ format('build_{0}{1}_{2}_{3}_{4}_{5}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.hostedOs, parameters.buildConfig, parameters.nameSuffix) }} + displayName: ${{ format('Build {0}{1} {2} {3} {4} {5}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.hostedOs, parameters.buildConfig, parameters.nameSuffix) }} pool: ${{ parameters.pool }} container: ${{ parameters.container }} condition: and(succeeded(), ${{ parameters.condition }}) diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index ade8c7aab981b..282fa56755081 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -273,7 +273,6 @@ jobs: jobTemplate: ${{ parameters.jobTemplate }} helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} variables: ${{ parameters.variables }} - hostedOs: Linux osGroup: Browser archType: wasm targetRid: browser-wasm @@ -282,6 +281,7 @@ jobs: image: ubuntu-18.04-webassembly-20210707133424-12f133e registry: mcr jobParameters: + hostedOs: Linux runtimeFlavor: ${{ parameters.runtimeFlavor }} stagedBuild: ${{ parameters.stagedBuild }} buildConfig: ${{ parameters.buildConfig }} @@ -297,12 +297,12 @@ jobs: jobTemplate: ${{ parameters.jobTemplate }} helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} variables: ${{ parameters.variables }} - hostedOs: windows osGroup: Browser archType: wasm targetRid: browser-wasm platform: Browser_wasm_win jobParameters: + hostedOs: windows runtimeFlavor: ${{ parameters.runtimeFlavor }} stagedBuild: ${{ parameters.stagedBuild }} buildConfig: ${{ parameters.buildConfig }} diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml index 214b56547b7ac..6aa8a54f24c0f 100644 --- a/eng/pipelines/common/templates/runtimes/run-test-job.yml +++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml @@ -73,7 +73,7 @@ jobs: - ${{ if not(or(eq(parameters.runtimeVariant, 'minijit'), eq(parameters.runtimeVariant, 'monointerpreter'))) }}: - ${{ if eq(parameters.runtimeVariant, 'llvmfullaot') }}: - ${{ format('{0}_llvmaot_product_build_{1}{2}_{3}_{4}', parameters.runtimeFlavor, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - - ${{ if not(eq(parameters.runtimeVariant, 'llvmfullaot')) }}: + - ${{ if ne(parameters.runtimeVariant, 'llvmfullaot') }}: - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: - ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }} @@ -109,7 +109,7 @@ jobs: - name: runtimeVariantArg value: '' - - ${{ if not(eq(parameters.runtimeVariant, '')) }}: + - ${{ if ne(parameters.runtimeVariant, '') }}: - name: runtimeVariantArg value: '/p:RuntimeVariant=${{ parameters.runtimeVariant }}' diff --git a/eng/pipelines/common/variables.yml b/eng/pipelines/common/variables.yml index d6b84f837c327..6e378369aa4fc 100644 --- a/eng/pipelines/common/variables.yml +++ b/eng/pipelines/common/variables.yml @@ -11,19 +11,17 @@ variables: - name: isOfficialBuild value: ${{ and(ne(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }} -- name: isFullMatrix +- name: isRollingBuild value: ${{ and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }} -- name: isNotFullMatrix - value: ${{ and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }} -- name: isNotManualAndIsPR - value: ${{ and(not(in(variables['Build.DefinitionName'], 'runtime-staging-manual', 'runtime-manual')), eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }} -- name: isManualOrIsNotPR - value: ${{ or(in(variables['Build.DefinitionName'], 'runtime-staging-manual', 'runtime-manual'), and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest'))) }} +- name: isExtraPlatformsBuild + value: ${{ eq(variables['Build.DefinitionName'], 'runtime-extra-platforms') }} +- name: isNotExtraPlatformsBuild + value: ${{ ne(variables['Build.DefinitionName'], 'runtime-extra-platforms') }} # We only run evaluate paths on runtime, runtime-staging and runtime-community pipelines on PRs # keep in sync with /eng/pipelines/common/xplat-setup.yml - name: dependOnEvaluatePaths - value: ${{ and(eq(variables['Build.Reason'], 'PullRequest'), in(variables['Build.DefinitionName'], 'runtime', 'runtime-staging', 'runtime-community')) }} + value: ${{ and(eq(variables['Build.Reason'], 'PullRequest'), in(variables['Build.DefinitionName'], 'runtime', 'runtime-staging', 'runtime-community', 'runtime-extra-platforms')) }} - name: debugOnPrReleaseOnRolling ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: value: Release diff --git a/eng/pipelines/common/xplat-setup.yml b/eng/pipelines/common/xplat-setup.yml index 05a6bc7c4a63c..e397bcdd456a6 100644 --- a/eng/pipelines/common/xplat-setup.yml +++ b/eng/pipelines/common/xplat-setup.yml @@ -22,8 +22,7 @@ jobs: shouldContinueOnError: ${{ and(endsWith(variables['Build.DefinitionName'], 'staging'), eq(variables['Build.Reason'], 'PullRequest')) }} # keep in sync with /eng/pipelines/common/variables.yml - nonPRBuild: ${{ and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }} - dependOnEvaluatePaths: ${{ and(eq(variables['Build.Reason'], 'PullRequest'), in(variables['Build.DefinitionName'], 'runtime', 'runtime-staging', 'runtime-community')) }} + dependOnEvaluatePaths: ${{ and(eq(variables['Build.Reason'], 'PullRequest'), in(variables['Build.DefinitionName'], 'runtime', 'runtime-staging', 'runtime-community', 'runtime-extra-platforms')) }} variables: # Disable component governance in our CI builds. These builds are not shipping nor @@ -50,8 +49,12 @@ jobs: value: $(buildConfigUpper) - name: _runSmokeTestsOnlyArg - value: '/p:RunSmokeTestsOnly=$(isNotManualAndIsPR)' - - ${{ if or(eq(parameters.osGroup, 'windows'), eq(parameters.hostedOs, 'windows')) }}: + value: '/p:RunSmokeTestsOnly=$(isNotExtraPlatformsBuild)' + + - name: _hostedOs + value: ${{ parameters.jobParameters.hostedOs }} + + - ${{ if or(eq(parameters.osGroup, 'windows'), eq(parameters.jobParameters.hostedOs, 'windows')) }}: - name: archiveExtension value: '.zip' - name: archiveType @@ -69,7 +72,7 @@ jobs: - name: logRootNameArg value: 'log ' - - ${{ if and(ne(parameters.osGroup, 'windows'), ne(parameters.hostedOs, 'windows')) }}: + - ${{ if and(ne(parameters.osGroup, 'windows'), ne(parameters.jobParameters.hostedOs, 'windows')) }}: - name: archiveExtension value: '.tar.gz' - name: archiveType @@ -117,12 +120,12 @@ jobs: ${{ if eq(parameters.jobParameters.pool, '') }}: pool: # Public Linux Build Pool - ${{ if and(or(in(parameters.osGroup, 'Linux', 'FreeBSD', 'Android', 'Tizen'), eq(parameters.hostedOs, 'Linux')), eq(variables['System.TeamProject'], 'public')) }}: + ${{ if and(or(in(parameters.osGroup, 'Linux', 'FreeBSD', 'Android', 'Tizen'), eq(parameters.jobParameters.hostedOs, 'Linux')), eq(variables['System.TeamProject'], 'public')) }}: name: NetCore1ESPool-Public demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open # Official Build Linux Pool - ${{ if and(or(in(parameters.osGroup, 'Linux', 'FreeBSD', 'Browser', 'Android', 'Tizen'), eq(parameters.hostedOs, 'Linux')), ne(variables['System.TeamProject'], 'public')) }}: + ${{ if and(or(in(parameters.osGroup, 'Linux', 'FreeBSD', 'Browser', 'Android', 'Tizen'), eq(parameters.jobParameters.hostedOs, 'Linux')), ne(variables['System.TeamProject'], 'public')) }}: name: NetCore1ESPool-Internal demands: ImageOverride -equals Build.Ubuntu.1804.Amd64 @@ -136,7 +139,7 @@ jobs: demands: ImageOverride -equals Build.Windows.10.Amd64.VS2019 # Public Windows Build Pool - ${{ if and(or(eq(parameters.osGroup, 'windows'), eq(parameters.hostedOs, 'windows')), eq(variables['System.TeamProject'], 'public')) }}: + ${{ if and(or(eq(parameters.osGroup, 'windows'), eq(parameters.jobParameters.hostedOs, 'windows')), eq(variables['System.TeamProject'], 'public')) }}: name: NetCore1ESPool-Public demands: ImageOverride -equals Build.Windows.10.Amd64.VS2019.Open diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index ac074ab9903f8..644c64d975bac 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -28,26 +28,26 @@ jobs: # Linux arm - ${{ if eq(parameters.platform, 'Linux_arm') }}: - - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: + - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - (Debian.10.Arm32.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-arm32v7-20210304164340-6616c63 - (Debian.11.Arm32.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-arm32v7-20210304164347-5a7c380 # Linux arm64 - ${{ if eq(parameters.platform, 'Linux_arm64') }}: - - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: - - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-helix-arm64v8-20210106155927-56c6673 + - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - (Ubuntu.2110.Arm64.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-21.10-helix-arm64v8-20211116135000-0f8d97e - - ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}: + - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-helix-arm64v8-20210106155927-56c6673 # Linux musl x64 - ${{ if eq(parameters.platform, 'Linux_musl_x64') }}: - - (Alpine.314.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.14-helix-amd64-20210910135833-1848e19 - - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: + - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: + - (Alpine.314.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.14-helix-amd64-20210910135833-1848e19 + - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - (Alpine.313.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.13-helix-amd64-20210910135845-8a6f4f3 # Linux musl arm64 - - ${{ if and(eq(parameters.platform, 'Linux_musl_arm64'), eq(parameters.jobParameters.isFullMatrix, true)) }}: + - ${{ if and(eq(parameters.platform, 'Linux_musl_arm64'), or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true))) }}: - (Alpine.313.Arm64.Open)ubuntu.1804.armarch.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.13-helix-arm64v8-20210910135808-8a6f4f3 - (Alpine.314.Arm64.Open)ubuntu.1804.armarch.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.14-helix-arm64v8-20210910135810-8a6f4f3 @@ -62,21 +62,16 @@ jobs: - (Ubuntu.2110.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-21.10-helix-amd64-20211116135132-0f8d97e - (Debian.10.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-amd64-bfcd90a-20200121150006 - ${{ if or(ne(parameters.jobParameters.testScope, 'outerloop'), ne(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: - - (Centos.7.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-mlnet-helix-20210714125435-dde38af - - (Centos.8.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-8-helix-20201229003624-c1bf759 - - RedHat.7.Amd64.Open - - Ubuntu.1804.Amd64.Open - - SLES.12.Amd64.Open + - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: + - (Centos.8.Amd64.Open)Ubuntu.1604.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-8-helix-20201229003624-c1bf759 - SLES.15.Amd64.Open - - (Fedora.34.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-34-helix-20210913123654-4f64125 - - (Ubuntu.2110.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-21.10-helix-amd64-20211116135132-0f8d97e - - (Debian.10.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-amd64-20210304164434-56c6673 + - (Fedora.34.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-34-helix-20210913123654-4f64125 + - (Ubuntu.2110.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-21.04-helix-amd64-20210922170909-34a2d72 - (Debian.11.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-amd64-20210304164428-5a7c380 - - (Mariner.1.0.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-1.0-helix-20210528192219-92bf620 - - (openSUSE.15.2.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.2-helix-amd64-20211018152525-9cc02fe - - ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}: - - (Centos.7.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-mlnet-helix-20210714125435-dde38af + - (Mariner.1.0.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-1.0-helix-20210528192219-92bf620 + - (openSUSE.15.2.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.2-helix-amd64-20211018152525-9cc02fe + - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: + - (Centos.7.Amd64.Open)Ubuntu.1604.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-mlnet-helix-20210714125435-dde38af - RedHat.7.Amd64.Open - (Debian.10.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-amd64-20210304164434-56c6673 - Ubuntu.1804.Amd64.Open @@ -94,10 +89,9 @@ jobs: # OSX x64 - ${{ if eq(parameters.platform, 'OSX_x64') }}: - - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: + - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - OSX.1014.Amd64.Open - - OSX.1015.Amd64.Open - - ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}: + - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - OSX.1015.Amd64.Open # Android @@ -126,18 +120,18 @@ jobs: - ${{ if eq(parameters.platform, 'windows_x64') }}: # netcoreapp - ${{ if notIn(parameters.jobParameters.framework, 'net48') }}: + # libraries on mono outerloop - ${{ if and(eq(parameters.jobParameters.testScope, 'outerloop'), eq(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - Windows.81.Amd64.Open - Windows.10.Amd64.Server19H1.Open + # libraries on coreclr (outerloop and innerloop), or libraries on mono innerloop - ${{ if or(ne(parameters.jobParameters.testScope, 'outerloop'), ne(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: - - Windows.81.Amd64.Open + - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - Windows.10.Amd64.ServerRS5.Open - - Windows.10.Amd64.Server19H1.Open - - ${{ if ne(parameters.jobParameters.runtimeFlavor, 'mono') }}: - - (Windows.Nano.1809.Amd64.Open)windows.10.amd64.serverrs5.open@mcr.microsoft.com/dotnet-buildtools/prereqs:nanoserver-1809-helix-amd64-08e8e40-20200107182504 + - ${{ if ne(parameters.jobParameters.testScope, 'outerloop') }}: + - Windows.10.Amd64.Server19H1.Open - (Windows.Server.Core.1909.Amd64.Open)windows.10.amd64.server20h1.open@mcr.microsoft.com/dotnet-buildtools/prereqs:windowsservercore-2004-helix-amd64-20200904200251-272704c - - ${{ if ne(parameters.jobParameters.isFullMatrix, true) }}: + - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - Windows.81.Amd64.Open - Windows.10.Amd64.Server19H1.ES.Open - Windows.11.Amd64.ClientPre.Open @@ -154,20 +148,18 @@ jobs: - ${{ if eq(parameters.platform, 'windows_x86') }}: # netcoreapp - ${{ if notIn(parameters.jobParameters.framework, 'net48') }}: + # mono outerloop - ${{ if and(eq(parameters.jobParameters.testScope, 'outerloop'), eq(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - Windows.7.Amd64.Open - Windows.10.Amd64.ServerRS5.Open + # libraries on coreclr (outerloop and innerloop), or libraries on mono innerloop - ${{ if or(ne(parameters.jobParameters.testScope, 'outerloop'), ne(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: - - Windows.7.Amd64.Open + - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - Windows.10.Amd64.ServerRS5.Open - Windows.10.Amd64.Server19H1.Open - - ${{ if ne(parameters.jobParameters.isFullMatrix, true) }}: - - ${{ if eq(parameters.jobParameters.buildConfig, 'Release') }}: - - Windows.10.Amd64.Server19H1.ES.Open - - ${{ if eq(parameters.jobParameters.buildConfig, 'Debug') }}: - - Windows.7.Amd64.Open - - Windows.10.Amd64.Server19H1.Open + - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: + - Windows.10.Amd64.Server19H1.ES.Open + - Windows.7.Amd64.Open # .NETFramework - ${{ if eq(parameters.jobParameters.framework, 'net48') }}: diff --git a/eng/pipelines/libraries/outerloop-mono.yml b/eng/pipelines/libraries/outerloop-mono.yml index 1267cf72a62de..17a7101e26004 100644 --- a/eng/pipelines/libraries/outerloop-mono.yml +++ b/eng/pipelines/libraries/outerloop-mono.yml @@ -23,7 +23,7 @@ jobs: platforms: - windows_x86 - Browser_wasm - - ${{ if eq(variables['isFullMatrix'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - windows_x64 - Linux_x64 - Linux_arm @@ -34,7 +34,7 @@ jobs: nameSuffix: AllSubsets_Mono buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) -testscope outerloop /p:ArchiveTests=true timeoutInMinutes: 180 - isFullMatrix: ${{ variables['isFullMatrix'] }} + includeAllPlatforms: ${{ variables['isRollingBuild'] }} # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -44,7 +44,7 @@ jobs: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) - - ${{ if eq(variables['isFullMatrix'], false) }}: + - ${{ if eq(variables['isRollingBuild'], false) }}: - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml @@ -61,7 +61,7 @@ jobs: nameSuffix: AllSubsets_Mono buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) -testscope outerloop /p:ArchiveTests=true timeoutInMinutes: 180 - isFullMatrix: ${{ variables['isFullMatrix'] }} + includeAllPlatforms: ${{ variables['isRollingBuild'] }} # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: diff --git a/eng/pipelines/libraries/outerloop.yml b/eng/pipelines/libraries/outerloop.yml index 28932a0baff3c..72c2de49363a2 100644 --- a/eng/pipelines/libraries/outerloop.yml +++ b/eng/pipelines/libraries/outerloop.yml @@ -27,7 +27,7 @@ jobs: - ${{ if eq(variables['includeLinuxOuterloop'], true) }}: - Linux_x64 - Linux_musl_x64 - - ${{ if eq(variables['isFullMatrix'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - Linux_arm - Linux_arm64 - Linux_musl_arm64 @@ -46,27 +46,27 @@ jobs: platforms: - ${{ if eq(variables['includeWindowsOuterloop'], true) }}: - windows_x86 - - ${{ if eq(variables['isFullMatrix'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - windows_x64 - ${{ if eq(variables['includeLinuxOuterloop'], true) }}: - - ${{ if eq(variables['isFullMatrix'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - Linux_x64 - Linux_arm - Linux_arm64 - Linux_musl_x64 - Linux_musl_arm64 - - ${{ if and(eq(variables['includeOsxOuterloop'], true), eq(variables['isFullMatrix'], true)) }}: + - ${{ if and(eq(variables['includeOsxOuterloop'], true), eq(variables['isRollingBuild'], true)) }}: - OSX_arm64 - OSX_x64 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: isOfficialBuild: ${{ variables['isOfficialBuild'] }} - isFullMatrix: ${{ variables['isFullMatrix'] }} + includeAllPlatforms: ${{ variables['isRollingBuild'] }} runTests: true testScope: outerloop liveRuntimeBuildConfig: release - - ${{ if eq(variables['isFullMatrix'], false) }}: + - ${{ if eq(variables['isRollingBuild'], false) }}: - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/libraries/build-job.yml @@ -83,7 +83,7 @@ jobs: helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: isOfficialBuild: ${{ variables['isOfficialBuild'] }} - isFullMatrix: ${{ variables['isFullMatrix'] }} + includeAllPlatforms: ${{ variables['isRollingBuild'] }} runTests: true testScope: outerloop liveRuntimeBuildConfig: release @@ -95,12 +95,12 @@ jobs: buildConfig: Release platforms: - windows_x86 - - ${{ if eq(variables['isFullMatrix'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - windows_x64 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: isOfficialBuild: ${{ variables['isOfficialBuild'] }} - isFullMatrix: ${{ variables['isFullMatrix'] }} + includeAllPlatforms: ${{ variables['isRollingBuild'] }} framework: net48 runTests: true testScope: outerloop diff --git a/eng/pipelines/libraries/variables.yml b/eng/pipelines/libraries/variables.yml index 9bb89d7d49384..2abd5adabe2c9 100644 --- a/eng/pipelines/libraries/variables.yml +++ b/eng/pipelines/libraries/variables.yml @@ -6,7 +6,7 @@ variables: value: $(Build.SourcesDirectory)/src/libraries - name: pipelinesPath value: /eng/pipelines/libraries - - name: isFullMatrix + - name: isRollingBuild value: ${{ notIn(variables['Build.Reason'], 'PullRequest') }} - name: includeWindowsOuterloop value: ${{ or(endsWith(variables['Build.DefinitionName'], 'windows'), endsWith(variables['Build.DefinitionName'], 'outerloop')) }} diff --git a/eng/pipelines/runtime-community.yml b/eng/pipelines/runtime-community.yml index 5bebcc00a2663..f588ad52b0f33 100644 --- a/eng/pipelines/runtime-community.yml +++ b/eng/pipelines/runtime-community.yml @@ -46,7 +46,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -56,4 +56,4 @@ jobs: or( eq(variables['librariesContainsChange'], true), eq(variables['monoContainsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) diff --git a/eng/pipelines/runtime-manual.yml b/eng/pipelines/runtime-extra-platforms.yml similarity index 60% rename from eng/pipelines/runtime-manual.yml rename to eng/pipelines/runtime-extra-platforms.yml index 997849ed2b86c..844666bdea5dc 100644 --- a/eng/pipelines/runtime-manual.yml +++ b/eng/pipelines/runtime-extra-platforms.yml @@ -1,161 +1,125 @@ +# This pipeline includes the platforms that we don't have resources to run on every PR but that we want +# to still have test coverage, we run this pipeline on a schedule and also developers can run it +# via /azp run command on PRs. This pipeline permits us to have the main runtime pipeline run the same +# platforms in PRs and Scheduled builds. + +# Setting batch to true, triggers one build at a time. +# if there is a push while a build in progress, it will wait, +# until the running build finishes, and produce a build with all the changes +# that happened during the last build. trigger: none +schedules: + - cron: "0 9,21 * * *" # run at 9:00 and 21:00 (UTC) which is 1:00 and 13:00 (PST). + displayName: Runtime extra main schedule + branches: + include: + - main + always: false # run only if there were changes since the last successful scheduled run. + - cron: "0 6,18 * * *" # run at 6:00 and 18:00 (UTC) which is 22:00 and 10:00 (PST). + displayName: Runtime extra release schedule + branches: + include: + - release/* + always: false # run only if there were changes since the last successful scheduled run. + variables: - template: /eng/pipelines/common/variables.yml jobs: # -# iOS/tvOS interp - requires AOT Compilation and Interp flags -# Build the whole product using Mono and run libraries tests +# Evaluate paths # -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - iOSSimulator_x64 - - tvOSSimulator_x64 - - iOSSimulator_arm64 - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:RunAOTCompilation=true /p:MonoForceInterpreter=true /p:BuildDarwinFrameworks=true - timeoutInMinutes: 180 - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - interpreter: true - testRunNamePrefixSuffix: Mono_$(_BuildConfig) +- ${{ if eq(variables.dependOnEvaluatePaths, true) }}: + - template: /eng/pipelines/common/evaluate-default-paths.yml # -# MacCatalyst interp - requires AOT Compilation and Interp flags -# Build the whole product using Mono and run libraries tests +# Build CoreCLR release +# Always as they are needed by Installer and we always build and test the Installer. # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono + jobTemplate: /eng/pipelines/coreclr/templates/build-job.yml + buildConfig: release platforms: - - MacCatalyst_x64 - # don't run tests on arm64 PRs until we can get significantly more devices - - ${{ if eq(variables['isFullMatrix'], true) }}: - - MacCatalyst_arm64 + - Linux_x64 + - Linux_arm + - Linux_arm64 + - Linux_musl_x64 + - OSX_x64 + - windows_x64 + - windows_x86 + - windows_arm64 jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=adhoc /p:RunAOTCompilation=true /p:MonoForceInterpreter=true /p:BuildDarwinFrameworks=true - timeoutInMinutes: 180 - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - interpreter: true - testRunNamePrefixSuffix: Mono_$(_BuildConfig) # -# MacCatalyst interp - requires AOT Compilation and Interp flags -# Build the whole product using Mono and run libraries tests -# The test app is built with the App Sandbox entitlement +# Build libraries using live CoreLib # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + jobTemplate: /eng/pipelines/libraries/build-job.yml buildConfig: Release - runtimeFlavor: mono platforms: - - MacCatalyst_x64 - # don't run tests on arm64 PRs until we can get significantly more devices - - ${{ if eq(variables['isFullMatrix'], true) }}: - - MacCatalyst_arm64 - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono_AppSandbox - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=adhoc /p:RunAOTCompilation=true /p:MonoForceInterpreter=true /p:BuildDarwinFrameworks=true /p:EnableAppSandbox=true - timeoutInMinutes: 180 - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - interpreter: true - testRunNamePrefixSuffix: Mono_$(_BuildConfig) + - Linux_x64 + - Linux_arm + - Linux_arm64 + - Linux_musl_x64 + - OSX_x64 + - windows_x64 + - windows_x86 + - windows_arm64 # -# iOS/tvOS devices - Full AOT + AggressiveTrimming to reduce size -# Build the whole product using Mono and run libraries tests +# Libraries Release Test Execution against a release coreclr runtime +# Only when the PR contains a libraries change # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + jobTemplate: /eng/pipelines/libraries/run-test-job.yml buildConfig: Release - runtimeFlavor: mono platforms: - - iOS_arm64 - - tvOS_arm64 - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true /p:BuildTestsOnHelix=true /p:UsePortableRuntimePack=true /p:BuildDarwinFrameworks=true - timeoutInMinutes: 180 - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:NeedsToBuildAppsOnHelix=true - -# -# Build the whole product using Mono and run libraries tests -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml + - Linux_x64 + - Linux_arm + - Linux_arm64 + - Linux_musl_x64 + - OSX_x64 + - windows_x64 + - windows_x86 + - windows_arm64 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Android_x86 - - Android_x64 jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) - timeoutInMinutes: 180 - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) + isOfficialBuild: false + isExtraPlatforms: ${{ variables.isExtraPlatformsBuild }} + testScope: innerloop + liveRuntimeBuildConfig: release + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(variables['isRollingBuild'], true)) +# Run net48 tests on win-x64 - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + jobTemplate: /eng/pipelines/libraries/build-job.yml buildConfig: Release - runtimeFlavor: mono platforms: - - Android_arm - - Android_arm64 + - windows_x64 + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) - timeoutInMinutes: 180 - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) + framework: net48 + runTests: true + testScope: innerloop + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(variables['isRollingBuild'], true)) + +#### MONO LEGS # -# Build the whole product using Mono and run libraries tests +# Build the whole product using Mono and run libraries tests, for Wasm.Build.Tests # - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -164,132 +128,137 @@ jobs: buildConfig: Release runtimeFlavor: mono platforms: - - Windows_x64 + # BuildWasmApps should only happen on the extra platforms build as we already have coverage for this build on PRs. + - Browser_wasm + # disable until https://github.com/dotnet/runtime/issues/63987 is fixed + # - Browser_wasm_win + variables: + # map dependencies variables to local variables + - name: wasmbuildtestsContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'] ] jobParameters: - testScope: innerloop - nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true - timeoutInMinutes: 120 + isExtraPlatforms: ${{ variables.isExtraPlatformsBuild }} + testGroup: innerloop + nameSuffix: WasmBuildTests + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmBuildTests=true /p:TestAssemblies=false /p:BrowserHost=$(_hostedOs) + timeoutInMinutes: 180 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'], true), + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) + testRunNamePrefixSuffix: Mono_$(_BuildConfig)_$(_hostedOs) + extraHelixArguments: /p:BrowserHost=$(_hostedOs) + scenarios: + - buildwasmapps + condition: >- + or( + eq(variables['wasmbuildtestsContainsChange'], true), + eq(variables['isRollingBuild'], true)) # -# Build the whole product using Mono for Android and run runtime tests with interpreter +# Build Browser_wasm, on windows, run console and browser tests # - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml - buildConfig: Release + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: release runtimeFlavor: mono platforms: - - Android_x64 + # disable until https://github.com/dotnet/runtime/issues/63987 is fixed + # - Browser_wasm_win variables: - - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: pr/dotnet/runtime/$(Build.SourceBranch) - - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: ci/dotnet/runtime/$(Build.SourceBranch) - - name: timeoutPerTestInMinutes - value: 60 - - name: timeoutPerTestCollectionInMinutes - value: 180 + # map dependencies variables to local variables + - name: librariesContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: monoContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono_RuntimeTests_Interp - buildArgs: -s mono+libs -c $(_BuildConfig) - timeoutInMinutes: 240 - runtimeVariant: monointerpreter + nameSuffix: ConsoleBrowserTests + buildArgs: -subset mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows + timeoutInMinutes: 180 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), + eq(variables['isRollingBuild'], true)) # extra steps, run tests - extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml + extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) + testRunNamePrefixSuffix: Windows_wasm_$(_BuildConfig) + extraHelixArguments: /p:BrowserHost=windows + scenarios: + - normal + - wasmtestonbrowser + condition: >- + or( + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true), + eq(variables['isRollingBuild'], true)) # -# Build the whole product using Mono and run runtime tests with the JIT. +# Build for Browser/wasm, with EnableAggressiveTrimming=true # - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml buildConfig: Release runtimeFlavor: mono platforms: - - iOSSimulator_x64 + - Browser_wasm variables: - - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: pr/dotnet/runtime/$(Build.SourceBranch) - - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: ci/dotnet/runtime/$(Build.SourceBranch) - - name: timeoutPerTestInMinutes - value: 60 - - name: timeoutPerTestCollectionInMinutes - value: 180 + # map dependencies variables to local variables + - name: librariesContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: monoContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: + isExtraPlatforms: ${{ variables.isExtraPlatformsBuild }} testGroup: innerloop - nameSuffix: AllSubsets_Mono_RuntimeTests - buildArgs: -s mono+libs -c $(_BuildConfig) - timeoutInMinutes: 240 + nameSuffix: AllSubsets_Mono_EAT + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=false + timeoutInMinutes: 180 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), + eq(variables['isRollingBuild'], true)) # extra steps, run tests - extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml + extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) + extraHelixArguments: /p:NeedsToBuildWasmAppsOnHelix=true $(_runSmokeTestsOnlyArg) + scenarios: + - normal + condition: >- + or( + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true), + eq(variables['isRollingBuild'], true)) # -# Build the whole product using Mono for Android and run runtime tests with Android devices -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Android_arm64 - variables: - - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: pr/dotnet/runtime/$(Build.SourceBranch) - - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: ci/dotnet/runtime/$(Build.SourceBranch) - - name: timeoutPerTestInMinutes - value: 60 - - name: timeoutPerTestCollectionInMinutes - value: 180 - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono_RuntimeTests - buildArgs: -s mono+libs -c $(_BuildConfig) - timeoutInMinutes: 240 - # don't run tests on PRs until we can get significantly more devices - # Turn off the testing for now, until https://github.com/dotnet/xharness/issues/663 gets resolved - # ${{ if eq(variables['isFullMatrix'], true) }}: - # # extra steps, run tests - # extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml - # extraStepsParameters: - # creator: dotnet-bot - # testRunNamePrefixSuffix: Mono_$(_BuildConfig) - -# -# Build Browser_wasm, on windows, run console and browser tests +# Build for Browser/wasm with RunAOTCompilation=true # - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: release + buildConfig: Release runtimeFlavor: mono platforms: - - Browser_wasm_win + - Browser_wasm + # disable until https://github.com/dotnet/runtime/issues/63987 is fixed + # - Browser_wasm_win variables: # map dependencies variables to local variables - name: librariesContainsChange @@ -297,78 +266,79 @@ jobs: - name: monoContainsChange value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: + isExtraPlatforms: ${{ variables.isExtraPlatformsBuild }} testGroup: innerloop - nameSuffix: Windows_wasm - buildArgs: -subset mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows + nameSuffix: AllSubsets_Mono_AOT + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true /p:BrowserHost=$(_hostedOs) timeoutInMinutes: 180 condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:BrowserHost=windows + testRunNamePrefixSuffix: Mono_AOT_$(_BuildConfig)_$(_hostedOs) + extraHelixArguments: /p:NeedsToBuildWasmAppsOnHelix=true $(_runSmokeTestsOnlyArg) /p:BrowserHost=$(_hostedOs) scenarios: - normal - - WasmTestOnBrowser - - WasmTestOnNodeJs condition: >- or( eq(variables['librariesContainsChange'], true), eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) +# +# Build the whole product using Mono and run runtime tests +# - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: release + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + buildConfig: Release runtimeFlavor: mono platforms: - - Browser_wasm_win + - Browser_wasm variables: - # map dependencies variables to local variables - - name: wasmbuildtestsContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'] ] + - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: + - name: _HelixSource + value: pr/dotnet/runtime/$(Build.SourceBranch) + - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: + - name: _HelixSource + value: ci/dotnet/runtime/$(Build.SourceBranch) + - name: timeoutPerTestInMinutes + value: 10 + - name: timeoutPerTestCollectionInMinutes + value: 200 jobParameters: testGroup: innerloop - nameSuffix: Windows_wasm_WBT - buildArgs: -subset mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows /p:TestWasmBuildTests=true /p:TestAssemblies=false + nameSuffix: AllSubsets_Mono_RuntimeTests + buildArgs: -s mono+libs -c $(_BuildConfig) timeoutInMinutes: 180 condition: >- or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(variables['isRollingBuild'], true)) + extraStepsTemplate: /eng/pipelines/common/templates/runtimes/wasm-runtime-and-send-to-helix.yml extraStepsParameters: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:BrowserHost=windows - scenarios: - - buildwasmapps - condition: >- - or( - eq(variables['wasmbuildtestsContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) +# +# Build the whole product using Mono and run libraries tests +# - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: release + buildConfig: Release runtimeFlavor: mono platforms: - - Browser_wasm_win + - Windows_x64 variables: # map dependencies variables to local variables - name: librariesContainsChange @@ -376,34 +346,30 @@ jobs: - name: monoContainsChange value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: - testGroup: innerloop - nameSuffix: Windows_wasm_AOT - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) - timeoutInMinutes: 180 + testScope: innerloop + nameSuffix: AllSubsets_Mono + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true + timeoutInMinutes: 120 condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:BrowserHost=windows /p:NeedsToBuildWasmAppsOnHelix=true $(_runSmokeTestsOnlyArg) - scenarios: - - normal condition: >- or( eq(variables['librariesContainsChange'], true), eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # -# Build for Browser/wasm, with EnableAggressiveTrimming=true +# iOS/tvOS devices - Full AOT + AggressiveTrimming to reduce size +# Build the whole product using Mono and run libraries tests # - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -412,7 +378,8 @@ jobs: buildConfig: Release runtimeFlavor: mono platforms: - - Browser_wasm + - iOS_arm64 + - tvOS_arm64 variables: # map dependencies variables to local variables - name: librariesContainsChange @@ -421,21 +388,26 @@ jobs: value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono_EAT - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:RunSmokeTestsOnly=false /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=false + nameSuffix: AllSubsets_Mono + buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:UsePortableRuntimePack=true /p:BuildDarwinFrameworks=true timeoutInMinutes: 180 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:NeedsToBuildWasmAppsOnHelix=true /p:RunSmokeTestsOnly=false - scenarios: - - normal + extraHelixArguments: /p:NeedsToBuildAppsOnHelix=true + condition: >- + or( + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true), + eq(variables['isRollingBuild'], true)) -# -# Build for Browser/wasm with RunAOTCompilation=true -# - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml @@ -443,7 +415,8 @@ jobs: buildConfig: Release runtimeFlavor: mono platforms: - - Browser_wasm + - Android_arm + - Android_arm64 variables: # map dependencies variables to local variables - name: librariesContainsChange @@ -452,17 +425,24 @@ jobs: value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono_AOT - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:RunSmokeTestsOnly=false /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true + nameSuffix: AllSubsets_Mono + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) timeoutInMinutes: 180 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:NeedsToBuildWasmAppsOnHelix=true /p:RunSmokeTestsOnly=false - scenarios: - - normal + condition: >- + or( + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true), + eq(variables['isRollingBuild'], true)) # # Build for Browser/wasm and test it on v8, browser, and nodejs @@ -477,8 +457,6 @@ jobs: - Browser_wasm variables: # map dependencies variables to local variables - - name: librariesContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] - name: monoContainsChange value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: @@ -488,8 +466,8 @@ jobs: timeoutInMinutes: 180 condition: >- or( - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -501,44 +479,46 @@ jobs: - WasmTestOnNodeJs condition: >- or( - eq(variables['librariesContainsChange'], true), eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build the whole product using Mono and run runtime tests +# Build Mono release +# Only when libraries, mono, or the runtime tests changed +# Currently only these architectures are needed for the runtime tests. +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/mono/templates/build-job.yml + runtimeFlavor: mono + buildConfig: release + platforms: + - Linux_arm64 + jobParameters: + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(variables['isRollingBuild'], true)) + # +# Mono Test builds with CoreCLR runtime tests using live libraries debug build +# Only when Mono is changed - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml - buildConfig: Release + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml + buildConfig: release runtimeFlavor: mono platforms: - - Browser_wasm - variables: - - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: pr/dotnet/runtime/$(Build.SourceBranch) - - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: ci/dotnet/runtime/$(Build.SourceBranch) - - name: timeoutPerTestInMinutes - value: 10 - - name: timeoutPerTestCollectionInMinutes - value: 200 + - CoreClrTestBuildHost # Either OSX_x64 or Linux_x64 jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono_RuntimeTests - buildArgs: -s mono+libs -c $(_BuildConfig) - timeoutInMinutes: 180 - # NOTE: Per PR test execution is not recommended for mobile runtime tests - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/common/templates/runtimes/wasm-runtime-and-send-to-helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(variables['isRollingBuild'], true)) # Wasm debugger tests - template: /eng/pipelines/common/platform-matrix.yml @@ -579,7 +559,8 @@ jobs: buildConfig: Release runtimeFlavor: mono platforms: - - Browser_wasm_win + # disable until https://github.com/dotnet/runtime/issues/63987 is fixed + # - Browser_wasm_win variables: # map dependencies variables to local variables - name: wasmdebuggertestsContainsChange @@ -630,9 +611,100 @@ jobs: nameSuffix: AllSubsets_Mono_RuntimeTests buildArgs: -s mono+libs -c $(_BuildConfig) timeoutInMinutes: 240 - # NOTE: Per PR test execution is not recommended for mobile runtime tests + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml extraStepsParameters: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) + +# +# Build the whole product using Mono for Android and run runtime tests with interpreter +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - Android_x64 + variables: + - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: + - name: _HelixSource + value: pr/dotnet/runtime/$(Build.SourceBranch) + - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: + - name: _HelixSource + value: ci/dotnet/runtime/$(Build.SourceBranch) + - name: timeoutPerTestInMinutes + value: 60 + - name: timeoutPerTestCollectionInMinutes + value: 180 + jobParameters: + testGroup: innerloop + nameSuffix: AllSubsets_Mono_RuntimeTests_Interp + buildArgs: -s mono+libs -c $(_BuildConfig) + timeoutInMinutes: 240 + runtimeVariant: monointerpreter + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(variables['isRollingBuild'], true)) + # NOTE: Per PR test execution is not recommended for runtime tests + ${{ if eq(variables['isRollingBuild'], true) }}: + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Mono_$(_BuildConfig) + +# +# Mono CoreCLR runtime Test executions using live libraries in jit mode +# Only when Mono is changed +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml + buildConfig: release + runtimeFlavor: mono + platforms: + - Linux_arm64 + helixQueueGroup: pr + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + jobParameters: + testGroup: innerloop + liveLibrariesBuildConfig: Release + liveRuntimeBuildConfig: release + runtimeVariant: minijit + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(variables['isRollingBuild'], true)) + +# +# Mono CoreCLR runtime Test executions using live libraries in interpreter mode +# Only when Mono is changed +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml + buildConfig: release + runtimeFlavor: mono + platforms: + - Linux_arm64 + helixQueueGroup: pr + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + jobParameters: + testGroup: innerloop + liveLibrariesBuildConfig: Release + liveRuntimeBuildConfig: release + runtimeVariant: monointerpreter + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(variables['isRollingBuild'], true)) diff --git a/eng/pipelines/runtime-staging.yml b/eng/pipelines/runtime-staging.yml index 4288d372433df..42803677d0037 100644 --- a/eng/pipelines/runtime-staging.yml +++ b/eng/pipelines/runtime-staging.yml @@ -75,7 +75,7 @@ jobs: - iOSSimulator_x64 - tvOSSimulator_x64 # don't run tests on arm64 PRs until we can get significantly more devices - - ${{ if eq(variables['isManualOrIsNotPR'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - iOSSimulator_arm64 variables: # map dependencies variables to local variables @@ -93,8 +93,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -105,8 +104,7 @@ jobs: or( eq(variables['librariesContainsChange'], true), eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # MacCatalyst interp - requires AOT Compilation and Interp flags @@ -121,7 +119,7 @@ jobs: platforms: - MacCatalyst_x64 # don't run tests on arm64 PRs until we can get significantly more devices - - ${{ if eq(variables['isFullMatrix'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - MacCatalyst_arm64 variables: # map dependencies variables to local variables @@ -139,8 +137,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -149,10 +146,9 @@ jobs: testRunNamePrefixSuffix: Mono_$(_BuildConfig) condition: >- or( - eq(variables['librariesContainsChange'], true), - eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true), + eq(variables['isRollingBuild'], true)) # # MacCatalyst interp - requires AOT Compilation and Interp flags @@ -168,7 +164,7 @@ jobs: platforms: - MacCatalyst_x64 # don't run tests on arm64 PRs until we can get significantly more devices - - ${{ if eq(variables['isFullMatrix'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - MacCatalyst_arm64 variables: # map dependencies variables to local variables @@ -185,8 +181,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -195,53 +190,9 @@ jobs: testRunNamePrefixSuffix: Mono_$(_BuildConfig) condition: >- or( - eq(variables['librariesContainsChange'], true), - eq(variables['monoContainsChange'], true), - eq(variables['isFullMatrix'], true)) - -# -# iOS/tvOS devices - Full AOT + AggressiveTrimming to reduce size -# Build the whole product using Mono and run libraries tests -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - iOS_arm64 - - tvOS_arm64 - variables: - # map dependencies variables to local variables - - name: librariesContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] - - name: monoContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:UsePortableRuntimePack=true /p:BuildDarwinFrameworks=true - timeoutInMinutes: 180 - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:NeedsToBuildAppsOnHelix=true - condition: >- - or( - eq(variables['librariesContainsChange'], true), - eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true), + eq(variables['isRollingBuild'], true)) # # Build the whole product using Mono and run libraries tests @@ -271,88 +222,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - condition: >- - or( - eq(variables['librariesContainsChange'], true), - eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Android_arm - - Android_arm64 - variables: - # map dependencies variables to local variables - - name: librariesContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] - - name: monoContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) - timeoutInMinutes: 180 - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - condition: >- - or( - eq(variables['librariesContainsChange'], true), - eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - -# -# Build the whole product using Mono and run libraries tests -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Windows_x64 - variables: - # map dependencies variables to local variables - - name: librariesContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] - - name: monoContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] - jobParameters: - testScope: innerloop - nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true - timeoutInMinutes: 120 - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -362,50 +232,7 @@ jobs: or( eq(variables['librariesContainsChange'], true), eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - -# -# Build the whole product using Mono for Android and run runtime tests with interpreter -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Android_x64 - variables: - - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: pr/dotnet/runtime/$(Build.SourceBranch) - - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: ci/dotnet/runtime/$(Build.SourceBranch) - - name: timeoutPerTestInMinutes - value: 60 - - name: timeoutPerTestCollectionInMinutes - value: 180 - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono_RuntimeTests_Interp - buildArgs: -s mono+libs -c $(_BuildConfig) - timeoutInMinutes: 240 - runtimeVariant: monointerpreter - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - # NOTE: Per PR test execution is not recommended for runtime tests - ${{ if eq(variables['isManualOrIsNotPR'], true) }}: - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) + eq(variables['isRollingBuild'], true)) # # Build the whole product using Mono and run runtime tests with the JIT. @@ -438,9 +265,8 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - ${{ if eq(variables['isManualOrIsNotPR'], true) }}: + eq(variables['isRollingBuild'], true)) + ${{ if eq(variables['isRollingBuild'], true) }}: # extra steps, run tests extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml extraStepsParameters: @@ -478,205 +304,16 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # don't run tests on PRs until we can get significantly more devices # Turn off the testing for now, until https://github.com/dotnet/runtime/issues/60128 gets resolved - # ${{ if eq(variables['isFullMatrix'], true) }}: + # ${{ if eq(variables['isRollingBuild'], true) }}: # # extra steps, run tests # extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml # extraStepsParameters: # creator: dotnet-bot # testRunNamePrefixSuffix: Mono_$(_BuildConfig) -# -# Build Browser_wasm, on windows, run console and browser tests -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: release - runtimeFlavor: mono - platforms: - - Browser_wasm_win - variables: - # map dependencies variables to local variables - - name: librariesContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] - - name: monoContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] - jobParameters: - testGroup: innerloop - nameSuffix: Windows_wasm - buildArgs: -subset mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows $(_runSmokeTestsOnlyArg) - timeoutInMinutes: 180 - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:BrowserHost=windows $(_runSmokeTestsOnlyArg) - scenarios: - - normal - - WasmTestOnBrowser - condition: >- - or( - eq(variables['librariesContainsChange'], true), - eq(variables['monoContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - -# -# Build Browser_wasm, on windows, and run tests with AOT -# -# Disabled due to https://github.com/dotnet/runtime/issues/61721 -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: release - runtimeFlavor: mono - platforms: - - Browser_wasm_win - variables: - # map dependencies variables to local variables - - name: librariesContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] - - name: monoContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] - jobParameters: - testGroup: innerloop - nameSuffix: Windows_wasm_AOT - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) - timeoutInMinutes: 180 - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:BrowserHost=windows /p:NeedsToBuildWasmAppsOnHelix=true $(_runSmokeTestsOnlyArg) - scenarios: - - normal - condition: >- - or( - eq(variables['librariesContainsChange'], true), - eq(variables['monoContainsChange'], true), - eq(variables['isFullMatrix'], true)) - -# -# Build Browser_wasm, on windows, and run Wasm.Build.Tests -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: release - runtimeFlavor: mono - platforms: - - Browser_wasm_win - variables: - # map dependencies variables to local variables - - name: wasmbuildtestsContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'] ] - jobParameters: - testGroup: innerloop - nameSuffix: Windows_wasm_WBT - buildArgs: -subset mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows /p:TestWasmBuildTests=true /p:TestAssemblies=false - timeoutInMinutes: 180 - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:BrowserHost=windows - scenarios: - - buildwasmapps - condition: >- - or( - eq(variables['wasmbuildtestsContainsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - -# Wasm debugger tests -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Browser_wasm - variables: - # map dependencies variables to local variables - - name: wasmdebuggertestsContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'] ] - jobParameters: - testGroup: innerloop - nameSuffix: Mono_DebuggerTests - buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmDebuggerTests=true /p:TestAssemblies=false - timeoutInMinutes: 180 - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - scenarios: - - wasmdebuggertests - -# Wasm debugger tests - windows -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Browser_wasm_win - variables: - # map dependencies variables to local variables - - name: wasmdebuggertestsContainsChange - value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'] ] - jobParameters: - testGroup: innerloop - nameSuffix: Windows_wasm_DebuggerTests - buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmDebuggerTests=true /p:TestAssemblies=false /p:BrowserHost=windows - timeoutInMinutes: 180 - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:BrowserHost=windows - scenarios: - - wasmdebuggertests - # # CoreCLR Build for running Apple Silicon libraries-innerloop # @@ -685,7 +322,7 @@ jobs: jobTemplate: /eng/pipelines/coreclr/templates/build-job.yml buildConfig: release platforms: - - ${{ if eq(variables['isFullMatrix'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - OSX_arm64 jobParameters: testGroup: innerloop @@ -697,12 +334,11 @@ jobs: jobTemplate: /eng/pipelines/libraries/build-job.yml buildConfig: Release platforms: - - ${{ if eq(variables['isFullMatrix'], true) }}: + - ${{ if eq(variables['isRollingBuild'], true) }}: - OSX_arm64 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: isOfficialBuild: ${{ variables['isOfficialBuild'] }} - isFullMatrix: ${{ variables['isFullMatrix'] }} runTests: true testScope: innerloop liveRuntimeBuildConfig: release diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 5d7f3ffde2f81..cfc899e8d808d 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -91,7 +91,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build the whole product using GNU compiler toolchain @@ -114,7 +114,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build CoreCLR OSX_x64 checked @@ -133,7 +133,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build CoreCLR release @@ -178,7 +178,7 @@ jobs: # # Build CoreCLR Formatting Job # Only when CoreCLR is changed, and only in the 'main' branch (no release branches; -# both CI and PR builds). +# both Rolling and PR builds). # - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -194,7 +194,7 @@ jobs: eq(variables['System.PullRequest.TargetBranch'], 'main')), or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr_jit.containsChange'], true), - eq(variables['isFullMatrix'], true))) + eq(variables['isRollingBuild'], true))) # # CoreCLR NativeAOT debug build and smoke tests @@ -277,7 +277,7 @@ jobs: condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # Build Mono AOT offset headers once, for consumption elsewhere # Only when mono changed @@ -297,7 +297,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # Build the whole product using Mono runtime # Only when libraries, mono or installer are changed @@ -323,7 +323,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -343,7 +343,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build the whole product using Mono and run libraries tests, multi-scenario @@ -372,7 +372,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -385,7 +385,7 @@ jobs: or( eq(variables['librariesContainsChange'], true), eq(variables['monoContainsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build the whole product using Mono and run libraries tests, for Wasm.Build.Tests @@ -410,7 +410,7 @@ jobs: condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -420,8 +420,8 @@ jobs: - buildwasmapps condition: >- or( - eq(variables['wasmbuildtestsContainsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['wasmbuildtestsContainsChange'], true), + eq(variables['isRollingBuild'], true)) # # Build for Browser/wasm, with EnableAggressiveTrimming=true @@ -450,7 +450,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -463,7 +463,7 @@ jobs: or( eq(variables['librariesContainsChange'], true), eq(variables['monoContainsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build for Browser/wasm with RunAOTCompilation=true @@ -492,7 +492,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -505,7 +505,7 @@ jobs: or( eq(variables['librariesContainsChange'], true), eq(variables['monoContainsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # Build and test libraries under single-file publishing - template: /eng/pipelines/common/platform-matrix.yml @@ -518,7 +518,6 @@ jobs: - Linux_x64 jobParameters: testGroup: innerloop - isFullMatrix: ${{ variables.isFullMatrix }} isSingleFile: true nameSuffix: SingleFile buildArgs: -s clr+libs+libs.tests -c $(_BuildConfig) /p:TestSingleFile=true /p:ArchiveTests=true @@ -529,78 +528,6 @@ jobs: creator: dotnet-bot testRunNamePrefixSuffix: SingleFile_$(_BuildConfig) -# -# Build the whole product using Mono and run runtime tests -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Browser_wasm - variables: - - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: pr/dotnet/runtime/$(Build.SourceBranch) - - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: ci/dotnet/runtime/$(Build.SourceBranch) - - name: timeoutPerTestInMinutes - value: 10 - - name: timeoutPerTestCollectionInMinutes - value: 200 - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono_RuntimeTests - buildArgs: -s mono+libs -c $(_BuildConfig) - timeoutInMinutes: 180 - condition: >- - eq(variables['isFullMatrix'], true) - # NOTE: Per PR test execution is not recommended for mobile runtime tests - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/common/templates/runtimes/wasm-runtime-and-send-to-helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - -# -# Build the whole product using Mono for Android and run runtime tests with Android emulator -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Android_x64 - variables: - - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: pr/dotnet/runtime/$(Build.SourceBranch) - - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: ci/dotnet/runtime/$(Build.SourceBranch) - - name: timeoutPerTestInMinutes - value: 60 - - name: timeoutPerTestCollectionInMinutes - value: 180 - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono_RuntimeTests - buildArgs: -s mono+libs -c $(_BuildConfig) - timeoutInMinutes: 240 - condition: >- - eq(variables['isFullMatrix'], true) - # NOTE: Per PR test execution is not recommended for mobile runtime tests - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - # # Build Mono and Installer on LLVMJIT mode # @@ -621,7 +548,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -641,7 +568,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build Mono and Installer on LLVMAOT mode @@ -664,7 +591,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -683,7 +610,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build Mono debug @@ -709,7 +636,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build Mono release AOT cross-compilers @@ -740,7 +667,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -767,7 +694,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build Mono release @@ -790,7 +717,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build Mono release @@ -810,7 +737,7 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build Mono release with LLVM AOT @@ -830,7 +757,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Build libraries using live CoreLib @@ -849,8 +776,6 @@ jobs: - windows_arm - windows_arm64 - windows_x86 - jobParameters: - liveRuntimeBuildConfig: release - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -864,9 +789,12 @@ jobs: - OSX_x64 - windows_x64 - FreeBSD_x64 + - ${{ if eq(variables['isRollingBuild'], false) }}: + # we need to build windows_x86 for debug on PRs in order to test + # against a checked runtime when the PR contains coreclr changes + - windows_x86 jobParameters: testScope: innerloop - liveRuntimeBuildConfig: release # # Libraries Build that only run when coreclr is changed @@ -874,7 +802,7 @@ jobs: # and those are already built above # -- ${{ if eq(variables['isFullMatrix'], false) }}: +- ${{ if eq(variables['isRollingBuild'], false) }}: - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/libraries/build-job.yml @@ -884,45 +812,24 @@ jobs: - Linux_musl_arm - Linux_musl_arm64 jobParameters: - liveRuntimeBuildConfig: release condition: >- eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true) -# -# Libraries Build that only run when libraries is changed -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/libraries/build-job.yml - buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} - platforms: - - ${{ if eq(variables['isFullMatrix'], false) }}: - - windows_x86 - jobParameters: - liveRuntimeBuildConfig: release - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(variables['isFullMatrix'], true)) - - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/libraries/build-job.yml buildConfig: Release platforms: - windows_x86 - - ${{ if eq(variables['isFullMatrix'], true) }}: - - windows_x64 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: - isFullMatrix: ${{ variables.isFullMatrix }} framework: net48 runTests: true testScope: innerloop condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -931,14 +838,13 @@ jobs: platforms: - windows_x64 jobParameters: - isFullMatrix: ${{ variables.isFullMatrix }} framework: allConfigurations runTests: true useHelix: false condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Installer Build and Test @@ -1006,7 +912,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # CoreCLR Test executions using live libraries @@ -1029,7 +935,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -1049,7 +955,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -1065,7 +971,7 @@ jobs: condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr_AppleSilicon.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Mono Test builds with CoreCLR runtime tests using live libraries debug build @@ -1083,7 +989,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Mono CoreCLR runtime Test executions using live libraries in jit mode @@ -1095,8 +1001,6 @@ jobs: runtimeFlavor: mono platforms: - OSX_x64 - - ${{ if eq(variables['isFullMatrix'], true) }}: - - Linux_arm64 helixQueueGroup: pr helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml jobParameters: @@ -1108,7 +1012,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Mono CoreCLR runtime Test executions using live libraries in interpreter mode @@ -1120,8 +1024,6 @@ jobs: runtimeFlavor: mono platforms: - OSX_x64 - - ${{ if eq(variables['isFullMatrix'], true) }}: - - Linux_arm64 helixQueueGroup: pr helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml jobParameters: @@ -1133,7 +1035,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Mono CoreCLR runtime Test executions using live libraries and LLVM AOT # Only when Mono is changed @@ -1158,7 +1060,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Mono CoreCLR runtime Test executions using live libraries and LLVM Full AOT @@ -1184,7 +1086,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Libraries Release Test Execution against a release mono runtime. @@ -1203,7 +1105,6 @@ jobs: helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: isOfficialBuild: false - isFullMatrix: ${{ variables.isFullMatrix }} runtimeDisplayName: mono testScope: innerloop liveRuntimeBuildConfig: release @@ -1211,7 +1112,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Libraries Release Test Execution against a release mono interpreter runtime. @@ -1229,7 +1130,6 @@ jobs: helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: isOfficialBuild: false - isFullMatrix: ${{ variables.isFullMatrix }} interpreter: true runtimeDisplayName: mono_interpreter testScope: innerloop @@ -1238,7 +1138,7 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Libraries Release Test Execution against a release coreclr runtime @@ -1250,18 +1150,15 @@ jobs: buildConfig: Release platforms: - windows_x86 - - ${{ if eq(variables['isFullMatrix'], true) }}: - - windows_arm64 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: isOfficialBuild: false - isFullMatrix: ${{ variables.isFullMatrix }} testScope: innerloop liveRuntimeBuildConfig: release condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Libraries Debug Test Execution against a release coreclr runtime @@ -1276,20 +1173,15 @@ jobs: - OSX_x64 - Linux_x64 - Linux_musl_x64 - - ${{ if eq(variables['isFullMatrix'], true) }}: - - Linux_arm64 - - ${{ if eq(variables['isFullMatrix'], false) }}: - - windows_x86 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: isOfficialBuild: false - isFullMatrix: ${{ variables.isFullMatrix }} testScope: innerloop liveRuntimeBuildConfig: release condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Libraries Test Execution against a checked runtime @@ -1313,7 +1205,7 @@ jobs: condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # # Libraries Test Execution against a checked runtime @@ -1335,7 +1227,7 @@ jobs: condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -1352,4 +1244,4 @@ jobs: or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) diff --git a/eng/pipelines/runtimelab.yml b/eng/pipelines/runtimelab.yml index 9f1cd90822e83..27e954a9a7026 100644 --- a/eng/pipelines/runtimelab.yml +++ b/eng/pipelines/runtimelab.yml @@ -190,7 +190,7 @@ stages: - Linux_x64 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: - isFullMatrix: false + isRollingBuild: false isOfficialBuild: false testScope: innerloop liveRuntimeBuildConfig: Release @@ -207,7 +207,7 @@ stages: - windows_x64 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: - isFullMatrix: false + isRollingBuild: false isOfficialBuild: false testScope: innerloop liveRuntimeBuildConfig: Release diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs index e6a39a0552129..67ab0317761f9 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs @@ -3751,6 +3751,7 @@ public void Vector128Int64SumTest() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63746", TestPlatforms.tvOS)] public void Vector128NIntSumTest() { Vector128 vector = Vector128.Create((nint)0x01); @@ -3766,6 +3767,7 @@ public void Vector128NIntSumTest() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63746", TestPlatforms.tvOS)] public void Vector128NUIntSumTest() { Vector128 vector = Vector128.Create((nuint)0x01); From 54eec5d1f4d7ded21e33e65c63ada26afe80b208 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Wed, 19 Jan 2022 14:23:48 -0800 Subject: [PATCH 068/308] Make ILStubGenerated event log ModuleID corresponding to that on other events (#63974) --- src/coreclr/vm/ceeload.h | 12 ------------ src/coreclr/vm/dllimport.cpp | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index e7dd5629a2c84..8a3caaddc7dbf 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -1985,18 +1985,6 @@ class Module return dac_cast(m_ModuleID); } - SIZE_T * GetAddrModuleID() - { - LIMITED_METHOD_CONTRACT; - return (SIZE_T*) &m_ModuleID; - } - - static SIZE_T GetOffsetOfModuleID() - { - LIMITED_METHOD_CONTRACT; - return offsetof(Module, m_ModuleID); - } - PTR_DomainLocalModule GetDomainLocalModule(); // LoaderHeap for storing IJW thunks diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 6c4ce7608660e..b9b86e3708cbd 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -959,7 +959,7 @@ class ILStubState : public StubState if (pTargetMD) { pTargetMD->GetMethodInfoWithNewSig(strNamespaceOrClassName, strMethodName, strMethodSignature); - uModuleId = (UINT64)pTargetMD->GetModule()->GetAddrModuleID(); + uModuleId = (UINT64)(TADDR)pTargetMD->GetModule_NoLogging(); } // From ae1b755cd074745b0f09e826d3c7064b2a8f20dd Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Wed, 19 Jan 2022 16:07:53 -0700 Subject: [PATCH 069/308] Retries for flaky WMI test (#64008) --- .../Management/ManagementObjectTests.cs | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Management/tests/System/Management/ManagementObjectTests.cs b/src/libraries/System.Management/tests/System/Management/ManagementObjectTests.cs index 4c349613a352f..15f0f6b48f6e9 100644 --- a/src/libraries/System.Management/tests/System/Management/ManagementObjectTests.cs +++ b/src/libraries/System.Management/tests/System/Management/ManagementObjectTests.cs @@ -5,6 +5,7 @@ using System.IO; using System.Runtime.Serialization.Formatters.Binary; using Xunit; +using Xunit.Sdk; namespace System.Management.Tests { @@ -64,28 +65,33 @@ public void Set_Property_Win32_ComputerSystem() [OuterLoop] public void Invoke_Instance_And_Static_Method_Win32_Process() { - var processClass = new ManagementClass("Win32_Process"); - object[] methodArgs = { "notepad.exe", null, null, 0 }; + // Retries are sometimes necessary as underlying API call can return + // ERROR_NOT_READY or occasionally ERROR_INVALID_BLOCK or ERROR_NOT_ENOUGH_MEMORY + RetryHelper.Execute(() => + { + var processClass = new ManagementClass("Win32_Process"); + object[] methodArgs = { "notepad.exe", null, null, 0 }; - object resultObj = processClass.InvokeMethod("Create", methodArgs); + object resultObj = processClass.InvokeMethod("Create", methodArgs); - var resultCode = (uint)resultObj; - Assert.Equal(0u, resultCode); + var resultCode = (uint)resultObj; + Assert.Equal(0u, resultCode); - var processId = (uint)methodArgs[3]; - Assert.True(0u != processId, $"Unexpected process ID: {processId}"); + var processId = (uint)methodArgs[3]; + Assert.True(0u != processId, $"Unexpected process ID: {processId}"); - using (Process targetProcess = Process.GetProcessById((int)processId)) - using (var process = new ManagementObject($"Win32_Process.Handle=\"{processId}\"")) - { - Assert.False(targetProcess.HasExited); + using (Process targetProcess = Process.GetProcessById((int)processId)) + using (var process = new ManagementObject($"Win32_Process.Handle=\"{processId}\"")) + { + Assert.False(targetProcess.HasExited); - resultObj = process.InvokeMethod("Terminate", new object[] { 0 }); - resultCode = (uint)resultObj; - Assert.Equal(0u, resultCode); + resultObj = process.InvokeMethod("Terminate", new object[] { 0 }); + resultCode = (uint)resultObj; + Assert.Equal(0u, resultCode); - Assert.True(targetProcess.HasExited); - } + Assert.True(targetProcess.HasExited); + } + }, maxAttempts: 10, retryWhen: e => e is XunitException); } [ConditionalFact(typeof(WmiTestHelper), nameof(WmiTestHelper.IsWmiSupported))] From 7f828a7e6b712bdeab02d75160249cd13c26a467 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 20 Jan 2022 02:08:10 +0300 Subject: [PATCH 070/308] [arm64] JIT: Redundant zero/sign extensions after ldrX/ldrsX (#62630) --- src/coreclr/jit/emit.h | 9 +++++++++ src/coreclr/jit/emitarm64.cpp | 19 +++++++++++++++++-- src/coreclr/jit/lowerarmarch.cpp | 11 ----------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 47daad7798fc2..bee6a159e0042 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -614,6 +614,15 @@ class emitter assert((ins != INS_invalid) && (ins < INS_count)); _idIns = ins; } + bool idInsIs(instruction ins) const + { + return idIns() == ins; + } + template + bool idInsIs(instruction ins, T... rest) const + { + return idInsIs(ins) || idInsIs(rest...); + } insFormat idInsFmt() const { diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 51e02c5c26895..ac113f35b61b7 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -15614,6 +15614,11 @@ bool emitter::IsMovInstruction(instruction ins) // mov Rx, Ry # <-- last instruction // mov Ry, Rx # <-- current instruction can be omitted. // +// 4. Move that does zero extension while previous instruction already did it +// +// ldr Wx, [Ry] # <-- ldr will clear upper 4 byte of Wx +// mov Wx, Wx # <-- clears upper 4 byte in Wx +// // Arguments: // ins - The current instruction // size - Operand size of current instruction @@ -15640,6 +15645,8 @@ bool emitter::IsRedundantMov(instruction ins, emitAttr size, regNumber dst, regN return false; } + const bool isFirstInstrInBlock = (emitCurIGinsCnt == 0) && ((emitCurIG->igFlags & IGF_EXTEND) == 0); + if (dst == src) { // A mov with a EA_4BYTE has the side-effect of clearing the upper bits @@ -15655,10 +15662,18 @@ bool emitter::IsRedundantMov(instruction ins, emitAttr size, regNumber dst, regN JITDUMP("\n -- suppressing mov because src and dst is same 16-byte register.\n"); return true; } + else if (isGeneralRegisterOrSP(dst) && (size == EA_4BYTE)) + { + // See if the previous instruction already cleared upper 4 bytes for us unintentionally + if (!isFirstInstrInBlock && (emitLastIns != nullptr) && (emitLastIns->idReg1() == dst) && + (emitLastIns->idOpSize() == size) && emitLastIns->idInsIs(INS_ldr, INS_ldrh, INS_ldrb)) + { + JITDUMP("\n -- suppressing mov because ldr already cleared upper 4 bytes\n"); + return true; + } + } } - bool isFirstInstrInBlock = (emitCurIGinsCnt == 0) && ((emitCurIG->igFlags & IGF_EXTEND) == 0); - if (!isFirstInstrInBlock && // Don't optimize if instruction is not the first instruction in IG. (emitLastIns != nullptr) && (emitLastIns->idIns() == INS_mov) && // Don't optimize if last instruction was not 'mov'. diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index e4ba37cffb1d5..eab4376157f95 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -490,7 +490,6 @@ void Lowering::LowerCast(GenTree* tree) GenTree* op1 = tree->AsOp()->gtOp1; var_types dstType = tree->CastToType(); var_types srcType = genActualType(op1->TypeGet()); - var_types tmpType = TYP_UNDEF; if (varTypeIsFloating(srcType)) { @@ -501,16 +500,6 @@ void Lowering::LowerCast(GenTree* tree) assert(!varTypeIsSmall(srcType)); - if (tmpType != TYP_UNDEF) - { - GenTree* tmp = comp->gtNewCastNode(tmpType, op1, tree->IsUnsigned(), tmpType); - tmp->gtFlags |= (tree->gtFlags & (GTF_OVERFLOW | GTF_EXCEPT)); - - tree->gtFlags &= ~GTF_UNSIGNED; - tree->AsOp()->gtOp1 = tmp; - BlockRange().InsertAfter(op1, tmp); - } - // Now determine if we have operands that should be contained. ContainCheckCast(tree->AsCast()); } From a618086f53fa755732697fba171a16e8bf67900a Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Wed, 19 Jan 2022 16:01:16 -0800 Subject: [PATCH 071/308] JIT: fix up switch map for out-of-loop predecessor (#64014) If we have a loop where some of the non-loop predecessors are switchs, and we add pre-header to the loop, we need to update the switch map for those predecessors. Fixes #63982. --- src/coreclr/jit/optimizer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index b5465259f1719..a6c9ea4d85c68 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -7572,6 +7572,8 @@ void Compiler::fgCreateLoopPreHeader(unsigned lnum) fgAddRefPred(preHead, predBlock); } } while (++jumpTab, --jumpCnt); + + UpdateSwitchTableTarget(predBlock, entry, preHead); break; default: From 94b699cc6f6b88c6de1d13152143d32285c59555 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 19 Jan 2022 16:46:00 -0800 Subject: [PATCH 072/308] Update StructMarshalling design now that DisableRuntimeMarshallingAttribute is approved (#63765) Co-authored-by: Elinor Fung --- .../DllImportGenerator/StructMarshalling.md | 73 +++++++++++-------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/docs/design/libraries/DllImportGenerator/StructMarshalling.md b/docs/design/libraries/DllImportGenerator/StructMarshalling.md index ab332616b7413..63781d6d77dbb 100644 --- a/docs/design/libraries/DllImportGenerator/StructMarshalling.md +++ b/docs/design/libraries/DllImportGenerator/StructMarshalling.md @@ -6,10 +6,11 @@ These types pose an interesting problem for a number of reasons listed below. Wi ## Problems -- Unmanaged vs Blittable - - The C# language (and Roslyn) do not have a concept of "blittable types". It only has the concept of "unmanaged types", which is similar to blittable, but differs for `bool`s and `char`s. `bool` and `char` types are "unmanaged", but are never (in the case of `bool`), or only sometimes (in the case of `char`) blittable. As a result, we cannot use the "is this type unmanaged" check in Roslyn for structures. +- What types require marshalling and what types can be passed as-is to native code? + - Unmanaged vs Blittable + - The C# language (and Roslyn) do not have a concept of "blittable types". It only has the concept of "unmanaged types", which is similar to blittable, but differs for `bool`s and `char`s. `bool` and `char` types are "unmanaged", but are never (in the case of `bool`), or only sometimes (in the case of `char`) blittable. As a result, we cannot use the "is this type unmanaged" check in Roslyn for structures without an additional mechanism provided by the runtime. - Limited type information in ref assemblies. - - In the ref assemblies generated by dotnet/runtime, we save space and prevent users from relying on private implementation details of structures by emitting limited information about their fields. Structures that have at least one non-object field are given a private `int` field, and structures that have at least one field that transitively contains an object are given one private `object`-typed field. As a result, we do not have full type information at code-generation time for any structures defined in the BCL when compiling a library that uses the ref assemblies. + - In the ref assemblies generated by dotnet/arcade's GenAPI (used in dotnet/runtime), we save space and prevent users from relying on private implementation details of structures by emitting limited information about their fields. Structures that have at least one non-object field are given a private `int` field, and structures that have at least one field that transitively contains an object are given one private `object`-typed field. As a result, we do not have full type information at code-generation time for any structures defined in the BCL when compiling a library that uses the ref assemblies. - Private reflection - Even when we do have information about all of the fields, we can't emit code that references them if they are private, so we would have to emit unsafe code and calculate offsets manually to support marshaling them. @@ -19,16 +20,13 @@ We've been working around another problem for a while in the runtime-integrated I propose an opt-in design where the owner of a struct has to explicitly opt-in to usage for interop. This enables our team to add special support as desired for various types such as `Span` while also avoiding the private reflection and limited type information issues mentioned above. -This design would use these attributes: +All design options would use these attributes: ```csharp [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)] public class GeneratedMarshallingAttribute : Attribute {} -[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)] -public class BlittableTypeAttribute : Attribute {} - [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)] public class NativeMarshallingAttribute : Attribute { @@ -42,7 +40,7 @@ public class MarshalUsingAttribute : Attribute } ``` -The `NativeMarshallingAttribute` and `MarshalUsingAttribute` attributes would require that the provided native type `TNative` is a blittable `struct` and has a subset of three methods with the following names and shapes (with the managed type named TManaged): +The `NativeMarshallingAttribute` and `MarshalUsingAttribute` attributes would require that the provided native type `TNative` is a `struct` that does not require any marshalling and has a subset of three methods with the following names and shapes (with the managed type named TManaged): ```csharp partial struct TNative @@ -59,7 +57,7 @@ The analyzer will report an error if neither the constructor nor the `ToManaged` > :question: Does this API surface and shape work for all marshalling scenarios we plan on supporting? It may have issues with the current "layout class" by-value `[Out]` parameter marshalling where the runtime updates a `class` typed object in place. We already recommend against using classes for interop for performance reasons and a struct value passed via `ref` or `out` with the same members would cover this scenario. -If the native type `TNative` also has a public `Value` property, then the value of the `Value` property will be passed to native code instead of the `TNative` value itself. As a result, the type `TNative` will be allowed to be non-blittable and the type of the `Value` property will be required to be blittable. If the `Value` property is settable, then when marshalling in the native-to-managed direction, a default value of `TNative` will have its `Value` property set to the native value. If `Value` does not have a setter, then marshalling from native to managed is not supported. +If the native type `TNative` also has a public `Value` property, then the value of the `Value` property will be passed to native code instead of the `TNative` value itself. As a result, the type `TNative` will be allowed to require marshalling and the type of the `Value` property will be required be passable to native code without any additional marshalling. If the `Value` property is settable, then when marshalling in the native-to-managed direction, a default value of `TNative` will have its `Value` property set to the native value. If `Value` does not have a setter, then marshalling from native to managed is not supported. If a `Value` property is provided, the developer may also provide a ref-returning or readonly-ref-returning `GetPinnableReference` method. The `GetPinnableReference` method will be called before the `Value` property getter is called. The ref returned by `GetPinnableReference` will be pinned with a `fixed` statement, but the pinned value will not be used (it acts exclusively as a side-effect). @@ -90,7 +88,7 @@ public struct TMarshaler #### Pinning -Since C# 7.3 added a feature to enable custom pinning logic for user types, we should also add support for custom pinning logic. If the user provides a `GetPinnableReference` method on the managed type that matches the requirements to be used in a `fixed` statement and the pointed-to type is blittable, then we will support using pinning to marshal the managed value when possible. The analyzer should issue a warning when the pointed-to type would not match the final native type, accounting for the `Value` property on the native type. Since `MarshalUsingAttribute` is applied at usage time instead of at type authoring time, we will not enable the pinning feature since the implementation of `GetPinnableReference` is likely designed to match the default marshalling rules provided by the type author, not the rules provided by the marshaller provided by the `MarshalUsingAttribute`. +Since C# 7.3 added a feature to enable custom pinning logic for user types, we should also add support for custom pinning logic. If the user provides a `GetPinnableReference` method on the managed type that matches the requirements to be used in a `fixed` statement and the pointed-to type would not require any additional marshalling, then we will support using pinning to marshal the managed value when possible. The analyzer should issue a warning when the pointed-to type would not match the final native type, accounting for the `Value` property on the native type. Since `MarshalUsingAttribute` is applied at usage time instead of at type authoring time, we will not enable the pinning feature since the implementation of `GetPinnableReference` is likely designed to match the default marshalling rules provided by the type author, not the rules provided by the marshaller provided by the `MarshalUsingAttribute`. #### Caller-allocated memory @@ -111,27 +109,18 @@ When these members are present, the source generator will call the two-parameter Type authors can pass down the `buffer` pointer to native code by defining a `Value` property that returns a pointer to the first element, generally through code using `MemoryMarshal.GetReference()` and `Unsafe.AsPointer`. If `RequiresStackBuffer` is not provided or set to `false`, the `buffer` span must be pinned to be used safely. The `buffer` span can be pinned by defining a `GetPinnableReference()` method on the native type that returns a reference to the first element of the span. -### Usage - -There are 2 usage mechanisms of these attributes. - -#### Usage 1, Source-generated interop - -The user can apply the `GeneratedMarshallingAttribute` to their structure `S`. The source generator will determine if the type is blittable. If it is blittable, the source generator will generate a partial definition and apply the `BlittableTypeAttribute` to the struct type `S`. Otherwise, it will generate a blittable representation of the struct with the aformentioned required shape and apply the `NativeMarshallingAttribute` and point it to the blittable representation. The blittable representation can either be generated as a separate top-level type or as a nested type on `S`. +### Determining if a type is doesn't need marshalling -#### Usage 2, Manual interop - -The user may want to manually mark their types as marshalable in this system due to specific restrictions in their code base around marshaling specific types that the source generator does not account for. We could also use this internally to support custom types in source instead of in the code generator. In this scenario, the user would apply either the `BlittableTypeAttribute` or the `NativeMarshallingAttribute` attribute to their struct type. An analyzer would validate that the struct is blittable if the `BlittableTypeAttribute` is applied or validate that the native struct type is blittable and has marshalling methods of the required shape when the `NativeMarshallingAttribute` is applied. - -The P/Invoke source generator (as well as the struct source generator when nested struct types are used) would use the `BlittableTypeAttribute` and `NativeMarshallingAttribute` to determine how to marshal a value type parameter or field instead of looking at the fields of the struct directly. +For this design, we need to decide how to determine a type doesn't need to be marshalled and already has a representation we can pass directly to native code - that is, we need a definition for "does not require marshalling". We have two designs that we have experimented with below, and we have decided to go with design 2. -If a structure type does not have either the `BlittableTypeAttribute` or the `NativeMarshallingAttribute` applied at the type definition, the user can supply a `MarshalUsingAttribute` at the marshalling location (field, parameter, or return value) with a native type matching the same requirements as `NativeMarshallingAttribute`'s native type. - -All generated stubs will be marked with [`SkipLocalsInitAttribute`](https://docs.microsoft.com/dotnet/api/system.runtime.compilerservices.skiplocalsinitattribute) on supported frameworks. This does require attention when performing custom marshalling as the state of stub allocated memory will be in an undefined state. +#### Design 1: Introducing `BlittableTypeAttribute` -### Why do we need `BlittableTypeAttribute`? +Traditionally, the concept of "does not require marshalling" is referred to as "blittable". The built-in runtime marshalling system has an issue as mentioned above that the concept of `unmanaged` is not the same as the concept of `blittable`. Additionally, due to the ref assembly issue above, we cannot rely on ref assemblies to have accurate information in terms of fields of a type. To solve these issues in combination with the desire to enable manual interop, we need to provide a way for users to signal that a given type should be blittable and that the source generator should not generate marshalling code. We'll introduce a new attribute, the `BlittableTypeAttribute`: -Based on the design above, it seems that we wouldn't need `BlittableTypeAttribute`. However, due to the ref assembly issue above in combination with the desire to enable manual interop, we need to provide a way for users to signal that a given type should be blittable and that the source generator should not generate marshalling code. +```csharp +[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)] +public class BlittableTypeAttribute : Attribute {} +``` I'll give a specific example for where we need the `BlittableTypeAttribute` below. Let's take a scenario where we don't have `BlittableTypeAttribute`. @@ -210,7 +199,7 @@ When the source generator (either Struct, P/Invoke, Reverse P/Invoke, etc.) enco If someone actively disables the analyzer or writes their types in IL, then they have stepped out of the supported scenarios and marshalling code generated for their types may be inaccurate. -#### Exception: Generics +##### Exception: Generics Because the Roslyn compiler needs to be able to validate that there are not recursive struct definitions, reference assemblies have to contain a field of a type parameter type in the reference assembly if they do in the runtime assembly. As a result, we can inspect private generic fields reliably. @@ -221,6 +210,32 @@ To enable blittable generics support in this struct marshalling model, we extend Since all fields typed with non-parameterized types are validated to be blittable at type definition time, we know that they are all blittable at type usage time. So, we only need to validate that the generic fields are instantiated with blittable types. +#### Design 2: [`DisableRuntimeMarshallingAttribute`](https://github.com/dotnet/runtime/issues/60639) + +As an alternative design, we can use a different definition of "does not require marshalling". This design proposes changing the definition from "the runtime's definition of blittable" to "types considered `unmanaged` in C#". The `DisableRuntimeMarshallingAttribute` attribute helps us solve this problem. When applied to an assembly, this attribute causes the runtime to not do any marshalling for any types that are `unmanaged` types and do not have any auto-layout fields for all P/Invokes in the assembly; this includes when the types do not fit the runtime's definition of "blittable". This definition of "does not require marshalling" will work for all of our scenarios, with one issue listed below. + +For the auto-layout clause, we have one small issue; today, our ref-assemblies do not expose if a value type is marked as `[StructLayout(LayoutKind.Auto)]`, so we'd still have some cases where we might have runtime failures. However, we can update the tooling used in dotnet/runtime, GenAPI, to expose this information if we so desire. Once that case is handled, we have a mechanism that we can safely use to determine, at compile time, which types will not require marshalling. If we decide to not cover this case (as cases where users mark types as `LayoutKind.Auto` manually are exceptionally rare), we still have a solid design as Roslyn will automatically determine for us if a type is `unmanaged`, so we don't need to do any additional work. + +As `unmanaged` is a C# language concept, we can use Roslyn's APIs to determine if a type is `unmanaged` to determine if it does not require marshalling without needing to define any new attributes and reshape the ecosystem. However, to enable this work, the DllImportGenerator, as well as any other source generators that generate calls to native code using the interop team's infrastructure, will need to require that the user applies the `DisableRuntimeMarshallingAttribute` to their assembly when custom user-defined types are used. As we believe that users should be able to move over their assemblies to the new source-generated interop world as a whole assembly, we do not believe that this will cause any serious issues in adoption. To help support users in this case, the interop team will provide a code-fix that will generate the `DisableRuntimeMarshallingAttribute` for users when they use the source generator. + +### Usage + +There are 2 usage mechanisms of these attributes. + +#### Usage 1, Source-generated interop + +The user can apply the `GeneratedMarshallingAttribute` to their structure `S`. The source generator will determine if the type requires marshalling. If it does, it will generate a representation of the struct that does not require marshalling with the aformentioned required shape and apply the `NativeMarshallingAttribute` and point it to that new type. This generated representation can either be generated as a separate top-level type or as a nested type on `S`. + +#### Usage 2, Manual interop + +The user may want to manually mark their types as marshalable with custom marshalling rules in this system due to specific restrictions in their code base around marshaling specific types that the source generator does not account for. We could also use this internally to support custom types in source instead of in the code generator. In this scenario, the user would apply either the `NativeMarshallingAttribute` attribute to their struct type. An analyzer would validate that the native struct type does not require marshalling and has marshalling methods of the required shape when the `NativeMarshallingAttribute` is applied. + +The P/Invoke source generator (as well as the struct source generator when nested struct types are used) would use the `NativeMarshallingAttribute` to determine how to marshal a parameter or field with an unknown type. + +If a structure type does not meet the requirements to not require marshalling or does not have the `NativeMarshallingAttribute` applied at the type definition, the user can supply a `MarshalUsingAttribute` at the marshalling location (field, parameter, or return value) with a native type matching the same requirements as `NativeMarshallingAttribute`'s native type. + +All generated stubs will be marked with [`SkipLocalsInitAttribute`](https://docs.microsoft.com/dotnet/api/system.runtime.compilerservices.skiplocalsinitattribute) on supported frameworks. This does require attention when performing custom marshalling as the state of stub allocated memory will be in an undefined state. + ### Special case: Transparent Structures There has been discussion about Transparent Structures, structure types that are treated as their underlying types when passed to native code. The support for a `Value` property on a generated marshalling type supports the transparent struct support. For example, we could support strongly typed `HRESULT` returns with this model as shown below: @@ -250,7 +265,7 @@ struct HRESULT In this case, the underlying native type would actually be an `int`, but the user could use the strongly-typed `HResult` type as the public surface area. -> :question: Should we support transparent structures on manually annotated blittable types? If we do, we should do so in an opt-in manner to make it possible to have a `Value` property on the blittable type. +> :question: Should we support transparent structures on manually annotated types that wouldn't need marshalling otherwise? If we do, we should do so in an opt-in manner to make it possible to have a `Value` property on the type without assuming that it is for interop in all cases. #### Example: ComWrappers marshalling with Transparent Structures From 93dc760481bdde2c463d725c2927b9da8787eb98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rylek?= Date: Thu, 20 Jan 2022 01:52:15 +0100 Subject: [PATCH 073/308] Fix Crossgen2 bug #61104 and add regression test (#63956) The issue tracks the runtime regression failure where Crossgen2-compiled app is unable to locate a type with non-ASCII characters in its name. The failure was caused by the fact that Crossgen2 was incorrectly zero-extending the individual UTF8 characters when calculating the hash whereas runtime is sign-extending them. Thanks Tomas --- .../Compiler/ReadyToRunHashCode.cs | 4 ++-- .../coreclr/GitHub_61104/test61104.cs | 12 ++++++++++++ .../coreclr/GitHub_61104/test61104.csproj | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/tests/Regressions/coreclr/GitHub_61104/test61104.cs create mode 100644 src/tests/Regressions/coreclr/GitHub_61104/test61104.csproj diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunHashCode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunHashCode.cs index e506bb8b3b6ef..9380a829b8f3c 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunHashCode.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunHashCode.cs @@ -34,10 +34,10 @@ public static int NameHashCode(string name) byte[] src = Encoding.UTF8.GetBytes(name); for (int i = 0; i < src.Length; i += 2) { - hash1 = unchecked(hash1 + RotateLeft(hash1, 5)) ^ src[i]; + hash1 = unchecked(hash1 + RotateLeft(hash1, 5)) ^ (int)unchecked((sbyte)src[i]); if (i + 1 < src.Length) { - hash2 = unchecked(hash2 + RotateLeft(hash2, 5)) ^ src[i + 1]; + hash2 = unchecked(hash2 + RotateLeft(hash2, 5)) ^ (int)unchecked((sbyte)src[i + 1]); } else { diff --git a/src/tests/Regressions/coreclr/GitHub_61104/test61104.cs b/src/tests/Regressions/coreclr/GitHub_61104/test61104.cs new file mode 100644 index 0000000000000..2e01b96bf31d5 --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_61104/test61104.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. + +var type = Type.GetType("_测试数据记录仪_Iiİı_åäö_Controller_DataLogger1_log_all_", false); +var obj = Activator.CreateInstance(type!); +Console.WriteLine(obj?.GetType().Name); + +return 100; + +public class _测试数据记录仪_Iiİı_åäö_Controller_DataLogger1_log_all_ +{ +} diff --git a/src/tests/Regressions/coreclr/GitHub_61104/test61104.csproj b/src/tests/Regressions/coreclr/GitHub_61104/test61104.csproj new file mode 100644 index 0000000000000..b72e9a46cf95a --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_61104/test61104.csproj @@ -0,0 +1,17 @@ + + + + Exe + enable + enable + 1 + + + true + + + + + + + From 5cefc0f9e618e2d8b38d7de67bbd8a50adb9646f Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Thu, 20 Jan 2022 04:23:50 +0300 Subject: [PATCH 074/308] Fix invalid threading of nodes in rationalization (#64012) The code in question assumes that the ASG will be reversed and thus threads "simdTree" before "location" in the linear order. That dependency, while valid, because "gtSetEvalOrder" will always reverse ASGs with locals on the LHS, is unnecessary and incorrect from the IR validity point of view. Fix this by using "InsertAfter" instead of manual node threading. --- src/coreclr/jit/rationalize.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/rationalize.cpp b/src/coreclr/jit/rationalize.cpp index 5e54ca8bd94d4..18503a4ce3c53 100644 --- a/src/coreclr/jit/rationalize.cpp +++ b/src/coreclr/jit/rationalize.cpp @@ -416,13 +416,10 @@ void Rationalizer::RewriteAssignment(LIR::Use& use) } GenTreeSIMD* simdTree = comp->gtNewSIMDNode(simdType, initVal, SIMDIntrinsicInit, simdBaseJitType, genTypeSize(simdType)); - assignment->AsOp()->gtOp2 = simdTree; - value = simdTree; - initVal->gtNext = simdTree; - simdTree->gtPrev = initVal; + assignment->gtOp2 = simdTree; + value = simdTree; - simdTree->gtNext = location; - location->gtPrev = simdTree; + BlockRange().InsertAfter(initVal, simdTree); } } #endif // FEATURE_SIMD From 752569f66bcde98fcc4dd1e651f9f1f138184c5c Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Wed, 19 Jan 2022 17:58:39 -0800 Subject: [PATCH 075/308] Check if the child object is in the heap range before get_region_plan_gen_num (#63828) --- src/coreclr/gc/gc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 5a2a9c2c2c20e..8d4f4b48467a3 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -30136,6 +30136,8 @@ inline void gc_heap::check_demotion_helper_sip (uint8_t** pval, int parent_gen_num, uint8_t* parent_loc) { uint8_t* child_object = *pval; + if (!is_in_heap_range (child_object)) + return; if (!child_object) return; int child_object_plan_gen = get_region_plan_gen_num (child_object); From 68a923a24edb47f1d0e3c38a69d4091a7587bfc4 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Wed, 19 Jan 2022 17:59:07 -0800 Subject: [PATCH 076/308] Check if the child object is in the heap range before object_gennum (#63970) --- src/coreclr/gc/gc.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 8d4f4b48467a3..958a4568a0f88 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -43430,8 +43430,15 @@ void GCHeap::SetYieldProcessorScalingFactor (float scalingFactor) unsigned int GCHeap::WhichGeneration (Object* object) { - gc_heap* hp = gc_heap::heap_of ((uint8_t*)object); - unsigned int g = hp->object_gennum ((uint8_t*)object); + uint8_t* o = (uint8_t*)object; +#ifdef FEATURE_BASICFREEZE + if (!((o < g_gc_highest_address) && (o >= g_gc_lowest_address))) + { + return max_generation; + } +#endif //FEATURE_BASICFREEZE + gc_heap* hp = gc_heap::heap_of (o); + unsigned int g = hp->object_gennum (o); dprintf (3, ("%Ix is in gen %d", (size_t)object, g)); return g; } From a5158df084780e52005e4dcbd02ee091542e06d0 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Wed, 19 Jan 2022 18:44:19 -0800 Subject: [PATCH 077/308] 'cmeq' and 'fcmeq' Vector64.Zero/Vector128.Zero ARM64 containment optimizations (#62933) * Initial work * Added a comma to display * Cleanup * Fixing build * More cleanup * Update comment * Update comment * Added CompareEqual Vector64/128 with Zero tests * Do not contain op1 for now * Wrong intrinsic id used * Removing generated tests * Removing generated tests * Added CompareEqual tests * Supporting containment for first operand * Fix test build * Passing correct register * Check IsVectorZero before not allocing a register * Update comment * Fixing test * Minor format change * Fixed formatting * Renamed test * Adding AdvSimd_Arm64 tests: * Adding support for rest of 'cmeq' and 'fcmeq' instructions * Removing github csproj * Minor test fix * Fixed tests * Fix print * Minor format change * Fixing test * Added some emitter tests * Feedback * Update emitarm64.cpp * Feedback --- src/coreclr/jit/codegenarm64.cpp | 5 +- src/coreclr/jit/codegenlinear.cpp | 2 +- src/coreclr/jit/emitarm64.cpp | 23 +- src/coreclr/jit/gentree.cpp | 14 + src/coreclr/jit/gentree.h | 79 ++- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 23 + src/coreclr/jit/hwintrinsiclistarm64.h | 6 +- src/coreclr/jit/instrsarm64.h | 8 +- src/coreclr/jit/lowerarmarch.cpp | 15 + src/coreclr/jit/lsraarm64.cpp | 75 ++- src/coreclr/jit/lsrabuild.cpp | 17 + .../JitBlue/Runtime_33972/Runtime_33972.cs | 559 ++++++++++++++++++ .../Runtime_33972/Runtime_33972.csproj | 13 + 13 files changed, 785 insertions(+), 54 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_33972/Runtime_33972.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_33972/Runtime_33972.csproj diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 250a23904944a..abcd70d040f0b 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -6922,9 +6922,12 @@ void CodeGen::genArm64EmitterUnitTests() #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // - // R_R fmov/fcmp/fcvt + // R_R cmeq/fmov/fcmp/fcvt // + // cmeq scalar + theEmitter->emitIns_R_R(INS_cmeq, EA_8BYTE, REG_V0, REG_V1); + // fmov to vector to vector theEmitter->emitIns_Mov(INS_fmov, EA_8BYTE, REG_V0, REG_V2, /* canSkip */ false); theEmitter->emitIns_Mov(INS_fmov, EA_4BYTE, REG_V1, REG_V3, /* canSkip */ false); diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 51e9afc074398..ff4e0b2d3c285 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1657,7 +1657,7 @@ void CodeGen::genConsumeRegs(GenTree* tree) #ifdef FEATURE_SIMD // (In)Equality operation that produces bool result, when compared // against Vector zero, marks its Vector Zero operand as contained. - assert(tree->OperIsLeaf() || tree->IsSIMDZero()); + assert(tree->OperIsLeaf() || tree->IsSIMDZero() || tree->IsVectorZero()); #else assert(tree->OperIsLeaf()); #endif diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index ac113f35b61b7..52f24d4524279 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -4732,19 +4732,19 @@ void emitter::emitIns_R_R( assert(isVectorRegister(reg1)); assert(isVectorRegister(reg2)); - if (isValidVectorDatasize(size)) + if (insOptsAnyArrangement(opt)) { // Vector operation - assert(insOptsAnyArrangement(opt)); + assert(isValidVectorDatasize(size)); assert(isValidArrangement(size, opt)); elemsize = optGetElemsize(opt); fmt = IF_DV_2M; } else { - NYI("Untested"); // Scalar operation - assert(size == EA_8BYTE); // Only Double supported + assert(size == EA_8BYTE); + assert(insOptsNone(opt)); fmt = IF_DV_2L; } break; @@ -12971,6 +12971,11 @@ void emitter::emitDispIns( emitDispVectorReg(id->idReg1(), id->idInsOpt(), true); emitDispVectorReg(id->idReg2(), id->idInsOpt(), false); } + if (ins == INS_fcmeq) + { + printf(", "); + emitDispImm(0, false); + } break; case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*, sha1su1) @@ -12990,6 +12995,11 @@ void emitter::emitDispIns( emitDispVectorReg(id->idReg1(), id->idInsOpt(), true); emitDispVectorReg(id->idReg2(), id->idInsOpt(), false); } + if (ins == INS_cmeq) + { + printf(", "); + emitDispImm(0, false); + } break; case IF_DV_2N: // DV_2N .........iiiiiii ......nnnnnddddd Vd Vn imm (shift - scalar) @@ -13126,6 +13136,11 @@ void emitter::emitDispIns( emitDispReg(id->idReg1(), size, true); emitDispReg(id->idReg2(), size, false); } + if (fmt == IF_DV_2L && ins == INS_cmeq) + { + printf(", "); + emitDispImm(0, false); + } break; case IF_DV_2H: // DV_2H X........X...... ......nnnnnddddd Rd Vn (fmov, fcvtXX - to general) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index ca588f4de9f6b..3ba0b8a8c9095 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17735,6 +17735,20 @@ bool GenTree::isContainableHWIntrinsic() const return true; } + default: + { + return false; + } + } +#elif TARGET_ARM64 + switch (AsHWIntrinsic()->GetHWIntrinsicId()) + { + case NI_Vector64_get_Zero: + case NI_Vector128_get_Zero: + { + return true; + } + default: { return false; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index e7a03d26547d3..8cab63e505b5f 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1704,6 +1704,8 @@ struct GenTree inline bool IsIntegralConst(ssize_t constVal) const; inline bool IsIntegralConstVector(ssize_t constVal) const; inline bool IsSIMDZero() const; + inline bool IsFloatPositiveZero() const; + inline bool IsVectorZero() const; inline bool IsBoxedValue(); @@ -2097,7 +2099,7 @@ struct GenTree inline bool IsCnsFltOrDbl() const; - inline bool IsCnsNonZeroFltOrDbl(); + inline bool IsCnsNonZeroFltOrDbl() const; bool IsIconHandle() const { @@ -7650,6 +7652,79 @@ inline bool GenTree::IsSIMDZero() const return false; } +//------------------------------------------------------------------- +// IsFloatPositiveZero: returns true if this is exactly a const float value of postive zero (+0.0) +// +// Returns: +// True if this represents a const floating-point value of exactly positive zero (+0.0). +// Will return false if the value is negative zero (-0.0). +// +inline bool GenTree::IsFloatPositiveZero() const +{ + return !(IsCnsNonZeroFltOrDbl()); +} + +//------------------------------------------------------------------- +// IsVectorZero: returns true if this is an integral or floating-point (SIMD or HW intrinsic) vector +// with all its elements equal to zero. +// +// Returns: +// True if this represents an integral or floating-point const (SIMD or HW intrinsic) vector with all its elements +// equal to zero. +// +// TODO: We already have IsSIMDZero() and IsIntegralConstVector(0), +// however, IsSIMDZero() does not cover hardware intrinsics, and IsIntegralConstVector(0) does not cover floating +// point. In order to not risk adverse behaviour by modifying those, this function 'IsVectorZero' was introduced. +// At some point, it makes sense to normalize this logic to be a single function call rather than have several +// separate ones; preferably this one. +inline bool GenTree::IsVectorZero() const +{ +#ifdef FEATURE_SIMD + if (gtOper == GT_SIMD) + { + const GenTreeSIMD* node = AsSIMD(); + + if (node->GetSIMDIntrinsicId() == SIMDIntrinsicInit) + { + return (node->Op(1)->IsIntegralConst(0) || node->Op(1)->IsFloatPositiveZero()); + } + } +#endif + +#ifdef FEATURE_HW_INTRINSICS + if (gtOper == GT_HWINTRINSIC) + { + const GenTreeHWIntrinsic* node = AsHWIntrinsic(); + const var_types simdBaseType = node->GetSimdBaseType(); + + if (varTypeIsIntegral(simdBaseType) || varTypeIsFloating(simdBaseType)) + { + const NamedIntrinsic intrinsicId = node->GetHWIntrinsicId(); + + if (node->GetOperandCount() == 0) + { +#if defined(TARGET_XARCH) + return (intrinsicId == NI_Vector128_get_Zero) || (intrinsicId == NI_Vector256_get_Zero); +#elif defined(TARGET_ARM64) + return (intrinsicId == NI_Vector64_get_Zero) || (intrinsicId == NI_Vector128_get_Zero); +#endif // !TARGET_XARCH && !TARGET_ARM64 + } + else if ((node->GetOperandCount() == 1) && + (node->Op(1)->IsIntegralConst(0) || node->Op(1)->IsFloatPositiveZero())) + { +#if defined(TARGET_XARCH) + return (intrinsicId == NI_Vector128_Create) || (intrinsicId == NI_Vector256_Create); +#elif defined(TARGET_ARM64) + return (intrinsicId == NI_Vector64_Create) || (intrinsicId == NI_Vector128_Create); +#endif // !TARGET_XARCH && !TARGET_ARM64 + } + } + } +#endif // FEATURE_HW_INTRINSICS + + return false; +} + inline bool GenTree::IsBoxedValue() { assert(gtOper != GT_BOX || AsBox()->BoxOp() != nullptr); @@ -8328,7 +8403,7 @@ inline bool GenTree::IsCnsFltOrDbl() const return OperGet() == GT_CNS_DBL; } -inline bool GenTree::IsCnsNonZeroFltOrDbl() +inline bool GenTree::IsCnsNonZeroFltOrDbl() const { if (OperGet() == GT_CNS_DBL) { diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 706b988f049e5..e4b9a1326680c 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -496,6 +496,29 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, opt); break; + case NI_AdvSimd_CompareEqual: + case NI_AdvSimd_Arm64_CompareEqual: + case NI_AdvSimd_Arm64_CompareEqualScalar: + if (intrin.op1->isContained()) + { + assert(HWIntrinsicInfo::SupportsContainment(intrin.id)); + assert(intrin.op1->IsVectorZero()); + + GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op2Reg, opt); + } + else if (intrin.op2->isContained()) + { + assert(HWIntrinsicInfo::SupportsContainment(intrin.id)); + assert(intrin.op2->IsVectorZero()); + + GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg, opt); + } + else + { + GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, opt); + } + break; + case NI_AdvSimd_AbsoluteCompareLessThan: case NI_AdvSimd_AbsoluteCompareLessThanOrEqual: case NI_AdvSimd_CompareLessThan: diff --git a/src/coreclr/jit/hwintrinsiclistarm64.h b/src/coreclr/jit/hwintrinsiclistarm64.h index 4b2e3fa132ad7..e119a38948a05 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/jit/hwintrinsiclistarm64.h @@ -240,7 +240,7 @@ HARDWARE_INTRINSIC(AdvSimd, BitwiseClear, HARDWARE_INTRINSIC(AdvSimd, BitwiseSelect, -1, 3, {INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl}, HW_Category_SIMD, HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AdvSimd, Ceiling, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frintp, INS_invalid}, HW_Category_SIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AdvSimd, CeilingScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frintp, INS_frintp}, HW_Category_SIMD, HW_Flag_SIMDScalar) -HARDWARE_INTRINSIC(AdvSimd, CompareEqual, -1, 2, {INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_invalid, INS_invalid, INS_fcmeq, INS_invalid}, HW_Category_SIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, CompareEqual, -1, 2, {INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_invalid, INS_invalid, INS_fcmeq, INS_invalid}, HW_Category_SIMD, HW_Flag_Commutative|HW_Flag_SpecialCodeGen|HW_Flag_SupportsContainment) HARDWARE_INTRINSIC(AdvSimd, CompareGreaterThan, -1, 2, {INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_invalid, INS_invalid, INS_fcmgt, INS_invalid}, HW_Category_SIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AdvSimd, CompareGreaterThanOrEqual, -1, 2, {INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_invalid, INS_invalid, INS_fcmge, INS_invalid}, HW_Category_SIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AdvSimd, CompareLessThan, -1, 2, {INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_invalid, INS_invalid, INS_fcmgt, INS_invalid}, HW_Category_SIMD, HW_Flag_SpecialCodeGen) @@ -492,8 +492,8 @@ HARDWARE_INTRINSIC(AdvSimd_Arm64, AddPairwiseScalar, HARDWARE_INTRINSIC(AdvSimd_Arm64, AddSaturate, -1, 2, {INS_suqadd, INS_usqadd, INS_suqadd, INS_usqadd, INS_suqadd, INS_usqadd, INS_suqadd, INS_usqadd, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasRMWSemantics) HARDWARE_INTRINSIC(AdvSimd_Arm64, AddSaturateScalar, 8, 2, {INS_sqadd, INS_uqadd, INS_sqadd, INS_uqadd, INS_sqadd, INS_uqadd, INS_suqadd, INS_usqadd, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_HasRMWSemantics|HW_Flag_SIMDScalar|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(AdvSimd_Arm64, Ceiling, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frintp}, HW_Category_SIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmeq, INS_cmeq, INS_invalid, INS_fcmeq}, HW_Category_SIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareEqualScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmeq, INS_cmeq, INS_fcmeq, INS_fcmeq}, HW_Category_SIMD, HW_Flag_Commutative|HW_Flag_SIMDScalar) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmeq, INS_cmeq, INS_invalid, INS_fcmeq}, HW_Category_SIMD, HW_Flag_Commutative|HW_Flag_SpecialCodeGen|HW_Flag_SupportsContainment) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareEqualScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmeq, INS_cmeq, INS_fcmeq, INS_fcmeq}, HW_Category_SIMD, HW_Flag_Commutative|HW_Flag_SIMDScalar|HW_Flag_SpecialCodeGen|HW_Flag_SupportsContainment) HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmgt, INS_cmhi, INS_invalid, INS_fcmgt}, HW_Category_SIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_invalid, INS_fcmge}, HW_Category_SIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThanOrEqualScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_fcmge, INS_fcmge}, HW_Category_SIMD, HW_Flag_SIMDScalar) diff --git a/src/coreclr/jit/instrsarm64.h b/src/coreclr/jit/instrsarm64.h index c89b006a41897..d4e7ef5b10c8d 100644 --- a/src/coreclr/jit/instrsarm64.h +++ b/src/coreclr/jit/instrsarm64.h @@ -312,8 +312,8 @@ INST4(neg, "neg", 0, IF_EN4G, 0x4B0003E0, 0x4B0003E0, INST4(cmeq, "cmeq", 0, IF_EN4H, 0x7EE08C00, 0x2E208C00, 0x5E209800, 0x0E209800) // cmeq Vd,Vn,Vm DV_3E 01111110111mmmmm 100011nnnnnddddd 7EE0 8C00 Vd,Vn,Vm (scalar) // cmeq Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 100011nnnnnddddd 2E20 8C00 Vd,Vn,Vm (vector) - // cmeq Vd,Vn DV_2L 01011110XX100000 100110nnnnnddddd 5E20 9800 Vd,Vn (scalar) - // cmeq Vd,Vn DV_2M 0Q001110XX100000 100110nnnnnddddd 0E20 9800 Vd,Vn (vector) + // cmeq Vd,Vn,#0 DV_2L 01011110XX100000 100110nnnnnddddd 5E20 9800 Vd,Vn,#0 (scalar - with zero) + // cmeq Vd,Vn,#0 DV_2M 0Q001110XX100000 100110nnnnnddddd 0E20 9800 Vd,Vn,#0 (vector - with zero) INST4(cmge, "cmge", 0, IF_EN4H, 0x5EE03C00, 0x0E203C00, 0x7E208800, 0x2E208800) // cmge Vd,Vn,Vm DV_3E 01011110111mmmmm 001111nnnnnddddd 5EE0 3C00 Vd,Vn,Vm (scalar) @@ -331,8 +331,8 @@ INST4(cmgt, "cmgt", 0, IF_EN4H, 0x5EE03400, 0x0E203400, INST4(fcmeq, "fcmeq", 0, IF_EN4I, 0x5E20E400, 0x0E20E400, 0x5EA0D800, 0x0EA0D800) // fcmeq Vd,Vn,Vm DV_3D 010111100X1mmmmm 111001nnnnnddddd 5E20 E400 Vd Vn Vm (scalar) // fcmeq Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 111001nnnnnddddd 0E20 E400 Vd,Vn,Vm (vector) - // fcmeq Vd,Vn DV_2G 010111101X100000 110110nnnnnddddd 5EA0 D800 Vd Vn (scalar) - // fcmeq Vd,Vn DV_2A 0Q0011101X100000 110110nnnnnddddd 0EA0 D800 Vd Vn (vector) + // fcmeq Vd,Vn,#0 DV_2G 010111101X100000 110110nnnnnddddd 5EA0 D800 Vd Vn,#0 (scalar - with zero) + // fcmeq Vd,Vn,#0 DV_2A 0Q0011101X100000 110110nnnnnddddd 0EA0 D800 Vd Vn,#0 (vector - with zero) INST4(fcmge, "fcmge", 0, IF_EN4I, 0x7E20E400, 0x2E20E400, 0x7EA0C800, 0x2EA0C800) // fcmge Vd,Vn,Vm DV_3D 011111100X1mmmmm 111001nnnnnddddd 7E20 E400 Vd Vn Vm (scalar) diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index eab4376157f95..e165469cbc77c 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -1842,6 +1842,21 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) MakeSrcContained(node, intrin.op4); break; + case NI_AdvSimd_CompareEqual: + case NI_AdvSimd_Arm64_CompareEqual: + case NI_AdvSimd_Arm64_CompareEqualScalar: + { + if (intrin.op1->IsVectorZero()) + { + MakeSrcContained(node, intrin.op1); + } + else if (intrin.op2->IsVectorZero()) + { + MakeSrcContained(node, intrin.op2); + } + break; + } + case NI_Vector64_CreateScalarUnsafe: case NI_Vector128_CreateScalarUnsafe: case NI_AdvSimd_DuplicateToVector64: diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index 73b971ec5932f..796a9e8126e6f 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1091,55 +1091,52 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) } } } - else + else if (intrin.op2 != nullptr) { - if (intrin.op2 != nullptr) - { - // RMW intrinsic operands doesn't have to be delayFree when they can be assigned the same register as op1Reg - // (i.e. a register that corresponds to read-modify-write operand) and one of them is the last use. + // RMW intrinsic operands doesn't have to be delayFree when they can be assigned the same register as op1Reg + // (i.e. a register that corresponds to read-modify-write operand) and one of them is the last use. - assert(intrin.op1 != nullptr); + assert(intrin.op1 != nullptr); - bool forceOp2DelayFree = false; - if ((intrin.id == NI_Vector64_GetElement) || (intrin.id == NI_Vector128_GetElement)) + bool forceOp2DelayFree = false; + if ((intrin.id == NI_Vector64_GetElement) || (intrin.id == NI_Vector128_GetElement)) + { + if (!intrin.op2->IsCnsIntOrI() && (!intrin.op1->isContained() || intrin.op1->OperIsLocal())) { - if (!intrin.op2->IsCnsIntOrI() && (!intrin.op1->isContained() || intrin.op1->OperIsLocal())) - { - // If the index is not a constant and the object is not contained or is a local - // we will need a general purpose register to calculate the address - // internal register must not clobber input index - // TODO-Cleanup: An internal register will never clobber a source; this code actually - // ensures that the index (op2) doesn't interfere with the target. - buildInternalIntRegisterDefForNode(intrinsicTree); - forceOp2DelayFree = true; - } - - if (!intrin.op2->IsCnsIntOrI() && !intrin.op1->isContained()) - { - // If the index is not a constant or op1 is in register, - // we will use the SIMD temp location to store the vector. - var_types requiredSimdTempType = (intrin.id == NI_Vector64_GetElement) ? TYP_SIMD8 : TYP_SIMD16; - compiler->getSIMDInitTempVarNum(requiredSimdTempType); - } + // If the index is not a constant and the object is not contained or is a local + // we will need a general purpose register to calculate the address + // internal register must not clobber input index + // TODO-Cleanup: An internal register will never clobber a source; this code actually + // ensures that the index (op2) doesn't interfere with the target. + buildInternalIntRegisterDefForNode(intrinsicTree); + forceOp2DelayFree = true; } - if (forceOp2DelayFree) - { - srcCount += BuildDelayFreeUses(intrin.op2); - } - else + if (!intrin.op2->IsCnsIntOrI() && !intrin.op1->isContained()) { - srcCount += isRMW ? BuildDelayFreeUses(intrin.op2, intrin.op1) : BuildOperandUses(intrin.op2); + // If the index is not a constant or op1 is in register, + // we will use the SIMD temp location to store the vector. + var_types requiredSimdTempType = (intrin.id == NI_Vector64_GetElement) ? TYP_SIMD8 : TYP_SIMD16; + compiler->getSIMDInitTempVarNum(requiredSimdTempType); } + } - if (intrin.op3 != nullptr) - { - srcCount += isRMW ? BuildDelayFreeUses(intrin.op3, intrin.op1) : BuildOperandUses(intrin.op3); + if (forceOp2DelayFree) + { + srcCount += BuildDelayFreeUses(intrin.op2); + } + else + { + srcCount += isRMW ? BuildDelayFreeUses(intrin.op2, intrin.op1) : BuildOperandUses(intrin.op2); + } - if (intrin.op4 != nullptr) - { - srcCount += isRMW ? BuildDelayFreeUses(intrin.op4, intrin.op1) : BuildOperandUses(intrin.op4); - } + if (intrin.op3 != nullptr) + { + srcCount += isRMW ? BuildDelayFreeUses(intrin.op3, intrin.op1) : BuildOperandUses(intrin.op3); + + if (intrin.op4 != nullptr) + { + srcCount += isRMW ? BuildDelayFreeUses(intrin.op4, intrin.op1) : BuildOperandUses(intrin.op4); } } } diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp index a48d7e7bdee57..d58f1996091fa 100644 --- a/src/coreclr/jit/lsrabuild.cpp +++ b/src/coreclr/jit/lsrabuild.cpp @@ -3078,6 +3078,15 @@ int LinearScan::BuildOperandUses(GenTree* node, regMaskTP candidates) return 1; } +#ifdef TARGET_ARM64 + // Must happen before OperIsHWIntrinsic case, + // but this occurs when a vector zero node is marked as contained. + if (node->IsVectorZero()) + { + return 0; + } +#endif + #if !defined(TARGET_64BIT) if (node->OperIs(GT_LONG)) { @@ -3164,6 +3173,14 @@ int LinearScan::BuildDelayFreeUses(GenTree* node, GenTree* rmwNode, regMaskTP ca { use = BuildUse(node, candidates); } +#ifdef TARGET_ARM64 + // Must happen before OperIsHWIntrinsic case, + // but this occurs when a vector zero node is marked as contained. + else if (node->IsVectorZero()) + { + return 0; + } +#endif #ifdef FEATURE_HW_INTRINSICS else if (node->OperIsHWIntrinsic()) { diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_33972/Runtime_33972.cs b/src/tests/JIT/Regression/JitBlue/Runtime_33972/Runtime_33972.cs new file mode 100644 index 0000000000000..7535cd334d962 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_33972/Runtime_33972.cs @@ -0,0 +1,559 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +class Program +{ + // CompareEqual + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_Byte_Zero(Vector64 left) + { + return AdvSimd.CompareEqual(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_SByte_Zero(Vector64 left) + { + return AdvSimd.CompareEqual(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_UInt16_Zero(Vector64 left) + { + return AdvSimd.CompareEqual(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_Int16_Zero(Vector64 left) + { + return AdvSimd.CompareEqual(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_UInt32_Zero(Vector64 left) + { + return AdvSimd.CompareEqual(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_Int32_Zero(Vector64 left) + { + return AdvSimd.CompareEqual(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_Single_Zero(Vector64 left) + { + return AdvSimd.CompareEqual(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_Byte_Zero(Vector128 left) + { + return AdvSimd.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_SByte_Zero(Vector128 left) + { + return AdvSimd.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_UInt16_Zero(Vector128 left) + { + return AdvSimd.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_Int16_Zero(Vector128 left) + { + return AdvSimd.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_UInt32_Zero(Vector128 left) + { + return AdvSimd.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_Int32_Zero(Vector128 left) + { + return AdvSimd.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_Single_Zero(Vector128 left) + { + return AdvSimd.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_Arm64_CompareEqual_Vector128_Double_Zero(Vector128 left) + { + return AdvSimd.Arm64.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_Arm64_CompareEqual_Vector128_UInt64_Zero(Vector128 left) + { + return AdvSimd.Arm64.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_Arm64_CompareEqual_Vector128_Int64_Zero(Vector128 left) + { + return AdvSimd.Arm64.CompareEqual(left, Vector128.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_Arm64_CompareEqualScalar_Vector64_Single_Zero(Vector64 left) + { + return AdvSimd.Arm64.CompareEqualScalar(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_Arm64_CompareEqualScalar_Vector64_Double_Zero(Vector64 left) + { + return AdvSimd.Arm64.CompareEqualScalar(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_Arm64_CompareEqualScalar_Vector64_UInt64_Zero(Vector64 left) + { + return AdvSimd.Arm64.CompareEqualScalar(left, Vector64.Zero); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_Arm64_CompareEqualScalar_Vector64_Int64_Zero(Vector64 left) + { + return AdvSimd.Arm64.CompareEqualScalar(left, Vector64.Zero); + } + + // CompareEqual Swapped + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_Byte_Zero_Swapped(Vector64 right) + { + return AdvSimd.CompareEqual(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_SByte_Zero_Swapped(Vector64 right) + { + return AdvSimd.CompareEqual(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_UInt16_Zero_Swapped(Vector64 right) + { + return AdvSimd.CompareEqual(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_Int16_Zero_Swapped(Vector64 right) + { + return AdvSimd.CompareEqual(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_UInt32_Zero_Swapped(Vector64 right) + { + return AdvSimd.CompareEqual(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_Int32_Zero_Swapped(Vector64 right) + { + return AdvSimd.CompareEqual(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_CompareEqual_Vector64_Single_Zero_Swapped(Vector64 right) + { + return AdvSimd.CompareEqual(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_Byte_Zero_Swapped(Vector128 right) + { + return AdvSimd.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_SByte_Zero_Swapped(Vector128 right) + { + return AdvSimd.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_UInt16_Zero_Swapped(Vector128 right) + { + return AdvSimd.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_Int16_Zero_Swapped(Vector128 right) + { + return AdvSimd.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_UInt32_Zero_Swapped(Vector128 right) + { + return AdvSimd.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_Int32_Zero_Swapped(Vector128 right) + { + return AdvSimd.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_CompareEqual_Vector128_Single_Zero_Swapped(Vector128 right) + { + return AdvSimd.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_Arm64_CompareEqual_Vector128_Double_Zero_Swapped(Vector128 right) + { + return AdvSimd.Arm64.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_Arm64_CompareEqual_Vector128_UInt64_Zero_Swapped(Vector128 right) + { + return AdvSimd.Arm64.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector128 AdvSimd_Arm64_CompareEqual_Vector128_Int64_Zero_Swapped(Vector128 right) + { + return AdvSimd.Arm64.CompareEqual(Vector128.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_Arm64_CompareEqualScalar_Vector64_Single_Zero_Swapped(Vector64 right) + { + return AdvSimd.Arm64.CompareEqualScalar(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_Arm64_CompareEqualScalar_Vector64_Double_Zero_Swapped(Vector64 right) + { + return AdvSimd.Arm64.CompareEqualScalar(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_Arm64_CompareEqualScalar_Vector64_UInt64_Zero_Swapped(Vector64 right) + { + return AdvSimd.Arm64.CompareEqualScalar(Vector64.Zero, right); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector64 AdvSimd_Arm64_CompareEqualScalar_Vector64_Int64_Zero_Swapped(Vector64 right) + { + return AdvSimd.Arm64.CompareEqualScalar(Vector64.Zero, right); + } + + // Validation + + unsafe static bool ValidateResult_Vector64(Vector64 result, T expectedElementValue) where T : unmanaged + { + var succeeded = true; + + for (var i = 0; i < (8 / sizeof(T)); i++) + { + if (!result.GetElement(i).Equals(expectedElementValue)) + { + succeeded = false; + } + } + + return succeeded; + } + + unsafe static bool ValidateResult_Vector64(Vector64 result, Vector64 expectedElementValue) where T : unmanaged + { + var succeeded = true; + + for (var i = 0; i < (8 / sizeof(T)); i++) + { + if (!result.GetElement(i).Equals(expectedElementValue.GetElement(i))) + { + succeeded = false; + } + } + + return succeeded; + } + + unsafe static bool ValidateResult_Vector128(Vector128 result, T expectedElementValue) where T : unmanaged + { + var succeeded = true; + + for (var i = 0; i < (16 / sizeof(T)); i++) + { + if (!result.GetElement(i).Equals(expectedElementValue)) + { + succeeded = false; + } + } + + return succeeded; + } + + unsafe static bool ValidateResult_Vector128(Vector128 result, Vector128 expectedElementValue) where T : unmanaged + { + var succeeded = true; + + for (var i = 0; i < (16 / sizeof(T)); i++) + { + if (!result.GetElement(i).Equals(expectedElementValue.GetElement(i))) + { + succeeded = false; + } + } + + return succeeded; + } + + static int Tests_AdvSimd() + { + var result = 100; + + // Begin CompareEqual Tests + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_Byte_Zero(Vector64.Zero), Byte.MaxValue)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_SByte_Zero(Vector64.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_UInt16_Zero(Vector64.Zero), UInt16.MaxValue)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_Int16_Zero(Vector64.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_UInt32_Zero(Vector64.Zero), UInt32.MaxValue)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_Int32_Zero(Vector64.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_Single_Zero(Vector64.Zero), Single.NaN)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_Byte_Zero(Vector128.Zero), Byte.MaxValue)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_SByte_Zero(Vector128.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_UInt16_Zero(Vector128.Zero), UInt16.MaxValue)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_Int16_Zero(Vector128.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_UInt32_Zero(Vector128.Zero), UInt32.MaxValue)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_Int32_Zero(Vector128.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_Single_Zero(Vector128.Zero), Single.NaN)) + result = -1; + + // End CompareEqual Tests + + return result; + } + + static int Tests_AdvSimd_Swapped() + { + var result = 100; + + // Begin CompareEqual Tests + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_Byte_Zero_Swapped(Vector64.Zero), Byte.MaxValue)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_SByte_Zero_Swapped(Vector64.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_UInt16_Zero_Swapped(Vector64.Zero), UInt16.MaxValue)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_Int16_Zero_Swapped(Vector64.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_UInt32_Zero_Swapped(Vector64.Zero), UInt32.MaxValue)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_Int32_Zero_Swapped(Vector64.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_CompareEqual_Vector64_Single_Zero_Swapped(Vector64.Zero), Single.NaN)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_Byte_Zero_Swapped(Vector128.Zero), Byte.MaxValue)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_SByte_Zero_Swapped(Vector128.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_UInt16_Zero_Swapped(Vector128.Zero), UInt16.MaxValue)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_Int16_Zero_Swapped(Vector128.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_UInt32_Zero_Swapped(Vector128.Zero), UInt32.MaxValue)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_Int32_Zero_Swapped(Vector128.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_CompareEqual_Vector128_Single_Zero_Swapped(Vector128.Zero), Single.NaN)) + result = -1; + + // End CompareEqual Tests + + return result; + } + + static int Tests_AdvSimd_Arm64() + { + var result = 100; + + // Begin CompareEqual Tests + + if (!ValidateResult_Vector128(AdvSimd_Arm64_CompareEqual_Vector128_Double_Zero(Vector128.Zero), Double.NaN)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_Arm64_CompareEqual_Vector128_UInt64_Zero(Vector128.Zero), UInt64.MaxValue)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_Arm64_CompareEqual_Vector128_Int64_Zero(Vector128.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_Arm64_CompareEqualScalar_Vector64_Single_Zero(Vector64.Zero), Vector64.CreateScalar(Single.NaN))) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_Arm64_CompareEqualScalar_Vector64_Double_Zero(Vector64.Zero), Vector64.CreateScalar(Double.NaN))) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_Arm64_CompareEqualScalar_Vector64_UInt64_Zero(Vector64.Zero), Vector64.CreateScalar(UInt64.MaxValue))) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_Arm64_CompareEqualScalar_Vector64_Int64_Zero(Vector64.Zero), Vector64.CreateScalar(-1L))) + result = -1; + + // End CompareEqual Tests + + return result; + } + + static int Tests_AdvSimd_Arm64_Swapped() + { + var result = 100; + + // Begin CompareEqual Tests + + if (!ValidateResult_Vector128(AdvSimd_Arm64_CompareEqual_Vector128_Double_Zero_Swapped(Vector128.Zero), Double.NaN)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_Arm64_CompareEqual_Vector128_UInt64_Zero_Swapped(Vector128.Zero), UInt64.MaxValue)) + result = -1; + + if (!ValidateResult_Vector128(AdvSimd_Arm64_CompareEqual_Vector128_Int64_Zero_Swapped(Vector128.Zero), -1)) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_Arm64_CompareEqualScalar_Vector64_Single_Zero_Swapped(Vector64.Zero), Vector64.CreateScalar(Single.NaN))) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_Arm64_CompareEqualScalar_Vector64_Double_Zero_Swapped(Vector64.Zero), Vector64.CreateScalar(Double.NaN))) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_Arm64_CompareEqualScalar_Vector64_UInt64_Zero_Swapped(Vector64.Zero), Vector64.CreateScalar(UInt64.MaxValue))) + result = -1; + + if (!ValidateResult_Vector64(AdvSimd_Arm64_CompareEqualScalar_Vector64_Int64_Zero_Swapped(Vector64.Zero), Vector64.CreateScalar(-1L))) + result = -1; + + // End CompareEqual Tests + + return result; + } + + static int Main(string[] args) + { + var result = 100; + + if (AdvSimd.IsSupported) + { + Console.WriteLine("Testing AdvSimd"); + + if (result != -1) + { + result = Tests_AdvSimd(); + } + if (result != -1) + { + result = Tests_AdvSimd_Swapped(); + } + + if (result == -1) + { + Console.WriteLine("AdvSimd Tests Failed"); + } + else + { + Console.WriteLine("AdvSimd Tests Passed"); + } + } + else + { + Console.WriteLine("Skipped AdvSimd Tests"); + } + + if (AdvSimd.Arm64.IsSupported) + { + Console.WriteLine("Testing AdvSimd_Arm64"); + + if (result != -1) + { + result = Tests_AdvSimd_Arm64(); + } + if (result != -1) + { + result = Tests_AdvSimd_Arm64_Swapped(); + } + + if (result == -1) + { + Console.WriteLine("AdvSimd_Arm64 Tests Failed"); + } + else + { + Console.WriteLine("AdvSimd_Arm64 Tests Passed"); + } + } + else + { + Console.WriteLine("Skipped AdvSimd_Arm64 Tests"); + } + + return result; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_33972/Runtime_33972.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_33972/Runtime_33972.csproj new file mode 100644 index 0000000000000..bf6f589eb325b --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_33972/Runtime_33972.csproj @@ -0,0 +1,13 @@ + + + Exe + + + None + True + True + + + + + From f1c8b10ef824c5abf0c851f610ab0961ca31693f Mon Sep 17 00:00:00 2001 From: Egor Chesakov Date: Wed, 19 Jan 2022 19:43:26 -0800 Subject: [PATCH 078/308] [Arm64] Keep unrolling InitBlock and CopyBlock up to 128 bytes (#63422) * Add INITBLK_LCL_UNROLL_LIMIT and CPBLK_LCL_UNROLL_LIMIT of 128 bytes in src/coreclr/jit/targetarm64.h * Keep unrolling InitBlock up to INITBLK_LCL_UNROLL_LIMIT bytes when dstAddr points to the stack in src/coreclr/jit/lowerarmarch.cpp * Keep unrolling CopyBlock up to CPBLK_LCL_UNROLL_LIMIT bytes when both srcAddr and dstAddr point to the stack in src/coreclr/jit/lowerarmarch.cpp --- src/coreclr/jit/lowerarmarch.cpp | 49 ++++++++++++++++++++++++++------ src/coreclr/jit/targetarm64.h | 6 ++-- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index e165469cbc77c..192c4abfc4386 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -293,6 +293,8 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) GenTree* src = blkNode->Data(); unsigned size = blkNode->Size(); + const bool isDstAddrLocal = dstAddr->OperIsLocalAddr(); + if (blkNode->OperIsInitBlkOp()) { if (src->OperIs(GT_INIT_VAL)) @@ -306,7 +308,18 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) blkNode->SetOper(GT_STORE_BLK); } - if (!blkNode->OperIs(GT_STORE_DYN_BLK) && (size <= INITBLK_UNROLL_LIMIT) && src->OperIs(GT_CNS_INT)) + unsigned initBlockUnrollLimit = INITBLK_UNROLL_LIMIT; + +#ifdef TARGET_ARM64 + if (isDstAddrLocal) + { + // Since dstAddr points to the stack CodeGen can use more optimal + // quad-word store SIMD instructions for InitBlock. + initBlockUnrollLimit = INITBLK_LCL_UNROLL_LIMIT; + } +#endif + + if (!blkNode->OperIs(GT_STORE_DYN_BLK) && (size <= initBlockUnrollLimit) && src->OperIs(GT_CNS_INT)) { blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll; @@ -353,19 +366,39 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) assert(src->OperIs(GT_IND, GT_LCL_VAR, GT_LCL_FLD)); src->SetContained(); + bool isSrcAddrLocal = false; + if (src->OperIs(GT_IND)) { + GenTree* srcAddr = src->AsIndir()->Addr(); // TODO-Cleanup: Make sure that GT_IND lowering didn't mark the source address as contained. // Sometimes the GT_IND type is a non-struct type and then GT_IND lowering may contain the // address, not knowing that GT_IND is part of a block op that has containment restrictions. - src->AsIndir()->Addr()->ClearContained(); + srcAddr->ClearContained(); + isSrcAddrLocal = srcAddr->OperIsLocalAddr(); + } + else + { + isSrcAddrLocal = true; + + if (src->OperIs(GT_LCL_VAR)) + { + // TODO-1stClassStructs: for now we can't work with STORE_BLOCK source in register. + const unsigned srcLclNum = src->AsLclVar()->GetLclNum(); + comp->lvaSetVarDoNotEnregister(srcLclNum DEBUGARG(DoNotEnregisterReason::BlockOp)); + } } - else if (src->OperIs(GT_LCL_VAR)) + + unsigned copyBlockUnrollLimit = CPBLK_UNROLL_LIMIT; + +#ifdef TARGET_ARM64 + if (isSrcAddrLocal && isDstAddrLocal) { - // TODO-1stClassStructs: for now we can't work with STORE_BLOCK source in register. - const unsigned srcLclNum = src->AsLclVar()->GetLclNum(); - comp->lvaSetVarDoNotEnregister(srcLclNum DEBUGARG(DoNotEnregisterReason::BlockOp)); + // Since both srcAddr and dstAddr point to the stack CodeGen can use more optimal + // quad-word load and store SIMD instructions for CopyBlock. + copyBlockUnrollLimit = CPBLK_LCL_UNROLL_LIMIT; } +#endif if (blkNode->OperIs(GT_STORE_OBJ)) { @@ -373,7 +406,7 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) { blkNode->SetOper(GT_STORE_BLK); } - else if (dstAddr->OperIsLocalAddr() && (size <= CPBLK_UNROLL_LIMIT)) + else if (isDstAddrLocal && (size <= copyBlockUnrollLimit)) { // If the size is small enough to unroll then we need to mark the block as non-interruptible // to actually allow unrolling. The generated code does not report GC references loaded in the @@ -389,7 +422,7 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll; } - else if (blkNode->OperIs(GT_STORE_BLK) && (size <= CPBLK_UNROLL_LIMIT)) + else if (blkNode->OperIs(GT_STORE_BLK) && (size <= copyBlockUnrollLimit)) { blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll; diff --git a/src/coreclr/jit/targetarm64.h b/src/coreclr/jit/targetarm64.h index cdab21582ffce..4cc6b63f73009 100644 --- a/src/coreclr/jit/targetarm64.h +++ b/src/coreclr/jit/targetarm64.h @@ -11,8 +11,10 @@ #define ROUND_FLOAT 0 // Do not round intermed float expression results #define CPU_HAS_BYTE_REGS 0 - #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk. - #define INITBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll InitBlk. + #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk + #define CPBLK_LCL_UNROLL_LIMIT 128 // Upper bound to let the code generator to loop unroll CpBlk (when both srcAddr and dstAddr point to the stack) + #define INITBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll InitBlk + #define INITBLK_LCL_UNROLL_LIMIT 128 // Upper bound to let the code generator to loop unroll InitBlk (when dstAddr points to the stack) #ifdef FEATURE_SIMD #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned From 65a5d0e8a3027f2b240d098f47327ba3e1f743b1 Mon Sep 17 00:00:00 2001 From: Tlakaelel Axayakatl Ceja Date: Wed, 19 Jan 2022 19:46:45 -0800 Subject: [PATCH 079/308] Add ProcessLinkerXmlBase to NativeAOT (#63666) Add Xml Parsing linker files as a reference source to NativeAOT Rename NativeAOT ProcessLinkerXmlBase version to ProcessXmlBase (uses XmlReader) Add ProcessLinkerXmlBase from linker and fix it so it can be used in NativeAOT (uses XPath) --- .../Compiler/FeatureSettings.cs | 52 ++ .../Compiler/FeatureSwitchManager.cs | 2 +- .../ManifestResourceBlockingPolicy.cs | 2 +- .../Compiler/ProcessLinkerXmlBase.cs | 661 ++++++++++++----- .../Compiler/ProcessXmlBase.cs | 404 +++++++++++ .../ReferenceSource/BodySubstitutionParser.cs | 174 +++++ .../ReferenceSource/DescriptorMarker.cs | 292 ++++++++ .../ReferenceSource/FeatureSettings.cs | 50 ++ .../ReferenceSource/LinkAttributesParser.cs | 578 +++++++++++++++ .../ReferenceSource/ProcessLinkerXmlBase.cs | 662 ++++++++++++++++++ .../Compiler/ReferenceSource/README.md | 1 + .../Compiler/UsageBasedMetadataManager.cs | 2 +- .../ILCompiler.Compiler.csproj | 2 + 13 files changed, 2696 insertions(+), 186 deletions(-) create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSettings.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessXmlBase.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/BodySubstitutionParser.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/DescriptorMarker.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/FeatureSettings.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/LinkAttributesParser.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/ProcessLinkerXmlBase.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/README.md diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSettings.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSettings.cs new file mode 100644 index 0000000000000..773c061081e45 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSettings.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Xml.XPath; +using ILLink.Shared; +using Internal.TypeSystem; + +namespace ILCompiler +{ + public static class FeatureSettings + { + public static bool ShouldProcessElement(XPathNavigator nav, IReadOnlyDictionary featureSwitchValues) + { + var feature = GetAttribute(nav, "feature"); + if (string.IsNullOrEmpty(feature)) + return true; + + var value = GetAttribute(nav, "featurevalue"); + if (string.IsNullOrEmpty(value)) + { + //context.LogError(null, DiagnosticId.XmlFeatureDoesNotSpecifyFeatureValue, documentLocation, feature); + return false; + } + + if (!bool.TryParse(value, out bool bValue)) + { + //context.LogError(null, DiagnosticId.XmlUnsupportedNonBooleanValueForFeature, documentLocation, feature); + return false; + } + + var isDefault = GetAttribute(nav, "featuredefault"); + bool bIsDefault = false; + if (!string.IsNullOrEmpty(isDefault) && (!bool.TryParse(isDefault, out bIsDefault) || !bIsDefault)) + { + //context.LogError(null, DiagnosticId.XmlDocumentLocationHasInvalidFeatureDefault, documentLocation); + return false; + } + + if (!featureSwitchValues.TryGetValue(feature, out bool featureSetting)) + return bIsDefault; + + return bValue == featureSetting; + } + + public static string GetAttribute(XPathNavigator nav, string attribute) + { + return nav.GetAttribute(attribute, String.Empty); + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs index 5f06913b97d37..20050db2c8cda 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs @@ -792,7 +792,7 @@ public MethodIL EmitIL(MethodDesc method) } } - private class SubstitutionsReader : ProcessLinkerXmlBase + private class SubstitutionsReader : ProcessXmlBase { private readonly Dictionary _methodSubstitutions; private readonly Dictionary _fieldSubstitutions; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManifestResourceBlockingPolicy.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManifestResourceBlockingPolicy.cs index f9df59bfa816f..3b2b3a2e25384 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManifestResourceBlockingPolicy.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ManifestResourceBlockingPolicy.cs @@ -100,7 +100,7 @@ public AssemblyFeatureInfo(EcmaModule module, IReadOnlyDictionary } } - private class SubstitutionsReader : ProcessLinkerXmlBase + private class SubstitutionsReader : ProcessXmlBase { private readonly HashSet _substitutions = new HashSet(); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs index c5101bde818fa..e157381162aa5 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs @@ -1,316 +1,511 @@ -// 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. using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; using System.Reflection; +using System.Reflection.Metadata; using System.Text; +using System.Text.RegularExpressions; using System.Xml; - +using System.Xml.Linq; +using System.Xml.XPath; +using ILLink.Shared; using Internal.TypeSystem; +#nullable enable + namespace ILCompiler { - /// - /// Base class for readers of IL Linker XML file format. - /// - internal abstract class ProcessLinkerXmlBase + [Flags] + public enum AllowedAssemblies { - private readonly XmlReader _reader; - private readonly ModuleDesc _owningModule; + ContainingAssembly = 0x1, + AnyAssembly = 0x2 | ContainingAssembly, + AllAssemblies = 0x4 | AnyAssembly + } + + public abstract class ProcessLinkerXmlBase + { + const string FullNameAttributeName = "fullname"; + const string LinkerElementName = "linker"; + const string TypeElementName = "type"; + const string SignatureAttributeName = "signature"; + const string NameAttributeName = "name"; + const string FieldElementName = "field"; + const string MethodElementName = "method"; + const string EventElementName = "event"; + const string PropertyElementName = "property"; + const string AllAssembliesFullName = "*"; + protected const string XmlNamespace = ""; + + protected readonly string _xmlDocumentLocation; + readonly XPathNavigator _document; + protected readonly ModuleDesc? _owningModule; private readonly IReadOnlyDictionary _featureSwitchValues; protected readonly TypeSystemContext _context; - public ProcessLinkerXmlBase(TypeSystemContext context, XmlReader reader, ModuleDesc owningModule, IReadOnlyDictionary featureSwitchValues) + protected ProcessLinkerXmlBase(TypeSystemContext context, UnmanagedMemoryStream documentStream, string xmlDocumentLocation, IReadOnlyDictionary featureSwitchValues) { - _reader = reader; - _owningModule = owningModule; - _featureSwitchValues = featureSwitchValues; _context = context; + using (documentStream) + { + _document = XDocument.Load(documentStream, LoadOptions.SetLineInfo).CreateNavigator(); + } + _xmlDocumentLocation = xmlDocumentLocation; + _featureSwitchValues = featureSwitchValues; } - public void ProcessXml() + protected ProcessLinkerXmlBase(TypeSystemContext context, UnmanagedMemoryStream documentStream, ManifestResource resource, ModuleDesc resourceAssembly, string xmlDocumentLocation, IReadOnlyDictionary featureSwitchValues) + : this(context, documentStream, xmlDocumentLocation, featureSwitchValues) { - if (_reader.IsStartElement() && _reader.Name == "linker") + _owningModule = resourceAssembly ?? throw new ArgumentNullException(nameof(resourceAssembly)); + } + + protected virtual bool ShouldProcessElement(XPathNavigator nav) => FeatureSettings.ShouldProcessElement(nav, _featureSwitchValues); + + protected virtual void ProcessXml(bool ignoreResource) + { + if (!AllowedAssemblySelector.HasFlag(AllowedAssemblies.AnyAssembly) && _owningModule == null) + throw new InvalidOperationException("The containing assembly must be specified for XML which is restricted to modifying that assembly only."); + + try { - if (!ShouldProcessElement()) + XPathNavigator nav = _document.CreateNavigator(); + + // Initial structure check - ignore XML document which don't look like linker XML format + if (!nav.MoveToChild(LinkerElementName, XmlNamespace)) + return; + + if (_owningModule != null) + { + if (ignoreResource) + return; + } + + if (!ShouldProcessElement(nav)) return; - _reader.Read(); + ProcessAssemblies(nav); - ProcessAssemblies(); + // For embedded XML, allow not specifying the assembly explicitly in XML. + if (_owningModule != null) + ProcessAssembly(_owningModule, nav, warnOnUnresolvedTypes: true); + + } + catch (Exception ex) + { + // throw new LinkerFatalErrorException(MessageContainer.CreateErrorMessage(null, DiagnosticId.ErrorProcessingXmlLocation, _xmlDocumentLocation), ex); + throw ex; } } - protected string GetAttribute(string attribute) - { - return _reader.GetAttribute(attribute); - } + protected virtual AllowedAssemblies AllowedAssemblySelector { get => _owningModule != null ? AllowedAssemblies.ContainingAssembly : AllowedAssemblies.AnyAssembly; } - protected bool IsEmpty() + bool ShouldProcessAllAssemblies(XPathNavigator nav, [NotNullWhen(false)] out AssemblyName? assemblyName) { - return _reader.IsEmptyElement; + assemblyName = null; + if (GetFullName(nav) == AllAssembliesFullName) + return true; + + assemblyName = GetAssemblyName(nav); + return false; } - private void ProcessAssemblies() + protected virtual void ProcessAssemblies(XPathNavigator nav) { - while (_reader.IsStartElement()) + foreach (XPathNavigator assemblyNav in nav.SelectChildren("assembly", "")) { - if (_reader.Name == "assembly") + // Errors for invalid assembly names should show up even if this element will be + // skipped due to feature conditions. + bool processAllAssemblies = ShouldProcessAllAssemblies(assemblyNav, out AssemblyName? name); + if (processAllAssemblies && AllowedAssemblySelector != AllowedAssemblies.AllAssemblies) { - string assemblyName = _reader.GetAttribute("fullname"); + //LogWarning(assemblyNav, DiagnosticId.XmlUnsuportedWildcard); + continue; + } - if (assemblyName == "*") + ModuleDesc? assemblyToProcess = null; + if (!AllowedAssemblySelector.HasFlag(AllowedAssemblies.AnyAssembly)) + { + Debug.Assert(!processAllAssemblies); + Debug.Assert(_owningModule != null); + if (_owningModule.Assembly.GetName().Name != name!.Name) { - // https://github.com/dotnet/runtimelab/issues/1381 - _reader.Skip(); + //LogWarning(assemblyNav, DiagnosticId.AssemblyWithEmbeddedXmlApplyToAnotherAssembly, _resource.Value.Assembly.Name.Name, name.ToString()); continue; } + assemblyToProcess = _owningModule; + } - // Errors for invalid assembly names should show up even if this element will be - // skipped due to feature conditions. - var name = new AssemblyName(assemblyName); + if (!ShouldProcessElement(assemblyNav)) + continue; - if (!ShouldProcessElement()) - { - _reader.Skip(); - continue; - } - - ModuleDesc assembly = GetAssembly(name); + if (processAllAssemblies) + { + throw new NotImplementedException(); + // We could avoid loading all references in this case: https://github.com/dotnet/linker/issues/1708 + //foreach (ModuleDesc assembly in GetReferencedAssemblies()) + // ProcessAssembly(assembly, assemblyNav, warnOnUnresolvedTypes: false); + } + else + { + Debug.Assert(!processAllAssemblies); + ModuleDesc? assembly = assemblyToProcess ?? _context.ResolveAssembly(name!); if (assembly == null) { - //Context.LogWarning($"Could not resolve assembly '{name.Name}'", 2007, _xmlDocumentLocation); - _reader.Skip(); + //LogWarning(assemblyNav, DiagnosticId.XmlCouldNotResolveAssembly, name!.Name); continue; } - _reader.Read(); - - ProcessAssembly(assembly); - } - else if (_reader.Name == "type") - { - ProcessType(_owningModule); - } - else if (_reader.Name == "resource") - { - ProcessResource(_owningModule); - } - else - { - _reader.Skip(); + ProcessAssembly(assembly, assemblyNav, warnOnUnresolvedTypes: true); } } } - protected ModuleDesc GetAssembly(AssemblyName name) - { - return _context.ResolveAssembly(name); - } - private void ProcessAssembly(ModuleDesc assembly) + protected abstract void ProcessAssembly(ModuleDesc assembly, XPathNavigator nav, bool warnOnUnresolvedTypes); + + protected virtual void ProcessTypes(ModuleDesc assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) { - while (_reader.IsStartElement()) + foreach (XPathNavigator typeNav in nav.SelectChildren(TypeElementName, XmlNamespace)) { - if (_reader.Name == "type") + + if (!ShouldProcessElement(typeNav)) + continue; + + string fullname = GetFullName(typeNav); + + if (fullname.IndexOf("*") != -1) { - ProcessType(assembly); + if (ProcessTypePattern(fullname, assembly, typeNav)) + continue; } - else if (_reader.Name == "resource") + + // TODO: Process exported types + + // TODO: Semantics differ and xml format is cecil specific, therefore they are discrepancies on things like nested types + TypeDesc type = CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(assembly, fullname, throwIfNotFound: false); + + if (type == null) { - ProcessResource(assembly); + //if (warnOnUnresolvedTypes) + // LogWarning(typeNav, DiagnosticId.XmlCouldNotResolveType, fullname); + continue; } - _reader.Skip(); + ProcessType(type, typeNav); } + } + + void MatchType(TypeDesc type, Regex regex, XPathNavigator nav) + { + StringBuilder sb = new StringBuilder(); + CecilTypeNameFormatter.Instance.AppendName(sb, type); + if (regex.Match(sb.ToString()).Success) + ProcessType(type, nav); + } - _reader.ReadEndElement(); + protected virtual bool ProcessTypePattern(string fullname, ModuleDesc assembly, XPathNavigator nav) + { + Regex regex = new Regex(fullname.Replace(".", @"\.").Replace("*", "(.*)")); + + foreach (TypeDesc type in assembly.GetAllTypes()) + MatchType(type, regex, nav); + + return true; } - private void ProcessType(ModuleDesc assembly) + protected abstract void ProcessType(TypeDesc type, XPathNavigator nav); + + protected void ProcessTypeChildren(TypeDesc type, XPathNavigator nav, object? customData = null) { - if (ShouldProcessElement()) + if (nav.HasChildren) { - string typeName = _reader.GetAttribute("fullname"); + ProcessSelectedFields(nav, type); + ProcessSelectedMethods(nav, type, customData); + // TODO: In order to be compatible with the format we need to be able to recognize properties, events and maybe attributes + } + } - if (typeName.Contains('*')) - throw new NotSupportedException(); + void ProcessSelectedFields(XPathNavigator nav, TypeDesc type) + { + foreach (XPathNavigator fieldNav in nav.SelectChildren(FieldElementName, XmlNamespace)) + { + if (!ShouldProcessElement(fieldNav)) + continue; + ProcessField(type, fieldNav); + } + } - TypeDesc type = CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(assembly, typeName, throwIfNotFound: false); - if (type == null) + protected virtual void ProcessField(TypeDesc type, XPathNavigator nav) + { + string signature = GetSignature(nav); + if (!String.IsNullOrEmpty(signature)) + { + FieldDesc? field = GetField(type, signature); + if (field == null) { - //Context.LogWarning ($"Could not resolve type '{fullname}'", 2008, _xmlDocumentLocation); - _reader.Skip(); + //LogWarning(nav, DiagnosticId.XmlCouldNotFindFieldOnType, signature, type.GetDisplayName()); return; } - _reader.Read(); + ProcessField(type, field, nav); + } - while (_reader.IsStartElement()) + string name = GetName(nav); + if (!String.IsNullOrEmpty(name)) + { + bool foundMatch = false; + foreach (FieldDesc field in type.GetFields()) { - if (_reader.Name == "method") - { - ProcessMethod(type); - } - else if (_reader.Name == "field") + if (field.Name == name) { - ProcessField(type); - } - else if (_reader.Name == "attribute") - { - ProcessAttribute(type); + foundMatch = true; + ProcessField(type, field, nav); } + } + - _reader.Skip(); + if (!foundMatch) + { + // LogWarning(nav, DiagnosticId.XmlCouldNotFindFieldOnType, name, type.GetDisplayName()); } } + } + + protected static FieldDesc? GetField(TypeDesc type, string signature) + { + StringBuilder sb = new StringBuilder(); + foreach (FieldDesc field in type.GetFields()) + { + sb.Clear(); + CecilTypeNameFormatter.Instance.AppendName(sb, field.FieldType); + if (signature == sb.ToString() + " " + field.Name) + return field; + } + + return null; + } + + protected virtual void ProcessField(TypeDesc type, FieldDesc field, XPathNavigator nav) { } - _reader.Skip(); + void ProcessSelectedMethods(XPathNavigator nav, TypeDesc type, object? customData) + { + foreach (XPathNavigator methodNav in nav.SelectChildren(MethodElementName, XmlNamespace)) + { + if (!ShouldProcessElement(methodNav)) + continue; + ProcessMethod(type, methodNav, customData); + } } - private void ProcessMethod(TypeDesc type) + protected virtual void ProcessMethod(TypeDesc type, XPathNavigator nav, object? customData) { - if (ShouldProcessElement()) + string signature = GetSignature(nav); + if (!String.IsNullOrEmpty(signature)) { - string signature = _reader.GetAttribute("signature"); - if (!String.IsNullOrEmpty(signature)) + MethodDesc? method = GetMethod(type, signature); + if (method == null) { - MethodDesc method = GetMethod(type, signature); - if (method == null) - { - //Context.LogWarning($"Could not find method '{signature}' on type '{type.GetDisplayName()}'", 2009, _xmlDocumentLocation); - return; - } - - ProcessMethod(method); + //LogWarning(nav, DiagnosticId.XmlCouldNotFindMethodOnType, signature, type.GetDisplayName()); + return; } - string methodName = _reader.GetAttribute("name"); - if (!String.IsNullOrEmpty(methodName)) - { - bool foundMatch = false; - foreach (MethodDesc method in type.GetMethods()) - { - if (method.Name == methodName) - { - foundMatch = true; - ProcessMethod(method); - } - } + ProcessMethod(type, method, nav, customData); + } - if (!foundMatch) + string name = GetAttribute(nav, NameAttributeName); + if (!String.IsNullOrEmpty(name)) + { + bool foundMatch = false; + foreach (MethodDesc method in type.GetAllMethods()) + { + if (name == method.Name) { - //Context.LogWarning($"Could not find method '{name}' on type '{type.GetDisplayName()}'", 2009, _xmlDocumentLocation); + foundMatch = true; + ProcessMethod(type, method, nav, customData); } } + if (!foundMatch) + { + // LogWarning(nav, DiagnosticId.XmlCouldNotFindMethodOnType, name, type.GetDisplayName()); + } } } - protected virtual void ProcessMethod(MethodDesc method) + protected virtual MethodDesc? GetMethod(TypeDesc type, string signature) => null; + + protected virtual void ProcessMethod(TypeDesc type, MethodDesc method, XPathNavigator nav, object? customData) { } + +#if false + void ProcessSelectedEvents(XPathNavigator nav, TypeDefinition type, object? customData) { + foreach (XPathNavigator eventNav in nav.SelectChildren(EventElementName, XmlNamespace)) + { + if (!ShouldProcessElement(eventNav)) + continue; + ProcessEvent(type, eventNav, customData); + } } - private void ProcessField(TypeDesc type) + protected virtual void ProcessEvent(TypeDefinition type, XPathNavigator nav, object? customData) { - if (ShouldProcessElement()) + string signature = GetSignature(nav); + if (!String.IsNullOrEmpty(signature)) { - string fieldName = _reader.GetAttribute("name"); - if (!String.IsNullOrEmpty(fieldName)) + EventDefinition? @event = GetEvent(type, signature); + if (@event == null) { - FieldDesc field = type.GetField(fieldName); + LogWarning(nav, DiagnosticId.XmlCouldNotFindEventOnType, signature, type.GetDisplayName()); + return; + } - if (field == null) - { - //Context.LogWarning($"Could not find field '{name}' on type '{type.GetDisplayName()}'", 2012, _xmlDocumentLocation); - } - else + ProcessEvent(type, @event, nav, customData); + } + + string name = GetAttribute(nav, NameAttributeName); + if (!String.IsNullOrEmpty(name)) + { + bool foundMatch = false; + foreach (EventDefinition @event in type.Events) + { + if (@event.Name == name) { - ProcessField(field); + foundMatch = true; + ProcessEvent(type, @event, nav, customData); } } + + if (!foundMatch) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindEventOnType, name, type.GetDisplayName()); + } } } - protected virtual void ProcessField(FieldDesc field) + protected static EventDefinition? GetEvent(TypeDefinition type, string signature) { - } + if (!type.HasEvents) + return null; - protected virtual void ProcessAttribute(TypeDesc type) - { - } + foreach (EventDefinition @event in type.Events) + if (signature == @event.EventType.FullName + " " + @event.Name) + return @event; - protected virtual void ProcessResource(ModuleDesc module) - { + return null; } - protected MethodDesc GetMethod(TypeDesc type, string signature) - { - foreach (MethodDesc meth in type.GetMethods()) - if (signature == GetMethodSignature(meth, false)) - return meth; + protected virtual void ProcessEvent(TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) { } - return null; + void ProcessSelectedProperties(XPathNavigator nav, TypeDefinition type, object? customData) + { + foreach (XPathNavigator propertyNav in nav.SelectChildren(PropertyElementName, XmlNamespace)) + { + if (!ShouldProcessElement(propertyNav)) + continue; + ProcessProperty(type, propertyNav, customData); + } } - public static string GetMethodSignature(MethodDesc meth, bool includeGenericParameters) + protected virtual void ProcessProperty(TypeDefinition type, XPathNavigator nav, object? customData) { - StringBuilder sb = new StringBuilder(); - CecilTypeNameFormatter.Instance.AppendName(sb, meth.Signature.ReturnType); - sb.Append(' '); - sb.Append(meth.Name); - if (includeGenericParameters && meth.HasInstantiation) + string signature = GetSignature(nav); + if (!String.IsNullOrEmpty(signature)) { - sb.Append('`'); - sb.Append(meth.Instantiation.Length); + PropertyDefinition? property = GetProperty(type, signature); + if (property == null) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindPropertyOnType, signature, type.GetDisplayName()); + return; + } + + ProcessProperty(type, property, nav, customData, true); } - sb.Append('('); - for (int i = 0; i < meth.Signature.Length; i++) + string name = GetAttribute(nav, NameAttributeName); + if (!String.IsNullOrEmpty(name)) { - if (i > 0) - sb.Append(','); + bool foundMatch = false; + foreach (PropertyDefinition property in type.Properties) + { + if (property.Name == name) + { + foundMatch = true; + ProcessProperty(type, property, nav, customData, false); + } + } - CecilTypeNameFormatter.Instance.AppendName(sb, meth.Signature[i]); + if (!foundMatch) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindPropertyOnType, name, type.GetDisplayName()); + } } + } + + protected static PropertyDefinition? GetProperty(TypeDefinition type, string signature) + { + if (!type.HasProperties) + return null; + + foreach (PropertyDefinition property in type.Properties) + if (signature == property.PropertyType.FullName + " " + property.Name) + return property; - sb.Append(')'); - return sb.ToString(); + return null; } - private bool ShouldProcessElement() + protected virtual void ProcessProperty(TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object? customData, bool fromSignature) { } +#endif + + protected virtual AssemblyName GetAssemblyName(XPathNavigator nav) { - string feature = _reader.GetAttribute("feature"); - if (string.IsNullOrEmpty(feature)) - return true; + return new AssemblyName(GetFullName(nav)); + } - string value = _reader.GetAttribute("featurevalue"); - if (string.IsNullOrEmpty(value)) - { - //context.LogError($"Failed to process '{documentLocation}'. Feature '{feature}' does not specify a 'featurevalue' attribute", 1001); - return false; - } + protected static string GetFullName(XPathNavigator nav) + { + return GetAttribute(nav, FullNameAttributeName); + } - if (!bool.TryParse(value, out bool bValue)) - { - //context.LogError($"Failed to process '{documentLocation}'. Unsupported non-boolean feature definition '{feature}'", 1002); - return false; - } + protected static string GetName(XPathNavigator nav) + { + return GetAttribute(nav, NameAttributeName); + } - var isDefault = _reader.GetAttribute("featuredefault"); - bool bIsDefault = false; - if (!string.IsNullOrEmpty(isDefault) && (!bool.TryParse(isDefault, out bIsDefault) || !bIsDefault)) - { - //context.LogError($"Failed to process '{documentLocation}'. Unsupported value for featuredefault attribute", 1014); - return false; - } + protected static string GetSignature(XPathNavigator nav) + { + return GetAttribute(nav, SignatureAttributeName); + } - if (!_featureSwitchValues.TryGetValue(feature, out bool featureSetting)) - return bIsDefault; + protected static string GetAttribute(XPathNavigator nav, string attribute) + { + return nav.GetAttribute(attribute, XmlNamespace); + } - return bValue == featureSetting; +#if false + protected MessageOrigin GetMessageOriginForPosition(XPathNavigator position) + { + return (position is IXmlLineInfo lineInfo) + ? new MessageOrigin(_xmlDocumentLocation, lineInfo.LineNumber, lineInfo.LinePosition, _resource?.Assembly) + : new MessageOrigin(_xmlDocumentLocation, 0, 0, _resource?.Assembly); + } + protected void LogWarning(string message, int warningCode, XPathNavigator position) + { + _context.LogWarning(message, warningCode, GetMessageOriginForPosition(position)); + } + + protected void LogWarning(XPathNavigator position, DiagnosticId id, params string[] args) + { + _context.LogWarning(GetMessageOriginForPosition(position), id, args); } +#endif class CecilTypeNameFormatter : TypeNameFormatter { @@ -399,6 +594,106 @@ protected override void AppendNameForNestedType(StringBuilder sb, DefType nested sb.Append('/'); sb.Append(nestedType.Name); } + +#if false + public bool TryConvertValue(string value, TypeDesc type, out object? result) + { + switch (type.UnderlyingType.Category) + { + case TypeFlags.Boolean: + if ((bool.TryParse(value, out bool bvalue))) + { + result = bvalue ? 1 : 0; + return true; + } + else + goto case TypeFlags.Int32; + + case TypeFlags.Byte: + if (!byte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out byte byteresult)) + break; + + result = (int)byteresult; + return true; + + case TypeFlags.SByte: + if (!sbyte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out sbyte sbyteresult)) + break; + + result = (int)sbyteresult; + return true; + + case TypeFlags.Int16: + if (!short.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out short shortresult)) + break; + + result = (int)shortresult; + return true; + + case TypeFlags.UInt16: + if (!ushort.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort ushortresult)) + break; + + result = (int)ushortresult; + return true; + + case TypeFlags.Int32: + if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int iresult)) + break; + + result = iresult; + return true; + + case TypeFlags.UInt32: + if (!uint.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out uint uresult)) + break; + + result = (int)uresult; + return true; + + case TypeFlags.Double: + if (!double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out double dresult)) + break; + + result = dresult; + return true; + + case TypeFlags.Single: + if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out float fresult)) + break; + + result = fresult; + return true; + + case TypeFlags.Int64: + if (!long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long lresult)) + break; + + result = lresult; + return true; + + case TypeFlags.UInt64: + if (!ulong.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong ulresult)) + break; + + result = (long)ulresult; + return true; + + case TypeFlags.Char: + if (!char.TryParse(value, out char chresult)) + break; + + result = (int)chresult; + return true; + + default: + throw new NotSupportedException(type.ToString()); + } + + result = null; + return false; + } +#endif } } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessXmlBase.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessXmlBase.cs new file mode 100644 index 0000000000000..b00f56a0c2ce4 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessXmlBase.cs @@ -0,0 +1,404 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.Xml; + +using Internal.TypeSystem; + +namespace ILCompiler +{ + /// + /// Base class for readers of IL Linker XML file format. + /// + internal abstract class ProcessXmlBase + { + private readonly XmlReader _reader; + private readonly ModuleDesc _owningModule; + private readonly IReadOnlyDictionary _featureSwitchValues; + protected readonly TypeSystemContext _context; + + public ProcessXmlBase(TypeSystemContext context, XmlReader reader, ModuleDesc owningModule, IReadOnlyDictionary featureSwitchValues) + { + _reader = reader; + _owningModule = owningModule; + _featureSwitchValues = featureSwitchValues; + _context = context; + } + + public void ProcessXml() + { + if (_reader.IsStartElement() && _reader.Name == "linker") + { + if (!ShouldProcessElement()) + return; + + _reader.Read(); + + ProcessAssemblies(); + } + } + + protected string GetAttribute(string attribute) + { + return _reader.GetAttribute(attribute); + } + + protected bool IsEmpty() + { + return _reader.IsEmptyElement; + } + + private void ProcessAssemblies() + { + while (_reader.IsStartElement()) + { + if (_reader.Name == "assembly") + { + string assemblyName = _reader.GetAttribute("fullname"); + + if (assemblyName == "*") + { + // https://github.com/dotnet/runtimelab/issues/1381 + _reader.Skip(); + continue; + } + + // Errors for invalid assembly names should show up even if this element will be + // skipped due to feature conditions. + var name = new AssemblyName(assemblyName); + + if (!ShouldProcessElement()) + { + _reader.Skip(); + continue; + } + + ModuleDesc assembly = GetAssembly(name); + + if (assembly == null) + { + //Context.LogWarning($"Could not resolve assembly '{name.Name}'", 2007, _xmlDocumentLocation); + _reader.Skip(); + continue; + } + + _reader.Read(); + + ProcessAssembly(assembly); + } + else if (_reader.Name == "type") + { + ProcessType(_owningModule); + } + else if (_reader.Name == "resource") + { + ProcessResource(_owningModule); + } + else + { + _reader.Skip(); + } + } + } + + protected ModuleDesc GetAssembly(AssemblyName name) + { + return _context.ResolveAssembly(name); + } + + private void ProcessAssembly(ModuleDesc assembly) + { + while (_reader.IsStartElement()) + { + if (_reader.Name == "type") + { + ProcessType(assembly); + } + else if (_reader.Name == "resource") + { + ProcessResource(assembly); + } + + _reader.Skip(); + } + + _reader.ReadEndElement(); + } + + private void ProcessType(ModuleDesc assembly) + { + if (ShouldProcessElement()) + { + string typeName = _reader.GetAttribute("fullname"); + + if (typeName.Contains('*')) + throw new NotSupportedException(); + + TypeDesc type = CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(assembly, typeName, throwIfNotFound: false); + if (type == null) + { + //Context.LogWarning ($"Could not resolve type '{fullname}'", 2008, _xmlDocumentLocation); + _reader.Skip(); + return; + } + + _reader.Read(); + + while (_reader.IsStartElement()) + { + if (_reader.Name == "method") + { + ProcessMethod(type); + } + else if (_reader.Name == "field") + { + ProcessField(type); + } + else if (_reader.Name == "attribute") + { + ProcessAttribute(type); + } + + _reader.Skip(); + } + } + + _reader.Skip(); + } + + private void ProcessMethod(TypeDesc type) + { + if (ShouldProcessElement()) + { + string signature = _reader.GetAttribute("signature"); + if (!String.IsNullOrEmpty(signature)) + { + MethodDesc method = GetMethod(type, signature); + if (method == null) + { + //Context.LogWarning($"Could not find method '{signature}' on type '{type.GetDisplayName()}'", 2009, _xmlDocumentLocation); + return; + } + + ProcessMethod(method); + } + + string methodName = _reader.GetAttribute("name"); + if (!String.IsNullOrEmpty(methodName)) + { + bool foundMatch = false; + foreach (MethodDesc method in type.GetMethods()) + { + if (method.Name == methodName) + { + foundMatch = true; + ProcessMethod(method); + } + } + + if (!foundMatch) + { + //Context.LogWarning($"Could not find method '{name}' on type '{type.GetDisplayName()}'", 2009, _xmlDocumentLocation); + } + } + } + } + + protected virtual void ProcessMethod(MethodDesc method) + { + } + + private void ProcessField(TypeDesc type) + { + if (ShouldProcessElement()) + { + string fieldName = _reader.GetAttribute("name"); + if (!String.IsNullOrEmpty(fieldName)) + { + FieldDesc field = type.GetField(fieldName); + + if (field == null) + { + //Context.LogWarning($"Could not find field '{name}' on type '{type.GetDisplayName()}'", 2012, _xmlDocumentLocation); + } + else + { + ProcessField(field); + } + } + } + } + + protected virtual void ProcessField(FieldDesc field) + { + } + + protected virtual void ProcessAttribute(TypeDesc type) + { + } + + protected virtual void ProcessResource(ModuleDesc module) + { + } + + protected MethodDesc GetMethod(TypeDesc type, string signature) + { + foreach (MethodDesc meth in type.GetMethods()) + if (signature == GetMethodSignature(meth, false)) + return meth; + + return null; + } + + public static string GetMethodSignature(MethodDesc meth, bool includeGenericParameters) + { + StringBuilder sb = new StringBuilder(); + CecilTypeNameFormatter.Instance.AppendName(sb, meth.Signature.ReturnType); + sb.Append(' '); + sb.Append(meth.Name); + if (includeGenericParameters && meth.HasInstantiation) + { + sb.Append('`'); + sb.Append(meth.Instantiation.Length); + } + + sb.Append('('); + for (int i = 0; i < meth.Signature.Length; i++) + { + if (i > 0) + sb.Append(','); + + CecilTypeNameFormatter.Instance.AppendName(sb, meth.Signature[i]); + } + + sb.Append(')'); + return sb.ToString(); + } + + private bool ShouldProcessElement() + { + string feature = _reader.GetAttribute("feature"); + if (string.IsNullOrEmpty(feature)) + return true; + + string value = _reader.GetAttribute("featurevalue"); + if (string.IsNullOrEmpty(value)) + { + //context.LogError($"Failed to process '{documentLocation}'. Feature '{feature}' does not specify a 'featurevalue' attribute", 1001); + return false; + } + + if (!bool.TryParse(value, out bool bValue)) + { + //context.LogError($"Failed to process '{documentLocation}'. Unsupported non-boolean feature definition '{feature}'", 1002); + return false; + } + + var isDefault = _reader.GetAttribute("featuredefault"); + bool bIsDefault = false; + if (!string.IsNullOrEmpty(isDefault) && (!bool.TryParse(isDefault, out bIsDefault) || !bIsDefault)) + { + //context.LogError($"Failed to process '{documentLocation}'. Unsupported value for featuredefault attribute", 1014); + return false; + } + + if (!_featureSwitchValues.TryGetValue(feature, out bool featureSetting)) + return bIsDefault; + + return bValue == featureSetting; + } + + class CecilTypeNameFormatter : TypeNameFormatter + { + public static readonly CecilTypeNameFormatter Instance = new CecilTypeNameFormatter(); + + public override void AppendName(StringBuilder sb, ArrayType type) + { + AppendName(sb, type.ElementType); + sb.Append('['); + if (type.Rank > 1) + sb.Append(new string(',', type.Rank - 1)); + sb.Append(']'); + } + public override void AppendName(StringBuilder sb, ByRefType type) + { + AppendName(sb, type.ParameterType); + sb.Append('&'); + } + + public override void AppendName(StringBuilder sb, PointerType type) + { + AppendName(sb, type.ParameterType); + sb.Append('*'); + } + + public override void AppendName(StringBuilder sb, FunctionPointerType type) + { + sb.Append(" "); + AppendName(sb, type.Signature.ReturnType); + sb.Append(" *"); + + sb.Append("("); + + for (int i = 0; i < type.Signature.Length; i++) + { + var parameter = type.Signature[i]; + if (i > 0) + sb.Append(","); + + AppendName(sb, parameter); + } + + sb.Append(")"); + } + + public override void AppendName(StringBuilder sb, GenericParameterDesc type) + { + sb.Append(type.Name); + } + public override void AppendName(StringBuilder sb, SignatureMethodVariable type) + { + } + public override void AppendName(StringBuilder sb, SignatureTypeVariable type) + { + } + protected override void AppendNameForInstantiatedType(StringBuilder sb, DefType type) + { + AppendName(sb, type.GetTypeDefinition()); + + sb.Append('<'); + + for (int i = 0; i < type.Instantiation.Length; i++) + { + if (i != 0) + sb.Append(','); + + AppendName(sb, type.Instantiation[i]); + } + + sb.Append('>'); + } + protected override void AppendNameForNamespaceType(StringBuilder sb, DefType type) + { + if (!String.IsNullOrEmpty(type.Namespace)) + { + sb.Append(type.Namespace); + sb.Append('.'); + } + + sb.Append(type.Name); + } + + protected override void AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType) + { + AppendName(sb, containingType); + sb.Append('/'); + sb.Append(nestedType.Name); + } + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/BodySubstitutionParser.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/BodySubstitutionParser.cs new file mode 100644 index 0000000000000..403eb9207342e --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/BodySubstitutionParser.cs @@ -0,0 +1,174 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Xml.XPath; +using ILLink.Shared; +using Mono.Cecil; + +namespace Mono.Linker.Steps +{ + public class BodySubstitutionParser : ProcessLinkerXmlBase + { + SubstitutionInfo? _substitutionInfo; + + public BodySubstitutionParser(LinkContext context, Stream documentStream, string xmlDocumentLocation) + : base(context, documentStream, xmlDocumentLocation) + { + } + + public BodySubstitutionParser(LinkContext context, Stream documentStream, EmbeddedResource resource, AssemblyDefinition resourceAssembly, string xmlDocumentLocation = "") + : base(context, documentStream, resource, resourceAssembly, xmlDocumentLocation) + { + } + + public void Parse(SubstitutionInfo xmlInfo) + { + _substitutionInfo = xmlInfo; + bool stripSubstitutions = _context.IsOptimizationEnabled(CodeOptimizations.RemoveSubstitutions, _resource?.Assembly); + ProcessXml(stripSubstitutions, _context.IgnoreSubstitutions); + } + + protected override void ProcessAssembly(AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) + { + ProcessTypes(assembly, nav, warnOnUnresolvedTypes); + ProcessResources(assembly, nav); + } + + protected override TypeDefinition? ProcessExportedType(ExportedType exported, AssemblyDefinition assembly, XPathNavigator nav) => null; + + protected override bool ProcessTypePattern(string fullname, AssemblyDefinition assembly, XPathNavigator nav) => false; + + protected override void ProcessType(TypeDefinition type, XPathNavigator nav) + { + Debug.Assert(ShouldProcessElement(nav)); + ProcessTypeChildren(type, nav); + } + + protected override void ProcessMethod(TypeDefinition type, XPathNavigator methodNav, object? _customData) + { + Debug.Assert(_substitutionInfo != null); + string signature = GetSignature(methodNav); + if (string.IsNullOrEmpty(signature)) + return; + + MethodDefinition? method = FindMethod(type, signature); + if (method == null) + { + LogWarning(methodNav, DiagnosticId.XmlCouldNotFindMethodOnType, signature, type.GetDisplayName()); + return; + } + + string action = GetAttribute(methodNav, "body"); + switch (action) + { + case "remove": + _substitutionInfo.SetMethodAction(method, MethodAction.ConvertToThrow); + return; + case "stub": + string value = GetAttribute(methodNav, "value"); + if (!string.IsNullOrEmpty(value)) + { + if (!TryConvertValue(value, method.ReturnType, out object? res)) + { + LogWarning(methodNav, DiagnosticId.XmlInvalidValueForStub, method.GetDisplayName()); + return; + } + + _substitutionInfo.SetMethodStubValue(method, res); + } + + _substitutionInfo.SetMethodAction(method, MethodAction.ConvertToStub); + return; + default: + LogWarning(methodNav, DiagnosticId.XmlUnkownBodyModification, action, method.GetDisplayName()); + return; + } + } + + protected override void ProcessField(TypeDefinition type, XPathNavigator fieldNav) + { + Debug.Assert(_substitutionInfo != null); + string name = GetAttribute(fieldNav, "name"); + if (string.IsNullOrEmpty(name)) + return; + + var field = type.Fields.FirstOrDefault(f => f.Name == name); + if (field == null) + { + LogWarning(fieldNav, DiagnosticId.XmlCouldNotFindFieldOnType, name, type.GetDisplayName()); + return; + } + + if (!field.IsStatic || field.IsLiteral) + { + LogWarning(fieldNav, DiagnosticId.XmlSubstitutedFieldNeedsToBeStatic, field.GetDisplayName()); + return; + } + + string value = GetAttribute(fieldNav, "value"); + if (string.IsNullOrEmpty(value)) + { + LogWarning(fieldNav, DiagnosticId.XmlMissingSubstitutionValueForField, field.GetDisplayName()); + return; + } + if (!TryConvertValue(value, field.FieldType, out object? res)) + { + LogWarning(fieldNav, DiagnosticId.XmlInvalidSubstitutionValueForField, value, field.GetDisplayName()); + return; + } + + _substitutionInfo.SetFieldValue(field, res); + + string init = GetAttribute(fieldNav, "initialize"); + if (init?.ToLowerInvariant() == "true") + { + _substitutionInfo.SetFieldInit(field); + } + } + + void ProcessResources(AssemblyDefinition assembly, XPathNavigator nav) + { + foreach (XPathNavigator resourceNav in nav.SelectChildren("resource", "")) + { + if (!ShouldProcessElement(resourceNav)) + continue; + + string name = GetAttribute(resourceNav, "name"); + if (String.IsNullOrEmpty(name)) + { + LogWarning(resourceNav, DiagnosticId.XmlMissingNameAttributeInResource); + continue; + } + + string action = GetAttribute(resourceNav, "action"); + if (action != "remove") + { + LogWarning(resourceNav, DiagnosticId.XmlInvalidValueForAttributeActionForResource, action, name); + continue; + } + + EmbeddedResource? resource = assembly.FindEmbeddedResource(name); + if (resource == null) + { + LogWarning(resourceNav, DiagnosticId.XmlCouldNotFindResourceToRemoveInAssembly, name, assembly.Name.Name); + continue; + } + + _context.Annotations.AddResourceToRemove(assembly, resource); + } + } + + static MethodDefinition? FindMethod(TypeDefinition type, string signature) + { + if (!type.HasMethods) + return null; + + foreach (MethodDefinition meth in type.Methods) + if (signature == DescriptorMarker.GetMethodSignature(meth, includeGenericParameters: true)) + return meth; + + return null; + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/DescriptorMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/DescriptorMarker.cs new file mode 100644 index 0000000000000..49404575e41f9 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/DescriptorMarker.cs @@ -0,0 +1,292 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml.XPath; +using ILLink.Shared; + +using Mono.Cecil; + +namespace Mono.Linker.Steps +{ + public class DescriptorMarker : ProcessLinkerXmlBase + { + const string NamespaceElementName = "namespace"; + + const string _required = "required"; + const string _preserve = "preserve"; + const string _accessors = "accessors"; + + static readonly string[] _accessorsAll = new string[] { "all" }; + static readonly char[] _accessorsSep = new char[] { ';' }; + + public DescriptorMarker(LinkContext context, Stream documentStream, string xmlDocumentLocation) + : base(context, documentStream, xmlDocumentLocation) + { + } + + public DescriptorMarker(LinkContext context, Stream documentStream, EmbeddedResource resource, AssemblyDefinition resourceAssembly, string xmlDocumentLocation = "") + : base(context, documentStream, resource, resourceAssembly, xmlDocumentLocation) + { + } + + public void Mark() + { + bool stripDescriptors = _context.IsOptimizationEnabled(CodeOptimizations.RemoveDescriptors, _resource?.Assembly); + ProcessXml(stripDescriptors, _context.IgnoreDescriptors); + } + + protected override AllowedAssemblies AllowedAssemblySelector { get => AllowedAssemblies.AnyAssembly; } + + protected override void ProcessAssembly(AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) + { + if (GetTypePreserve(nav) == TypePreserve.All) + { + foreach (var type in assembly.MainModule.Types) + MarkAndPreserveAll(type, nav); + + foreach (var exportedType in assembly.MainModule.ExportedTypes) + _context.MarkingHelpers.MarkExportedType(exportedType, assembly.MainModule, new DependencyInfo(DependencyKind.XmlDescriptor, assembly.MainModule), GetMessageOriginForPosition(nav)); + } + else + { + ProcessTypes(assembly, nav, warnOnUnresolvedTypes); + ProcessNamespaces(assembly, nav); + } + } + + void ProcessNamespaces(AssemblyDefinition assembly, XPathNavigator nav) + { + foreach (XPathNavigator namespaceNav in nav.SelectChildren(NamespaceElementName, XmlNamespace)) + { + if (!ShouldProcessElement(namespaceNav)) + continue; + + string fullname = GetFullName(namespaceNav); + bool foundMatch = false; + foreach (TypeDefinition type in assembly.MainModule.Types) + { + if (type.Namespace != fullname) + continue; + + foundMatch = true; + MarkAndPreserveAll(type, nav); + } + + if (!foundMatch) + { + LogWarning(namespaceNav, DiagnosticId.XmlCouldNotFindAnyTypeInNamespace, fullname); + } + } + } + + void MarkAndPreserveAll(TypeDefinition type, XPathNavigator nav) + { + _context.Annotations.Mark(type, new DependencyInfo(DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition(nav)); + _context.Annotations.SetPreserve(type, TypePreserve.All); + + if (!type.HasNestedTypes) + return; + + foreach (TypeDefinition nested in type.NestedTypes) + MarkAndPreserveAll(nested, nav); + } + + protected override TypeDefinition? ProcessExportedType(ExportedType exported, AssemblyDefinition assembly, XPathNavigator nav) + { + _context.MarkingHelpers.MarkExportedType(exported, assembly.MainModule, new DependencyInfo(DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition(nav)); + return base.ProcessExportedType(exported, assembly, nav); + } + + protected override void ProcessType(TypeDefinition type, XPathNavigator nav) + { + Debug.Assert(ShouldProcessElement(nav)); + + TypePreserve preserve = GetTypePreserve(nav); + switch (preserve) + { + case TypePreserve.Fields when !type.HasFields: + LogWarning(nav, DiagnosticId.TypeHasNoFieldsToPreserve, type.GetDisplayName()); + break; + + case TypePreserve.Methods when !type.HasMethods: + LogWarning(nav, DiagnosticId.TypeHasNoMethodsToPreserve, type.GetDisplayName()); + break; + + case TypePreserve.Fields: + case TypePreserve.Methods: + case TypePreserve.All: + _context.Annotations.SetPreserve(type, preserve); + break; + } + + bool required = IsRequired(nav); + ProcessTypeChildren(type, nav, required); + + if (!required) + return; + + _context.Annotations.Mark(type, new DependencyInfo(DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition(nav)); + + if (type.IsNested) + { + var currentType = type; + while (currentType.IsNested) + { + var parent = currentType.DeclaringType; + _context.Annotations.Mark(parent, new DependencyInfo(DependencyKind.DeclaringType, currentType), GetMessageOriginForPosition(nav)); + currentType = parent; + } + } + } + + static TypePreserve GetTypePreserve(XPathNavigator nav) + { + string attribute = GetAttribute(nav, _preserve); + if (string.IsNullOrEmpty(attribute)) + return nav.HasChildren ? TypePreserve.Nothing : TypePreserve.All; + + if (Enum.TryParse(attribute, true, out TypePreserve result)) + return result; + return TypePreserve.Nothing; + } + + protected override void ProcessField(TypeDefinition type, FieldDefinition field, XPathNavigator nav) + { + if (_context.Annotations.IsMarked(field)) + LogWarning(nav, DiagnosticId.XmlDuplicatePreserveMember, field.FullName); + + _context.Annotations.Mark(field, new DependencyInfo(DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition(nav)); + } + + protected override void ProcessMethod(TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) + { + if (_context.Annotations.IsMarked(method)) + LogWarning(nav, DiagnosticId.XmlDuplicatePreserveMember, method.GetDisplayName()); + + _context.Annotations.MarkIndirectlyCalledMethod(method); + _context.Annotations.SetAction(method, MethodAction.Parse); + + if (customData is bool required && !required) + { + _context.Annotations.AddPreservedMethod(type, method); + } + else + { + _context.Annotations.Mark(method, new DependencyInfo(DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition(nav)); + } + } + + void ProcessMethodIfNotNull(TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) + { + if (method == null) + return; + + ProcessMethod(type, method, nav, customData); + } + + protected override MethodDefinition? GetMethod(TypeDefinition type, string signature) + { + if (type.HasMethods) + foreach (MethodDefinition meth in type.Methods) + if (signature == GetMethodSignature(meth, false)) + return meth; + + return null; + } + + public static string GetMethodSignature(MethodDefinition meth, bool includeGenericParameters) + { + StringBuilder sb = new StringBuilder(); + sb.Append(meth.ReturnType.FullName); + sb.Append(" "); + sb.Append(meth.Name); + if (includeGenericParameters && meth.HasGenericParameters) + { + sb.Append("`"); + sb.Append(meth.GenericParameters.Count); + } + + sb.Append("("); + if (meth.HasParameters) + { + for (int i = 0; i < meth.Parameters.Count; i++) + { + if (i > 0) + sb.Append(","); + + sb.Append(meth.Parameters[i].ParameterType.FullName); + } + } + sb.Append(")"); + return sb.ToString(); + } + + protected override void ProcessEvent(TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) + { + if (_context.Annotations.IsMarked(@event)) + LogWarning(nav, DiagnosticId.XmlDuplicatePreserveMember, @event.FullName); + + ProcessMethod(type, @event.AddMethod, nav, customData); + ProcessMethod(type, @event.RemoveMethod, nav, customData); + ProcessMethodIfNotNull(type, @event.InvokeMethod, nav, customData); + } + + protected override void ProcessProperty(TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object? customData, bool fromSignature) + { + string[] accessors = fromSignature ? GetAccessors(nav) : _accessorsAll; + + if (_context.Annotations.IsMarked(property)) + LogWarning(nav, DiagnosticId.XmlDuplicatePreserveMember, property.FullName); + + if (Array.IndexOf(accessors, "all") >= 0) + { + ProcessMethodIfNotNull(type, property.GetMethod, nav, customData); + ProcessMethodIfNotNull(type, property.SetMethod, nav, customData); + return; + } + + if (property.GetMethod != null && Array.IndexOf(accessors, "get") >= 0) + ProcessMethod(type, property.GetMethod, nav, customData); + else if (property.GetMethod == null) + LogWarning(nav, DiagnosticId.XmlCouldNotFindGetAccesorOfPropertyOnType, property.Name, type.FullName); + + if (property.SetMethod != null && Array.IndexOf(accessors, "set") >= 0) + ProcessMethod(type, property.SetMethod, nav, customData); + else if (property.SetMethod == null) + LogWarning(nav, DiagnosticId.XmlCouldNotFindSetAccesorOfPropertyOnType, property.Name, type.FullName); + } + + static bool IsRequired(XPathNavigator nav) + { + string attribute = GetAttribute(nav, _required); + if (attribute == null || attribute.Length == 0) + return true; + + return bool.TryParse(attribute, out bool result) && result; + } + + protected static string[] GetAccessors(XPathNavigator nav) + { + string accessorsValue = GetAttribute(nav, _accessors); + + if (accessorsValue != null) + { + string[] accessors = accessorsValue.Split( + _accessorsSep, StringSplitOptions.RemoveEmptyEntries); + + if (accessors.Length > 0) + { + for (int i = 0; i < accessors.Length; ++i) + accessors[i] = accessors[i].ToLower(); + + return accessors; + } + } + return _accessorsAll; + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/FeatureSettings.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/FeatureSettings.cs new file mode 100644 index 0000000000000..5e89376022684 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/FeatureSettings.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. + +using System; +using System.Xml.XPath; +using ILLink.Shared; + +namespace Mono.Linker +{ + public static class FeatureSettings + { + public static bool ShouldProcessElement(XPathNavigator nav, LinkContext context, string documentLocation) + { + var feature = GetAttribute(nav, "feature"); + if (string.IsNullOrEmpty(feature)) + return true; + + var value = GetAttribute(nav, "featurevalue"); + if (string.IsNullOrEmpty(value)) + { + context.LogError(null, DiagnosticId.XmlFeatureDoesNotSpecifyFeatureValue, documentLocation, feature); + return false; + } + + if (!bool.TryParse(value, out bool bValue)) + { + context.LogError(null, DiagnosticId.XmlUnsupportedNonBooleanValueForFeature, documentLocation, feature); + return false; + } + + var isDefault = GetAttribute(nav, "featuredefault"); + bool bIsDefault = false; + if (!string.IsNullOrEmpty(isDefault) && (!bool.TryParse(isDefault, out bIsDefault) || !bIsDefault)) + { + context.LogError(null, DiagnosticId.XmlDocumentLocationHasInvalidFeatureDefault, documentLocation); + return false; + } + + if (!context.FeatureSettings.TryGetValue(feature, out bool featureSetting)) + return bIsDefault; + + return bValue == featureSetting; + } + + public static string GetAttribute(XPathNavigator nav, string attribute) + { + return nav.GetAttribute(attribute, String.Empty); + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/LinkAttributesParser.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/LinkAttributesParser.cs new file mode 100644 index 0000000000000..0acfdda2dccbe --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/LinkAttributesParser.cs @@ -0,0 +1,578 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.XPath; +using ILLink.Shared; +using Mono.Cecil; + +namespace Mono.Linker.Steps +{ + public class LinkAttributesParser : ProcessLinkerXmlBase + { + AttributeInfo? _attributeInfo; + + public LinkAttributesParser(LinkContext context, Stream documentStream, string xmlDocumentLocation) + : base(context, documentStream, xmlDocumentLocation) + { + } + + public LinkAttributesParser(LinkContext context, Stream documentStream, EmbeddedResource resource, AssemblyDefinition resourceAssembly, string xmlDocumentLocation = "") + : base(context, documentStream, resource, resourceAssembly, xmlDocumentLocation) + { + } + + public void Parse(AttributeInfo xmlInfo) + { + _attributeInfo = xmlInfo; + bool stripLinkAttributes = _context.IsOptimizationEnabled(CodeOptimizations.RemoveLinkAttributes, _resource?.Assembly); + ProcessXml(stripLinkAttributes, _context.IgnoreLinkAttributes); + } + + CustomAttribute[]? ProcessAttributes(XPathNavigator nav, ICustomAttributeProvider provider) + { + var builder = new ArrayBuilder(); + foreach (XPathNavigator argumentNav in nav.SelectChildren("attribute", string.Empty)) + { + if (!ShouldProcessElement(argumentNav)) + continue; + + TypeDefinition? attributeType; + string internalAttribute = GetAttribute(argumentNav, "internal"); + if (!string.IsNullOrEmpty(internalAttribute)) + { + attributeType = GenerateRemoveAttributeInstancesAttribute(); + if (attributeType == null) + continue; + + // TODO: Replace with IsAttributeType check once we have it + if (provider is not TypeDefinition) + { + LogWarning(argumentNav, DiagnosticId.XmlRemoveAttributeInstancesCanOnlyBeUsedOnType, attributeType.Name); + continue; + } + } + else + { + string attributeFullName = GetFullName(argumentNav); + if (string.IsNullOrEmpty(attributeFullName)) + { + LogWarning(argumentNav, DiagnosticId.XmlElementDoesNotContainRequiredAttributeFullname); + continue; + } + + if (!GetAttributeType(argumentNav, attributeFullName, out attributeType)) + continue; + } + + CustomAttribute? customAttribute = CreateCustomAttribute(argumentNav, attributeType); + if (customAttribute != null) + { + _context.LogMessage($"Assigning external custom attribute '{FormatCustomAttribute(customAttribute)}' instance to '{provider}'."); + builder.Add(customAttribute); + } + } + + return builder.ToArray(); + + static string FormatCustomAttribute(CustomAttribute ca) + { + StringBuilder sb = new StringBuilder(); + sb.Append(ca.Constructor.GetDisplayName()); + sb.Append(" { args: "); + for (int i = 0; i < ca.ConstructorArguments.Count; ++i) + { + if (i > 0) + sb.Append(", "); + + var caa = ca.ConstructorArguments[i]; + sb.Append($"{caa.Type.GetDisplayName()} {caa.Value}"); + } + sb.Append(" }"); + + return sb.ToString(); + } + } + + TypeDefinition? GenerateRemoveAttributeInstancesAttribute() + { + if (_context.MarkedKnownMembers.RemoveAttributeInstancesAttributeDefinition != null) + return _context.MarkedKnownMembers.RemoveAttributeInstancesAttributeDefinition; + + var voidType = BCL.FindPredefinedType("System", "Void", _context); + if (voidType == null) + return null; + + var attributeType = BCL.FindPredefinedType("System", "Attribute", _context); + if (attributeType == null) + return null; + + var objectType = BCL.FindPredefinedType("System", "Object", _context); + if (objectType == null) + return null; + + // + // Generates metadata information for internal type + // + // public sealed class RemoveAttributeInstancesAttribute : Attribute + // { + // public RemoveAttributeInstancesAttribute () {} + // public RemoveAttributeInstancesAttribute (object value1) {} + // } + // + var td = new TypeDefinition("", "RemoveAttributeInstancesAttribute", TypeAttributes.Public); + td.BaseType = attributeType; + + const MethodAttributes ctorAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Final; + var ctor = new MethodDefinition(".ctor", ctorAttributes, voidType); + td.Methods.Add(ctor); + + ctor = new MethodDefinition(".ctor", ctorAttributes, voidType); + ctor.Parameters.Add(new ParameterDefinition(objectType)); + td.Methods.Add(ctor); + + return _context.MarkedKnownMembers.RemoveAttributeInstancesAttributeDefinition = td; + } + + CustomAttribute? CreateCustomAttribute(XPathNavigator nav, TypeDefinition attributeType) + { + CustomAttributeArgument[] arguments = ReadCustomAttributeArguments(nav, attributeType); + + MethodDefinition? constructor = FindBestMatchingConstructor(attributeType, arguments); + if (constructor == null) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindMatchingConstructorForCustomAttribute, attributeType.GetDisplayName()); + return null; + } + + CustomAttribute customAttribute = new CustomAttribute(constructor); + foreach (var argument in arguments) + customAttribute.ConstructorArguments.Add(argument); + + ReadCustomAttributeProperties(nav, attributeType, customAttribute); + + return customAttribute; + } + + MethodDefinition? FindBestMatchingConstructor(TypeDefinition attributeType, CustomAttributeArgument[] args) + { + var methods = attributeType.Methods; + for (int i = 0; i < attributeType.Methods.Count; ++i) + { + var m = methods[i]; + if (!m.IsInstanceConstructor()) + continue; + + var p = m.Parameters; + if (args.Length != p.Count) + continue; + + bool match = true; + for (int ii = 0; match && ii != args.Length; ++ii) + { + // + // No candidates betterness, only exact matches are supported + // + var parameterType = _context.TryResolve(p[ii].ParameterType); + if (parameterType == null || parameterType != _context.TryResolve(args[ii].Type)) + match = false; + } + + if (match) + return m; + } + + return null; + } + + void ReadCustomAttributeProperties(XPathNavigator nav, TypeDefinition attributeType, CustomAttribute customAttribute) + { + foreach (XPathNavigator propertyNav in nav.SelectChildren("property", string.Empty)) + { + string propertyName = GetName(propertyNav); + if (string.IsNullOrEmpty(propertyName)) + { + LogWarning(propertyNav, DiagnosticId.XmlPropertyDoesNotContainAttributeName); + continue; + } + + PropertyDefinition? property = attributeType.Properties.Where(prop => prop.Name == propertyName).FirstOrDefault(); + if (property == null) + { + LogWarning(propertyNav, DiagnosticId.XmlCouldNotFindProperty, propertyName); + continue; + } + + var caa = ReadCustomAttributeArgument(propertyNav, property); + if (caa is null) + continue; + + customAttribute.Properties.Add(new CustomAttributeNamedArgument(property.Name, caa.Value)); + } + } + + CustomAttributeArgument[] ReadCustomAttributeArguments(XPathNavigator nav, TypeDefinition attributeType) + { + var args = new ArrayBuilder(); + + foreach (XPathNavigator argumentNav in nav.SelectChildren("argument", string.Empty)) + { + CustomAttributeArgument? caa = ReadCustomAttributeArgument(argumentNav, attributeType); + if (caa is not null) + args.Add(caa.Value); + } + + return args.ToArray() ?? Array.Empty(); + } + + CustomAttributeArgument? ReadCustomAttributeArgument(XPathNavigator nav, IMemberDefinition memberWithAttribute) + { + TypeReference? typeref = ResolveArgumentType(nav, memberWithAttribute); + if (typeref is null) + return null; + + string svalue = nav.Value; + + // + // Builds CustomAttributeArgument in the same way as it would be + // represented in the metadata if encoded there. This simplifies + // any custom attributes handling in linker by using same attributes + // value extraction or mathing logic. + // + switch (typeref.MetadataType) + { + case MetadataType.Object: + var argumentIterator = nav.SelectChildren("argument", string.Empty); + if (argumentIterator?.MoveNext() != true) + { + _context.LogError(null, DiagnosticId.CustomAttributeArgumentForTypeRequiresNestedNode, "System.Object", "argument"); + return null; + } + + var typedef = _context.TryResolve(typeref); + if (typedef == null) + return null; + + var boxedValue = ReadCustomAttributeArgument(argumentIterator.Current!, typedef); + if (boxedValue is null) + return null; + + return new CustomAttributeArgument(typeref, boxedValue); + + case MetadataType.Char: + case MetadataType.Byte: + case MetadataType.SByte: + case MetadataType.Int16: + case MetadataType.UInt16: + case MetadataType.Int32: + case MetadataType.UInt32: + case MetadataType.UInt64: + case MetadataType.Int64: + case MetadataType.String: + return new CustomAttributeArgument(typeref, ConvertStringValue(svalue, typeref)); + + case MetadataType.ValueType: + var enumType = _context.Resolve(typeref); + if (enumType?.IsEnum != true) + goto default; + + var enumField = enumType.Fields.Where(f => f.IsStatic && f.Name == svalue).FirstOrDefault(); + object evalue = enumField?.Constant ?? svalue; + + typeref = enumType.GetEnumUnderlyingType(); + return new CustomAttributeArgument(enumType, ConvertStringValue(evalue, typeref)); + + case MetadataType.Class: + if (!typeref.IsTypeOf("System", "Type")) + goto default; + + if (!_context.TypeNameResolver.TryResolveTypeName(svalue, memberWithAttribute, out TypeReference? type, out _)) + { + _context.LogError(GetMessageOriginForPosition(nav), DiagnosticId.CouldNotResolveCustomAttributeTypeValue, svalue); + return null; + } + + return new CustomAttributeArgument(typeref, type); + default: + // No support for null and arrays, consider adding - dotnet/linker/issues/1957 + _context.LogError(GetMessageOriginForPosition(nav), DiagnosticId.UnexpectedAttributeArgumentType, typeref.GetDisplayName()); + return null; + } + + TypeReference? ResolveArgumentType(XPathNavigator nav, IMemberDefinition memberWithAttribute) + { + string typeName = GetAttribute(nav, "type"); + if (string.IsNullOrEmpty(typeName)) + typeName = "System.String"; + + if (!_context.TypeNameResolver.TryResolveTypeName(typeName, memberWithAttribute, out TypeReference? typeref, out _)) + { + _context.LogError(GetMessageOriginForPosition(nav), DiagnosticId.TypeUsedWithAttributeValueCouldNotBeFound, typeName, nav.Value); + return null; + } + + return typeref; + } + } + + object? ConvertStringValue(object value, TypeReference targetType) + { + TypeCode typeCode; + switch (targetType.MetadataType) + { + case MetadataType.String: + typeCode = TypeCode.String; + break; + case MetadataType.Char: + typeCode = TypeCode.Char; + break; + case MetadataType.Byte: + typeCode = TypeCode.Byte; + break; + case MetadataType.SByte: + typeCode = TypeCode.SByte; + break; + case MetadataType.Int16: + typeCode = TypeCode.Int16; + break; + case MetadataType.UInt16: + typeCode = TypeCode.UInt16; + break; + case MetadataType.Int32: + typeCode = TypeCode.Int32; + break; + case MetadataType.UInt32: + typeCode = TypeCode.UInt32; + break; + case MetadataType.UInt64: + typeCode = TypeCode.UInt64; + break; + case MetadataType.Int64: + typeCode = TypeCode.Int64; + break; + case MetadataType.Boolean: + typeCode = TypeCode.Boolean; + break; + case MetadataType.Single: + typeCode = TypeCode.Single; + break; + case MetadataType.Double: + typeCode = TypeCode.Double; + break; + default: + throw new NotSupportedException(targetType.ToString()); + } + + try + { + return Convert.ChangeType(value, typeCode); + } + catch + { + _context.LogError(null, DiagnosticId.CannotConverValueToType, value.ToString() ?? "", targetType.GetDisplayName()); + return null; + } + } + + bool GetAttributeType(XPathNavigator nav, string attributeFullName, [NotNullWhen(true)] out TypeDefinition? attributeType) + { + string assemblyName = GetAttribute(nav, "assembly"); + if (string.IsNullOrEmpty(assemblyName)) + { + attributeType = _context.GetType(attributeFullName); + } + else + { + AssemblyDefinition? assembly; + try + { + assembly = _context.TryResolve(AssemblyNameReference.Parse(assemblyName)); + if (assembly == null) + { + LogWarning(nav, DiagnosticId.XmlCouldNotResolveAssemblyForAttribute, assemblyName, attributeFullName); + + attributeType = default; + return false; + } + } + catch (Exception) + { + LogWarning(nav, DiagnosticId.XmlCouldNotResolveAssemblyForAttribute, assemblyName, attributeFullName); + attributeType = default; + return false; + } + + attributeType = _context.TryResolve(assembly, attributeFullName); + } + + if (attributeType == null) + { + LogWarning(nav, DiagnosticId.XmlAttributeTypeCouldNotBeFound, attributeFullName); + return false; + } + + return true; + } + + protected override AllowedAssemblies AllowedAssemblySelector + { + get + { + if (_resource?.Assembly == null) + return AllowedAssemblies.AllAssemblies; + + // Corelib XML may contain assembly wildcard to support compiler-injected attribute types + if (_resource?.Assembly.Name.Name == PlatformAssemblies.CoreLib) + return AllowedAssemblies.AllAssemblies; + + return AllowedAssemblies.ContainingAssembly; + } + } + + protected override void ProcessAssembly(AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) + { + PopulateAttributeInfo(assembly, nav); + ProcessTypes(assembly, nav, warnOnUnresolvedTypes); + } + + protected override void ProcessType(TypeDefinition type, XPathNavigator nav) + { + Debug.Assert(ShouldProcessElement(nav)); + + PopulateAttributeInfo(type, nav); + ProcessTypeChildren(type, nav); + + if (!type.HasNestedTypes) + return; + + foreach (XPathNavigator nestedTypeNav in nav.SelectChildren("type", string.Empty)) + { + foreach (TypeDefinition nested in type.NestedTypes) + { + if (nested.Name == GetAttribute(nestedTypeNav, "name") && ShouldProcessElement(nestedTypeNav)) + ProcessType(nested, nestedTypeNav); + } + } + } + + protected override void ProcessField(TypeDefinition type, FieldDefinition field, XPathNavigator nav) + { + PopulateAttributeInfo(field, nav); + } + + protected override void ProcessMethod(TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) + { + PopulateAttributeInfo(method, nav); + ProcessReturnParameters(method, nav); + ProcessParameters(method, nav); + } + + void ProcessParameters(MethodDefinition method, XPathNavigator nav) + { + Debug.Assert(_attributeInfo != null); + foreach (XPathNavigator parameterNav in nav.SelectChildren("parameter", string.Empty)) + { + var attributes = ProcessAttributes(parameterNav, method); + if (attributes != null) + { + string paramName = GetAttribute(parameterNav, "name"); + foreach (ParameterDefinition parameter in method.Parameters) + { + if (paramName == parameter.Name) + { + if (parameter.HasCustomAttributes || _attributeInfo.CustomAttributes.ContainsKey(parameter)) + LogWarning(parameterNav, DiagnosticId.XmlMoreThanOneValyForParameterOfMethod, paramName, method.GetDisplayName()); + _attributeInfo.AddCustomAttributes(parameter, attributes); + break; + } + } + } + } + } + + void ProcessReturnParameters(MethodDefinition method, XPathNavigator nav) + { + bool firstAppearance = true; + foreach (XPathNavigator returnNav in nav.SelectChildren("return", string.Empty)) + { + if (firstAppearance) + { + firstAppearance = false; + PopulateAttributeInfo(method.MethodReturnType, returnNav); + } + else + { + LogWarning(returnNav, DiagnosticId.XmlMoreThanOneReturnElementForMethod, method.GetDisplayName()); + } + } + } + + protected override MethodDefinition? GetMethod(TypeDefinition type, string signature) + { + if (type.HasMethods) + foreach (MethodDefinition method in type.Methods) + if (signature.Replace(" ", "") == GetMethodSignature(method) || signature.Replace(" ", "") == GetMethodSignature(method, true)) + return method; + + return null; + } + + static string GetMethodSignature(MethodDefinition method, bool includeReturnType = false) + { + StringBuilder sb = new StringBuilder(); + if (includeReturnType) + { + sb.Append(method.ReturnType.FullName); + } + sb.Append(method.Name); + if (method.HasGenericParameters) + { + sb.Append("<"); + for (int i = 0; i < method.GenericParameters.Count; i++) + { + if (i > 0) + sb.Append(","); + + sb.Append(method.GenericParameters[i].Name); + } + sb.Append(">"); + } + sb.Append("("); + if (method.HasParameters) + { + for (int i = 0; i < method.Parameters.Count; i++) + { + if (i > 0) + sb.Append(","); + + sb.Append(method.Parameters[i].ParameterType.FullName); + } + } + sb.Append(")"); + return sb.ToString(); + } + + protected override void ProcessProperty(TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object? customData, bool fromSignature) + { + PopulateAttributeInfo(property, nav); + } + + protected override void ProcessEvent(TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) + { + PopulateAttributeInfo(@event, nav); + } + + void PopulateAttributeInfo(ICustomAttributeProvider provider, XPathNavigator nav) + { + Debug.Assert(_attributeInfo != null); + var attributes = ProcessAttributes(nav, provider); + if (attributes != null) + _attributeInfo.AddCustomAttributes(provider, attributes); + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/ProcessLinkerXmlBase.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/ProcessLinkerXmlBase.cs new file mode 100644 index 0000000000000..842c56639fdd0 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/ProcessLinkerXmlBase.cs @@ -0,0 +1,662 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using ILLink.Shared; +using Mono.Cecil; + +namespace Mono.Linker.Steps +{ + [Flags] + public enum AllowedAssemblies + { + ContainingAssembly = 0x1, + AnyAssembly = 0x2 | ContainingAssembly, + AllAssemblies = 0x4 | AnyAssembly + } + + public abstract class ProcessLinkerXmlBase + { + const string FullNameAttributeName = "fullname"; + const string LinkerElementName = "linker"; + const string TypeElementName = "type"; + const string SignatureAttributeName = "signature"; + const string NameAttributeName = "name"; + const string FieldElementName = "field"; + const string MethodElementName = "method"; + const string EventElementName = "event"; + const string PropertyElementName = "property"; + const string AllAssembliesFullName = "*"; + protected const string XmlNamespace = ""; + + protected readonly string _xmlDocumentLocation; + readonly XPathNavigator _document; + protected readonly (EmbeddedResource Resource, AssemblyDefinition Assembly)? _resource; + protected readonly LinkContext _context; + + protected ProcessLinkerXmlBase(LinkContext context, Stream documentStream, string xmlDocumentLocation) + { + _context = context; + using (documentStream) + { + _document = XDocument.Load(documentStream, LoadOptions.SetLineInfo).CreateNavigator(); + } + _xmlDocumentLocation = xmlDocumentLocation; + } + + protected ProcessLinkerXmlBase(LinkContext context, Stream documentStream, EmbeddedResource resource, AssemblyDefinition resourceAssembly, string xmlDocumentLocation) + : this(context, documentStream, xmlDocumentLocation) + { + _resource = ( + resource ?? throw new ArgumentNullException(nameof(resource)), + resourceAssembly ?? throw new ArgumentNullException(nameof(resourceAssembly)) + ); + } + + protected virtual bool ShouldProcessElement(XPathNavigator nav) => FeatureSettings.ShouldProcessElement(nav, _context, _xmlDocumentLocation); + + protected virtual void ProcessXml(bool stripResource, bool ignoreResource) + { + if (!AllowedAssemblySelector.HasFlag(AllowedAssemblies.AnyAssembly) && _resource == null) + throw new InvalidOperationException("The containing assembly must be specified for XML which is restricted to modifying that assembly only."); + + try + { + XPathNavigator nav = _document.CreateNavigator(); + + // Initial structure check - ignore XML document which don't look like linker XML format + if (!nav.MoveToChild(LinkerElementName, XmlNamespace)) + return; + + if (_resource != null) + { + if (stripResource) + _context.Annotations.AddResourceToRemove(_resource.Value.Assembly, _resource.Value.Resource); + if (ignoreResource) + return; + } + + if (!ShouldProcessElement(nav)) + return; + + ProcessAssemblies(nav); + + // For embedded XML, allow not specifying the assembly explicitly in XML. + if (_resource != null) + ProcessAssembly(_resource.Value.Assembly, nav, warnOnUnresolvedTypes: true); + + } + catch (Exception ex) when (!(ex is LinkerFatalErrorException)) + { + throw new LinkerFatalErrorException(MessageContainer.CreateErrorMessage(null, DiagnosticId.ErrorProcessingXmlLocation, _xmlDocumentLocation), ex); + } + } + + protected virtual AllowedAssemblies AllowedAssemblySelector { get => _resource != null ? AllowedAssemblies.ContainingAssembly : AllowedAssemblies.AnyAssembly; } + + bool ShouldProcessAllAssemblies(XPathNavigator nav, [NotNullWhen(false)] out AssemblyNameReference? assemblyName) + { + assemblyName = null; + if (GetFullName(nav) == AllAssembliesFullName) + return true; + + assemblyName = GetAssemblyName(nav); + return false; + } + + protected virtual void ProcessAssemblies(XPathNavigator nav) + { + foreach (XPathNavigator assemblyNav in nav.SelectChildren("assembly", "")) + { + // Errors for invalid assembly names should show up even if this element will be + // skipped due to feature conditions. + bool processAllAssemblies = ShouldProcessAllAssemblies(assemblyNav, out AssemblyNameReference? name); + if (processAllAssemblies && AllowedAssemblySelector != AllowedAssemblies.AllAssemblies) + { + LogWarning(assemblyNav, DiagnosticId.XmlUnsuportedWildcard); + continue; + } + + AssemblyDefinition? assemblyToProcess = null; + if (!AllowedAssemblySelector.HasFlag(AllowedAssemblies.AnyAssembly)) + { + Debug.Assert(!processAllAssemblies); + Debug.Assert(_resource != null); + if (_resource.Value.Assembly.Name.Name != name!.Name) + { + LogWarning(assemblyNav, DiagnosticId.AssemblyWithEmbeddedXmlApplyToAnotherAssembly, _resource.Value.Assembly.Name.Name, name.ToString()); + continue; + } + assemblyToProcess = _resource.Value.Assembly; + } + + if (!ShouldProcessElement(assemblyNav)) + continue; + + if (processAllAssemblies) + { + // We could avoid loading all references in this case: https://github.com/dotnet/linker/issues/1708 + foreach (AssemblyDefinition assembly in _context.GetReferencedAssemblies()) + ProcessAssembly(assembly, assemblyNav, warnOnUnresolvedTypes: false); + } + else + { + Debug.Assert(!processAllAssemblies); + AssemblyDefinition? assembly = assemblyToProcess ?? _context.TryResolve(name!); + + if (assembly == null) + { + LogWarning(assemblyNav, DiagnosticId.XmlCouldNotResolveAssembly, name!.Name); + continue; + } + + ProcessAssembly(assembly, assemblyNav, warnOnUnresolvedTypes: true); + } + } + } + + protected abstract void ProcessAssembly(AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes); + + protected virtual void ProcessTypes(AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) + { + foreach (XPathNavigator typeNav in nav.SelectChildren(TypeElementName, XmlNamespace)) + { + + if (!ShouldProcessElement(typeNav)) + continue; + + string fullname = GetFullName(typeNav); + + if (fullname.IndexOf("*") != -1) + { + if (ProcessTypePattern(fullname, assembly, typeNav)) + continue; + } + + TypeDefinition type = assembly.MainModule.GetType(fullname); + + if (type == null && assembly.MainModule.HasExportedTypes) + { + foreach (var exported in assembly.MainModule.ExportedTypes) + { + if (fullname == exported.FullName) + { + var resolvedExternal = ProcessExportedType(exported, assembly, typeNav); + if (resolvedExternal != null) + { + type = resolvedExternal; + break; + } + } + } + } + + if (type == null) + { + if (warnOnUnresolvedTypes) + LogWarning(typeNav, DiagnosticId.XmlCouldNotResolveType, fullname); + continue; + } + + ProcessType(type, typeNav); + } + } + + protected virtual TypeDefinition? ProcessExportedType(ExportedType exported, AssemblyDefinition assembly, XPathNavigator nav) => exported.Resolve(); + + void MatchType(TypeDefinition type, Regex regex, XPathNavigator nav) + { + if (regex.Match(type.FullName).Success) + ProcessType(type, nav); + + if (!type.HasNestedTypes) + return; + + foreach (var nt in type.NestedTypes) + MatchType(nt, regex, nav); + } + + protected virtual bool ProcessTypePattern(string fullname, AssemblyDefinition assembly, XPathNavigator nav) + { + Regex regex = new Regex(fullname.Replace(".", @"\.").Replace("*", "(.*)")); + + foreach (TypeDefinition type in assembly.MainModule.Types) + { + MatchType(type, regex, nav); + } + + if (assembly.MainModule.HasExportedTypes) + { + foreach (var exported in assembly.MainModule.ExportedTypes) + { + if (regex.Match(exported.FullName).Success) + { + var type = ProcessExportedType(exported, assembly, nav); + if (type != null) + { + ProcessType(type, nav); + } + } + } + } + + return true; + } + + protected abstract void ProcessType(TypeDefinition type, XPathNavigator nav); + + protected void ProcessTypeChildren(TypeDefinition type, XPathNavigator nav, object? customData = null) + { + if (nav.HasChildren) + { + ProcessSelectedFields(nav, type); + ProcessSelectedMethods(nav, type, customData); + ProcessSelectedEvents(nav, type, customData); + ProcessSelectedProperties(nav, type, customData); + } + } + + void ProcessSelectedFields(XPathNavigator nav, TypeDefinition type) + { + foreach (XPathNavigator fieldNav in nav.SelectChildren(FieldElementName, XmlNamespace)) + { + if (!ShouldProcessElement(fieldNav)) + continue; + ProcessField(type, fieldNav); + } + } + + protected virtual void ProcessField(TypeDefinition type, XPathNavigator nav) + { + string signature = GetSignature(nav); + if (!String.IsNullOrEmpty(signature)) + { + FieldDefinition? field = GetField(type, signature); + if (field == null) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindFieldOnType, signature, type.GetDisplayName()); + return; + } + + ProcessField(type, field, nav); + } + + string name = GetName(nav); + if (!String.IsNullOrEmpty(name)) + { + bool foundMatch = false; + if (type.HasFields) + { + foreach (FieldDefinition field in type.Fields) + { + if (field.Name == name) + { + foundMatch = true; + ProcessField(type, field, nav); + } + } + } + + if (!foundMatch) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindFieldOnType, name, type.GetDisplayName()); + } + } + } + + protected static FieldDefinition? GetField(TypeDefinition type, string signature) + { + if (!type.HasFields) + return null; + + foreach (FieldDefinition field in type.Fields) + if (signature == field.FieldType.FullName + " " + field.Name) + return field; + + return null; + } + + protected virtual void ProcessField(TypeDefinition type, FieldDefinition field, XPathNavigator nav) { } + + void ProcessSelectedMethods(XPathNavigator nav, TypeDefinition type, object? customData) + { + foreach (XPathNavigator methodNav in nav.SelectChildren(MethodElementName, XmlNamespace)) + { + if (!ShouldProcessElement(methodNav)) + continue; + ProcessMethod(type, methodNav, customData); + } + } + + protected virtual void ProcessMethod(TypeDefinition type, XPathNavigator nav, object? customData) + { + string signature = GetSignature(nav); + if (!String.IsNullOrEmpty(signature)) + { + MethodDefinition? method = GetMethod(type, signature); + if (method == null) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindMethodOnType, signature, type.GetDisplayName()); + return; + } + + ProcessMethod(type, method, nav, customData); + } + + string name = GetAttribute(nav, NameAttributeName); + if (!String.IsNullOrEmpty(name)) + { + bool foundMatch = false; + if (type.HasMethods) + { + foreach (MethodDefinition method in type.Methods) + { + if (name == method.Name) + { + foundMatch = true; + ProcessMethod(type, method, nav, customData); + } + } + } + + if (!foundMatch) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindMethodOnType, name, type.GetDisplayName()); + } + } + } + + protected virtual MethodDefinition? GetMethod(TypeDefinition type, string signature) => null; + + protected virtual void ProcessMethod(TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) { } + + void ProcessSelectedEvents(XPathNavigator nav, TypeDefinition type, object? customData) + { + foreach (XPathNavigator eventNav in nav.SelectChildren(EventElementName, XmlNamespace)) + { + if (!ShouldProcessElement(eventNav)) + continue; + ProcessEvent(type, eventNav, customData); + } + } + + protected virtual void ProcessEvent(TypeDefinition type, XPathNavigator nav, object? customData) + { + string signature = GetSignature(nav); + if (!String.IsNullOrEmpty(signature)) + { + EventDefinition? @event = GetEvent(type, signature); + if (@event == null) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindEventOnType, signature, type.GetDisplayName()); + return; + } + + ProcessEvent(type, @event, nav, customData); + } + + string name = GetAttribute(nav, NameAttributeName); + if (!String.IsNullOrEmpty(name)) + { + bool foundMatch = false; + foreach (EventDefinition @event in type.Events) + { + if (@event.Name == name) + { + foundMatch = true; + ProcessEvent(type, @event, nav, customData); + } + } + + if (!foundMatch) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindEventOnType, name, type.GetDisplayName()); + } + } + } + + protected static EventDefinition? GetEvent(TypeDefinition type, string signature) + { + if (!type.HasEvents) + return null; + + foreach (EventDefinition @event in type.Events) + if (signature == @event.EventType.FullName + " " + @event.Name) + return @event; + + return null; + } + + protected virtual void ProcessEvent(TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) { } + + void ProcessSelectedProperties(XPathNavigator nav, TypeDefinition type, object? customData) + { + foreach (XPathNavigator propertyNav in nav.SelectChildren(PropertyElementName, XmlNamespace)) + { + if (!ShouldProcessElement(propertyNav)) + continue; + ProcessProperty(type, propertyNav, customData); + } + } + + protected virtual void ProcessProperty(TypeDefinition type, XPathNavigator nav, object? customData) + { + string signature = GetSignature(nav); + if (!String.IsNullOrEmpty(signature)) + { + PropertyDefinition? property = GetProperty(type, signature); + if (property == null) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindPropertyOnType, signature, type.GetDisplayName()); + return; + } + + ProcessProperty(type, property, nav, customData, true); + } + + string name = GetAttribute(nav, NameAttributeName); + if (!String.IsNullOrEmpty(name)) + { + bool foundMatch = false; + foreach (PropertyDefinition property in type.Properties) + { + if (property.Name == name) + { + foundMatch = true; + ProcessProperty(type, property, nav, customData, false); + } + } + + if (!foundMatch) + { + LogWarning(nav, DiagnosticId.XmlCouldNotFindPropertyOnType, name, type.GetDisplayName()); + } + } + } + + protected static PropertyDefinition? GetProperty(TypeDefinition type, string signature) + { + if (!type.HasProperties) + return null; + + foreach (PropertyDefinition property in type.Properties) + if (signature == property.PropertyType.FullName + " " + property.Name) + return property; + + return null; + } + + protected virtual void ProcessProperty(TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object? customData, bool fromSignature) { } + + protected virtual AssemblyNameReference GetAssemblyName(XPathNavigator nav) + { + return AssemblyNameReference.Parse(GetFullName(nav)); + } + + protected static string GetFullName(XPathNavigator nav) + { + return GetAttribute(nav, FullNameAttributeName); + } + + protected static string GetName(XPathNavigator nav) + { + return GetAttribute(nav, NameAttributeName); + } + + protected static string GetSignature(XPathNavigator nav) + { + return GetAttribute(nav, SignatureAttributeName); + } + + protected static string GetAttribute(XPathNavigator nav, string attribute) + { + return nav.GetAttribute(attribute, XmlNamespace); + } + + protected MessageOrigin GetMessageOriginForPosition(XPathNavigator position) + { + return (position is IXmlLineInfo lineInfo) + ? new MessageOrigin(_xmlDocumentLocation, lineInfo.LineNumber, lineInfo.LinePosition, _resource?.Assembly) + : new MessageOrigin(_xmlDocumentLocation, 0, 0, _resource?.Assembly); + } + protected void LogWarning(string message, int warningCode, XPathNavigator position) + { + _context.LogWarning(message, warningCode, GetMessageOriginForPosition(position)); + } + + protected void LogWarning(XPathNavigator position, DiagnosticId id, params string[] args) + { + _context.LogWarning(GetMessageOriginForPosition(position), id, args); + } + + public override string ToString() => GetType().Name + ": " + _xmlDocumentLocation; + + public bool TryConvertValue(string value, TypeReference target, out object? result) + { + switch (target.MetadataType) + { + case MetadataType.Boolean: + if (bool.TryParse(value, out bool bvalue)) + { + result = bvalue ? 1 : 0; + return true; + } + + goto case MetadataType.Int32; + + case MetadataType.Byte: + if (!byte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out byte byteresult)) + break; + + result = (int)byteresult; + return true; + + case MetadataType.SByte: + if (!sbyte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out sbyte sbyteresult)) + break; + + result = (int)sbyteresult; + return true; + + case MetadataType.Int16: + if (!short.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out short shortresult)) + break; + + result = (int)shortresult; + return true; + + case MetadataType.UInt16: + if (!ushort.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort ushortresult)) + break; + + result = (int)ushortresult; + return true; + + case MetadataType.Int32: + if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int iresult)) + break; + + result = iresult; + return true; + + case MetadataType.UInt32: + if (!uint.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out uint uresult)) + break; + + result = (int)uresult; + return true; + + case MetadataType.Double: + if (!double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out double dresult)) + break; + + result = dresult; + return true; + + case MetadataType.Single: + if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out float fresult)) + break; + + result = fresult; + return true; + + case MetadataType.Int64: + if (!long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long lresult)) + break; + + result = lresult; + return true; + + case MetadataType.UInt64: + if (!ulong.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong ulresult)) + break; + + result = (long)ulresult; + return true; + + case MetadataType.Char: + if (!char.TryParse(value, out char chresult)) + break; + + result = (int)chresult; + return true; + + case MetadataType.String: + if (value is string || value == null) + { + result = value; + return true; + } + + break; + + case MetadataType.ValueType: + if (value is string && + _context.TryResolve(target) is TypeDefinition typeDefinition && + typeDefinition.IsEnum) + { + var enumField = typeDefinition.Fields.Where(f => f.IsStatic && f.Name == value).FirstOrDefault(); + if (enumField != null) + { + result = Convert.ToInt32(enumField.Constant); + return true; + } + } + + break; + } + + result = null; + return false; + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/README.md b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/README.md new file mode 100644 index 0000000000000..a75e53a1f949a --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ReferenceSource/README.md @@ -0,0 +1 @@ +Sources taken from https://github.com/dotnet/linker/tree/c4abaf33f967a8fa42eb20fc386b774ad74ef319/src/linker/Linker.Steps. diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs index bd649904129bf..439d4e014e6db 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs @@ -973,7 +973,7 @@ public AssemblyFeatureInfo(EcmaModule module, IReadOnlyDictionary } } - private class LinkAttributesReader : ProcessLinkerXmlBase + private class LinkAttributesReader : ProcessXmlBase { private readonly HashSet _removedAttributes; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index 3420564b0715e..d2df0a825ca40 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -373,6 +373,7 @@ + @@ -527,6 +528,7 @@ + From 2cf6b0d07309a3c19938f4c886fe13e8d5cc28ee Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Wed, 19 Jan 2022 20:57:41 -0800 Subject: [PATCH 080/308] Fix gc_heap::remove_ro_segment (#63473) --- src/coreclr/gc/gc.cpp | 2 +- src/tests/GC/API/Frozen/Frozen.cs | 188 ++++++++++++++++++++++++++ src/tests/GC/API/Frozen/Frozen.csproj | 16 +++ 3 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 src/tests/GC/API/Frozen/Frozen.cs create mode 100644 src/tests/GC/API/Frozen/Frozen.csproj diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 958a4568a0f88..268930f2befd4 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -9404,7 +9404,7 @@ void gc_heap::remove_ro_segment (heap_segment* seg) enter_spin_lock (&gc_heap::gc_lock); - seg_table->remove ((uint8_t*)seg); + seg_table->remove (heap_segment_mem (seg)); seg_mapping_table_remove_ro_segment (seg); // Locate segment (and previous segment) in the list. diff --git a/src/tests/GC/API/Frozen/Frozen.cs b/src/tests/GC/API/Frozen/Frozen.cs new file mode 100644 index 0000000000000..3a9ad49175064 --- /dev/null +++ b/src/tests/GC/API/Frozen/Frozen.cs @@ -0,0 +1,188 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace HelloFrozenSegment +{ + using System; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; + + struct FrozenSegment + { + IntPtr underlyingSegment; + IntPtr underlyingBuffer; + + public FrozenSegment(IntPtr underlyingSegment, IntPtr underlyingBuffer) + { + this.underlyingSegment = underlyingSegment; + this.underlyingBuffer = underlyingBuffer; + } + + public void Release() + { + GCHelpers.UnregisterFrozenSegment(this.underlyingSegment); + Marshal.FreeHGlobal(this.underlyingBuffer); + } + } + + internal static class GCHelpers + { + private static MethodInfo s_registerFrozenSegmentMethod; + private static MethodInfo s_unregisterFrozenSegmentMethod; + + private static MethodInfo RegisterFrozenSegmentMethod + { + get + { + if (s_registerFrozenSegmentMethod == null) + { + s_registerFrozenSegmentMethod = typeof(GC).GetMethod("_RegisterFrozenSegment", BindingFlags.NonPublic|BindingFlags.Static); + } + + return s_registerFrozenSegmentMethod; + } + } + + private static MethodInfo UnregisterFrozenSegmentMethod + { + get + { + if (s_unregisterFrozenSegmentMethod == null) + { + s_unregisterFrozenSegmentMethod = typeof(GC).GetMethod("_UnregisterFrozenSegment", BindingFlags.NonPublic|BindingFlags.Static); + } + + return s_unregisterFrozenSegmentMethod; + } + } + + public static IntPtr RegisterFrozenSegment(IntPtr buffer, nint size) + { + return (IntPtr)RegisterFrozenSegmentMethod.Invoke(null, new object[]{buffer, size}); + + } + + public static void UnregisterFrozenSegment(IntPtr segment) + { + UnregisterFrozenSegmentMethod.Invoke(null, new object[]{segment}); + } + } + + internal unsafe class FrozenSegmentBuilder + { + private IntPtr _buffer; + private IntPtr _allocated; + private IntPtr _limit; + + // This only work for BaseSize (i.e. not arrays) + private static unsafe short GetObjectSize(IntPtr methodTable) + { + IntPtr pointerToSize = methodTable + 4; + return *((short*)pointerToSize); + } + + public FrozenSegmentBuilder(int capacity) + { + _buffer = Marshal.AllocHGlobal(capacity); + for (int i = 0; i < capacity; i++) + { + *((byte*)(_buffer + i)) = 0; + } + _allocated = _buffer + IntPtr.Size; + _limit = _buffer + capacity; + } + + public IntPtr Allocate(IntPtr methodTable) + { + if (_allocated == IntPtr.Zero) + { + throw new Exception("Segment already built"); + } + int objectSize = GetObjectSize(methodTable); + if ((_allocated + objectSize).CompareTo(_limit) > 0) + { + throw new Exception("OutOfCapacity"); + } + + IntPtr* pMethodTable = (IntPtr*)_allocated; + *pMethodTable = methodTable; + IntPtr result = _allocated; + _allocated = _allocated + objectSize; + return result; + } + + public FrozenSegment GetSegment() + { + if (_allocated == IntPtr.Zero) + { + throw new Exception("Segment already built"); + } + + nint size = (nint)(_allocated.ToInt64() - _buffer.ToInt64()); + _allocated = IntPtr.Zero; + IntPtr segment = GCHelpers.RegisterFrozenSegment(_buffer, size); + return new FrozenSegment(segment, _buffer); + } + } + + internal class Node + { + public Node next; + public int number; + } + + internal static class Program + { + private static unsafe IntPtr GetMethodTablePointer(object obj) + { + GCHandle gch = GCHandle.Alloc(obj); + IntPtr pointerToPointerToObject = GCHandle.ToIntPtr(gch); + IntPtr pointerToObject = *((IntPtr*)pointerToPointerToObject); + IntPtr methodTable = *((IntPtr*)pointerToObject); + gch.Free(); + return methodTable; + } + + private static unsafe int Main(string[] args) + { + Node template = new Node(); + IntPtr methodTable = GetMethodTablePointer(template); + + FrozenSegmentBuilder frozenSegmentBuilder = new FrozenSegmentBuilder(1000); + IntPtr node1Ptr = frozenSegmentBuilder.Allocate(methodTable); + IntPtr node2Ptr = frozenSegmentBuilder.Allocate(methodTable); + + FrozenSegment frozenSegment = frozenSegmentBuilder.GetSegment(); + Node root = new Node(); + Node node1 = Unsafe.AsRef((void*)&node1Ptr); + Node node2 = Unsafe.AsRef((void*)&node2Ptr); + // It is okay for any object to reference a frozen object. + root.next = node1; + + // It is not okay for a frozen object to reference another frozen object + // This is because the WriteBarrier code may (depending on the pointer + // value returned by AllocHGlobal) determine node2 to be an ephemeral object + // when it isn't. + // node1.next = node2; + + // It is not okay for a frozen object to reference another object that is not frozen + // This is because we may miss the marking of the new Node or miss the relocation + // of the new Node. + // node2.next = new Node(); + + // Making changes to non-GC references is fine + node1.number = 10086; + node2.number = 12580; + + GC.Collect(); + node1 = null; + GC.Collect(); + node2 = null; + GC.Collect(); + Console.WriteLine(root.next.next != null); + frozenSegment.Release(); + return 100; + } + } +} diff --git a/src/tests/GC/API/Frozen/Frozen.csproj b/src/tests/GC/API/Frozen/Frozen.csproj new file mode 100644 index 0000000000000..365f9ae36ae06 --- /dev/null +++ b/src/tests/GC/API/Frozen/Frozen.csproj @@ -0,0 +1,16 @@ + + + Exe + true + 1 + true + true + + + + PdbOnly + + + + + From e4bfedd847990795eb28cda4008b5ff4c58fd561 Mon Sep 17 00:00:00 2001 From: Jeremy Barton Date: Thu, 20 Jan 2022 00:06:28 -0800 Subject: [PATCH 081/308] Fix OpenSSL version check in GetAlpnSupport The previous check failed 3.0.0 because the Minor was 0 and Build was 0. It could probably be rewritten to be `>= new Version(1, 0, 2)`, but that'd require more thinking. --- .../Common/tests/TestUtilities/System/PlatformDetection.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index bdab9c979cc49..52fb34e0e8cd8 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -216,7 +216,12 @@ private static bool GetAlpnSupport() if (IsOpenSslSupported) { - return OpenSslVersion.Major >= 1 && (OpenSslVersion.Minor >= 1 || OpenSslVersion.Build >= 2); + if (OpenSslVersion.Major >= 3) + { + return true; + } + + return OpenSslVersion.Major == 1 && (OpenSslVersion.Minor >= 1 || OpenSslVersion.Build >= 2); } if (IsAndroid) From 8f2c84f02b74dbbe6e1f02dc9be37cf3ee288d6e Mon Sep 17 00:00:00 2001 From: Peter Sollich Date: Thu, 20 Jan 2022 10:06:45 +0100 Subject: [PATCH 082/308] Fix issues with verify_regions, clear_batch_mark_array_bits. (#63798) Details: - we cannot verify the tail of the region list from background GC, as it may be updated by threads allocating. - fix case in clear_batch_mark_array_bits where end is equal to the very end of a segment and we write into uncommitted memory in the mark_array. - bgc_clear_batch_mark_array_bits did some checks and then called clear_batch_mark_array_bits which repeated the exact same checks. Renamed clear_batch_mark_array_bits to bgc_batch_mark_array_bits and removed the old copy, removed the declaration for clear_batch_mark_array_bits. --- src/coreclr/gc/gc.cpp | 47 +++++++++++++++++++++-------------------- src/coreclr/gc/gcpriv.h | 6 ++---- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 268930f2befd4..e270bcdc91ee4 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -10892,7 +10892,7 @@ void gc_heap::seg_clear_mark_array_bits_soh (heap_segment* seg) } } -void gc_heap::clear_batch_mark_array_bits (uint8_t* start, uint8_t* end) +void gc_heap::bgc_clear_batch_mark_array_bits (uint8_t* start, uint8_t* end) { if ((start < background_saved_highest_address) && (end > background_saved_lowest_address)) @@ -10916,8 +10916,15 @@ void gc_heap::clear_batch_mark_array_bits (uint8_t* start, uint8_t* end) if (startwrd == endwrd) { - unsigned int wrd = firstwrd | lastwrd; - mark_array[startwrd] &= wrd; + if (startbit != endbit) + { + unsigned int wrd = firstwrd | lastwrd; + mark_array[startwrd] &= wrd; + } + else + { + assert (start == end); + } return; } @@ -10940,18 +10947,6 @@ void gc_heap::clear_batch_mark_array_bits (uint8_t* start, uint8_t* end) } } } - -void gc_heap::bgc_clear_batch_mark_array_bits (uint8_t* start, uint8_t* end) -{ - if ((start < background_saved_highest_address) && - (end > background_saved_lowest_address)) - { - start = max (start, background_saved_lowest_address); - end = min (end, background_saved_highest_address); - - clear_batch_mark_array_bits (start, end); - } -} #endif //BACKGROUND_GC inline @@ -29741,7 +29736,7 @@ void gc_heap::thread_final_regions (bool compact_p) } } - verify_regions (true); + verify_regions (true, false); } void gc_heap::thread_start_region (generation* gen, heap_segment* region) @@ -29792,7 +29787,7 @@ heap_segment* gc_heap::get_new_region (int gen_number, size_t size) heap_segment_next (generation_tail_region (gen)) = new_region; generation_tail_region (gen) = new_region; - verify_regions (gen_number, false); + verify_regions (gen_number, false, settings.concurrent); } return new_region; @@ -29861,7 +29856,7 @@ void gc_heap::update_start_tail_regions (generation* gen, (size_t)prev_region, heap_segment_mem (prev_region))); } - verify_regions (false); + verify_regions (false, settings.concurrent); } // There's one complication with deciding whether we can make a region SIP or not - if the plan_gen_num of @@ -42159,7 +42154,7 @@ gc_heap::verify_free_lists () } } -void gc_heap::verify_regions (int gen_number, bool can_verify_gen_num) +void gc_heap::verify_regions (int gen_number, bool can_verify_gen_num, bool can_verify_tail) { #ifdef USE_REGIONS // For the given generation, verify that @@ -42222,7 +42217,7 @@ void gc_heap::verify_regions (int gen_number, bool can_verify_gen_num) FATAL_GC_ERROR(); } - if (tail_region != prev_region_in_gen) + if (can_verify_tail && (tail_region != prev_region_in_gen)) { dprintf (REGIONS_LOG, ("h%d gen%d tail region is %Ix(%Ix), diff from last region %Ix(%Ix)!!", heap_number, gen_number, @@ -42233,12 +42228,18 @@ void gc_heap::verify_regions (int gen_number, bool can_verify_gen_num) #endif //USE_REGIONS } -void gc_heap::verify_regions (bool can_verify_gen_num) +inline bool is_user_alloc_gen (int gen_number) +{ + return ((gen_number == soh_gen0) || (gen_number == loh_generation) || (gen_number == poh_generation)); +} + +void gc_heap::verify_regions (bool can_verify_gen_num, bool concurrent_p) { #ifdef USE_REGIONS for (int i = 0; i < total_generation_count; i++) { - verify_regions (i, can_verify_gen_num); + bool can_verify_tail = (concurrent_p ? !is_user_alloc_gen (i) : true); + verify_regions (i, can_verify_gen_num, can_verify_tail); } #endif //USE_REGIONS } @@ -42369,7 +42370,7 @@ void gc_heap::verify_heap (BOOL begin_gc_p) //verify that the generation structures makes sense { #ifdef USE_REGIONS - verify_regions (true); + verify_regions (true, settings.concurrent); #else //USE_REGIONS generation* gen = generation_of (max_generation); diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h index bed8857bc8328..baa0272db1368 100644 --- a/src/coreclr/gc/gcpriv.h +++ b/src/coreclr/gc/gcpriv.h @@ -1286,9 +1286,9 @@ class gc_heap PER_HEAP void verify_free_lists(); PER_HEAP - void verify_regions (int gen_number, bool can_verify_gen_num); + void verify_regions (int gen_number, bool can_verify_gen_num, bool can_verify_tail); PER_HEAP - void verify_regions (bool can_verify_gen_num); + void verify_regions (bool can_verify_gen_num, bool concurrent_p); PER_HEAP_ISOLATED void enter_gc_lock_for_verify_heap(); PER_HEAP_ISOLATED @@ -2156,8 +2156,6 @@ class gc_heap PER_HEAP void seg_clear_mark_array_bits_soh (heap_segment* seg); PER_HEAP - void clear_batch_mark_array_bits (uint8_t* start, uint8_t* end); - PER_HEAP void bgc_clear_batch_mark_array_bits (uint8_t* start, uint8_t* end); #ifdef VERIFY_HEAP PER_HEAP From 5a523cf27a9b73e61adb1408f21b5e75a2246d9e Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Thu, 20 Jan 2022 10:26:06 +0100 Subject: [PATCH 083/308] [debugger][wasm] Added support for non user code attribute (#63876) * Hidden methods and step through methods behave the same way. * Perpared flow for setting JustMyCode in the future. * Tests for JustMyCode setting before debug launch. * Transformed into dynamic JustMyCode change flow. * JustMyCode disabled, first 3 cases solved. * Finished behavior for JMC disabled (with 1 difference). * JMC enabled: stepIn np bp + stepIn bp + resume bp. * Functional version (with minor deviations from expected behavior). * Refactoring. * All tests for NonUserCode work. * Fix line number after adding code above. * Fix error in merge. * Removing duplicated tests. --- .../debugger/BrowserDebugProxy/DebugStore.cs | 33 +++-- .../debugger/BrowserDebugProxy/MonoProxy.cs | 9 +- .../DebuggerTestSuite/BreakpointTests.cs | 134 ++++++++++-------- .../debugger/DebuggerTestSuite/MiscTests.cs | 2 +- .../tests/debugger-test/debugger-test.cs | 28 +++- 5 files changed, 132 insertions(+), 74 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index e37f75191c511..3c74bf450911e 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -332,8 +332,7 @@ internal class MethodInfo internal LocalScopeHandleCollection localScopes; public bool IsStatic() => (methodDef.Attributes & MethodAttributes.Static) != 0; public int IsAsync { get; set; } - public bool IsHiddenFromDebugger { get; } - public bool HasStepThroughAttribute { get; } + public DebuggerAttributesInfo DebuggerAttrInfo { get; set; } public TypeInfo TypeInfo { get; } public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type, MetadataReader asmMetadataReader, MetadataReader pdbMetadataReader) @@ -371,6 +370,7 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, StartLocation = new SourceLocation(this, start); EndLocation = new SourceLocation(this, end); + DebuggerAttrInfo = new DebuggerAttributesInfo(); foreach (var cattr in methodDef.GetCustomAttributes()) { var ctorHandle = asmMetadataReader.GetCustomAttribute(cattr).Constructor; @@ -378,16 +378,24 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, { var container = asmMetadataReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent; var name = asmMetadataReader.GetString(asmMetadataReader.GetTypeReference((TypeReferenceHandle)container).Name); - if (name == "DebuggerHiddenAttribute") + var stopSearch = true; + switch (name) { - IsHiddenFromDebugger = true; - break; + case "DebuggerHiddenAttribute": + DebuggerAttrInfo.HasDebuggerHidden = true; + break; + case "DebuggerStepThroughAttribute": + DebuggerAttrInfo.HasStepThrough = true; + break; + case "DebuggerNonUserCodeAttribute": + DebuggerAttrInfo.HasNonUserCode = true; + break; + default: + stopSearch = false; + break; } - if (name == "DebuggerStepThroughAttribute") - { - HasStepThroughAttribute = true; + if (stopSearch) break; - } } } @@ -478,6 +486,13 @@ public VarInfo[] GetLiveVarsAt(int offset) } public override string ToString() => "MethodInfo(" + Name + ")"; + + public class DebuggerAttributesInfo + { + public bool HasDebuggerHidden { get; internal set; } + public bool HasStepThrough { get; internal set; } + public bool HasNonUserCode { get; internal set; } + } } internal class TypeInfo diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 33d1dc4c59d98..5fff1c5a7f1fc 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -853,9 +853,12 @@ private async Task SendCallStack(SessionId sessionId, ExecutionContext con if (shouldReturn) return true; - if (j == 0 && (method?.Info.HasStepThroughAttribute == true || method?.Info.IsHiddenFromDebugger == true)) + if (j == 0 && + (method?.Info.DebuggerAttrInfo.HasStepThrough == true || + method?.Info.DebuggerAttrInfo.HasDebuggerHidden == true || + (method?.Info.DebuggerAttrInfo.HasNonUserCode == true && JustMyCode))) { - if (method.Info.IsHiddenFromDebugger) + if (method.Info.DebuggerAttrInfo.HasDebuggerHidden) { if (event_kind == EventKind.Step) context.IsSkippingHiddenMethod = true; @@ -1443,7 +1446,7 @@ private async Task SetBreakpoint(SessionId sessionId, DebugStore store, Breakpoi { SourceLocation loc = sourceId.First(); req.Method = loc.IlLocation.Method; - if (req.Method.IsHiddenFromDebugger) + if (req.Method.DebuggerAttrInfo.HasDebuggerHidden) continue; Breakpoint bp = await SetMonoBreakpoint(sessionId, req.Id, loc, req.Condition, token); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs index 01f526e8c78db..1252bb4135f32 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs @@ -709,128 +709,148 @@ await SendCommandAndCheck(null, "Debugger.resume", } [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task StepThroughAttributeStepInNoBp(bool justMyCodeEnabled) + [InlineData(false, "RunStepThrough")] + [InlineData(true, "RunStepThrough")] + [InlineData(true, "RunNonUserCode")] + [InlineData(false, "RunNonUserCode")] + public async Task StepThroughOrNonUserCodeAttributeStepInNoBp(bool justMyCodeEnabled, string evalFunName) { - var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 1); + var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", evalFunName, 1); if (justMyCodeEnabled) await SetJustMyCode(true); var init_location = await EvaluateAndCheck( - "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerAttribute:RunStepThrough'); }, 1);", + $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] DebuggerAttribute:{evalFunName}'); }}, 1);", "dotnet://debugger-test.dll/debugger-test.cs", bp_init.Value["locations"][0]["lineNumber"].Value(), bp_init.Value["locations"][0]["columnNumber"].Value(), - "RunStepThrough" + evalFunName ); - await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", 868, 8, "RunStepThrough"); + var (funcName, line, col) = (evalFunName, 868, 8); + if (evalFunName == "RunNonUserCode") + (funcName, line, col) = justMyCodeEnabled ? (evalFunName, 888, 8) : ("NonUserCodeBp", 873, 4); + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line, col, funcName); } [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task StepThroughAttributeStepInWithBp(bool justMyCodeEnabled) + [InlineData(false, "RunStepThrough", "StepThrougBp")] + [InlineData(true, "RunStepThrough", "StepThrougBp")] + [InlineData(true, "RunNonUserCode", "NonUserCodeBp")] + [InlineData(false, "RunNonUserCode", "NonUserCodeBp")] + public async Task StepThroughOrNonUserCodeAttributeStepInWithBp(bool justMyCodeEnabled, string evalFunName, string decoratedFunName) { - var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 1); - var bp1_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "NotStopOnJustMyCode", 1); - var bp2_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "NotStopOnJustMyCode", 3); - + var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", evalFunName, 1); var init_location = await EvaluateAndCheck( - "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerAttribute:RunStepThrough'); }, 1);", + $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] DebuggerAttribute:{evalFunName}'); }}, 1);", "dotnet://debugger-test.dll/debugger-test.cs", bp_init.Value["locations"][0]["lineNumber"].Value(), bp_init.Value["locations"][0]["columnNumber"].Value(), - "RunStepThrough" + evalFunName ); if (justMyCodeEnabled) { await SetJustMyCode(true); - await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", 868, 8, "RunStepThrough"); + var line = (evalFunName == "RunNonUserCode") ? 888 : 868; + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line, 8, evalFunName); } else { - var line1 = bp1_decorated_fun.Value["locations"][0]["lineNumber"].Value(); - var line2 = bp2_decorated_fun.Value["locations"][0]["lineNumber"].Value(); - var line3 = 867; - var step_throgh_fun = "NotStopOnJustMyCode"; - var outer_fun = "RunStepThrough"; - await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line1, 8, step_throgh_fun); - await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line2, 8, step_throgh_fun); - await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line3, 8, outer_fun); + var (finalFunName, line3, col) = (decoratedFunName, 873, 4); + if (evalFunName == "RunStepThrough") + { + var bp1_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", decoratedFunName, 1); + var bp2_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", decoratedFunName, 3); + (finalFunName, line3, col) = (evalFunName, 867, 8); + var line1 = bp1_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + var line2 = bp2_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line1, col, decoratedFunName); + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line2, col, decoratedFunName); + } + await SendCommandAndCheck(null, "Debugger.stepInto", "dotnet://debugger-test.dll/debugger-test.cs", line3, col, finalFunName); } } [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task StepThroughAttributeResumeWithBp(bool justMyCodeEnabled) + [InlineData(false, "RunStepThrough", "StepThrougBp")] + [InlineData(true, "RunStepThrough", "StepThrougBp")] + [InlineData(true, "RunNonUserCode", "NonUserCodeBp")] + [InlineData(false, "RunNonUserCode", "NonUserCodeBp")] + public async Task StepThroughOrNonUserCodeAttributeResumeWithBp(bool justMyCodeEnabled, string evalFunName, string decoratedFunName) { - var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 1); - var bp1_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "NotStopOnJustMyCode", 1); - var bp_outside_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 2); - + var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", evalFunName, 1); var init_location = await EvaluateAndCheck( - "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerAttribute:RunStepThrough'); }, 1);", + $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] DebuggerAttribute:{evalFunName}'); }}, 1);", "dotnet://debugger-test.dll/debugger-test.cs", bp_init.Value["locations"][0]["lineNumber"].Value(), bp_init.Value["locations"][0]["columnNumber"].Value(), - "RunStepThrough" + evalFunName ); if (justMyCodeEnabled) await SetJustMyCode(true); else { + var bp1_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", decoratedFunName, 1); var line1 = bp1_decorated_fun.Value["locations"][0]["lineNumber"].Value(); - var function_name1 = "NotStopOnJustMyCode"; - await SendCommandAndCheck(null, "Debugger.resume", "dotnet://debugger-test.dll/debugger-test.cs", line1, 8, function_name1); + await SendCommandAndCheck(null, "Debugger.resume", "dotnet://debugger-test.dll/debugger-test.cs", line1, 8, decoratedFunName); } - + var bp_outside_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", evalFunName, 2); var line2 = bp_outside_decorated_fun.Value["locations"][0]["lineNumber"].Value(); - var function_name2 = "RunStepThrough"; - await SendCommandAndCheck(null, "Debugger.resume", "dotnet://debugger-test.dll/debugger-test.cs", line2, 8, function_name2); + await SendCommandAndCheck(null, "Debugger.resume", "dotnet://debugger-test.dll/debugger-test.cs", line2, 8, evalFunName); } [Theory] - [InlineData(false, "Debugger.resume")] - [InlineData(false, "Debugger.stepInto")] - [InlineData(true, "Debugger.stepInto")] - [InlineData(true, "Debugger.resume")] - public async Task StepThroughAttributeWithUserBp(bool justMyCodeEnabled, string debuggingFunction) + [InlineData(false, "Debugger.resume", "RunStepThrough", "StepThrougUserBp")] + [InlineData(false, "Debugger.stepInto", "RunStepThrough", "StepThrougUserBp")] + [InlineData(true, "Debugger.stepInto", "RunStepThrough", null)] + [InlineData(true, "Debugger.resume", "RunStepThrough", null)] + [InlineData(true, "Debugger.stepInto", "RunNonUserCode", null)] + [InlineData(true, "Debugger.resume", "RunNonUserCode", null)] + [InlineData(false, "Debugger.stepInto", "RunNonUserCode", "NonUserCodeUserBp")] + [InlineData(false, "Debugger.resume", "RunNonUserCode", "NonUserCodeUserBp")] + public async Task StepThroughOrNonUserCodAttributeWithUserBp(bool justMyCodeEnabled, string debuggingFunction, string evalFunName, string decoratedFunName) { - var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 2); - var bp_outside_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunStepThrough", 3); + var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", evalFunName, 2); + var bp_outside_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", evalFunName, 3); var init_location = await EvaluateAndCheck( - "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerAttribute:RunStepThrough'); }, 1);", + $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] DebuggerAttribute:{evalFunName}'); }}, 1);", "dotnet://debugger-test.dll/debugger-test.cs", bp_init.Value["locations"][0]["lineNumber"].Value(), bp_init.Value["locations"][0]["columnNumber"].Value(), - "RunStepThrough" + evalFunName ); - int line1, line2; + int line1, line2; + var (col1, col2) = (8, 4); string function_name1, function_name2; if (justMyCodeEnabled) { await SetJustMyCode(true); line1 = bp_outside_decorated_fun.Value["locations"][0]["lineNumber"].Value() - 1; - function_name1 = "RunStepThrough"; line2 = bp_outside_decorated_fun.Value["locations"][0]["lineNumber"].Value(); - function_name2 = "RunStepThrough"; + function_name1 = function_name2 = evalFunName; } else { - line1 = 862; - function_name1 = "NotStopOnJustMyCodeUserBp"; - line2 = bp_outside_decorated_fun.Value["locations"][0]["lineNumber"].Value(); - function_name2 = "RunStepThrough"; + if (debuggingFunction == "Debugger.stepInto" && evalFunName == "RunNonUserCode") + { + (line1, col1) = (881, 4); + (line2, col2) = (882, 8); + function_name1 = function_name2 = decoratedFunName; + } + else + { + line1 = evalFunName == "RunNonUserCode" ? 882 : 862; + function_name1 = decoratedFunName; + line2 = bp_outside_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + function_name2 = evalFunName; + } } - await SendCommandAndCheck(null, debuggingFunction, "dotnet://debugger-test.dll/debugger-test.cs", line1, 8, function_name1); - await SendCommandAndCheck(null, debuggingFunction, "dotnet://debugger-test.dll/debugger-test.cs", line2, 4, function_name2); + await SendCommandAndCheck(null, debuggingFunction, "dotnet://debugger-test.dll/debugger-test.cs", line1, col1, function_name1); + await SendCommandAndCheck(null, debuggingFunction, "dotnet://debugger-test.dll/debugger-test.cs", line2, col2, function_name2); } [Fact] diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs index 9bb227f43f409..8752e8a240757 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs @@ -913,7 +913,7 @@ public async Task InspectLocalsUsingClassFromLibraryUsingDebugTypeFull() await EvaluateAndCheck( "window.setTimeout(function() {" + expression + "; }, 1);", - "dotnet://debugger-test.dll/debugger-test.cs", 880, 8, + "dotnet://debugger-test.dll/debugger-test.cs", 900, 8, "CallToEvaluateLocal", wait_for_event_fn: async (pause_location) => { diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 49c811faaa317..52c8822982395 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -850,7 +850,7 @@ public static void RunDebuggerBreak() } [System.Diagnostics.DebuggerStepThroughAttribute] - public static void NotStopOnJustMyCode() + public static void StepThrougBp() { var a = 0; currentCount++; @@ -858,15 +858,35 @@ public static void NotStopOnJustMyCode() } [System.Diagnostics.DebuggerStepThroughAttribute] - public static void NotStopOnJustMyCodeUserBp() + public static void StepThrougUserBp() { System.Diagnostics.Debugger.Break(); } public static void RunStepThrough() { - NotStopOnJustMyCode(); - NotStopOnJustMyCodeUserBp(); + StepThrougBp(); + StepThrougUserBp(); + } + + [System.Diagnostics.DebuggerNonUserCode] + public static void NonUserCodeBp() + { + var a = 0; + currentCount++; + var b = 1; + } + + [System.Diagnostics.DebuggerNonUserCode] + public static void NonUserCodeUserBp() + { + System.Diagnostics.Debugger.Break(); + } + + public static void RunNonUserCode() + { + NonUserCodeBp(); + NonUserCodeUserBp(); } } From 36cdb5fc0c38cbb44291114e48e2b202ff37db01 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Thu, 20 Jan 2022 11:03:02 +0100 Subject: [PATCH 084/308] [wasm][debugger] Added support for stepper boundary attribute (#63991) * Hidden methods and step through methods behave the same way. * Perpared flow for setting JustMyCode in the future. * Tests for JustMyCode setting before debug launch. * Transformed into dynamic JustMyCode change flow. * JustMyCode disabled, first 3 cases solved. * Finished behavior for JMC disabled (with 1 difference). * JMC enabled: stepIn np bp + stepIn bp + resume bp. * Functional version (with minor deviations from expected behavior). * Refactoring. * All tests for NonUserCode work. * Fix line number after adding code above. * Stepper boundary with tests. * Save information about multiple decorators. * Fix error in merge. --- .../debugger/BrowserDebugProxy/DebugStore.cs | 8 ++--- .../debugger/BrowserDebugProxy/MonoProxy.cs | 28 ++++++++------- .../DebuggerTestSuite/BreakpointTests.cs | 35 +++++++++++++++++++ .../debugger/DebuggerTestSuite/MiscTests.cs | 2 +- .../tests/debugger-test/debugger-test.cs | 26 +++++++++++++- 5 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index 3c74bf450911e..88ad41efc2172 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -378,7 +378,6 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, { var container = asmMetadataReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent; var name = asmMetadataReader.GetString(asmMetadataReader.GetTypeReference((TypeReferenceHandle)container).Name); - var stopSearch = true; switch (name) { case "DebuggerHiddenAttribute": @@ -390,12 +389,10 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, case "DebuggerNonUserCodeAttribute": DebuggerAttrInfo.HasNonUserCode = true; break; - default: - stopSearch = false; + case "DebuggerStepperBoundaryAttribute": + DebuggerAttrInfo.HasStepperBoundary = true; break; } - if (stopSearch) - break; } } @@ -492,6 +489,7 @@ public class DebuggerAttributesInfo public bool HasDebuggerHidden { get; internal set; } public bool HasStepThrough { get; internal set; } public bool HasNonUserCode { get; internal set; } + public bool HasStepperBoundary { get; internal set; } } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 5fff1c5a7f1fc..36d6289bf241c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -856,28 +856,32 @@ private async Task SendCallStack(SessionId sessionId, ExecutionContext con if (j == 0 && (method?.Info.DebuggerAttrInfo.HasStepThrough == true || method?.Info.DebuggerAttrInfo.HasDebuggerHidden == true || + method?.Info.DebuggerAttrInfo.HasStepperBoundary == true || (method?.Info.DebuggerAttrInfo.HasNonUserCode == true && JustMyCode))) { - if (method.Info.DebuggerAttrInfo.HasDebuggerHidden) + if (method.Info.DebuggerAttrInfo.HasDebuggerHidden || + (method.Info.DebuggerAttrInfo.HasStepperBoundary && event_kind == EventKind.Step)) { if (event_kind == EventKind.Step) context.IsSkippingHiddenMethod = true; if (await SkipMethod(isSkippable: true, shouldBeSkipped: true, StepKind.Out)) return true; } - - if (event_kind == EventKind.Step || - (JustMyCode && (event_kind == EventKind.Breakpoint || event_kind == EventKind.UserBreak))) + if (!method.Info.DebuggerAttrInfo.HasStepperBoundary) { - if (context.IsResumedAfterBp) - context.IsResumedAfterBp = false; - else if (event_kind != EventKind.UserBreak) - context.IsSteppingThroughMethod = true; - if (await SkipMethod(isSkippable: true, shouldBeSkipped: true, StepKind.Out)) - return true; + if (event_kind == EventKind.Step || + (JustMyCode && (event_kind == EventKind.Breakpoint || event_kind == EventKind.UserBreak))) + { + if (context.IsResumedAfterBp) + context.IsResumedAfterBp = false; + else if (event_kind != EventKind.UserBreak) + context.IsSteppingThroughMethod = true; + if (await SkipMethod(isSkippable: true, shouldBeSkipped: true, StepKind.Out)) + return true; + } + if (event_kind == EventKind.Breakpoint) + context.IsResumedAfterBp = true; } - if (event_kind == EventKind.Breakpoint) - context.IsResumedAfterBp = true; } SourceLocation location = method?.Info.GetLocationByIl(il_pos); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs index 1252bb4135f32..b8c58a27f1e5f 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs @@ -853,6 +853,41 @@ public async Task StepThroughOrNonUserCodAttributeWithUserBp(bool justMyCodeEnab await SendCommandAndCheck(null, debuggingFunction, "dotnet://debugger-test.dll/debugger-test.cs", line2, col2, function_name2); } + [Theory] + [InlineData("Debugger.stepInto", 1, 2, false)] + [InlineData("Debugger.stepInto", 1, 2, true)] + [InlineData("Debugger.resume", 1, 2, true)] + [InlineData("Debugger.stepInto", 2, 3, false)] + [InlineData("Debugger.resume", 2, 3, false)] + public async Task StepperBoundary(string debuggingAction, int lineBpInit, int lineBpFinal, bool hasBpInDecoratedFun) + { + // behavior of StepperBoundary is the same for JMC enabled and disabled + // but the effect of NonUserCode escape is better visible for JMC: enabled + await SetJustMyCode(true); + var bp_init = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunNoBoundary", lineBpInit); + var init_location = await EvaluateAndCheck( + $"window.setTimeout(function() {{ invoke_static_method('[debugger-test] DebuggerAttribute:RunNoBoundary'); }}, {lineBpInit});", + "dotnet://debugger-test.dll/debugger-test.cs", + bp_init.Value["locations"][0]["lineNumber"].Value(), + bp_init.Value["locations"][0]["columnNumber"].Value(), + "RunNoBoundary" + ); + var bp_final = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "RunNoBoundary", lineBpFinal); + if (hasBpInDecoratedFun) + { + var bp_decorated_fun = await SetBreakpointInMethod("debugger-test.dll", "DebuggerAttribute", "BoundaryBp", 2); + var line_decorated_fun = bp_decorated_fun.Value["locations"][0]["lineNumber"].Value(); + var col_decorated_fun = bp_decorated_fun.Value["locations"][0]["columnNumber"].Value(); + await SendCommandAndCheck(null, debuggingAction, "dotnet://debugger-test.dll/debugger-test.cs", line_decorated_fun, col_decorated_fun, "BoundaryBp"); + } + if (lineBpInit == 2) + await SendCommandAndCheck(null, debuggingAction, "dotnet://debugger-test.dll/debugger-test.cs", 900, 8, "BoundaryUserBp"); + + var line = bp_final.Value["locations"][0]["lineNumber"].Value(); + var col = bp_final.Value["locations"][0]["columnNumber"].Value(); + await SendCommandAndCheck(null, debuggingAction, "dotnet://debugger-test.dll/debugger-test.cs", line, col, "RunNoBoundary"); + } + [Fact] public async Task CreateGoodBreakpointAndHitGoToWasmPageWithoutAssetsComeBackAndHitAgain() { diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs index 8752e8a240757..76f79a663f6e9 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs @@ -913,7 +913,7 @@ public async Task InspectLocalsUsingClassFromLibraryUsingDebugTypeFull() await EvaluateAndCheck( "window.setTimeout(function() {" + expression + "; }, 1);", - "dotnet://debugger-test.dll/debugger-test.cs", 900, 8, + "dotnet://debugger-test.dll/debugger-test.cs", 924, 8, "CallToEvaluateLocal", wait_for_event_fn: async (pause_location) => { diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 52c8822982395..3ecd2869fa210 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -870,7 +870,7 @@ public static void RunStepThrough() } [System.Diagnostics.DebuggerNonUserCode] - public static void NonUserCodeBp() + public static void NonUserCodeBp(Action boundaryTestFun=null) { var a = 0; currentCount++; @@ -888,6 +888,30 @@ public static void RunNonUserCode() NonUserCodeBp(); NonUserCodeUserBp(); } + + [System.Diagnostics.DebuggerStepperBoundary] + public static void BoundaryBp() + { + var a = 5; + } + + [System.Diagnostics.DebuggerStepperBoundary] + public static void BoundaryUserBp() + { + System.Diagnostics.Debugger.Break(); + } + + [System.Diagnostics.DebuggerNonUserCode] + public static void NonUserCodeForBoundaryEscape(Action boundaryTestFun) + { + boundaryTestFun(); + } + + public static void RunNoBoundary() + { + NonUserCodeForBoundaryEscape(DebuggerAttribute.BoundaryBp); + NonUserCodeForBoundaryEscape(DebuggerAttribute.BoundaryUserBp); + } } public class DebugTypeFull From 4e48641996cfc890163a49ef13bb2121de58d31d Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Thu, 20 Jan 2022 15:29:18 +0300 Subject: [PATCH 085/308] Polish the PR build doc (#64036) --- docs/pr-builds.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/pr-builds.md b/docs/pr-builds.md index 1d098b5c1b9da..f5f7555ae7e67 100644 --- a/docs/pr-builds.md +++ b/docs/pr-builds.md @@ -1,9 +1,9 @@ ## PR Builds When submitting a PR to the `dotnet/runtime` repository various builds will run validation in many areas to ensure we keep productivity and quality high. -The `dotnet/runtime` validation system can become overwhelming as we need to cover a lot of build scenarios and test in all the platforms that we support. In order to try to make this more reliable and spend the least amount of time testing what the PR change need we have various pipelines, required and optional that are covered in this document. +The `dotnet/runtime` validation system can become overwhelming as we need to cover a lot of build scenarios and test in all the platforms that we support. In order to try to make this more reliable and spend the least amount of time testing what the PR changes need we have various pipelines, required and optional that are covered in this document. -Most of the repository pipelines use a custom mechanism to evaluate paths based on the changes contained in the PR to try and build/test the least that we can without compromising quality. This is the initial step on every pipeline that depends on this infrastructure, called "Evalute Paths". In this step you can see the result of the evaluation for each subset of the repository. For more details on which subsets we have based on paths see [here](https://github.com/dotnet/runtime/blob/513fe2863ad5ec6dc453d223d4b60f787a0ffa78/eng/pipelines/common/evaluate-default-paths.yml). Also to understand how this mechanism you can read this [comment](https://github.com/dotnet/runtime/blob/513fe2863ad5ec6dc453d223d4b60f787a0ffa78/eng/pipelines/evaluate-changed-paths.sh#L3-L12). +Most of the repository pipelines use a custom mechanism to evaluate paths based on the changes contained in the PR to try and build/test the least that we can without compromising quality. This is the initial step on every pipeline that depends on this infrastructure, called "Evalute Paths". In this step you can see the result of the evaluation for each subset of the repository. For more details on which subsets we have based on paths see [here](https://github.com/dotnet/runtime/blob/513fe2863ad5ec6dc453d223d4b60f787a0ffa78/eng/pipelines/common/evaluate-default-paths.yml). Also to understand how this mechanism works you can read this [comment](https://github.com/dotnet/runtime/blob/513fe2863ad5ec6dc453d223d4b60f787a0ffa78/eng/pipelines/evaluate-changed-paths.sh#L3-L12). ### Runtime pipeline This is the "main" pipeline for the runtime product. In this pipeline we include the most critical tests and platforms where we have enough test resources in order to deliver test results in a reasonable amount of time. The tests executed in this pipeline for runtime and libraries are considered innerloop, are the tests that are executed locally when one runs tests locally. @@ -22,7 +22,7 @@ This pipeline runs on every change, however it behaves a little different than t The tests will not fail because the intent of this platform is to stage new platforms where the test infrastructure is new and we need to test if we have enough capacity to include that new platform on the "main" runtime pipeline without causing flakiness. Once we analyze data and a platform is stable when running on PRs in this pipeline for at least a weak it can be promoted either to the `runtime-extra-platforms` pipeline or to the `runtime` pipeline. ### Runtime-extra-platforms -This pipeline does not run by default as it is not required for a PR, but it runs twice a day, and it can also be invoked in specific PRs by commenting `/azp run runtime-extra-platforms` However, this pipeline is still an important part of our testing. +This pipeline does not run by default as it is not required for a PR, but it runs twice a day, and it can also be invoked in specific PRs by commenting `/azp run runtime-extra-platforms`. However, this pipeline is still an important part of our testing. This pipeline runs innerloop tests on platforms where we don't have enough hardware capacity to run tests (mobile, browser) or on platforms where we believe tests should organically pass based on the coverage we have in the "main" runtime pipeline. For example, in the "main" pipeline we run tests on Ubuntu 21.10 but since we also support Ubuntu 18.04 which is an LTS release, we run tests on Ubuntu 18.04 of this pipeline just to make sure we have healthy tests on those platforms which we are releasing a product for. @@ -46,7 +46,7 @@ Validation may fail for several reasons: * Your assumption should be that a failed test indicates a problem in your PR. (If we don't operate this way, chaos ensues.) If the test fails when run again, it is almost surely a failure caused by your PR. However, there are occasions where unrelated failures occur. Here's some ways to know: * Perhaps you see the same failure in CI results for unrelated active PR's. * It's a known issue listed in our [big tracking issue](https://github.com/dotnet/runtime/issues/702) or tagged `blocking-clean-ci` [(query here)](https://github.com/dotnet/runtime/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Ablocking-clean-ci+) - * Its otherwise beyond any reasonable doubt that your code changes could not have caused this. + * It's otherwise beyond any reasonable doubt that your code changes could not have caused this. * If the tests pass on rerun, that may suggest it's not related. * In this situation, you want to re-run but not necessarily rebase on main. * To rerun just the failed leg(s): @@ -88,7 +88,7 @@ If you have determined the failure is definitely not caused by changes in your P * Update the original pull request with a comment linking to the new or existing issue. * In a follow-up Pull Request, disable the failing test(s) with the corresponding issue link tracking the disable. * Update the tracking issue with the label `disabled-test`. - * For libraries tests add a [`[ActiveIssue(link)]`](https://github.com/dotnet/arcade/blob/master/src/Microsoft.DotNet.XUnitExtensions/src/Attributes/ActiveIssueAttribute.cs) attribute on the test method. You can narrow the disabling down to runtime variant, flavor, and platform. For an example see [File_AppendAllLinesAsync_Encoded](https://github.com/dotnet/runtime/blob/a259ec2e967d502f82163beba6b84da5319c5e08/src/libraries/System.IO.FileSystem/tests/File/AppendAsync.cs#L899) + * For libraries tests add a [`[ActiveIssue(link)]`](https://github.com/dotnet/arcade/blob/master/src/Microsoft.DotNet.XUnitExtensions/src/Attributes/ActiveIssueAttribute.cs) attribute on the test method. You can narrow the disabling down to runtime variant, flavor, and platform. For an example see [File_AppendAllLinesAsync_Encoded](https://github.com/dotnet/runtime/blob/cf49643711ad8aa4685a8054286c1348cef6e1d8/src/libraries/System.IO.FileSystem/tests/File/AppendAsync.cs#L74) * For runtime tests found under `src/tests`, please edit [`issues.targets`](https://github.com/dotnet/runtime/blob/main/src/tests/issues.targets). There are several groups for different types of disable (mono vs. coreclr, different platforms, different scenarios). Add the folder containing the test and issue mimicking any of the samples in the file. There are plenty of possible bugs, e.g. race conditions, where a failure might highlight a real problem and it won't manifest again on a retry. Therefore these steps should be followed for every iteration of the PR build, e.g. before retrying/rebuilding. \ No newline at end of file From 3361b2f86acdfb9095ecc0e2e4aea539d8fb72cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Thu, 20 Jan 2022 13:58:49 +0100 Subject: [PATCH 086/308] [wasm] WebSocket tests on NodeJS (#63441) - NPM package with WS. - Restore npm during build. - Load npm modules in test-main.js. Co-authored-by: Pavel Savara --- eng/testing/WasmRunnerTemplate.cmd | 2 +- eng/testing/WasmRunnerTemplate.sh | 2 +- eng/testing/tests.wasm.targets | 4 +- .../Net/Prerequisites/LocalEchoServer.props | 4 -- .../TestUtilities/System/PlatformDetection.cs | 9 ++-- .../tests/AbortTest.cs | 1 + .../tests/ConnectTest.cs | 4 ++ .../System.Net.WebSockets.Client.Tests.csproj | 23 +++++++++- .../tests/WebSocketHelper.cs | 2 +- .../tests/package-lock.json | 44 +++++++++++++++++++ .../tests/package.json | 7 +++ src/mono/wasm/test-main.js | 21 +++++++++ .../WebAssembly.Browser.HotReload.Test.csproj | 3 ++ ...Assembly.Browser.RuntimeConfig.Test.csproj | 3 ++ 14 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 src/libraries/System.Net.WebSockets.Client/tests/package-lock.json create mode 100644 src/libraries/System.Net.WebSockets.Client/tests/package.json diff --git a/eng/testing/WasmRunnerTemplate.cmd b/eng/testing/WasmRunnerTemplate.cmd index a668ce2c6a464..2ebcbcf8e93a9 100644 --- a/eng/testing/WasmRunnerTemplate.cmd +++ b/eng/testing/WasmRunnerTemplate.cmd @@ -54,7 +54,7 @@ if /I [%XHARNESS_COMMAND%] == [test] ( ) if [%XHARNESS_ARGS%] == [] ( - set "XHARNESS_ARGS=%JS_ENGINE% %JS_ENGINE_ARGS% %BROWSER_PATH% %MAIN_JS%" + set "XHARNESS_ARGS=%JS_ENGINE% %JS_ENGINE_ARGS% %BROWSER_PATH% %MAIN_JS% %WASM_XHARNESS_MONO_ARGS%" ) echo EXECUTION_DIR=%EXECUTION_DIR% diff --git a/eng/testing/WasmRunnerTemplate.sh b/eng/testing/WasmRunnerTemplate.sh index ae78d5304e8ae..d4e352976e807 100644 --- a/eng/testing/WasmRunnerTemplate.sh +++ b/eng/testing/WasmRunnerTemplate.sh @@ -50,7 +50,7 @@ if [[ "$XHARNESS_COMMAND" == "test" ]]; then fi if [[ -z "$XHARNESS_ARGS" ]]; then - XHARNESS_ARGS="$JS_ENGINE $JS_ENGINE_ARGS $MAIN_JS" + XHARNESS_ARGS="$JS_ENGINE $JS_ENGINE_ARGS $MAIN_JS $WASM_XHARNESS_MONO_ARGS" fi echo EXECUTION_DIR=$EXECUTION_DIR diff --git a/eng/testing/tests.wasm.targets b/eng/testing/tests.wasm.targets index 191d2c2295690..bed571a306402 100644 --- a/eng/testing/tests.wasm.targets +++ b/eng/testing/tests.wasm.targets @@ -29,13 +29,13 @@ See also eng\testing\WasmRunnerTemplate.sh --> - + - + diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/LocalEchoServer.props b/src/libraries/Common/tests/System/Net/Prerequisites/LocalEchoServer.props index f70812e39b685..3df500bdb8e3e 100644 --- a/src/libraries/Common/tests/System/Net/Prerequisites/LocalEchoServer.props +++ b/src/libraries/Common/tests/System/Net/Prerequisites/LocalEchoServer.props @@ -1,9 +1,5 @@ - WasmTestOnBrowser - $(TestArchiveRoot)browseronly/ - $(TestArchiveTestsRoot)$(OSPlatformConfig)/ - <_TestEchoMiddleware Condition="'$(ContinuousIntegrationBuild)' == 'true' and '$(OS)' == 'Windows_NT'">%HELIX_CORRELATION_PAYLOAD%/xharness/TestEchoMiddleware <_TestEchoMiddleware Condition="'$(ContinuousIntegrationBuild)' == 'true' and '$(OS)' != 'Windows_NT'">$HELIX_CORRELATION_PAYLOAD/xharness/TestEchoMiddleware diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index 52fb34e0e8cd8..f9b929480ab30 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -69,9 +69,10 @@ public static partial class PlatformDetection public static bool IsSpeedOptimized => !IsSizeOptimized; public static bool IsSizeOptimized => IsBrowser || IsAndroid || IsAppleMobile; - public static bool IsBrowserDomSupported => GetIsBrowserDomSupported(); - public static bool IsBrowserDomSupportedOrNotBrowser => IsNotBrowser || GetIsBrowserDomSupported(); + public static bool IsBrowserDomSupported => IsEnvironmentVariableTrue("IsBrowserDomSupported"); + public static bool IsBrowserDomSupportedOrNotBrowser => IsNotBrowser || IsBrowserDomSupported; public static bool IsNotBrowserDomSupported => !IsBrowserDomSupported; + public static bool IsWebSocketSupported => IsEnvironmentVariableTrue("IsWebSocketSupported"); public static bool LocalEchoServerIsNotAvailable => !LocalEchoServerIsAvailable; public static bool LocalEchoServerIsAvailable => IsBrowser; @@ -499,12 +500,12 @@ private static bool GetIsRunningOnMonoInterpreter() #endif } - private static bool GetIsBrowserDomSupported() + private static bool IsEnvironmentVariableTrue(string variableName) { if (!IsBrowser) return false; - var val = Environment.GetEnvironmentVariable("IsBrowserDomSupported"); + var val = Environment.GetEnvironmentVariable(variableName); return (val != null && val == "true"); } } diff --git a/src/libraries/System.Net.WebSockets.Client/tests/AbortTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/AbortTest.cs index 209a6f10ff23b..a5d97a9a42188 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/AbortTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/AbortTest.cs @@ -17,6 +17,7 @@ public AbortTest(ITestOutputHelper output) : base(output) { } [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63673", TestPlatforms.Browser)] public async Task Abort_ConnectAndAbort_ThrowsWebSocketExceptionWithmessage(Uri server) { using (var cws = new ClientWebSocket()) diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs index 31c375a9cd499..75b378f505636 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs @@ -170,6 +170,7 @@ public async Task ConnectAsync_CookieHeaders_Success(Uri server) [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63681", TestPlatforms.Browser)] public async Task ConnectAsync_PassNoSubProtocol_ServerRequires_ThrowsWebSocketException(Uri server) { const string AcceptedProtocol = "CustomProtocol"; @@ -256,6 +257,7 @@ public async Task ConnectAndCloseAsync_UseProxyServer_ExpectedClosedState(Uri se } [ConditionalFact(nameof(WebSocketsSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63672", TestPlatforms.Browser)] public async Task ConnectAsync_CancellationRequestedBeforeConnect_ThrowsOperationCanceledException() { using (var clientSocket = new ClientWebSocket()) @@ -268,6 +270,7 @@ public async Task ConnectAsync_CancellationRequestedBeforeConnect_ThrowsOperatio } [ConditionalFact(nameof(WebSocketsSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63672", TestPlatforms.Browser)] public async Task ConnectAsync_CancellationRequestedInflightConnect_ThrowsOperationCanceledException() { using (var clientSocket = new ClientWebSocket()) @@ -281,6 +284,7 @@ public async Task ConnectAsync_CancellationRequestedInflightConnect_ThrowsOperat [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/63671", TestPlatforms.Browser)] public async Task ConnectAsync_CancellationRequestedAfterConnect_ThrowsOperationCanceledException() { var releaseServer = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); diff --git a/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj b/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj index 956ee4d414612..c553a385144b3 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj +++ b/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj @@ -6,14 +6,35 @@ + WasmTestOnBrowser - $(TestArchiveRoot)browseronly/ + $(TestArchiveRoot)browserornodejs/ $(TestArchiveTestsRoot)$(OSPlatformConfig)/ $(DefineConstants);TARGET_BROWSER + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs index 1f0ccd5591321..0782f9d5232e4 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/WebSocketHelper.cs @@ -125,7 +125,7 @@ public static async Task Retry(ITestOutputHelper output, Func> fun private static bool InitWebSocketSupported() { ClientWebSocket cws = null; - if (PlatformDetection.IsBrowser && !PlatformDetection.IsBrowserDomSupported) + if (PlatformDetection.IsBrowser && !PlatformDetection.IsWebSocketSupported) { return false; } diff --git a/src/libraries/System.Net.WebSockets.Client/tests/package-lock.json b/src/libraries/System.Net.WebSockets.Client/tests/package-lock.json new file mode 100644 index 0000000000000..55a66ba4d40f9 --- /dev/null +++ b/src/libraries/System.Net.WebSockets.Client/tests/package-lock.json @@ -0,0 +1,44 @@ +{ + "name": "system.net.websockets.client.tests", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "system.net.websockets.client.tests", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "ws": "^8.4.0" + } + }, + "node_modules/ws": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.0.tgz", + "integrity": "sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + }, + "dependencies": { + "ws": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.0.tgz", + "integrity": "sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ==", + "requires": {} + } + } +} diff --git a/src/libraries/System.Net.WebSockets.Client/tests/package.json b/src/libraries/System.Net.WebSockets.Client/tests/package.json new file mode 100644 index 0000000000000..cb5a738db17e5 --- /dev/null +++ b/src/libraries/System.Net.WebSockets.Client/tests/package.json @@ -0,0 +1,7 @@ +{ + "name": "system.net.websockets.client.tests", + "private": true, + "dependencies": { + "ws": "8.4.0" + } +} diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index 4348444be6299..9de96a2749fcc 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -354,6 +354,27 @@ try { console.error(e); } +if (is_node) { + const modulesToLoad = processedArguments.setenv["NPM_MODULES"]; + if (modulesToLoad) { + modulesToLoad.split(',').forEach(module => { + const parts = module.split(':'); + + let message = `Loading npm '${parts[0]}'`; + const moduleExport = require(parts[0]); + if (parts.length == 2) { + message += ` and attaching to global as '${parts[1]}'.`; + globalThis[parts[1]] = moduleExport; + } + + console.log(message); + }); + } +} + +// Must be after loading npm modules. +processedArguments.setenv["IsWebSocketSupported"] = ("WebSocket" in globalThis).toString().toLowerCase(); + async function loadDotnet(file) { let loadScript = undefined; if (typeof WScript !== "undefined") { // Chakra diff --git a/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/WebAssembly.Browser.HotReload.Test.csproj b/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/WebAssembly.Browser.HotReload.Test.csproj index f3ca0161fc5fe..7e2602501266f 100644 --- a/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/WebAssembly.Browser.HotReload.Test.csproj +++ b/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/WebAssembly.Browser.HotReload.Test.csproj @@ -5,6 +5,9 @@ false true WasmTestOnBrowser + $(TestArchiveRoot)browseronly/ + $(TestArchiveTestsRoot)$(OSPlatformConfig)/ + $(DefineConstants);TARGET_BROWSER 42 main.js false diff --git a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/WebAssembly.Browser.RuntimeConfig.Test.csproj b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/WebAssembly.Browser.RuntimeConfig.Test.csproj index d9c7984051cd3..90d9fa155b924 100644 --- a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/WebAssembly.Browser.RuntimeConfig.Test.csproj +++ b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/WebAssembly.Browser.RuntimeConfig.Test.csproj @@ -2,6 +2,9 @@ true WasmTestOnBrowser + $(TestArchiveRoot)browseronly/ + $(TestArchiveTestsRoot)$(OSPlatformConfig)/ + $(DefineConstants);TARGET_BROWSER 42 main.js From df9ba64a1cf240887867efcdd4ec595d38277bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Thu, 20 Jan 2022 14:36:09 +0100 Subject: [PATCH 087/308] Fix dependency in runtime-official.yml (#64040) After https://github.com/dotnet/runtime/pull/62564 the `hostedOs` value is included in the job name. --- eng/pipelines/runtime-official.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index 34b0ae68c78e2..1ad7ad72d3171 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -416,7 +416,7 @@ stages: - Build_Android_arm64_release_AllSubsets_Mono - Build_Android_x86_release_AllSubsets_Mono - Build_Android_x64_release_AllSubsets_Mono - - Build_Browser_wasm_release_AllSubsets_Mono + - Build_Browser_wasm_Linux_release_AllSubsets_Mono - Build_iOS_arm_release_AllSubsets_Mono - Build_iOS_arm64_release_AllSubsets_Mono - Build_iOSSimulator_x64_release_AllSubsets_Mono From cbb5b55ff60e7f6e71c80adcaccbf26d97fe2efd Mon Sep 17 00:00:00 2001 From: Robin Lindner Date: Thu, 20 Jan 2022 15:21:44 +0100 Subject: [PATCH 088/308] [API Implementation]: System.Diagnostics.CodeAnalysis.StringSyntaxAttribute (#62995) * Add StringSyntaxAttribute * Fix attribute declaration and add usage * Address PR feedback Co-authored-by: Stephen Toub --- .../Microsoft.Extensions.Logging.Console.cs | 1 + ...icrosoft.Extensions.Logging.Console.csproj | 4 ++ .../src/ConsoleFormatterOptions.cs | 2 + ...icrosoft.Extensions.Logging.Console.csproj | 8 ++- .../ref/System.ComponentModel.Annotations.cs | 2 +- .../RegularExpressionAttribute.cs | 3 +- .../ref/System.Net.WebProxy.cs | 8 +-- .../ref/System.Net.WebProxy.csproj | 3 +- .../src/System/Net/WebProxy.cs | 8 +-- .../System.Private.CoreLib.Shared.projitems | 13 +++-- .../src/System/DateTime.cs | 24 ++++---- .../src/System/DateTimeOffset.cs | 24 ++++---- .../CodeAnalysis/StringSyntaxAttribute.cs | 46 +++++++++++++++ .../src/System/Xml/XmlConvert.cs | 12 ++-- .../System.Runtime/ref/System.Runtime.cs | 58 +++++++++++-------- .../tests/System.Runtime.Tests.csproj | 1 + .../StringSyntaxAttributeTests.cs | 24 ++++++++ .../ref/System.Text.RegularExpressions.cs | 48 +++++++-------- .../Text/RegularExpressions/Regex.Match.cs | 20 ++++--- .../Text/RegularExpressions/Regex.Replace.cs | 14 +++-- .../Text/RegularExpressions/Regex.Split.cs | 7 ++- .../System/Text/RegularExpressions/Regex.cs | 6 +- .../RegexGeneratorAttribute.cs | 7 ++- .../ref/System.Xml.ReaderWriter.cs | 12 ++-- 24 files changed, 228 insertions(+), 127 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs create mode 100644 src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.cs b/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.cs index 8cac9db32a976..c315783ab58c0 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.cs @@ -41,6 +41,7 @@ public partial class ConsoleFormatterOptions { public ConsoleFormatterOptions() { } public bool IncludeScopes { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] public string TimestampFormat { get { throw null; } set { } } public bool UseUtcTimestamp { get { throw null; } set { } } } diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.csproj index ba0bf1821d39d..71aeb235fd3b0 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.csproj @@ -14,6 +14,10 @@ + + + + diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleFormatterOptions.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleFormatterOptions.cs index 0fcdd2f038ef9..e4a9800ad6e3e 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleFormatterOptions.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleFormatterOptions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; using System.Text; namespace Microsoft.Extensions.Logging.Console @@ -21,6 +22,7 @@ public ConsoleFormatterOptions() { } /// /// Gets or sets format string used to format timestamp in logging messages. Defaults to null. /// + [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] public string TimestampFormat { get; set; } /// diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj index 9256474085a47..e3bc7f50b436b 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) @@ -38,6 +38,10 @@ + + + + @@ -63,4 +67,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs b/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs index c78333ddf6433..cc7dfb6120ef1 100644 --- a/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs +++ b/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs @@ -235,7 +235,7 @@ public RangeAttribute([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMember [System.AttributeUsageAttribute(System.AttributeTargets.Field | System.AttributeTargets.Parameter | System.AttributeTargets.Property, AllowMultiple=false)] public partial class RegularExpressionAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute { - public RegularExpressionAttribute(string pattern) { } + public RegularExpressionAttribute([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern) { } public int MatchTimeoutInMilliseconds { get { throw null; } set { } } public string Pattern { get { throw null; } } public override string FormatErrorMessage(string name) { throw null; } diff --git a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RegularExpressionAttribute.cs b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RegularExpressionAttribute.cs index e7f4eb1db432e..cf2ec8a7697c2 100644 --- a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RegularExpressionAttribute.cs +++ b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RegularExpressionAttribute.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text.RegularExpressions; @@ -17,7 +18,7 @@ public class RegularExpressionAttribute : ValidationAttribute /// Constructor that accepts the regular expression pattern /// /// The regular expression to use. It cannot be null. - public RegularExpressionAttribute(string pattern) + public RegularExpressionAttribute([StringSyntax(StringSyntaxAttribute.Regex)] string pattern) : base(() => SR.RegexAttribute_ValidationError) { Pattern = pattern; diff --git a/src/libraries/System.Net.WebProxy/ref/System.Net.WebProxy.cs b/src/libraries/System.Net.WebProxy/ref/System.Net.WebProxy.cs index 99b154b7d4c6f..5c19b271bc2cb 100644 --- a/src/libraries/System.Net.WebProxy/ref/System.Net.WebProxy.cs +++ b/src/libraries/System.Net.WebProxy/ref/System.Net.WebProxy.cs @@ -18,13 +18,13 @@ public WebProxy() { } protected WebProxy(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } public WebProxy(string? Address) { } public WebProxy(string? Address, bool BypassOnLocal) { } - public WebProxy(string? Address, bool BypassOnLocal, string[]? BypassList) { } - public WebProxy(string? Address, bool BypassOnLocal, string[]? BypassList, System.Net.ICredentials? Credentials) { } + public WebProxy(string? Address, bool BypassOnLocal, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.CultureInvariant)] string[]? BypassList) { } + public WebProxy(string? Address, bool BypassOnLocal, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.CultureInvariant)] string[]? BypassList, System.Net.ICredentials? Credentials) { } public WebProxy(string Host, int Port) { } public WebProxy(System.Uri? Address) { } public WebProxy(System.Uri? Address, bool BypassOnLocal) { } - public WebProxy(System.Uri? Address, bool BypassOnLocal, string[]? BypassList) { } - public WebProxy(System.Uri? Address, bool BypassOnLocal, string[]? BypassList, System.Net.ICredentials? Credentials) { } + public WebProxy(System.Uri? Address, bool BypassOnLocal, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.CultureInvariant)] string[]? BypassList) { } + public WebProxy(System.Uri? Address, bool BypassOnLocal, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.CultureInvariant)] string[]? BypassList, System.Net.ICredentials? Credentials) { } public System.Uri? Address { get { throw null; } set { } } public System.Collections.ArrayList BypassArrayList { get { throw null; } } [System.Diagnostics.CodeAnalysis.AllowNullAttribute] diff --git a/src/libraries/System.Net.WebProxy/ref/System.Net.WebProxy.csproj b/src/libraries/System.Net.WebProxy/ref/System.Net.WebProxy.csproj index 477ecb4cfa2a3..43de764895500 100644 --- a/src/libraries/System.Net.WebProxy/ref/System.Net.WebProxy.csproj +++ b/src/libraries/System.Net.WebProxy/ref/System.Net.WebProxy.csproj @@ -11,5 +11,6 @@ + - \ No newline at end of file + diff --git a/src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs b/src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs index 7e1b3fbe01f1a..a8b9d60651d8b 100644 --- a/src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs +++ b/src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs @@ -20,9 +20,9 @@ public WebProxy(Uri? Address) : this(Address, false, null, null) { } public WebProxy(Uri? Address, bool BypassOnLocal) : this(Address, BypassOnLocal, null, null) { } - public WebProxy(Uri? Address, bool BypassOnLocal, string[]? BypassList) : this(Address, BypassOnLocal, BypassList, null) { } + public WebProxy(Uri? Address, bool BypassOnLocal, [StringSyntax(StringSyntaxAttribute.Regex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)] string[]? BypassList) : this(Address, BypassOnLocal, BypassList, null) { } - public WebProxy(Uri? Address, bool BypassOnLocal, string[]? BypassList, ICredentials? Credentials) + public WebProxy(Uri? Address, bool BypassOnLocal, [StringSyntax(StringSyntaxAttribute.Regex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)] string[]? BypassList, ICredentials? Credentials) { this.Address = Address; this.Credentials = Credentials; @@ -49,12 +49,12 @@ public WebProxy(string? Address, bool BypassOnLocal) { } - public WebProxy(string? Address, bool BypassOnLocal, string[]? BypassList) + public WebProxy(string? Address, bool BypassOnLocal, [StringSyntax(StringSyntaxAttribute.Regex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)] string[]? BypassList) : this(CreateProxyUri(Address), BypassOnLocal, BypassList, null) { } - public WebProxy(string? Address, bool BypassOnLocal, string[]? BypassList, ICredentials? Credentials) + public WebProxy(string? Address, bool BypassOnLocal, [StringSyntax(StringSyntaxAttribute.Regex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)] string[]? BypassList, ICredentials? Credentials) : this(CreateProxyUri(Address), BypassOnLocal, BypassList, Credentials) { } 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 59796633cc4db..6272743925a92 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 @@ -57,8 +57,8 @@ - - + + @@ -254,15 +254,16 @@ - - - - + + + + + diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs index 1783d197b8ab8..53a7b278fd212 100644 --- a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs +++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs @@ -1134,7 +1134,7 @@ public static DateTime Parse(ReadOnlySpan s, IFormatProvider? provider = n // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTime ParseExact(string s, string format, IFormatProvider? provider) + public static DateTime ParseExact(string s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string format, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format); @@ -1145,7 +1145,7 @@ public static DateTime ParseExact(string s, string format, IFormatProvider? prov // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTime ParseExact(string s, string format, IFormatProvider? provider, DateTimeStyles style) + public static DateTime ParseExact(string s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string format, IFormatProvider? provider, DateTimeStyles style) { DateTimeFormatInfo.ValidateStyles(style); if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); @@ -1153,20 +1153,20 @@ public static DateTime ParseExact(string s, string format, IFormatProvider? prov return DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style); } - public static DateTime ParseExact(ReadOnlySpan s, ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style = DateTimeStyles.None) + public static DateTime ParseExact(ReadOnlySpan s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style = DateTimeStyles.None) { DateTimeFormatInfo.ValidateStyles(style); return DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style); } - public static DateTime ParseExact(string s, string[] formats, IFormatProvider? provider, DateTimeStyles style) + public static DateTime ParseExact(string s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string[] formats, IFormatProvider? provider, DateTimeStyles style) { DateTimeFormatInfo.ValidateStyles(style); if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style); } - public static DateTime ParseExact(ReadOnlySpan s, string[] formats, IFormatProvider? provider, DateTimeStyles style = DateTimeStyles.None) + public static DateTime ParseExact(ReadOnlySpan s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string[] formats, IFormatProvider? provider, DateTimeStyles style = DateTimeStyles.None) { DateTimeFormatInfo.ValidateStyles(style); return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style); @@ -1282,7 +1282,7 @@ public override string ToString() return DateTimeFormat.Format(this, null, null); } - public string ToString(string? format) + public string ToString([StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string? format) { return DateTimeFormat.Format(this, format, null); } @@ -1292,12 +1292,12 @@ public string ToString(IFormatProvider? provider) return DateTimeFormat.Format(this, null, provider); } - public string ToString(string? format, IFormatProvider? provider) + public string ToString([StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string? format, IFormatProvider? provider) { return DateTimeFormat.Format(this, format, provider); } - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) => + public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) => DateTimeFormat.TryFormat(this, destination, out charsWritten, format, provider); public DateTime ToUniversalTime() @@ -1339,7 +1339,7 @@ public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, Dat return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result); } - public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true)] string? format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string? format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style); @@ -1352,13 +1352,13 @@ public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(tru return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact(ReadOnlySpan s, ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact(ReadOnlySpan s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style); return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style); @@ -1371,7 +1371,7 @@ public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(tru return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact(ReadOnlySpan s, [NotNullWhen(true)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact(ReadOnlySpan s, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style); return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs b/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs index 1d4dc7dcfa3ff..d0778363fb34f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs +++ b/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs @@ -544,7 +544,7 @@ public static DateTimeOffset Parse(ReadOnlySpan input, IFormatProvider? fo // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTimeOffset ParseExact(string input, string format, IFormatProvider? formatProvider) + public static DateTimeOffset ParseExact(string input, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string format, IFormatProvider? formatProvider) { if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format); @@ -555,7 +555,7 @@ public static DateTimeOffset ParseExact(string input, string format, IFormatProv // date and optionally a time in a culture-specific or universal format. // Leading and trailing whitespace characters are allowed. // - public static DateTimeOffset ParseExact(string input, string format, IFormatProvider? formatProvider, DateTimeStyles styles) + public static DateTimeOffset ParseExact(string input, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string format, IFormatProvider? formatProvider, DateTimeStyles styles) { styles = ValidateStyles(styles, nameof(styles)); if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); @@ -569,14 +569,14 @@ public static DateTimeOffset ParseExact(string input, string format, IFormatProv return new DateTimeOffset(dateResult.Ticks, offset); } - public static DateTimeOffset ParseExact(ReadOnlySpan input, ReadOnlySpan format, IFormatProvider? formatProvider, DateTimeStyles styles = DateTimeStyles.None) + public static DateTimeOffset ParseExact(ReadOnlySpan input, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan format, IFormatProvider? formatProvider, DateTimeStyles styles = DateTimeStyles.None) { styles = ValidateStyles(styles, nameof(styles)); DateTime dateResult = DateTimeParse.ParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, out TimeSpan offset); return new DateTimeOffset(dateResult.Ticks, offset); } - public static DateTimeOffset ParseExact(string input, string[] formats, IFormatProvider? formatProvider, DateTimeStyles styles) + public static DateTimeOffset ParseExact(string input, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string[] formats, IFormatProvider? formatProvider, DateTimeStyles styles) { styles = ValidateStyles(styles, nameof(styles)); if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); @@ -589,7 +589,7 @@ public static DateTimeOffset ParseExact(string input, string[] formats, IFormatP return new DateTimeOffset(dateResult.Ticks, offset); } - public static DateTimeOffset ParseExact(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, DateTimeStyles styles = DateTimeStyles.None) + public static DateTimeOffset ParseExact(ReadOnlySpan input, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string[] formats, IFormatProvider? formatProvider, DateTimeStyles styles = DateTimeStyles.None) { styles = ValidateStyles(styles, nameof(styles)); DateTime dateResult = DateTimeParse.ParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, out TimeSpan offset); @@ -658,16 +658,16 @@ private static DateTimeOffset ToLocalTime(DateTime utcDateTime, bool throwOnOver public override string ToString() => DateTimeFormat.Format(ClockDateTime, null, null, Offset); - public string ToString(string? format) => + public string ToString([StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string? format) => DateTimeFormat.Format(ClockDateTime, format, null, Offset); public string ToString(IFormatProvider? formatProvider) => DateTimeFormat.Format(ClockDateTime, null, formatProvider, Offset); - public string ToString(string? format, IFormatProvider? formatProvider) => + public string ToString([StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string? format, IFormatProvider? formatProvider) => DateTimeFormat.Format(ClockDateTime, format, formatProvider, Offset); - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? formatProvider = null) => + public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan format = default, IFormatProvider? formatProvider = null) => DateTimeFormat.TryFormat(ClockDateTime, destination, out charsWritten, format, formatProvider, Offset); public DateTimeOffset ToUniversalTime() => @@ -717,7 +717,7 @@ public static bool TryParse(ReadOnlySpan input, IFormatProvider? formatPro return parsed; } - public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, IFormatProvider? formatProvider, DateTimeStyles styles, + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string? format, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); @@ -738,7 +738,7 @@ public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen } public static bool TryParseExact( - ReadOnlySpan input, ReadOnlySpan format, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) + ReadOnlySpan input, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan format, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); bool parsed = DateTimeParse.TryParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset); @@ -746,7 +746,7 @@ public static bool TryParseExact( return parsed; } - public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); @@ -767,7 +767,7 @@ public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen } public static bool TryParseExact( - ReadOnlySpan input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) + ReadOnlySpan input, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); bool parsed = DateTimeParse.TryParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset); diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs new file mode 100644 index 0000000000000..5b9dbda76e5f1 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies the syntax used in a string. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class StringSyntaxAttribute : Attribute + { + /// Initializes the with the identifier of the syntax used. + /// The syntax identifier. + public StringSyntaxAttribute(string syntax) + { + Syntax = syntax; + Arguments = Array.Empty(); + } + + /// Initializes the with the identifier of the syntax used. + /// The syntax identifier. + /// Optional arguments associated with the specific syntax employed. + public StringSyntaxAttribute(string syntax, params object?[] arguments) + { + Syntax = syntax; + Arguments = arguments; + } + + /// Gets the identifier of the syntax used. + public string Syntax { get; } + + /// Optional arguments associated with the specific syntax employed. + public object?[] Arguments { get; } + + /// The syntax identifier for strings containing date and time format specifiers. + public const string DateTimeFormat = nameof(DateTimeFormat); + + /// The syntax identifier for strings containing regular expressions. + public const string Regex = nameof(Regex); + } +} diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlConvert.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlConvert.cs index 7f2e13f22e52e..ed42e646f8df2 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlConvert.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlConvert.cs @@ -755,7 +755,7 @@ public static string ToString(DateTime value) return ToString(value, "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz"); } - public static string ToString(DateTime value, string format) + public static string ToString(DateTime value, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string format) { return value.ToString(format, DateTimeFormatInfo.InvariantInfo); } @@ -793,7 +793,7 @@ public static string ToString(DateTimeOffset value) return xsdDateTime.ToString(); } - public static string ToString(DateTimeOffset value, string format) + public static string ToString(DateTimeOffset value, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string format) { return value.ToString(format, DateTimeFormatInfo.InvariantInfo); } @@ -1250,12 +1250,12 @@ public static DateTime ToDateTime(string s) return ToDateTime(s, AllDateTimeFormats); } - public static DateTime ToDateTime(string s, string format) + public static DateTime ToDateTime(string s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string format) { return DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite); } - public static DateTime ToDateTime(string s, string[] formats) + public static DateTime ToDateTime(string s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string[] formats) { return DateTime.ParseExact(s, formats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite); } @@ -1299,7 +1299,7 @@ public static DateTimeOffset ToDateTimeOffset(string s) return dateTimeOffset; } - public static DateTimeOffset ToDateTimeOffset(string s, string format) + public static DateTimeOffset ToDateTimeOffset(string s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string format) { if (s == null) { @@ -1308,7 +1308,7 @@ public static DateTimeOffset ToDateTimeOffset(string s, string format) return DateTimeOffset.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite); } - public static DateTimeOffset ToDateTimeOffset(string s, string[] formats) + public static DateTimeOffset ToDateTimeOffset(string s, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string[] formats) { if (s == null) { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 27cbc4c98d261..851f9dcc38714 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -1774,11 +1774,11 @@ public static partial class Convert public static System.DateTime Parse(string s) { throw null; } public static System.DateTime Parse(string s, System.IFormatProvider? provider) { throw null; } public static System.DateTime Parse(string s, System.IFormatProvider? provider, System.Globalization.DateTimeStyles styles) { throw null; } - public static System.DateTime ParseExact(System.ReadOnlySpan s, System.ReadOnlySpan format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style = System.Globalization.DateTimeStyles.None) { throw null; } - public static System.DateTime ParseExact(System.ReadOnlySpan s, string[] formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style = System.Globalization.DateTimeStyles.None) { throw null; } - public static System.DateTime ParseExact(string s, string format, System.IFormatProvider? provider) { throw null; } - public static System.DateTime ParseExact(string s, string format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style) { throw null; } - public static System.DateTime ParseExact(string s, string[] formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style) { throw null; } + public static System.DateTime ParseExact(System.ReadOnlySpan s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] System.ReadOnlySpan format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style = System.Globalization.DateTimeStyles.None) { throw null; } + public static System.DateTime ParseExact(System.ReadOnlySpan s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string[] formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style = System.Globalization.DateTimeStyles.None) { throw null; } + public static System.DateTime ParseExact(string s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string format, System.IFormatProvider? provider) { throw null; } + public static System.DateTime ParseExact(string s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style) { throw null; } + public static System.DateTime ParseExact(string s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string[] formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style) { throw null; } public static System.DateTime SpecifyKind(System.DateTime value, System.DateTimeKind kind) { throw null; } public System.TimeSpan Subtract(System.DateTime value) { throw null; } public System.DateTime Subtract(System.TimeSpan value) { throw null; } @@ -1809,18 +1809,18 @@ void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Ser public string ToShortTimeString() { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } - public string ToString(string? format) { throw null; } - public string ToString(string? format, System.IFormatProvider? provider) { throw null; } + public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string? format) { throw null; } + public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string? format, System.IFormatProvider? provider) { throw null; } public System.DateTime ToUniversalTime() { throw null; } - public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } + public bool TryFormat(System.Span destination, out int charsWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.DateTime result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, System.Globalization.DateTimeStyles styles, out System.DateTime result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.DateTime result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, System.Globalization.DateTimeStyles styles, out System.DateTime result) { throw null; } - public static bool TryParseExact(System.ReadOnlySpan s, System.ReadOnlySpan format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } - public static bool TryParseExact(System.ReadOnlySpan s, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } - public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } - public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } + public static bool TryParseExact(System.ReadOnlySpan s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] System.ReadOnlySpan format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } + public static bool TryParseExact(System.ReadOnlySpan s, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true), System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string?[]? formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true), System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string? format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true), System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string?[]? formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } #if FEATURE_GENERIC_MATH [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute("Generic Math is in preview.", Url = "https://aka.ms/dotnet-warnings/generic-math-preview")] @@ -1944,11 +1944,11 @@ public enum DateTimeKind public static System.DateTimeOffset Parse(string input) { throw null; } public static System.DateTimeOffset Parse(string input, System.IFormatProvider? formatProvider) { throw null; } public static System.DateTimeOffset Parse(string input, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles) { throw null; } - public static System.DateTimeOffset ParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles = System.Globalization.DateTimeStyles.None) { throw null; } - public static System.DateTimeOffset ParseExact(System.ReadOnlySpan input, string[] formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles = System.Globalization.DateTimeStyles.None) { throw null; } - public static System.DateTimeOffset ParseExact(string input, string format, System.IFormatProvider? formatProvider) { throw null; } - public static System.DateTimeOffset ParseExact(string input, string format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles) { throw null; } - public static System.DateTimeOffset ParseExact(string input, string[] formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles) { throw null; } + public static System.DateTimeOffset ParseExact(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] System.ReadOnlySpan format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles = System.Globalization.DateTimeStyles.None) { throw null; } + public static System.DateTimeOffset ParseExact(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string[] formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles = System.Globalization.DateTimeStyles.None) { throw null; } + public static System.DateTimeOffset ParseExact(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string format, System.IFormatProvider? formatProvider) { throw null; } + public static System.DateTimeOffset ParseExact(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles) { throw null; } + public static System.DateTimeOffset ParseExact(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string[] formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles) { throw null; } public System.TimeSpan Subtract(System.DateTimeOffset value) { throw null; } public System.DateTimeOffset Subtract(System.TimeSpan value) { throw null; } int System.IComparable.CompareTo(object? obj) { throw null; } @@ -1959,20 +1959,20 @@ void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Ser public System.DateTimeOffset ToOffset(System.TimeSpan offset) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? formatProvider) { throw null; } - public string ToString(string? format) { throw null; } - public string ToString(string? format, System.IFormatProvider? formatProvider) { throw null; } + public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string? format) { throw null; } + public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string? format, System.IFormatProvider? formatProvider) { throw null; } public System.DateTimeOffset ToUniversalTime() { throw null; } public long ToUnixTimeMilliseconds() { throw null; } public long ToUnixTimeSeconds() { throw null; } - public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? formatProvider = null) { throw null; } + public bool TryFormat(System.Span destination, out int charsWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? formatProvider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan input, out System.DateTimeOffset result) { throw null; } public static bool TryParse(System.ReadOnlySpan input, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, out System.DateTimeOffset result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } - public static bool TryParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } - public static bool TryParseExact(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } - public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } - public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } + public static bool TryParseExact(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] System.ReadOnlySpan format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } + public static bool TryParseExact(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true), System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true), System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string? format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true), System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } #if FEATURE_GENERIC_MATH [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute("Generic Math is in preview.", Url = "https://aka.ms/dotnet-warnings/generic-math-preview")] @@ -9179,6 +9179,16 @@ public RequiresUnreferencedCodeAttribute(string message) { } public string Message { get { throw null; } } public string? Url { get { throw null; } set { } } } + [System.AttributeUsageAttribute(System.AttributeTargets.Parameter | System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + public sealed partial class StringSyntaxAttribute : System.Attribute + { + public StringSyntaxAttribute(string syntax) { } + public StringSyntaxAttribute(string syntax, params object?[] arguments) { } + public string Syntax { get { throw null; } } + public object?[] Arguments { get { throw null; } } + public const string DateTimeFormat = "DateTimeFormat"; + public const string Regex = "Regex"; + } [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.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index 801f04ca42ea9..3ef404493078e 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -62,6 +62,7 @@ + diff --git a/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs new file mode 100644 index 0000000000000..2dde50c727a3f --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.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. + +using Xunit; + +namespace System.Diagnostics.CodeAnalysis.Tests +{ + public sealed class StringSyntaxAttributeTests + { + [Theory] + [InlineData(StringSyntaxAttribute.DateTimeFormat)] + [InlineData(StringSyntaxAttribute.Regex)] + public void Ctor_Roundtrips(string syntax) + { + var attribute = new StringSyntaxAttribute(syntax); + Assert.Equal(syntax, attribute.Syntax); + Assert.Empty(attribute.Arguments); + + attribute = new StringSyntaxAttribute(syntax, "a", DayOfWeek.Monday); + Assert.Equal(syntax, attribute.Syntax); + Assert.Equal(new object[] { "a", DayOfWeek.Monday }, attribute.Arguments); + } + } +} diff --git a/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs b/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs index 9c0062d5b810c..75ed12a69731f 100644 --- a/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs +++ b/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs @@ -142,9 +142,9 @@ public partial class Regex : System.Runtime.Serialization.ISerializable protected internal System.Text.RegularExpressions.RegexOptions roptions; protected Regex() { } protected Regex(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } - public Regex(string pattern) { } - public Regex(string pattern, System.Text.RegularExpressions.RegexOptions options) { } - public Regex(string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { } + public Regex([System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern) { } + public Regex([System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options) { } + public Regex([System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { } public static int CacheSize { get { throw null; } set { } } [System.CLSCompliantAttribute(false)] [System.Diagnostics.CodeAnalysis.DisallowNullAttribute] @@ -169,38 +169,38 @@ public static void CompileToAssembly(System.Text.RegularExpressions.RegexCompila protected void InitializeReferences() { } public bool IsMatch(string input) { throw null; } public bool IsMatch(string input, int startat) { throw null; } - public static bool IsMatch(string input, string pattern) { throw null; } - public static bool IsMatch(string input, string pattern, System.Text.RegularExpressions.RegexOptions options) { throw null; } - public static bool IsMatch(string input, string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } + public static bool IsMatch(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern) { throw null; } + public static bool IsMatch(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options) { throw null; } + public static bool IsMatch(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } public System.Text.RegularExpressions.Match Match(string input) { throw null; } public System.Text.RegularExpressions.Match Match(string input, int startat) { throw null; } public System.Text.RegularExpressions.Match Match(string input, int beginning, int length) { throw null; } - public static System.Text.RegularExpressions.Match Match(string input, string pattern) { throw null; } - public static System.Text.RegularExpressions.Match Match(string input, string pattern, System.Text.RegularExpressions.RegexOptions options) { throw null; } - public static System.Text.RegularExpressions.Match Match(string input, string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } + public static System.Text.RegularExpressions.Match Match(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern) { throw null; } + public static System.Text.RegularExpressions.Match Match(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options) { throw null; } + public static System.Text.RegularExpressions.Match Match(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } public System.Text.RegularExpressions.MatchCollection Matches(string input) { throw null; } public System.Text.RegularExpressions.MatchCollection Matches(string input, int startat) { throw null; } - public static System.Text.RegularExpressions.MatchCollection Matches(string input, string pattern) { throw null; } - public static System.Text.RegularExpressions.MatchCollection Matches(string input, string pattern, System.Text.RegularExpressions.RegexOptions options) { throw null; } - public static System.Text.RegularExpressions.MatchCollection Matches(string input, string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } + public static System.Text.RegularExpressions.MatchCollection Matches(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern) { throw null; } + public static System.Text.RegularExpressions.MatchCollection Matches(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options) { throw null; } + public static System.Text.RegularExpressions.MatchCollection Matches(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } public string Replace(string input, string replacement) { throw null; } public string Replace(string input, string replacement, int count) { throw null; } public string Replace(string input, string replacement, int count, int startat) { throw null; } - public static string Replace(string input, string pattern, string replacement) { throw null; } - public static string Replace(string input, string pattern, string replacement, System.Text.RegularExpressions.RegexOptions options) { throw null; } - public static string Replace(string input, string pattern, string replacement, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } - public static string Replace(string input, string pattern, System.Text.RegularExpressions.MatchEvaluator evaluator) { throw null; } - public static string Replace(string input, string pattern, System.Text.RegularExpressions.MatchEvaluator evaluator, System.Text.RegularExpressions.RegexOptions options) { throw null; } - public static string Replace(string input, string pattern, System.Text.RegularExpressions.MatchEvaluator evaluator, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } + public static string Replace(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern, string replacement) { throw null; } + public static string Replace(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, string replacement, System.Text.RegularExpressions.RegexOptions options) { throw null; } + public static string Replace(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, string replacement, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } + public static string Replace(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern, System.Text.RegularExpressions.MatchEvaluator evaluator) { throw null; } + public static string Replace(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.MatchEvaluator evaluator, System.Text.RegularExpressions.RegexOptions options) { throw null; } + public static string Replace(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.MatchEvaluator evaluator, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } public string Replace(string input, System.Text.RegularExpressions.MatchEvaluator evaluator) { throw null; } public string Replace(string input, System.Text.RegularExpressions.MatchEvaluator evaluator, int count) { throw null; } public string Replace(string input, System.Text.RegularExpressions.MatchEvaluator evaluator, int count, int startat) { throw null; } public string[] Split(string input) { throw null; } public string[] Split(string input, int count) { throw null; } public string[] Split(string input, int count, int startat) { throw null; } - public static string[] Split(string input, string pattern) { throw null; } - public static string[] Split(string input, string pattern, System.Text.RegularExpressions.RegexOptions options) { throw null; } - public static string[] Split(string input, string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } + public static string[] Split(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern) { throw null; } + public static string[] Split(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options) { throw null; } + public static string[] Split(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo si, System.Runtime.Serialization.StreamingContext context) { } public override string ToString() { throw null; } public static string Unescape(string str) { throw null; } @@ -223,9 +223,9 @@ public RegexCompilationInfo(string pattern, System.Text.RegularExpressions.Regex [System.AttributeUsageAttribute(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public sealed partial class RegexGeneratorAttribute : System.Attribute { - public RegexGeneratorAttribute(string pattern) { } - public RegexGeneratorAttribute(string pattern, System.Text.RegularExpressions.RegexOptions options) { } - public RegexGeneratorAttribute(string pattern, System.Text.RegularExpressions.RegexOptions options, int matchTimeoutMilliseconds) { } + public RegexGeneratorAttribute([System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern) { } + public RegexGeneratorAttribute([System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options) { } + public RegexGeneratorAttribute([System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options, int matchTimeoutMilliseconds) { } public string Pattern { get; } public System.Text.RegularExpressions.RegexOptions Options { get; } public int MatchTimeoutMilliseconds { get; } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Match.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Match.cs index 0770ba90cd216..cd0494c3dc009 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Match.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Match.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace System.Text.RegularExpressions { public partial class Regex @@ -8,7 +10,7 @@ public partial class Regex /// /// Searches the input string for one or more occurrences of the text supplied in the given pattern. /// - public static bool IsMatch(string input, string pattern) => + public static bool IsMatch(string input, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern) => RegexCache.GetOrAdd(pattern).IsMatch(input); /// @@ -16,10 +18,10 @@ public static bool IsMatch(string input, string pattern) => /// supplied in the pattern parameter with matching options supplied in the options /// parameter. /// - public static bool IsMatch(string input, string pattern, RegexOptions options) => + public static bool IsMatch(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options) => RegexCache.GetOrAdd(pattern, options, s_defaultMatchTimeout).IsMatch(input); - public static bool IsMatch(string input, string pattern, RegexOptions options, TimeSpan matchTimeout) => + public static bool IsMatch(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options, TimeSpan matchTimeout) => RegexCache.GetOrAdd(pattern, options, matchTimeout).IsMatch(input); /// @@ -54,7 +56,7 @@ public bool IsMatch(string input, int startat) /// Searches the input string for one or more occurrences of the text /// supplied in the pattern parameter. /// - public static Match Match(string input, string pattern) => + public static Match Match(string input, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern) => RegexCache.GetOrAdd(pattern).Match(input); /// @@ -62,10 +64,10 @@ public static Match Match(string input, string pattern) => /// supplied in the pattern parameter. Matching is modified with an option /// string. /// - public static Match Match(string input, string pattern, RegexOptions options) => + public static Match Match(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options) => RegexCache.GetOrAdd(pattern, options, s_defaultMatchTimeout).Match(input); - public static Match Match(string input, string pattern, RegexOptions options, TimeSpan matchTimeout) => + public static Match Match(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options, TimeSpan matchTimeout) => RegexCache.GetOrAdd(pattern, options, matchTimeout).Match(input); /// @@ -112,16 +114,16 @@ public Match Match(string input, int beginning, int length) /// /// Returns all the successful matches as if Match were called iteratively numerous times. /// - public static MatchCollection Matches(string input, string pattern) => + public static MatchCollection Matches(string input, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern) => RegexCache.GetOrAdd(pattern).Matches(input); /// /// Returns all the successful matches as if Match were called iteratively numerous times. /// - public static MatchCollection Matches(string input, string pattern, RegexOptions options) => + public static MatchCollection Matches(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options) => RegexCache.GetOrAdd(pattern, options, s_defaultMatchTimeout).Matches(input); - public static MatchCollection Matches(string input, string pattern, RegexOptions options, TimeSpan matchTimeout) => + public static MatchCollection Matches(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options, TimeSpan matchTimeout) => RegexCache.GetOrAdd(pattern, options, matchTimeout).Matches(input); /// diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs index 1b048fc687506..ba1f9a91e4449 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace System.Text.RegularExpressions { // Callback class @@ -14,7 +16,7 @@ public partial class Regex /// Replaces all occurrences of the pattern with the pattern, starting at /// the first character in the input string. /// - public static string Replace(string input, string pattern, string replacement) => + public static string Replace(string input, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern, string replacement) => RegexCache.GetOrAdd(pattern).Replace(input, replacement); /// @@ -22,10 +24,10 @@ public static string Replace(string input, string pattern, string replacement) = /// the with the /// pattern, starting at the first character in the input string. /// - public static string Replace(string input, string pattern, string replacement, RegexOptions options) => + public static string Replace(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, string replacement, RegexOptions options) => RegexCache.GetOrAdd(pattern, options, s_defaultMatchTimeout).Replace(input, replacement); - public static string Replace(string input, string pattern, string replacement, RegexOptions options, TimeSpan matchTimeout) => + public static string Replace(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, string replacement, RegexOptions options, TimeSpan matchTimeout) => RegexCache.GetOrAdd(pattern, options, matchTimeout).Replace(input, replacement); /// @@ -85,17 +87,17 @@ public string Replace(string input, string replacement, int count, int startat) /// Replaces all occurrences of the with the recent /// replacement pattern. /// - public static string Replace(string input, string pattern, MatchEvaluator evaluator) => + public static string Replace(string input, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern, MatchEvaluator evaluator) => RegexCache.GetOrAdd(pattern).Replace(input, evaluator); /// /// Replaces all occurrences of the with the recent /// replacement pattern, starting at the first character. /// - public static string Replace(string input, string pattern, MatchEvaluator evaluator, RegexOptions options) => + public static string Replace(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, MatchEvaluator evaluator, RegexOptions options) => RegexCache.GetOrAdd(pattern, options, s_defaultMatchTimeout).Replace(input, evaluator); - public static string Replace(string input, string pattern, MatchEvaluator evaluator, RegexOptions options, TimeSpan matchTimeout) => + public static string Replace(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, MatchEvaluator evaluator, RegexOptions options, TimeSpan matchTimeout) => RegexCache.GetOrAdd(pattern, options, matchTimeout).Replace(input, evaluator); /// diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs index f223c4e6ed97d..454aeacfa6df6 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace System.Text.RegularExpressions { @@ -11,16 +12,16 @@ public partial class Regex /// Splits the string at the position defined /// by . /// - public static string[] Split(string input, string pattern) => + public static string[] Split(string input, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern) => RegexCache.GetOrAdd(pattern).Split(input); /// /// Splits the string at the position defined by . /// - public static string[] Split(string input, string pattern, RegexOptions options) => + public static string[] Split(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options) => RegexCache.GetOrAdd(pattern, options, s_defaultMatchTimeout).Split(input); - public static string[] Split(string input, string pattern, RegexOptions options, TimeSpan matchTimeout) => + public static string[] Split(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options, TimeSpan matchTimeout) => RegexCache.GetOrAdd(pattern, options, matchTimeout).Split(input); /// diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs index 9d108abfb8f02..f34cc2329d291 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs @@ -42,7 +42,7 @@ protected Regex() /// /// Creates a regular expression object for the specified regular expression. /// - public Regex(string pattern) : + public Regex([StringSyntax(StringSyntaxAttribute.Regex)] string pattern) : this(pattern, culture: null) { } @@ -50,12 +50,12 @@ public Regex(string pattern) : /// /// Creates a regular expression object for the specified regular expression, with options that modify the pattern. /// - public Regex(string pattern, RegexOptions options) : + public Regex([StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options) : this(pattern, options, s_defaultMatchTimeout, culture: null) { } - public Regex(string pattern, RegexOptions options, TimeSpan matchTimeout) : + public Regex([StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options, TimeSpan matchTimeout) : this(pattern, options, matchTimeout, culture: null) { } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGeneratorAttribute.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGeneratorAttribute.cs index 5b55a41c4cad8..827a43fc2dbfb 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGeneratorAttribute.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGeneratorAttribute.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using System.Threading; namespace System.Text.RegularExpressions; @@ -12,14 +13,14 @@ public sealed class RegexGeneratorAttribute : Attribute { /// Initializes a new instance of the with the specified pattern. /// The regular expression pattern to match. - public RegexGeneratorAttribute(string pattern) : this (pattern, RegexOptions.None) + public RegexGeneratorAttribute([StringSyntax(StringSyntaxAttribute.Regex)] string pattern) : this (pattern, RegexOptions.None) { } /// Initializes a new instance of the with the specified pattern and options. /// The regular expression pattern to match. /// A bitwise combination of the enumeration values that modify the regular expression. - public RegexGeneratorAttribute(string pattern, RegexOptions options) : this (pattern, options, Timeout.Infinite) + public RegexGeneratorAttribute([StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options) : this (pattern, options, Timeout.Infinite) { } @@ -27,7 +28,7 @@ public RegexGeneratorAttribute(string pattern, RegexOptions options) : this (pat /// The regular expression pattern to match. /// A bitwise combination of the enumeration values that modify the regular expression. /// A time-out interval (milliseconds), or to indicate that the method should not time out. - public RegexGeneratorAttribute(string pattern, RegexOptions options, int matchTimeoutMilliseconds) + public RegexGeneratorAttribute([StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options, int matchTimeoutMilliseconds) { Pattern = pattern; Options = options; diff --git a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs index a576ee8439dfe..d894d797c2f46 100644 --- a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs +++ b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs @@ -216,12 +216,12 @@ public XmlConvert() { } public static char ToChar(string s) { throw null; } [System.ObsoleteAttribute("Use XmlConvert.ToDateTime() that accepts an XmlDateTimeSerializationMode instead.")] public static System.DateTime ToDateTime(string s) { throw null; } - public static System.DateTime ToDateTime(string s, string format) { throw null; } - public static System.DateTime ToDateTime(string s, string[] formats) { throw null; } + public static System.DateTime ToDateTime(string s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string format) { throw null; } + public static System.DateTime ToDateTime(string s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string[] formats) { throw null; } public static System.DateTime ToDateTime(string s, System.Xml.XmlDateTimeSerializationMode dateTimeOption) { throw null; } public static System.DateTimeOffset ToDateTimeOffset(string s) { throw null; } - public static System.DateTimeOffset ToDateTimeOffset(string s, string format) { throw null; } - public static System.DateTimeOffset ToDateTimeOffset(string s, string[] formats) { throw null; } + public static System.DateTimeOffset ToDateTimeOffset(string s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string format) { throw null; } + public static System.DateTimeOffset ToDateTimeOffset(string s, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string[] formats) { throw null; } public static decimal ToDecimal(string s) { throw null; } public static double ToDouble(string s) { throw null; } public static System.Guid ToGuid(string s) { throw null; } @@ -236,10 +236,10 @@ public XmlConvert() { } public static string ToString(char value) { throw null; } [System.ObsoleteAttribute("Use XmlConvert.ToString() that accepts an XmlDateTimeSerializationMode instead.")] public static string ToString(System.DateTime value) { throw null; } - public static string ToString(System.DateTime value, string format) { throw null; } + public static string ToString(System.DateTime value, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string format) { throw null; } public static string ToString(System.DateTime value, System.Xml.XmlDateTimeSerializationMode dateTimeOption) { throw null; } public static string ToString(System.DateTimeOffset value) { throw null; } - public static string ToString(System.DateTimeOffset value, string format) { throw null; } + public static string ToString(System.DateTimeOffset value, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.DateTimeFormat)] string format) { throw null; } public static string ToString(decimal value) { throw null; } public static string ToString(double value) { throw null; } public static string ToString(System.Guid value) { throw null; } From bc359a8922be4ecf6e66a9344892a3091e62b7ef Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Thu, 20 Jan 2022 08:22:20 -0800 Subject: [PATCH 089/308] Reduce the memory footprint of HttpHeaders (#62981) * Change HttpHeaders backing store to an array * Reduce the size of HeaderDescriptor to 1 object * Update UnitTests, fix GetOrCreateHeaderInfo * Switch to a dictionary after ArrayThreshold headers * Add unit tests * Use storeValueRef naming consistently * Workaround field layout regression (#63005) * Mark _descriptor on HeaderDescriptor as nullable * Remove HeaderDescriptor.Descriptor and add HasValue, IsKnownHeader, Equals * Simplify HttpHeaderParser.Separator logic * Add comments on HasValue checks * Lazily group headers by name * Add a header ordering+grouping test * Make use of the _count field * Revert all HeaderDescriptor changes from PR * Switch back to always grouping by name * Assert that the collection is not empty in GetEnumeratorCore * Optimize AddHeaders for empty collections * Reference the Roslyn bug issue * Assert that multiValues are never empty * Don't preserve a Dictionary across Clear * Add comment about why a custom HeaderEntry type is used --- .../System/Net/Http/Headers/HttpHeaders.cs | 574 +++++++++++++----- .../Http/Headers/HttpHeadersNonValidated.cs | 37 +- .../SocketsHttpHandler/Http2Connection.cs | 9 +- .../SocketsHttpHandler/Http3RequestStream.cs | 9 +- .../Http/SocketsHttpHandler/HttpConnection.cs | 10 +- .../UnitTests/HPack/HPackRoundtripTests.cs | 2 +- .../UnitTests/Headers/HttpHeadersTest.cs | 162 +++++ 7 files changed, 604 insertions(+), 199 deletions(-) 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 ee53b9e626c75..3eae142edcd4c 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 @@ -5,11 +5,28 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; namespace System.Net.Http.Headers { + /// + /// Key/value pairs of headers. The value is either a raw or a . + /// We're using a custom type instead of because we need ref access to fields. + /// + internal struct HeaderEntry + { + public HeaderDescriptor Key; + public object Value; + + public HeaderEntry(HeaderDescriptor key, object value) + { + Key = key; + Value = value; + } + } + public abstract class HttpHeaders : IEnumerable>> { // This type is used to store a collection of headers in 'headerStore': @@ -32,8 +49,9 @@ public abstract class HttpHeaders : IEnumerableKey/value pairs of headers. The value is either a raw or a . - private Dictionary? _headerStore; + /// Either a array or a Dictionary<, > + private object? _headerStore; + private int _count; private readonly HttpHeaderType _allowedHeaderTypes; private readonly HttpHeaderType _treatAsCustomHeaderTypes; @@ -52,8 +70,6 @@ internal HttpHeaders(HttpHeaderType allowedHeaderTypes, HttpHeaderType treatAsCu _treatAsCustomHeaderTypes = treatAsCustomHeaderTypes & ~HttpHeaderType.NonTrailing; } - internal Dictionary? HeaderStore => _headerStore; - /// Gets a view of the contents of this headers collection that does not parse nor validate the data upon access. public HttpHeadersNonValidated NonValidated => new HttpHeadersNonValidated(this); @@ -71,7 +87,8 @@ internal void Add(HeaderDescriptor descriptor, string? value) // it to the store if we added at least one value. if (addToStore && (info.ParsedValue != null)) { - AddHeaderToStore(descriptor, info); + Debug.Assert(!ContainsKey(descriptor)); + AddEntryToStore(new HeaderEntry(descriptor, info)); } } @@ -104,7 +121,8 @@ internal void Add(HeaderDescriptor descriptor, IEnumerable values) // However, if all values for a _new_ header were invalid, then don't add the header. if (addToStore && (info.ParsedValue != null)) { - AddHeaderToStore(descriptor, info); + Debug.Assert(!ContainsKey(descriptor)); + AddEntryToStore(new HeaderEntry(descriptor, info)); } } } @@ -120,29 +138,24 @@ internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, string? value // values, e.g. adding two null-strings (or empty, or whitespace-only) results in "My-Header: ,". value ??= string.Empty; - // Ensure the header store dictionary has been created. - _headerStore ??= new Dictionary(); + ref object? storeValueRef = ref GetValueRefOrAddDefault(descriptor); + object? currentValue = storeValueRef; - if (_headerStore.TryGetValue(descriptor, out object? currentValue)) + if (currentValue is null) { - if (currentValue is HeaderStoreItemInfo info) - { - // The header store already contained a HeaderStoreItemInfo, so add to it. - AddRawValue(info, value); - } - else + storeValueRef = value; + } + else + { + if (currentValue is not HeaderStoreItemInfo info) { // The header store contained a single raw string value, so promote it // to being a HeaderStoreItemInfo and add to it. Debug.Assert(currentValue is string); - _headerStore[descriptor] = info = new HeaderStoreItemInfo() { RawValue = currentValue }; - AddRawValue(info, value); + storeValueRef = info = new HeaderStoreItemInfo() { RawValue = currentValue }; } - } - else - { - // The header store did not contain the header. Add the raw string. - _headerStore.Add(descriptor, value); + + AddRawValue(info, value); } return true; @@ -159,28 +172,33 @@ internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, IEnumerable enumerator = values.GetEnumerator()) + using IEnumerator enumerator = values.GetEnumerator(); + if (enumerator.MoveNext()) { + TryAddWithoutValidation(descriptor, enumerator.Current); if (enumerator.MoveNext()) { - TryAddWithoutValidation(descriptor, enumerator.Current); - if (enumerator.MoveNext()) + ref object? storeValueRef = ref GetValueRefOrAddDefault(descriptor); + Debug.Assert(storeValueRef is not null); + + object value = storeValueRef; + if (value is not HeaderStoreItemInfo info) { - HeaderStoreItemInfo info = GetOrCreateHeaderInfo(descriptor, parseRawValues: false); - do - { - AddRawValue(info, enumerator.Current ?? string.Empty); - } - while (enumerator.MoveNext()); + Debug.Assert(value is string); + storeValueRef = info = new HeaderStoreItemInfo { RawValue = value }; } + + do + { + AddRawValue(info, enumerator.Current ?? string.Empty); + } + while (enumerator.MoveNext()); } } return true; } - public void Clear() => _headerStore?.Clear(); - public IEnumerable GetValues(string name) => GetValues(GetHeaderDescriptor(name)); internal IEnumerable GetValues(HeaderDescriptor descriptor) @@ -206,7 +224,7 @@ public bool TryGetValues(string name, [NotNullWhen(true)] out IEnumerable? values) { - if (_headerStore != null && TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) + if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) { values = GetStoreValuesAsStringArray(descriptor, info); return true; @@ -223,7 +241,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 newline chars, we remove the header). So try to parse the // header value. - return _headerStore != null && TryGetAndParseHeaderInfo(descriptor, out _); + return TryGetAndParseHeaderInfo(descriptor, out _); } public override string ToString() @@ -235,35 +253,34 @@ public override string ToString() var vsb = new ValueStringBuilder(stackalloc char[512]); - if (_headerStore is Dictionary headerStore) + foreach (HeaderEntry entry in GetEntries()) { - foreach (KeyValuePair header in headerStore) - { - vsb.Append(header.Key.Name); - vsb.Append(": "); + vsb.Append(entry.Key.Name); + vsb.Append(": "); - GetStoreValuesAsStringOrStringArray(header.Key, header.Value, out string? singleValue, out string[]? multiValue); - Debug.Assert(singleValue is not null ^ multiValue is not null); + GetStoreValuesAsStringOrStringArray(entry.Key, entry.Value, out string? singleValue, out string[]? multiValue); + Debug.Assert(singleValue is not null ^ multiValue is not null); - if (singleValue is not null) - { - vsb.Append(singleValue); - } - else - { - // 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 = header.Key.Parser is HttpHeaderParser parser && parser.SupportsMultipleValues ? parser.Separator : HttpHeaderParser.DefaultSeparator; + if (singleValue is not null) + { + vsb.Append(singleValue); + } + else + { + // 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 = entry.Key.Parser is HttpHeaderParser parser && parser.SupportsMultipleValues ? parser.Separator : HttpHeaderParser.DefaultSeparator; - for (int i = 0; i < multiValue!.Length; i++) - { - if (i != 0) vsb.Append(separator); - vsb.Append(multiValue[i]); - } + Debug.Assert(multiValue is not null && multiValue.Length > 0); + vsb.Append(multiValue[0]); + for (int i = 1; i < multiValue.Length; i++) + { + vsb.Append(separator); + vsb.Append(multiValue[i]); } - - vsb.Append(Environment.NewLine); } + + vsb.Append(Environment.NewLine); } return vsb.ToString(); @@ -292,39 +309,57 @@ internal string GetHeaderString(HeaderDescriptor descriptor) #region IEnumerable>> Members - public IEnumerator>> GetEnumerator() => _headerStore != null && _headerStore.Count > 0 ? - GetEnumeratorCore() : - ((IEnumerable>>)Array.Empty>>()).GetEnumerator(); + public IEnumerator>> GetEnumerator() => _count == 0 ? + ((IEnumerable>>)Array.Empty>>()).GetEnumerator() : + GetEnumeratorCore(); private IEnumerator>> GetEnumeratorCore() { - foreach (KeyValuePair header in _headerStore!) + HeaderEntry[]? entries = GetEntriesArray(); + Debug.Assert(_count != 0 && entries is not null, "Caller should have validated the collection is not empty"); + + int count = _count; + for (int i = 0; i < count; i++) { - HeaderDescriptor descriptor = header.Key; - object value = header.Value; + HeaderEntry entry = entries[i]; - HeaderStoreItemInfo? info = value as HeaderStoreItemInfo; - if (info is null) + if (entry.Value is not HeaderStoreItemInfo info) { // To retain consistent semantics, we need to upgrade a raw string to a HeaderStoreItemInfo // during enumeration so that we can parse the raw value in order to a) return // the correct set of parsed values, and b) update the instance for subsequent enumerations // to reflect that parsing. - _headerStore[descriptor] = info = new HeaderStoreItemInfo() { RawValue = value }; + info = new HeaderStoreItemInfo() { RawValue = entry.Value }; + + if (EntriesAreLiveView) + { + entries[i].Value = info; + } + else + { + Debug.Assert(ContainsKey(entry.Key)); + ((Dictionary)_headerStore!)[entry.Key] = info; + } } // Make sure we parse all raw values before returning the result. Note that this has to be // done before we calculate the array length (next line): A raw value may contain a list of // values. - if (!ParseRawHeaderValues(descriptor, info, removeEmptyHeader: false)) + if (!ParseRawHeaderValues(entry.Key, info)) { - // We have an invalid header value (contains newline chars). Delete it. - _headerStore.Remove(descriptor); + // We saw an invalid header value (contains newline chars) and deleted it. + + // If the HeaderEntry[] we are enumerating is the live header store, the entries have shifted. + if (EntriesAreLiveView) + { + i--; + count--; + } } else { - string[] values = GetStoreValuesAsStringArray(descriptor, info); - yield return new KeyValuePair>(descriptor.Name, values); + string[] values = GetStoreValuesAsStringArray(entry.Key, info); + yield return new KeyValuePair>(entry.Key.Name, values); } } } @@ -342,7 +377,7 @@ internal void AddParsedValue(HeaderDescriptor descriptor, object value) Debug.Assert(value != null); Debug.Assert(descriptor.Parser != null, "Can't add parsed value if there is no parser available."); - HeaderStoreItemInfo info = GetOrCreateHeaderInfo(descriptor, parseRawValues: true); + HeaderStoreItemInfo info = GetOrCreateHeaderInfo(descriptor); // If the current header has only one value, we can't add another value. The strongly typed property // must not call AddParsedValue(), but SetParsedValue(). E.g. for headers like 'Date', 'Host'. @@ -358,7 +393,7 @@ internal void SetParsedValue(HeaderDescriptor descriptor, object value) // This method will first clear all values. This is used e.g. when setting the 'Date' or 'Host' header. // i.e. headers not supporting collections. - HeaderStoreItemInfo info = GetOrCreateHeaderInfo(descriptor, parseRawValues: true); + HeaderStoreItemInfo info = GetOrCreateHeaderInfo(descriptor); info.InvalidValue = null; info.ParsedValue = null; @@ -381,17 +416,10 @@ internal void SetOrRemoveParsedValue(HeaderDescriptor descriptor, object? value) public bool Remove(string name) => Remove(GetHeaderDescriptor(name)); - internal bool Remove(HeaderDescriptor descriptor) => _headerStore != null && _headerStore.Remove(descriptor); - internal bool RemoveParsedValue(HeaderDescriptor descriptor, object value) { Debug.Assert(value != null); - if (_headerStore == null) - { - return false; - } - // 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. if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) @@ -462,11 +490,6 @@ internal bool ContainsParsedValue(HeaderDescriptor descriptor, object value) { Debug.Assert(value != null); - if (_headerStore == null) - { - return false; - } - // 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'. if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) @@ -517,41 +540,58 @@ internal virtual void AddHeaders(HttpHeaders sourceHeaders) Debug.Assert(sourceHeaders != null); Debug.Assert(GetType() == sourceHeaders.GetType(), "Can only copy headers from an instance of the same type."); - Dictionary? sourceHeadersStore = sourceHeaders._headerStore; - if (sourceHeadersStore is null || sourceHeadersStore.Count == 0) + // Only add header values if they're not already set on the message. Note that we don't merge + // collections: If both the default headers and the message have set some values for a certain + // header, then we don't try to merge the values. + if (_count == 0 && sourceHeaders._headerStore is HeaderEntry[] sourceEntries) { - return; - } - - _headerStore ??= new Dictionary(); + // If the target collection is empty, we don't have to search for existing values + _count = sourceHeaders._count; + if (_headerStore is not HeaderEntry[] entries || entries.Length < _count) + { + entries = new HeaderEntry[sourceEntries.Length]; + _headerStore = entries; + } - foreach (KeyValuePair header in sourceHeadersStore) - { - // Only add header values if they're not already set on the message. Note that we don't merge - // collections: If both the default headers and the message have set some values for a certain - // header, then we don't try to merge the values. - if (!_headerStore.ContainsKey(header.Key)) + for (int i = 0; i < _count && i < sourceEntries.Length; i++) { - object sourceValue = header.Value; - if (sourceValue is HeaderStoreItemInfo info) + HeaderEntry entry = sourceEntries[i]; + if (entry.Value is HeaderStoreItemInfo info) { - AddHeaderInfo(header.Key, info); + entry.Value = CloneHeaderInfo(entry.Key, info); } - else + entries[i] = entry; + } + } + else + { + foreach (HeaderEntry entry in sourceHeaders.GetEntries()) + { + ref object? storeValueRef = ref GetValueRefOrAddDefault(entry.Key); + if (storeValueRef is null) { - Debug.Assert(sourceValue is string); - _headerStore.Add(header.Key, sourceValue); + object sourceValue = entry.Value; + if (sourceValue is HeaderStoreItemInfo info) + { + storeValueRef = CloneHeaderInfo(entry.Key, info); + } + else + { + Debug.Assert(sourceValue is string); + storeValueRef = sourceValue; + } } } } } - private void AddHeaderInfo(HeaderDescriptor descriptor, HeaderStoreItemInfo sourceInfo) + private HeaderStoreItemInfo CloneHeaderInfo(HeaderDescriptor descriptor, HeaderStoreItemInfo sourceInfo) { - HeaderStoreItemInfo destinationInfo = CreateAndAddHeaderToStore(descriptor); - - // Always copy raw values - destinationInfo.RawValue = CloneStringHeaderInfoValues(sourceInfo.RawValue); + var destinationInfo = new HeaderStoreItemInfo + { + // Always copy raw values + RawValue = CloneStringHeaderInfoValues(sourceInfo.RawValue) + }; if (descriptor.Parser == null) { @@ -585,6 +625,8 @@ private void AddHeaderInfo(HeaderDescriptor descriptor, HeaderStoreItemInfo sour } } } + + return destinationInfo; } private static void CloneAndAddValue(HeaderStoreItemInfo destinationInfo, object source) @@ -623,74 +665,54 @@ private static void CloneAndAddValue(HeaderStoreItemInfo destinationInfo, object } } - private HeaderStoreItemInfo GetOrCreateHeaderInfo(HeaderDescriptor descriptor, bool parseRawValues) + private HeaderStoreItemInfo GetOrCreateHeaderInfo(HeaderDescriptor descriptor) { - HeaderStoreItemInfo? result = null; - bool found; - if (parseRawValues) + if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info)) { - found = TryGetAndParseHeaderInfo(descriptor, out result); + return info; } else { - found = TryGetHeaderValue(descriptor, out object? value); - if (found) - { - if (value is HeaderStoreItemInfo hsti) - { - result = hsti; - } - else - { - Debug.Assert(value is string); - _headerStore![descriptor] = result = new HeaderStoreItemInfo { RawValue = value }; - } - } - } - - if (!found) - { - result = CreateAndAddHeaderToStore(descriptor); + return CreateAndAddHeaderToStore(descriptor); } - - Debug.Assert(result != null); - return result; } private HeaderStoreItemInfo CreateAndAddHeaderToStore(HeaderDescriptor descriptor) { + Debug.Assert(!ContainsKey(descriptor)); + // If we don't have the header in the store yet, add it now. HeaderStoreItemInfo result = new HeaderStoreItemInfo(); // If the descriptor header type is in _treatAsCustomHeaderTypes, it must be converted to a custom header before calling this method Debug.Assert((descriptor.HeaderType & _treatAsCustomHeaderTypes) == 0); - AddHeaderToStore(descriptor, result); + AddEntryToStore(new HeaderEntry(descriptor, result)); return result; } - private void AddHeaderToStore(HeaderDescriptor descriptor, object value) - { - Debug.Assert(value is string || value is HeaderStoreItemInfo); - (_headerStore ??= new Dictionary()).Add(descriptor, value); - } - internal bool TryGetHeaderValue(HeaderDescriptor descriptor, [NotNullWhen(true)] out object? value) { - if (_headerStore == null) + ref object storeValueRef = ref GetValueRefOrNullRef(descriptor); + if (Unsafe.IsNullRef(ref storeValueRef)) { value = null; return false; } - - return _headerStore.TryGetValue(descriptor, out value); + else + { + value = storeValueRef; + return true; + } } private bool TryGetAndParseHeaderInfo(HeaderDescriptor key, [NotNullWhen(true)] out HeaderStoreItemInfo? info) { - if (TryGetHeaderValue(key, out object? value)) + ref object storeValueRef = ref GetValueRefOrNullRef(key); + if (!Unsafe.IsNullRef(ref storeValueRef)) { + object value = storeValueRef; if (value is HeaderStoreItemInfo hsi) { info = hsi; @@ -698,20 +720,21 @@ private bool TryGetAndParseHeaderInfo(HeaderDescriptor key, [NotNullWhen(true)] else { Debug.Assert(value is string); - _headerStore![key] = info = new HeaderStoreItemInfo() { RawValue = value }; + storeValueRef = info = new HeaderStoreItemInfo() { RawValue = value }; } - return ParseRawHeaderValues(key, info, removeEmptyHeader: true); + return ParseRawHeaderValues(key, info); } info = null; return false; } - private bool ParseRawHeaderValues(HeaderDescriptor descriptor, HeaderStoreItemInfo info, bool removeEmptyHeader) + private bool ParseRawHeaderValues(HeaderDescriptor descriptor, HeaderStoreItemInfo info) { // Unlike TryGetHeaderInfo() this method tries to parse all non-validated header values (if any) // before returning to the caller. + Debug.Assert(!info.IsEmpty); if (info.RawValue != null) { List? rawValues = info.RawValue as List; @@ -730,16 +753,12 @@ private bool ParseRawHeaderValues(HeaderDescriptor descriptor, HeaderStoreItemIn info.RawValue = null; // During parsing, we removed the value since it contains newline chars. Return false to indicate that - // this is an empty header. If the caller specified to remove empty headers, we'll remove the header before - // returning. + // this is an empty header. if ((info.InvalidValue == null) && (info.ParsedValue == null)) { - if (removeEmptyHeader) - { - // After parsing the raw value, no value is left because all values contain newline chars. - Debug.Assert(_headerStore != null); - _headerStore.Remove(descriptor); - } + // After parsing the raw value, no value is left because all values contain newline chars. + Debug.Assert(_count > 0); + Remove(descriptor); return false; } } @@ -808,7 +827,8 @@ internal bool TryParseAndAddValue(HeaderDescriptor descriptor, string? value) { // If we get here, then the value could be parsed correctly. If we created a new HeaderStoreItemInfo, add // it to the store if we added at least one value. - AddHeaderToStore(descriptor, info); + Debug.Assert(!ContainsKey(descriptor)); + AddEntryToStore(new HeaderEntry(descriptor, info)); } return result; @@ -1061,12 +1081,14 @@ internal bool TryGetHeaderDescriptor(string name, out HeaderDescriptor descripto if (HeaderDescriptor.TryGet(name, out descriptor)) { - if ((descriptor.HeaderType & _allowedHeaderTypes) != 0) + HttpHeaderType headerType = descriptor.HeaderType; + + if ((headerType & _allowedHeaderTypes) != 0) { return true; } - if ((descriptor.HeaderType & _treatAsCustomHeaderTypes) != 0) + if ((headerType & _treatAsCustomHeaderTypes) != 0) { descriptor = descriptor.AsCustomHeader(); return true; @@ -1128,7 +1150,8 @@ internal static void GetStoreValuesAsStringOrStringArray(HeaderDescriptor descri } else { - values = multiValue = length != 0 ? new string[length] : Array.Empty(); + Debug.Assert(length > 1, "The header should have been removed when it became empty"); + values = multiValue = new string[length]; } int currentIndex = 0; @@ -1252,5 +1275,234 @@ internal bool CanAddParsedValue(HttpHeaderParser parser) internal bool IsEmpty => (RawValue == null) && (InvalidValue == null) && (ParsedValue == null); } + + + #region Low-level implementation details that work with _headerStore directly + + // Used to store the CollectionsMarshal.GetValueRefOrAddDefault out parameter. + // This is a workaround for the Roslyn bug where we can't use a discard instead: + // https://github.com/dotnet/roslyn/issues/56587#issuecomment-934955526 + private static bool s_dictionaryGetValueRefOrAddDefaultExistsDummy; + + private const int InitialCapacity = 4; + internal const int ArrayThreshold = 64; // Above this threshold, header ordering will not be preserved + + internal HeaderEntry[]? GetEntriesArray() + { + object? store = _headerStore; + if (store is null) + { + return null; + } + else if (store is HeaderEntry[] entries) + { + return entries; + } + else + { + return GetEntriesFromDictionary(); + } + + HeaderEntry[] GetEntriesFromDictionary() + { + var dictionary = (Dictionary)_headerStore!; + var entries = new HeaderEntry[dictionary.Count]; + int i = 0; + foreach (KeyValuePair entry in dictionary) + { + entries[i++] = new HeaderEntry + { + Key = entry.Key, + Value = entry.Value + }; + } + return entries; + } + } + + internal ReadOnlySpan GetEntries() + { + return new ReadOnlySpan(GetEntriesArray(), 0, _count); + } + + internal int Count => _count; + + private bool EntriesAreLiveView => _headerStore is HeaderEntry[]; + + private ref object GetValueRefOrNullRef(HeaderDescriptor key) + { + ref object valueRef = ref Unsafe.NullRef(); + + object? store = _headerStore; + if (store is HeaderEntry[] entries) + { + for (int i = 0; i < _count && i < entries.Length; i++) + { + if (key.Equals(entries[i].Key)) + { + valueRef = ref entries[i].Value; + break; + } + } + } + else if (store is not null) + { + valueRef = ref CollectionsMarshal.GetValueRefOrNullRef(Unsafe.As>(store), key); + } + + return ref valueRef; + } + + private ref object? GetValueRefOrAddDefault(HeaderDescriptor key) + { + object? store = _headerStore; + if (store is HeaderEntry[] entries) + { + for (int i = 0; i < _count && i < entries.Length; i++) + { + if (key.Equals(entries[i].Key)) + { + return ref entries[i].Value!; + } + } + + int count = _count; + _count++; + if ((uint)count < (uint)entries.Length) + { + entries[count].Key = key; + return ref entries[count].Value!; + } + + return ref GrowEntriesAndAddDefault(key); + } + else if (store is null) + { + _count++; + entries = new HeaderEntry[InitialCapacity]; + _headerStore = entries; + ref HeaderEntry firstEntry = ref MemoryMarshal.GetArrayDataReference(entries); + firstEntry.Key = key; + return ref firstEntry.Value!; + } + else + { + return ref DictionaryGetValueRefOrAddDefault(key); + } + + ref object? GrowEntriesAndAddDefault(HeaderDescriptor key) + { + var entries = (HeaderEntry[])_headerStore!; + if (entries.Length == ArrayThreshold) + { + return ref ConvertToDictionaryAndAddDefault(key); + } + else + { + Array.Resize(ref entries, entries.Length << 1); + _headerStore = entries; + ref HeaderEntry firstNewEntry = ref entries[entries.Length >> 1]; + firstNewEntry.Key = key; + return ref firstNewEntry.Value!; + } + } + + ref object? ConvertToDictionaryAndAddDefault(HeaderDescriptor key) + { + var entries = (HeaderEntry[])_headerStore!; + var dictionary = new Dictionary(ArrayThreshold); + _headerStore = dictionary; + foreach (HeaderEntry entry in entries) + { + dictionary.Add(entry.Key, entry.Value); + } + Debug.Assert(dictionary.Count == _count - 1); + return ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out s_dictionaryGetValueRefOrAddDefaultExistsDummy); + } + + ref object? DictionaryGetValueRefOrAddDefault(HeaderDescriptor key) + { + var dictionary = (Dictionary)_headerStore!; + ref object? value = ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out s_dictionaryGetValueRefOrAddDefaultExistsDummy); + if (value is null) + { + _count++; + } + return ref value; + } + } + + private void AddEntryToStore(HeaderEntry entry) + { + Debug.Assert(!ContainsKey(entry.Key)); + + if (_headerStore is HeaderEntry[] entries) + { + int count = _count; + if ((uint)count < (uint)entries.Length) + { + entries[count] = entry; + _count++; + return; + } + } + + GetValueRefOrAddDefault(entry.Key) = entry.Value; + } + + internal bool ContainsKey(HeaderDescriptor key) + { + return !Unsafe.IsNullRef(ref GetValueRefOrNullRef(key)); + } + + public void Clear() + { + if (_headerStore is HeaderEntry[] entries) + { + Array.Clear(entries, 0, _count); + } + else + { + _headerStore = null; + } + _count = 0; + } + + internal bool Remove(HeaderDescriptor key) + { + bool removed = false; + + object? store = _headerStore; + if (store is HeaderEntry[] entries) + { + for (int i = 0; i < _count && i < entries.Length; i++) + { + if (key.Equals(entries[i].Key)) + { + while (i + 1 < _count && (uint)(i + 1) < (uint)entries.Length) + { + entries[i] = entries[i + 1]; + i++; + } + entries[i] = default; + removed = true; + break; + } + } + } + else if (store is not null) + { + removed = Unsafe.As>(store).Remove(key); + } + + if (removed) + { + _count--; + } + + return removed; + } + + #endregion // _headerStore implementation } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeadersNonValidated.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeadersNonValidated.cs index 5e67476d116a9..b2d2f5c3a8727 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeadersNonValidated.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeadersNonValidated.cs @@ -25,7 +25,7 @@ namespace System.Net.Http.Headers /// Gets the number of headers stored in the collection. /// Multiple header values associated with the same header name are considered to be one header as far as this count is concerned. - public int Count => _headers?.HeaderStore?.Count ?? 0; + public int Count => _headers?.Count ?? 0; /// Gets whether the collection contains the specified header. /// The name of the header. @@ -33,7 +33,7 @@ namespace System.Net.Http.Headers public bool Contains(string headerName) => _headers is HttpHeaders headers && headers.TryGetHeaderDescriptor(headerName, out HeaderDescriptor descriptor) && - headers.TryGetHeaderValue(descriptor, out _); + headers.ContainsKey(descriptor); /// Gets the values for the specified header name. /// The name of the header. @@ -83,8 +83,8 @@ public bool TryGetValues(string headerName, out HeaderStringValues values) /// Gets an enumerator that iterates through the . /// An enumerator that iterates through the . public Enumerator GetEnumerator() => - _headers is HttpHeaders headers && headers.HeaderStore is Dictionary store ? - new Enumerator(store.GetEnumerator()) : + _headers is HttpHeaders headers && headers.GetEntriesArray() is HeaderEntry[] entries ? + new Enumerator(entries, headers.Count) : default; /// @@ -120,35 +120,34 @@ IEnumerable IReadOnlyDictionary. /// Enumerates the elements of a . public struct Enumerator : IEnumerator> { - /// The wrapped enumerator for the underlying headers dictionary. - private Dictionary.Enumerator _headerStoreEnumerator; - /// The current value. + private readonly HeaderEntry[] _entries; + private readonly int _numberOfEntries; + private int _index; private KeyValuePair _current; - /// true if the enumerator was constructed via the ctor; otherwise, false./ - private bool _valid; - /// Initializes the enumerator. - /// The underlying dictionary enumerator. - internal Enumerator(Dictionary.Enumerator headerStoreEnumerator) + internal Enumerator(HeaderEntry[] entries, int numberOfEntries) { - _headerStoreEnumerator = headerStoreEnumerator; + _entries = entries; + _numberOfEntries = numberOfEntries; + _index = 0; _current = default; - _valid = true; } /// public bool MoveNext() { - if (_valid && _headerStoreEnumerator.MoveNext()) + int index = _index; + if (_entries is HeaderEntry[] entries && index < _numberOfEntries && (uint)index < (uint)entries.Length) { - KeyValuePair current = _headerStoreEnumerator.Current; + HeaderEntry entry = entries[index]; + _index++; - HttpHeaders.GetStoreValuesAsStringOrStringArray(current.Key, current.Value, out string? singleValue, out string[]? multiValue); + HttpHeaders.GetStoreValuesAsStringOrStringArray(entry.Key, entry.Value, out string? singleValue, out string[]? multiValue); Debug.Assert(singleValue is not null ^ multiValue is not null); _current = new KeyValuePair( - current.Key.Name, - singleValue is not null ? new HeaderStringValues(current.Key, singleValue) : new HeaderStringValues(current.Key, multiValue!)); + entry.Key.Name, + singleValue is not null ? new HeaderStringValues(entry.Key, singleValue) : new HeaderStringValues(entry.Key, multiValue!)); return true; } 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 811d33dbfb4ef..1a1b4b00bbb60 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 @@ -1337,15 +1337,10 @@ private void WriteHeaderCollection(HttpRequestMessage request, HttpHeaders heade { if (NetEventSource.Log.IsEnabled()) Trace(""); - if (headers.HeaderStore is null) - { - return; - } - HeaderEncodingSelector? encodingSelector = _pool.Settings._requestHeaderEncodingSelector; ref string[]? tmpHeaderValuesArray = ref t_headerValues; - foreach (KeyValuePair header in headers.HeaderStore) + foreach (HeaderEntry header in headers.GetEntries()) { int headerValuesCount = HttpHeaders.GetStoreValuesIntoStringArray(header.Key, header.Value, ref tmpHeaderValuesArray); Debug.Assert(headerValuesCount > 0, "No values for header??"); @@ -1361,7 +1356,7 @@ private void WriteHeaderCollection(HttpRequestMessage request, HttpHeaders heade // The Connection, Upgrade and ProxyConnection headers are also not supported in HTTP2. if (knownHeader != KnownHeaders.Host && knownHeader != KnownHeaders.Connection && knownHeader != KnownHeaders.Upgrade && knownHeader != KnownHeaders.ProxyConnection) { - if (header.Key.KnownHeader == KnownHeaders.TE) + if (knownHeader == KnownHeaders.TE) { // HTTP/2 allows only 'trailers' TE header. rfc7540 8.1.2.2 foreach (string value in headerValues) 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 3a236ccc65ae3..9a7ebccc416a8 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 @@ -622,14 +622,9 @@ private void BufferHeaders(HttpRequestMessage request) // TODO: special-case Content-Type for static table values values? private void BufferHeaderCollection(HttpHeaders headers) { - if (headers.HeaderStore == null) - { - return; - } - HeaderEncodingSelector? encodingSelector = _connection.Pool.Settings._requestHeaderEncodingSelector; - foreach (KeyValuePair header in headers.HeaderStore) + foreach (HeaderEntry header in headers.GetEntries()) { int headerValuesCount = HttpHeaders.GetStoreValuesIntoStringArray(header.Key, header.Value, ref _headerValues); Debug.Assert(headerValuesCount > 0, "No values for header??"); @@ -645,7 +640,7 @@ private void BufferHeaderCollection(HttpHeaders headers) // The Connection, Upgrade and ProxyConnection headers are also not supported in HTTP/3. if (knownHeader != KnownHeaders.Host && knownHeader != KnownHeaders.Connection && knownHeader != KnownHeaders.Upgrade && knownHeader != KnownHeaders.ProxyConnection) { - if (header.Key.KnownHeader == KnownHeaders.TE) + if (knownHeader == KnownHeaders.TE) { // HTTP/2 allows only 'trailers' TE header. rfc7540 8.1.2.2 // HTTP/3 does not mention this one way or another; assume it has the same rule. 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 12b6b4bf3c55a..deb0f5d9373d1 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 @@ -258,10 +258,12 @@ private async ValueTask WriteHeadersAsync(HttpHeaders headers, string? cookiesFr { Debug.Assert(_currentRequest != null); - if (headers.HeaderStore != null) + if (headers.GetEntriesArray() is HeaderEntry[] entries) { - foreach (KeyValuePair header in headers.HeaderStore) + for (int i = 0; i < headers.Count; i++) { + HeaderEntry header = entries[i]; + if (header.Key.KnownHeader != null) { await WriteBytesAsync(header.Key.KnownHeader.AsciiBytesWithColonSpace, async).ConfigureAwait(false); @@ -298,10 +300,10 @@ private async ValueTask WriteHeadersAsync(HttpHeaders headers, string? cookiesFr separator = parser.Separator!; } - for (int i = 1; i < headerValuesCount; i++) + for (int j = 1; j < headerValuesCount; j++) { await WriteAsciiStringAsync(separator, async).ConfigureAwait(false); - await WriteStringAsync(_headerValues[i], async, valueEncoding).ConfigureAwait(false); + await WriteStringAsync(_headerValues[j], async, valueEncoding).ConfigureAwait(false); } } } diff --git a/src/libraries/System.Net.Http/tests/UnitTests/HPack/HPackRoundtripTests.cs b/src/libraries/System.Net.Http/tests/UnitTests/HPack/HPackRoundtripTests.cs index c3b16afb47360..d2f81304dd912 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/HPack/HPackRoundtripTests.cs +++ b/src/libraries/System.Net.Http/tests/UnitTests/HPack/HPackRoundtripTests.cs @@ -60,7 +60,7 @@ private static Memory HPackEncode(HttpHeaders headers, Encoding? valueEnco FillAvailableSpaceWithOnes(buffer); string[] headerValues = Array.Empty(); - foreach (KeyValuePair header in headers.HeaderStore) + foreach (HeaderEntry header in headers.GetEntries()) { int headerValuesCount = HttpHeaders.GetStoreValuesIntoStringArray(header.Key, header.Value, ref headerValues); Assert.InRange(headerValuesCount, 0, int.MaxValue); diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeadersTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeadersTest.cs index 139422163a95b..79196e77c75ea 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeadersTest.cs +++ b/src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeadersTest.cs @@ -1710,6 +1710,24 @@ public void GetEnumerator_UseExplicitInterfaceImplementation_EnumeratorReturnsNo Assert.False(enumerator.MoveNext(), "Only 2 values expected, but enumerator returns a third one."); } + [Fact] + public void GetEnumerator_InvalidValueBetweenValidHeaders_EnumeratorReturnsAllValidValuesAndRemovesInvalidValue() + { + MockHeaders headers = new MockHeaders(); + headers.TryAddWithoutValidation("foo", "fooValue"); + headers.TryAddWithoutValidation("invalid", "invalid\nvalue"); + headers.TryAddWithoutValidation("bar", "barValue"); + + Assert.Equal(3, headers.Count); + + IDictionary> dict = headers.ToDictionary(pair => pair.Key, pair => pair.Value); + Assert.Equal("fooValue", Assert.Single(Assert.Contains("foo", dict))); + Assert.Equal("barValue", Assert.Single(Assert.Contains("bar", dict))); + + Assert.Equal(2, headers.Count); + Assert.False(headers.NonValidated.Contains("invalid")); + } + [Fact] public void AddParsedValue_AddSingleValueToNonExistingHeader_HeaderGetsCreatedAndValueAdded() { @@ -2208,6 +2226,150 @@ public void HeaderStringValues_Constructed_ProducesExpectedResults() } } + [Theory] + [MemberData(nameof(NumberOfHeadersUpToArrayThreshold_AddNonValidated_EnumerateNonValidated))] + public void Add_WithinArrayThresholdHeaders_EnumerationPreservesOrdering(int numberOfHeaders, bool addNonValidated, bool enumerateNonValidated) + { + var headers = new MockHeaders(); + + for (int i = 0; i < numberOfHeaders; i++) + { + if (addNonValidated) + { + headers.TryAddWithoutValidation(i.ToString(), i.ToString()); + } + else + { + headers.Add(i.ToString(), i.ToString()); + } + } + + KeyValuePair[] entries = enumerateNonValidated + ? headers.NonValidated.Select(pair => KeyValuePair.Create(pair.Key, Assert.Single(pair.Value))).ToArray() + : headers.Select(pair => KeyValuePair.Create(pair.Key, Assert.Single(pair.Value))).ToArray(); + + Assert.Equal(numberOfHeaders, entries.Length); + for (int i = 0; i < numberOfHeaders; i++) + { + Assert.Equal(i.ToString(), entries[i].Key); + Assert.Equal(i.ToString(), entries[i].Value); + } + } + + [Fact] + public void Add_Remove_HeaderOrderingIsPreserved() + { + var headers = new MockHeaders(); + headers.Add("a", ""); + headers.Add("b", ""); + headers.Add("c", ""); + + headers.Remove("b"); + + Assert.Equal(new[] { "a", "c" }, headers.Select(pair => pair.Key)); + } + + [Fact] + public void Add_AddToExistingKey_OriginalOrderingIsPreserved() + { + var headers = new MockHeaders(); + headers.Add("a", "a1"); + headers.Add("b", "b1"); + headers.Add("a", "a2"); + + Assert.Equal(new[] { "a", "b" }, headers.Select(pair => pair.Key)); + } + + [Theory] + [InlineData(3)] + [InlineData(4)] + [InlineData(5)] + [InlineData(HttpHeaders.ArrayThreshold / 4)] + [InlineData(HttpHeaders.ArrayThreshold / 2)] + [InlineData(HttpHeaders.ArrayThreshold - 1)] + [InlineData(HttpHeaders.ArrayThreshold)] + [InlineData(HttpHeaders.ArrayThreshold + 1)] + [InlineData(HttpHeaders.ArrayThreshold * 2)] + [InlineData(HttpHeaders.ArrayThreshold * 4)] + public void Add_LargeNumberOfHeaders_OperationsStillSupported(int numberOfHeaders) + { + string[] keys = Enumerable.Range(1, numberOfHeaders).Select(i => i.ToString()).ToArray(); + + var headers = new MockHeaders(); + foreach (string key in keys) + { + Assert.False(headers.NonValidated.Contains(key)); + headers.TryAddWithoutValidation(key, key); + Assert.True(headers.NonValidated.Contains(key)); + } + + string[] nonValidatedKeys = headers.NonValidated.Select(pair => pair.Key).ToArray(); + Assert.Equal(numberOfHeaders, nonValidatedKeys.Length); + + string[] newKeys = headers.Select(pair => pair.Key).ToArray(); + Assert.Equal(numberOfHeaders, newKeys.Length); + + string[] nonValidatedKeysAfterValidation = headers.NonValidated.Select(pair => pair.Key).ToArray(); + Assert.Equal(numberOfHeaders, nonValidatedKeysAfterValidation.Length); + + if (numberOfHeaders > HttpHeaders.ArrayThreshold) + { + // Ordering is lost when adding more than ArrayThreshold headers + Array.Sort(nonValidatedKeys, (a, b) => int.Parse(a).CompareTo(int.Parse(b))); + Array.Sort(newKeys, (a, b) => int.Parse(a).CompareTo(int.Parse(b))); + Array.Sort(nonValidatedKeysAfterValidation, (a, b) => int.Parse(a).CompareTo(int.Parse(b))); + } + Assert.Equal(keys, nonValidatedKeys); + Assert.Equal(keys, newKeys); + Assert.Equal(keys, nonValidatedKeysAfterValidation); + + headers.Add("3", "secondValue"); + Assert.True(headers.TryGetValues("3", out IEnumerable valuesFor3)); + Assert.Equal(new[] { "3", "secondValue" }, valuesFor3); + + Assert.True(headers.TryAddWithoutValidation("invalid", "invalid\nvalue")); + Assert.True(headers.TryAddWithoutValidation("valid", "validValue")); + + Assert.Equal(numberOfHeaders + 2, headers.NonValidated.Count); + + // Remove all headers except for "1", "valid", "invalid" + for (int i = 2; i <= numberOfHeaders; i++) + { + Assert.True(headers.Remove(i.ToString())); + } + + Assert.False(headers.Remove("3")); + + // "1", "invalid", "valid" + Assert.True(headers.NonValidated.Contains("invalid")); + Assert.Equal(3, headers.NonValidated.Count); + + Assert.Equal(new[] { "1", "valid" }, headers.Select(pair => pair.Key).OrderBy(i => i)); + + Assert.Equal(2, headers.NonValidated.Count); + + headers.Clear(); + + Assert.Equal(0, headers.NonValidated.Count); + Assert.Empty(headers); + Assert.False(headers.Contains("3")); + + Assert.True(headers.TryAddWithoutValidation("3", "newValue")); + Assert.True(headers.TryGetValues("3", out valuesFor3)); + Assert.Equal(new[] { "newValue" }, valuesFor3); + } + + public static IEnumerable NumberOfHeadersUpToArrayThreshold_AddNonValidated_EnumerateNonValidated() + { + for (int i = 0; i <= HttpHeaders.ArrayThreshold; i++) + { + yield return new object[] { i, false, false }; + yield return new object[] { i, false, true }; + yield return new object[] { i, true, false }; + yield return new object[] { i, true, true }; + } + } + public static IEnumerable GetInvalidHeaderNames() { yield return new object[] { "invalid header" }; From a7aff062a07f6a52fdfe69854dd28cf1c5f539a9 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 20 Jan 2022 11:24:09 -0500 Subject: [PATCH 090/308] Disable DirectoryLongerThanMaxLongPathWithExtendedSyntax_ThrowsException (#64044) --- .../System.IO.FileSystem/tests/Directory/CreateDirectory.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs b/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs index fb3a74305bca2..ae0f89d32da08 100644 --- a/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs +++ b/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs @@ -264,6 +264,7 @@ public void DirectoryLongerThanMaxLongPath_ThrowsPathTooLongException() }); } + [ActiveIssue("https://github.com/dotnet/runtime/issues/64019")] [ConditionalFact(nameof(LongPathsAreNotBlocked), nameof(UsingNewNormalization))] [PlatformSpecific(TestPlatforms.Windows)] public void DirectoryLongerThanMaxLongPathWithExtendedSyntax_ThrowsException() From df7f4dc0ac9ed629facf39a03883c47b33000475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 21 Jan 2022 01:50:37 +0900 Subject: [PATCH 091/308] Add test coverage for frozen objects and GC interaction (#64030) * Test coverage for frozen objects and GC interaction * Update Preinitialization.cs --- .../Preinitialization/Preinitialization.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs b/src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs index 658ab86b07822..eb4c63f1d1e5e 100644 --- a/src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs +++ b/src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime; using System.Runtime.InteropServices; using BindingFlags = System.Reflection.BindingFlags; @@ -40,6 +41,7 @@ private static int Main() TestDrawCircle.Run(); TestValueTypeDup.Run(); TestFunctionPointers.Run(); + TestGCInteraction.Run(); #else Console.WriteLine("Preinitialization is disabled in multimodule builds for now. Skipping test."); #endif @@ -834,6 +836,39 @@ public static void Run() } } +class TestGCInteraction +{ + class WithFrozenObjects + { + internal readonly static string s_someStringLiteral = "Some string literal"; + internal readonly static object s_someObject = new object(); + } + + public static void Run() + { + Assert.IsPreinitialized(typeof(WithFrozenObjects)); + + var holder = new object[] + { + WithFrozenObjects.s_someStringLiteral, + WithFrozenObjects.s_someObject, + }; + + var h1 = new DependentHandle(WithFrozenObjects.s_someObject, WithFrozenObjects.s_someStringLiteral); + var h2 = new DependentHandle(WithFrozenObjects.s_someStringLiteral, WithFrozenObjects.s_someObject); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + + Assert.AreSame(holder[0], WithFrozenObjects.s_someStringLiteral); + Assert.AreSame(holder[1], WithFrozenObjects.s_someObject); + + h1.Dispose(); + h2.Dispose(); + } +} + static class Assert { private static bool HasCctor(Type type) From 71c4e37431759310e02c45ef4d11f312a4c58908 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Thu, 20 Jan 2022 17:00:41 +0000 Subject: [PATCH 092/308] Remove Type.MakeGenericType dependency from source generation (#64004) * Remove Type.MakeGenericType dependency from srcgen * address feedback * add trimmer warning suppression * address feedback --- .../src/System.Text.Json.csproj | 5 +- .../Metadata/DefaultValueHolder.cs | 42 +++++++++++++++ .../Metadata/GenericMethodHolder.cs | 52 ------------------- .../Metadata/JsonParameterInfo.cs | 6 +-- .../Metadata/JsonPropertyInfoOfT.cs | 2 +- .../Serialization/Metadata/JsonTypeInfo.cs | 13 ++--- 6 files changed, 51 insertions(+), 69 deletions(-) create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultValueHolder.cs delete mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/GenericMethodHolder.cs 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 d5975ec253668..3c9c90848ff36 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -228,7 +228,7 @@ System.Text.Json.Nodes.JsonValue - + @@ -355,8 +355,7 @@ System.Text.Json.Nodes.JsonValue - + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultValueHolder.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultValueHolder.cs new file mode 100644 index 0000000000000..224376d3859da --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultValueHolder.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. + +using System.Diagnostics.CodeAnalysis; + +namespace System.Text.Json.Serialization.Metadata +{ + /// + /// Helper class used for calculating the default value for a given System.Type instance. + /// + internal sealed class DefaultValueHolder + { + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern", + Justification = "GetUninitializedObject is only called on a struct. You can always create an instance of a struct.")] + private DefaultValueHolder(Type type) + { + if (type.IsValueType && Nullable.GetUnderlyingType(type) == null) + { +#if NETCOREAPP + DefaultValue = System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject(type); +#else + DefaultValue = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type); +#endif + } + } + + /// + /// Returns the default value for the specified type. + /// + public object? DefaultValue { get; } + + /// + /// Returns true if contains only default values. + /// + public bool IsDefaultValue(object value) => DefaultValue is null ? value is null : DefaultValue.Equals(value); + + /// + /// Creates a holder instance representing a type. + /// + public static DefaultValueHolder CreateHolder(Type type) => new DefaultValueHolder(type); + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/GenericMethodHolder.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/GenericMethodHolder.cs deleted file mode 100644 index 2c143f95e59cc..0000000000000 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/GenericMethodHolder.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text.Json.Reflection; - -namespace System.Text.Json.Serialization.Metadata -{ - /// - /// Allows virtual dispatch to GenericMethodHolder{T}. - /// - internal abstract class GenericMethodHolder - { - /// - /// Returns the default value for the specified type. - /// - public abstract object? DefaultValue { get; } - - /// - /// Returns true if contains only default values. - /// - public abstract bool IsDefaultValue(object value); - - /// - /// Creates a holder instance representing a type. - /// - public static GenericMethodHolder CreateHolder(Type type) - { - Type holderType = typeof(GenericMethodHolder<>).MakeGenericType(type); - return (GenericMethodHolder)Activator.CreateInstance(holderType)!; - } - } - - /// - /// Generic methods for {T}. - /// - internal sealed class GenericMethodHolder : GenericMethodHolder - { - public override object? DefaultValue => default(T); - - public override bool IsDefaultValue(object value) - { - // For performance, we only want to call this method for non-nullable value types. - // Nullable types should be checked againt 'null' before calling this method. - Debug.Assert(!value.GetType().CanBeNull()); - - return EqualityComparer.Default.Equals(default, (T)value); - } - } -} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonParameterInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonParameterInfo.cs index 3905c70402024..9139a027c5ea4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonParameterInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonParameterInfo.cs @@ -101,14 +101,14 @@ public static JsonParameterInfo CreateIgnoredParameterPlaceholder( // doesn't match the parameter type, use reflection to get the default value. Type parameterType = parameterInfo.ParameterType; - GenericMethodHolder holder; + DefaultValueHolder holder; if (matchingProperty.Options.TryGetClass(parameterType, out JsonTypeInfo? typeInfo)) { - holder = typeInfo.GenericMethods; + holder = typeInfo.DefaultValueHolder; } else { - holder = GenericMethodHolder.CreateHolder(parameterInfo.ParameterType); + holder = DefaultValueHolder.CreateHolder(parameterInfo.ParameterType); } jsonParameterInfo.DefaultValue = holder.DefaultValue; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfoOfT.cs index e98f08dd54cdc..a3670f2d8b362 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfoOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfoOfT.cs @@ -287,7 +287,7 @@ value is not null && Debug.Assert(RuntimeTypeInfo.Type == DeclaredPropertyType); // Use a late-bound call to EqualityComparer. - if (RuntimeTypeInfo.GenericMethods.IsDefaultValue(value)) + if (RuntimeTypeInfo.DefaultValueHolder.IsDefaultValue(value)) { return true; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs index 4bd852e447e2b..aea2e5a8e8c28 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs @@ -124,19 +124,12 @@ internal JsonTypeInfo? KeyTypeInfo internal bool IsObjectWithParameterizedCtor => PropertyInfoForTypeInfo.ConverterBase.ConstructorIsParameterized; - private GenericMethodHolder? _genericMethods; /// - /// Returns a helper class used when generic methods need to be invoked on Type. + /// Returns a helper class used for computing the default value. /// - internal GenericMethodHolder GenericMethods - { - get - { - _genericMethods ??= GenericMethodHolder.CreateHolder(Type); - return _genericMethods; - } - } + internal DefaultValueHolder DefaultValueHolder => _defaultValueHolder ??= DefaultValueHolder.CreateHolder(Type); + private DefaultValueHolder? _defaultValueHolder; internal JsonNumberHandling? NumberHandling { get; set; } From 1fc2352b1f7104b54881c12ecf7de33a5571b0ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Thu, 20 Jan 2022 09:49:27 -0800 Subject: [PATCH 093/308] Add ns2.0 support to System.Formats.Cbor (#62872) * Add ns2.0 support to System.Formats.Cbor * Add NetFrameworkMinimum to tfms * Add ReadHalf and WriteHalf to compatibility suppressions * Remove unwanted comment --- .../ref/System.Formats.Cbor.cs | 2 - .../ref/System.Formats.Cbor.csproj | 7 +- .../ref/System.Formats.Cbor.netcoreapp.cs | 17 ++ .../src/CompatibilitySuppressions.xml | 14 +- .../src/System.Formats.Cbor.csproj | 29 +- .../Formats/Cbor/CborHelpers.netcoreapp.cs | 63 +++++ .../Formats/Cbor/CborHelpers.netstandard.cs | 255 ++++++++++++++++++ .../src/System/Formats/Cbor/HalfHelpers.cs | 50 ---- .../Formats/Cbor/HalfHelpers.netcoreapp.cs | 17 ++ .../Formats/Cbor/HalfHelpers.netstandard.cs | 203 ++++++++++++++ .../Formats/Cbor/Reader/CborReader.Simple.cs | 54 +--- .../Reader/CborReader.Simple.netcoreapp.cs | 45 ++++ .../Formats/Cbor/Reader/CborReader.String.cs | 12 +- .../Formats/Cbor/Reader/CborReader.Tag.cs | 4 +- .../Formats/Cbor/Writer/CborWriter.Simple.cs | 46 +--- .../Writer/CborWriter.Simple.netcoreapp.cs | 36 +++ .../Writer/CborWriter.Simple.netstandard.cs | 36 +++ .../Formats/Cbor/Writer/CborWriter.String.cs | 4 +- .../Formats/Cbor/Writer/CborWriter.Tag.cs | 6 +- .../tests/CborTestHelpers.netcoreapp.cs | 10 + .../tests/CborTestHelpers.netstandard.cs | 11 + .../tests/CoseKeyHelpers.cs | 8 +- .../Reader/CborReaderTests.ByteString.cs | 2 +- .../tests/Reader/CborReaderTests.Map.cs | 2 +- .../tests/Reader/CborReaderTests.Simple.cs | 58 +--- .../CborReaderTests.Simple.netcoreapp.cs | 69 +++++ .../tests/Reader/CborReaderTests.Tag.cs | 2 +- .../Reader/CborReaderTests.TextString.cs | 27 +- .../tests/System.Formats.Cbor.Tests.csproj | 23 +- .../tests/Writer/CborWriterTests.Simple.cs | 20 -- .../CborWriterTests.Simple.netcoreapp.cs | 31 +++ .../tests/Writer/CborWriterTests.Tag.cs | 2 +- .../Writer/CborWriterTests.TextString.cs | 2 +- 33 files changed, 921 insertions(+), 246 deletions(-) create mode 100644 src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.netcoreapp.cs create mode 100644 src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborHelpers.netcoreapp.cs create mode 100644 src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborHelpers.netstandard.cs delete mode 100644 src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.cs create mode 100644 src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netcoreapp.cs create mode 100644 src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netstandard.cs create mode 100644 src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Simple.netcoreapp.cs create mode 100644 src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.netcoreapp.cs create mode 100644 src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.netstandard.cs create mode 100644 src/libraries/System.Formats.Cbor/tests/CborTestHelpers.netcoreapp.cs create mode 100644 src/libraries/System.Formats.Cbor/tests/CborTestHelpers.netstandard.cs create mode 100644 src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Simple.netcoreapp.cs create mode 100644 src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Simple.netcoreapp.cs diff --git a/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.cs b/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.cs index bd7bf6946eff1..54b232c9864a7 100644 --- a/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.cs +++ b/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.cs @@ -44,7 +44,6 @@ public void ReadEndArray() { } public void ReadEndIndefiniteLengthByteString() { } public void ReadEndIndefiniteLengthTextString() { } public void ReadEndMap() { } - public System.Half ReadHalf() { throw null; } public int ReadInt32() { throw null; } public long ReadInt64() { throw null; } public void ReadNull() { } @@ -145,7 +144,6 @@ public void WriteEndArray() { } public void WriteEndIndefiniteLengthByteString() { } public void WriteEndIndefiniteLengthTextString() { } public void WriteEndMap() { } - public void WriteHalf(System.Half value) { } public void WriteInt32(int value) { } public void WriteInt64(long value) { } public void WriteNull() { } diff --git a/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.csproj b/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.csproj index 963fb857541bd..6aa93dd583d89 100644 --- a/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.csproj +++ b/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.csproj @@ -1,11 +1,12 @@ - $(NetCoreAppCurrent);$(NetCoreAppMinimum) + $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) enable + @@ -17,4 +18,8 @@ + + + + diff --git a/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.netcoreapp.cs b/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.netcoreapp.cs new file mode 100644 index 0000000000000..a68c16ee24dbd --- /dev/null +++ b/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.netcoreapp.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ + +namespace System.Formats.Cbor +{ + public partial class CborReader + { + public System.Half ReadHalf() { throw null; } + } + public partial class CborWriter + { + public void WriteHalf(System.Half value) { } + } +} diff --git a/src/libraries/System.Formats.Cbor/src/CompatibilitySuppressions.xml b/src/libraries/System.Formats.Cbor/src/CompatibilitySuppressions.xml index 8520fb12af7b6..22aa07a6de51c 100644 --- a/src/libraries/System.Formats.Cbor/src/CompatibilitySuppressions.xml +++ b/src/libraries/System.Formats.Cbor/src/CompatibilitySuppressions.xml @@ -1,7 +1,17 @@  - PKV006 - net5.0 + CP0002 + M:System.Formats.Cbor.CborReader.ReadHalf + lib/net5.0/System.Formats.Cbor.dll + lib/netstandard2.0/System.Formats.Cbor.dll + true + + + CP0002 + M:System.Formats.Cbor.CborWriter.WriteHalf(System.Half) + lib/net5.0/System.Formats.Cbor.dll + lib/netstandard2.0/System.Formats.Cbor.dll + true \ No newline at end of file diff --git a/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj b/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj index d456daec3ab4b..29b98e8541577 100644 --- a/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj +++ b/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj @@ -1,6 +1,6 @@ - $(NetCoreAppCurrent);$(NetCoreAppMinimum) + $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true enable true @@ -12,7 +12,6 @@ System.Formats.Cbor.CborWriter - @@ -35,7 +34,21 @@ System.Formats.Cbor.CborWriter - + + + + + + + + + + + + + + + @@ -47,4 +60,14 @@ System.Formats.Cbor.CborWriter + + + + + + + + + + diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborHelpers.netcoreapp.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborHelpers.netcoreapp.cs new file mode 100644 index 0000000000000..3832e832569c9 --- /dev/null +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborHelpers.netcoreapp.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers; +using System.Buffers.Binary; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Text; + +namespace System.Formats.Cbor +{ + internal static partial class CborHelpers + { + public static readonly DateTimeOffset UnixEpoch = DateTimeOffset.UnixEpoch; + + public static int GetBytes(Encoding encoding, ReadOnlySpan source, Span destination) + => encoding.GetBytes(source, destination); + + public static int GetByteCount(Encoding encoding, ReadOnlySpan chars) + => encoding.GetByteCount(chars); + + public static int GetChars(Encoding encoding, ReadOnlySpan source, Span destination) + => encoding.GetChars(source, destination); + + public static int GetCharCount(Encoding encoding, ReadOnlySpan source) + => encoding.GetCharCount(source); + + public static string GetString(Encoding encoding, ReadOnlySpan bytes) + => encoding.GetString(bytes); + + public static BigInteger CreateBigIntegerFromUnsignedBigEndianBytes(byte[] bytes) + => new BigInteger(bytes, isUnsigned: true, isBigEndian: true); + + public static byte[] CreateUnsignedBigEndianBytesFromBigInteger(BigInteger value) + => value.ToByteArray(isUnsigned: true, isBigEndian: true); + + public static void GetBitsFromDecimal(decimal d, Span destination) + => decimal.GetBits(d, destination); + + public static string BuildStringFromIndefiniteLengthTextString(int length, TState state, SpanAction action) + => string.Create(length, state, action); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Half ReadHalfBigEndian(ReadOnlySpan source) + => BinaryPrimitives.ReadHalfBigEndian(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe float ReadSingleBigEndian(ReadOnlySpan source) + => BinaryPrimitives.ReadSingleBigEndian(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double ReadDoubleBigEndian(ReadOnlySpan source) + => BinaryPrimitives.ReadDoubleBigEndian(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteSingleBigEndian(Span destination, float value) + => BinaryPrimitives.WriteSingleBigEndian(destination, value); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteDoubleBigEndian(Span destination, double value) + => BinaryPrimitives.WriteDoubleBigEndian(destination, value); + } +} diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborHelpers.netstandard.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborHelpers.netstandard.cs new file mode 100644 index 0000000000000..b4aafd735d5f8 --- /dev/null +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborHelpers.netstandard.cs @@ -0,0 +1,255 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.Formats.Cbor +{ + internal static partial class CborHelpers + { + private const long UnixEpochTicks = 719162L /*Number of days from 1/1/0001 to 12/31/1969*/ * 10000 * 1000 * 60 * 60 * 24; /* Ticks per day.*/ + + public static readonly DateTimeOffset UnixEpoch = new DateTimeOffset(UnixEpochTicks, TimeSpan.Zero); + + public static unsafe int GetBytes(Encoding encoding, ReadOnlySpan source, Span destination) + { + if (source.IsEmpty || destination.IsEmpty) + { + return 0; + } + + fixed (char* charPtr = source) + fixed (byte* bytePtr = destination) + { + return encoding.GetBytes(charPtr, source.Length, bytePtr, destination.Length); + } + } + + public static unsafe int GetByteCount(Encoding encoding, ReadOnlySpan chars) + { + if (chars.IsEmpty) + { + return 0; + } + + fixed (char* charPtr = chars) + { + return encoding.GetByteCount(charPtr, chars.Length); + } + } + + public static unsafe int GetChars(Encoding encoding, ReadOnlySpan source, Span destination) + { + if (source.IsEmpty || destination.IsEmpty) + { + return 0; + } + + fixed (byte* bytePtr = source) + fixed (char* charPtr = destination) + { + return encoding.GetChars(bytePtr, source.Length, charPtr, destination.Length); + } + } + + public static unsafe int GetCharCount(Encoding encoding, ReadOnlySpan source) + { + if (source.IsEmpty) + { + return 0; + } + + fixed (byte* bytePtr = source) + { + return encoding.GetCharCount(bytePtr, source.Length); + } + } + + public static unsafe string GetString(Encoding encoding, ReadOnlySpan bytes) + { + if (bytes.IsEmpty) + { + return string.Empty; + } + + fixed (byte* bytePtr = bytes) + { + return encoding.GetString(bytePtr, bytes.Length); + } + } + + public static BigInteger CreateBigIntegerFromUnsignedBigEndianBytes(byte[] bigEndianBytes) + { + if (bigEndianBytes.Length == 0) + { + return new BigInteger(bigEndianBytes); + } + + byte[] temp; + if ((bigEndianBytes[0] & 0x80) != 0) // Is negative? + { + // To prevent positive values from being misinterpreted as negative values, + // you can add a zero-byte value to the most significant side of the array. + // Right in this case as it is Big-endian. + var bytesPlusOne = new byte[bigEndianBytes.Length + 1]; + bigEndianBytes.CopyTo(bytesPlusOne.AsSpan().Slice(1)); + temp = bytesPlusOne; + } + else + { + temp = bigEndianBytes; + } + + // Reverse endianness + temp.AsSpan().Reverse(); + + return new BigInteger(temp); + } + + public static byte[] CreateUnsignedBigEndianBytesFromBigInteger(BigInteger value) + { + byte[] littleEndianBytes = value.ToByteArray(); + + if (littleEndianBytes.Length == 1) + { + return littleEndianBytes; + } + + Span bytesAsSpan = littleEndianBytes; + bytesAsSpan.Reverse(); + + int start = 0; + for (int i = 0; i < bytesAsSpan.Length; i++) + { + if (bytesAsSpan[i] == 0x00) + { + start++; + } + else + { + break; + } + } + + Debug.Assert(start <= 1); // If there is a case where we trim more than one byte, we want to add it to our tests. + + return start == 0 ? littleEndianBytes : bytesAsSpan.Slice(start).ToArray(); + } + + public static void GetBitsFromDecimal(decimal d, Span destination) + { + decimal.GetBits(d).CopyTo(destination); + } + + public delegate void SpanAction(Span span, TArg arg); + + public static string BuildStringFromIndefiniteLengthTextString(int length, TState state, SpanAction action) + { + char[] arr = new char[length]; + action(arr, state); + return new string(arr); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ReadHalfBigEndian(ReadOnlySpan source) + { + ushort value = BitConverter.IsLittleEndian ? + BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read(source)) : + MemoryMarshal.Read(source); + + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteHalfBigEndian(Span destination, ushort value) + { + if (BitConverter.IsLittleEndian) + { + ushort tmp = BinaryPrimitives.ReverseEndianness(value); + MemoryMarshal.Write(destination, ref tmp); + } + else + { + MemoryMarshal.Write(destination, ref value); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe float ReadSingleBigEndian(ReadOnlySpan source) + { + return BitConverter.IsLittleEndian ? + Int32BitsToSingle(BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read(source))) : + MemoryMarshal.Read(source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteSingleBigEndian(Span destination, float value) + { + if (BitConverter.IsLittleEndian) + { + int tmp = BinaryPrimitives.ReverseEndianness(SingleToInt32Bits(value)); + MemoryMarshal.Write(destination, ref tmp); + } + else + { + MemoryMarshal.Write(destination, ref value); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double ReadDoubleBigEndian(ReadOnlySpan source) + { + return BitConverter.IsLittleEndian ? + BitConverter.Int64BitsToDouble(BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read(source))) : + MemoryMarshal.Read(source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void WriteDoubleBigEndian(Span destination, double value) + { + if (BitConverter.IsLittleEndian) + { + long tmp = BinaryPrimitives.ReverseEndianness(BitConverter.DoubleToInt64Bits(value)); + MemoryMarshal.Write(destination, ref tmp); + } + else + { + MemoryMarshal.Write(destination, ref value); + } + } + + internal static uint SingleToUInt32Bits(float value) + => (uint)SingleToInt32Bits(value); + + internal static unsafe int SingleToInt32Bits(float value) + => *((int*)&value); + + internal static float UInt32BitsToSingle(uint value) + => Int32BitsToSingle((int)value); + + internal static unsafe float Int32BitsToSingle(int value) + => *((float*)&value); + } + + internal static class StackExtensions + { + public static bool TryPop(this Stack stack, [MaybeNullWhen(false)] out T result) + { + if (stack.Count > 0) + { + result = stack.Pop(); + return true; + } + + result = default; + return false; + } + } +} diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.cs deleted file mode 100644 index e3ac9428b037e..0000000000000 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers.Binary; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace System.Formats.Cbor -{ - // Temporarily implements missing APIs for System.Half - // Remove class once https://github.com/dotnet/runtime/issues/38288 has been addressed - internal static class HalfHelpers - { - public const int SizeOfHalf = sizeof(short); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Half ReadHalfBigEndian(ReadOnlySpan source) - { - return BitConverter.IsLittleEndian ? - Int16BitsToHalf(BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read(source))) : - MemoryMarshal.Read(source); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteHalfBigEndian(Span destination, Half value) - { - if (BitConverter.IsLittleEndian) - { - short tmp = BinaryPrimitives.ReverseEndianness(HalfToInt16Bits(value)); - MemoryMarshal.Write(destination, ref tmp); - } - else - { - MemoryMarshal.Write(destination, ref value); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe short HalfToInt16Bits(Half value) - { - return *((short*)&value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Half Int16BitsToHalf(short value) - { - return *(Half*)&value; - } - } -} diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netcoreapp.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netcoreapp.cs new file mode 100644 index 0000000000000..96514354547b2 --- /dev/null +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netcoreapp.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Formats.Cbor +{ + internal static partial class HalfHelpers + { + public static unsafe float HalfToFloat(Half value) + => (float)value; + + public static unsafe double HalfToDouble(Half value) + => (double)value; + } +} diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netstandard.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netstandard.cs new file mode 100644 index 0000000000000..36dfafd6ff340 --- /dev/null +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netstandard.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Formats.Cbor +{ + internal static partial class HalfHelpers + { + // Half constants + private const ushort HalfExponentMask = 0x7C00; + private const ushort HalfExponentShift = 10; + private const ushort HalfSignShift = 15; + private const ushort HalfPositiveInfinityBits = 0x7C00; + private const ushort HalfNegativeInfinityBits = 0xFC00; + + // Float constants + private const uint FloatExponentMask = 0x7F80_0000; + private const int FloatExponentShift = 23; + private const uint FloatSignificandMask = 0x007F_FFFF; + private const uint FloatSignMask = 0x8000_0000; + private const int FloatSignShift = 31; + + #region From Half and related helpers. + // Instead of copying (yet again) the explicit operator, + // we perform a Half to float to double conversion. + public static double HalfToDouble(ushort value) + => (double)HalfToFloat(value); + + public static unsafe float HalfToFloat(ushort value) + { + const ushort ExponentMask = 0x7C00; + const ushort ExponentShift = 10; + const ushort SignificandMask = 0x03FF; + const ushort SignificandShift = 0; + const ushort MaxExponent = 0x1F; + + bool sign = (short)value < 0; + int exp = (sbyte)((value & ExponentMask) >> ExponentShift); + uint sig = (ushort)((value & SignificandMask) >> SignificandShift); + + if (exp == MaxExponent) + { + if (sig != 0) + { + return CreateSingleNaN(sign, (ulong)sig << 54); + } + return sign ? float.NegativeInfinity : float.PositiveInfinity; + } + + if (exp == 0) + { + if (sig == 0) + { + return CborHelpers.UInt32BitsToSingle(sign ? FloatSignMask : 0); // Positive / Negative zero + } + (exp, sig) = NormSubnormalF16Sig(sig); + exp -= 1; + } + + return CreateSingle(sign, (byte)(exp + 0x70), sig << 13); + + static float CreateSingle(bool sign, byte exp, uint sig) + => CborHelpers.Int32BitsToSingle((int)(((sign ? 1U : 0U) << FloatSignShift) + ((uint)exp << FloatExponentShift) + sig)); + } + + private static (int Exp, uint Sig) NormSubnormalF16Sig(uint sig) + { + int shiftDist = LeadingZeroCount(sig) - 16 - 5; + return (1 - shiftDist, sig << shiftDist); + } + + public static int LeadingZeroCount(uint value) + { + // Unguarded fallback contract is 0->31, BSR contract is 0->undefined + if (value == 0) + { + return 32; + } + + return 31 ^ Log2SoftwareFallback(value); + } + + private static ReadOnlySpan Log2DeBruijn => new byte[32] + { + 00, 09, 01, 10, 13, 21, 02, 29, + 11, 14, 16, 18, 22, 25, 03, 30, + 08, 12, 20, 28, 15, 17, 24, 07, + 19, 27, 23, 06, 26, 05, 04, 31 + }; + + private static int Log2SoftwareFallback(uint value) + { + // No AggressiveInlining due to large method size + // Has conventional contract 0->0 (Log(0) is undefined) + + // Fill trailing zeros with ones, eg 00010010 becomes 00011111 + value |= value >> 01; + value |= value >> 02; + value |= value >> 04; + value |= value >> 08; + value |= value >> 16; + + // uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check + return Unsafe.AddByteOffset( + // Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_1100_0100_1010_1100_1101_1101u + ref MemoryMarshal.GetReference(Log2DeBruijn), + // uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here + (IntPtr)(int)((value * 0x07C4ACDDu) >> 27)); + } + + private static float CreateSingleNaN(bool sign, ulong significand) + { + const uint NaNBits = FloatExponentMask | 0x400000; // Most significant significand bit + + uint signInt = (sign ? 1U : 0U) << FloatSignShift; + uint sigInt = (uint)(significand >> 41); + + return CborHelpers.UInt32BitsToSingle(signInt | NaNBits | sigInt); + } + #endregion + + #region To Half and related helpers. + public static ushort FloatToHalf(float value) + { + const int SingleMaxExponent = 0xFF; + + uint floatInt = CborHelpers.SingleToUInt32Bits(value); + bool sign = (floatInt & FloatSignMask) >> FloatSignShift != 0; + int exp = (int)(floatInt & FloatExponentMask) >> FloatExponentShift; + uint sig = floatInt & FloatSignificandMask; + + if (exp == SingleMaxExponent) + { + if (sig != 0) // NaN + { + return CreateHalfNaN(sign, (ulong)sig << 41); // Shift the significand bits to the left end + } + return sign ? HalfNegativeInfinityBits : HalfPositiveInfinityBits; + } + + uint sigHalf = sig >> 9 | ((sig & 0x1FFU) != 0 ? 1U : 0U); // RightShiftJam + + if ((exp | (int)sigHalf) == 0) + { + return HalfCtor(sign, 0, 0); + } + + return RoundPackToHalf(sign, (short)(exp - 0x71), (ushort)(sigHalf | 0x4000)); + } + + private static ushort CreateHalfNaN(bool sign, ulong significand) + { + const uint NaNBits = HalfExponentMask | 0x200; // Most significant significand bit + + uint signInt = (sign ? 1U : 0U) << HalfSignShift; + uint sigInt = (uint)(significand >> 54); + + return (ushort)(signInt | NaNBits | sigInt); + } + + private static ushort HalfCtor(bool sign, ushort exp, ushort sig) + => (ushort)(((sign ? 1 : 0) << HalfSignShift) + (exp << HalfExponentShift) + sig); + + private static ushort RoundPackToHalf(bool sign, short exp, ushort sig) + { + const int RoundIncrement = 0x8; // Depends on rounding mode but it's always towards closest / ties to even + int roundBits = sig & 0xF; + + if ((uint)exp >= 0x1D) + { + if (exp < 0) + { + sig = (ushort)ShiftRightJam(sig, -exp); + exp = 0; + roundBits = sig & 0xF; + } + else if (exp > 0x1D || sig + RoundIncrement >= 0x8000) // Overflow + { + return sign ? HalfNegativeInfinityBits : HalfPositiveInfinityBits; + } + } + + sig = (ushort)((sig + RoundIncrement) >> 4); + sig &= (ushort)~(((roundBits ^ 8) != 0 ? 0 : 1) & 1); + + if (sig == 0) + { + exp = 0; + } + + return HalfCtor(sign, (ushort)exp, sig); + } + + // If any bits are lost by shifting, "jam" them into the LSB. + // if dist > bit count, Will be 1 or 0 depending on i + // (unlike bitwise operators that masks the lower 5 bits) + private static uint ShiftRightJam(uint i, int dist) + => dist < 31 ? (i >> dist) | (i << (-dist & 31) != 0 ? 1U : 0U) : (i != 0 ? 1U : 0U); + #endregion + } +} diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Simple.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Simple.cs index 9d2188ac34723..6c1e6c0b6087d 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Simple.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Simple.cs @@ -7,42 +7,6 @@ namespace System.Formats.Cbor { public partial class CborReader { - /// Reads the next data item as a half-precision floating point number (major type 7). - /// The decoded value. - /// The next data item does not have the correct major type. - /// -or- - /// The next simple value is not a floating-point number encoding. - /// -or- - /// The encoded value is a double-precision float. - /// The next value has an invalid CBOR encoding. - /// -or- - /// There was an unexpected end of CBOR encoding data. - /// -or- - /// The next value uses a CBOR encoding that is not valid under the current conformance mode. - public Half ReadHalf() - { - CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Simple); - ReadOnlySpan buffer = GetRemainingBytes(); - Half result; - - switch (header.AdditionalInfo) - { - case CborAdditionalInfo.Additional16BitData: - EnsureReadCapacity(buffer, 1 + HalfHelpers.SizeOfHalf); - result = HalfHelpers.ReadHalfBigEndian(buffer.Slice(1)); - AdvanceBuffer(1 + HalfHelpers.SizeOfHalf); - AdvanceDataItemCounters(); - return result; - - case CborAdditionalInfo.Additional32BitData: - case CborAdditionalInfo.Additional64BitData: - throw new InvalidOperationException(SR.Cbor_Reader_ReadingAsLowerPrecision); - - default: - throw new InvalidOperationException(SR.Cbor_Reader_NotAFloatEncoding); - } - } - /// Reads the next data item as a single-precision floating point number (major type 7). /// The decoded value. /// The next data item does not have the correct major type. @@ -64,15 +28,15 @@ public float ReadSingle() switch (header.AdditionalInfo) { case CborAdditionalInfo.Additional16BitData: - EnsureReadCapacity(buffer, 1 + HalfHelpers.SizeOfHalf); - result = (float)HalfHelpers.ReadHalfBigEndian(buffer.Slice(1)); - AdvanceBuffer(1 + HalfHelpers.SizeOfHalf); + EnsureReadCapacity(buffer, 1 + sizeof(ushort)); + result = HalfHelpers.HalfToFloat(CborHelpers.ReadHalfBigEndian(buffer.Slice(1))); + AdvanceBuffer(1 + sizeof(ushort)); AdvanceDataItemCounters(); return result; case CborAdditionalInfo.Additional32BitData: EnsureReadCapacity(buffer, 1 + sizeof(float)); - result = BinaryPrimitives.ReadSingleBigEndian(buffer.Slice(1)); + result = CborHelpers.ReadSingleBigEndian(buffer.Slice(1)); AdvanceBuffer(1 + sizeof(float)); AdvanceDataItemCounters(); return result; @@ -105,22 +69,22 @@ public double ReadDouble() switch (header.AdditionalInfo) { case CborAdditionalInfo.Additional16BitData: - EnsureReadCapacity(buffer, 1 + HalfHelpers.SizeOfHalf); - result = (double)HalfHelpers.ReadHalfBigEndian(buffer.Slice(1)); - AdvanceBuffer(1 + HalfHelpers.SizeOfHalf); + EnsureReadCapacity(buffer, 1 + sizeof(short)); + result = HalfHelpers.HalfToDouble(CborHelpers.ReadHalfBigEndian(buffer.Slice(1))); + AdvanceBuffer(1 + sizeof(short)); AdvanceDataItemCounters(); return result; case CborAdditionalInfo.Additional32BitData: EnsureReadCapacity(buffer, 1 + sizeof(float)); - result = BinaryPrimitives.ReadSingleBigEndian(buffer.Slice(1)); + result = CborHelpers.ReadSingleBigEndian(buffer.Slice(1)); AdvanceBuffer(1 + sizeof(float)); AdvanceDataItemCounters(); return result; case CborAdditionalInfo.Additional64BitData: EnsureReadCapacity(buffer, 1 + sizeof(double)); - result = BinaryPrimitives.ReadDoubleBigEndian(buffer.Slice(1)); + result = CborHelpers.ReadDoubleBigEndian(buffer.Slice(1)); AdvanceBuffer(1 + sizeof(double)); AdvanceDataItemCounters(); return result; diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Simple.netcoreapp.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Simple.netcoreapp.cs new file mode 100644 index 0000000000000..d02fc0cd6b2aa --- /dev/null +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Simple.netcoreapp.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. + +using System.Buffers.Binary; + +namespace System.Formats.Cbor +{ + public partial class CborReader + { + /// Reads the next data item as a half-precision floating point number (major type 7). + /// The decoded value. + /// The next data item does not have the correct major type. + /// -or- + /// The next simple value is not a floating-point number encoding. + /// -or- + /// The encoded value is a double-precision float. + /// The next value has an invalid CBOR encoding. + /// -or- + /// There was an unexpected end of CBOR encoding data. + /// -or- + /// The next value uses a CBOR encoding that is not valid under the current conformance mode. + public Half ReadHalf() + { + CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Simple); + ReadOnlySpan buffer = GetRemainingBytes(); + Half result; + + switch (header.AdditionalInfo) + { + case CborAdditionalInfo.Additional16BitData: + EnsureReadCapacity(buffer, 1 + sizeof(short)); + result = BinaryPrimitives.ReadHalfBigEndian(buffer.Slice(1)); + AdvanceBuffer(1 + sizeof(short)); + AdvanceDataItemCounters(); + return result; + case CborAdditionalInfo.Additional32BitData: + case CborAdditionalInfo.Additional64BitData: + throw new InvalidOperationException(SR.Cbor_Reader_ReadingAsLowerPrecision); + + default: + throw new InvalidOperationException(SR.Cbor_Reader_NotAFloatEncoding); + } + } + } +} diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.String.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.String.cs index 6ede28d84230b..b9eac39f55343 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.String.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.String.cs @@ -192,7 +192,7 @@ public string ReadTextString() string result; try { - result = utf8Encoding.GetString(encodedString); + result = CborHelpers.GetString(utf8Encoding, encodedString); } catch (DecoderFallbackException e) { @@ -244,7 +244,7 @@ public bool TryReadTextString(Span destination, out int charsWritten) return false; } - utf8Encoding.GetChars(encodedSlice, destination); + CborHelpers.GetChars(utf8Encoding, encodedSlice, destination); AdvanceBuffer(bytesRead + byteLength); AdvanceDataItemCounters(); charsWritten = charLength; @@ -387,7 +387,7 @@ private string ReadIndefiniteLengthTextStringConcatenated() } // build the string using range data - string output = string.Create(concatenatedStringSize, (ranges, _data.Slice(_offset), utf8Encoding), BuildString); + string output = CborHelpers.BuildStringFromIndefiniteLengthTextString(concatenatedStringSize, (ranges, _data.Slice(_offset), utf8Encoding), BuildString); AdvanceBuffer(encodingLength); AdvanceDataItemCounters(); @@ -400,7 +400,7 @@ static void BuildString(Span target, (List<(int Offset, int Length)> range foreach ((int o, int l) in input.ranges) { - int charsWritten = input.utf8Encoding.GetChars(source.Slice(o, l), target); + int charsWritten = CborHelpers.GetChars(input.utf8Encoding, source.Slice(o, l), target); target = target.Slice(charsWritten); } @@ -429,7 +429,7 @@ private bool TryReadIndefiniteLengthTextStringConcatenated(Span destinatio foreach ((int o, int l) in ranges) { - utf8Encoding.GetChars(buffer.Slice(o, l), destination); + CborHelpers.GetChars(utf8Encoding, buffer.Slice(o, l), destination); destination = destination.Slice(l); } @@ -507,7 +507,7 @@ private int ValidateUtf8AndGetCharCount(ReadOnlySpan buffer, Encoding utf8 { try { - return utf8Encoding.GetCharCount(buffer); + return CborHelpers.GetCharCount(utf8Encoding, buffer); } catch (DecoderFallbackException e) { diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Tag.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Tag.cs index edf6d868b7f62..a2107ccf0f8ae 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Tag.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Reader/CborReader.Tag.cs @@ -125,7 +125,7 @@ public DateTimeOffset ReadUnixTimeSeconds() } TimeSpan timespan = TimeSpan.FromSeconds(seconds); - return DateTimeOffset.UnixEpoch + timespan; + return CborHelpers.UnixEpoch + timespan; default: throw new CborContentException(SR.Cbor_Reader_InvalidUnixTimeEncoding); @@ -175,7 +175,7 @@ public BigInteger ReadBigInteger() } byte[] unsignedBigEndianEncoding = ReadByteString(); - BigInteger unsignedValue = new BigInteger(unsignedBigEndianEncoding, isUnsigned: true, isBigEndian: true); + BigInteger unsignedValue = CborHelpers.CreateBigIntegerFromUnsignedBigEndianBytes(unsignedBigEndianEncoding); return isNegative ? -1 - unsignedValue : unsignedValue; } catch diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.cs index 6d4178bae79bb..74f0524b01638 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Buffers.Binary; using System.Runtime.CompilerServices; namespace System.Formats.Cbor @@ -10,22 +9,6 @@ public partial class CborWriter { // Implements major type 7 encoding per https://tools.ietf.org/html/rfc7049#section-2.1 - /// Writes a half-precision floating point number (major type 7). - /// The value to write. - /// Writing a new value exceeds the definite length of the parent data item. - /// -or- - /// The major type of the encoded value is not permitted in the parent data item. - /// -or- - /// The written data is not accepted under the current conformance mode. - public void WriteHalf(Half value) - { - EnsureWriteCapacity(1 + HalfHelpers.SizeOfHalf); - WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional16BitData)); - HalfHelpers.WriteHalfBigEndian(_buffer.AsSpan(_offset), value); - _offset += HalfHelpers.SizeOfHalf; - AdvanceDataItemCounters(); - } - /// Writes a single-precision floating point number (major type 7). /// The value to write. /// Writing a new value exceeds the definite length of the parent data item. @@ -36,7 +19,7 @@ public void WriteHalf(Half value) public void WriteSingle(float value) { if (!CborConformanceModeHelpers.RequiresPreservingFloatPrecision(ConformanceMode) && - FloatSerializationHelpers.TryConvertSingleToHalf(value, out Half half)) + TryConvertSingleToHalf(value, out var half)) { WriteHalf(half); } @@ -56,9 +39,9 @@ public void WriteSingle(float value) public void WriteDouble(double value) { if (!CborConformanceModeHelpers.RequiresPreservingFloatPrecision(ConformanceMode) && - FloatSerializationHelpers.TryConvertDoubleToSingle(value, out float single)) + TryConvertDoubleToSingle(value, out float single)) { - if (FloatSerializationHelpers.TryConvertSingleToHalf(single, out Half half)) + if (TryConvertSingleToHalf(single, out var half)) { WriteHalf(half); } @@ -72,12 +55,11 @@ public void WriteDouble(double value) WriteDoubleCore(value); } } - private void WriteSingleCore(float value) { EnsureWriteCapacity(1 + sizeof(float)); WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional32BitData)); - BinaryPrimitives.WriteSingleBigEndian(_buffer.AsSpan(_offset), value); + CborHelpers.WriteSingleBigEndian(_buffer.AsSpan(_offset), value); _offset += sizeof(float); AdvanceDataItemCounters(); } @@ -86,7 +68,7 @@ private void WriteDoubleCore(double value) { EnsureWriteCapacity(1 + sizeof(double)); WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional64BitData)); - BinaryPrimitives.WriteDoubleBigEndian(_buffer.AsSpan(_offset), value); + CborHelpers.WriteDoubleBigEndian(_buffer.AsSpan(_offset), value); _offset += sizeof(double); AdvanceDataItemCounters(); } @@ -144,21 +126,11 @@ public void WriteSimpleValue(CborSimpleValue value) AdvanceDataItemCounters(); } - private static class FloatSerializationHelpers + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryConvertDoubleToSingle(double value, out float result) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool TryConvertDoubleToSingle(double value, out float result) - { - result = (float)value; - return BitConverter.DoubleToInt64Bits(result) == BitConverter.DoubleToInt64Bits(value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool TryConvertSingleToHalf(float value, out Half result) - { - result = (Half)value; - return BitConverter.SingleToInt32Bits((float)result) == BitConverter.SingleToInt32Bits(value); - } + result = (float)value; + return BitConverter.DoubleToInt64Bits(result) == BitConverter.DoubleToInt64Bits(value); } } } diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.netcoreapp.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.netcoreapp.cs new file mode 100644 index 0000000000000..db8986b1f20f1 --- /dev/null +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.netcoreapp.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. + +using System.Buffers.Binary; +using System.Runtime.CompilerServices; + +namespace System.Formats.Cbor +{ + public partial class CborWriter + { + // Implements major type 7 encoding per https://tools.ietf.org/html/rfc7049#section-2.1 + + /// Writes a half-precision floating point number (major type 7). + /// The value to write. + /// Writing a new value exceeds the definite length of the parent data item. + /// -or- + /// The major type of the encoded value is not permitted in the parent data item. + /// -or- + /// The written data is not accepted under the current conformance mode. + public void WriteHalf(Half value) + { + EnsureWriteCapacity(1 + sizeof(short)); + WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional16BitData)); + BinaryPrimitives.WriteHalfBigEndian(_buffer.AsSpan(_offset), value); + _offset += sizeof(short); + AdvanceDataItemCounters(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool TryConvertSingleToHalf(float value, out Half result) + { + result = (Half)value; + return BitConverter.SingleToInt32Bits((float)result) == BitConverter.SingleToInt32Bits(value); + } + } +} diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.netstandard.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.netstandard.cs new file mode 100644 index 0000000000000..02f134513facc --- /dev/null +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Simple.netstandard.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. + +using System.Buffers.Binary; +using System.Runtime.CompilerServices; + +namespace System.Formats.Cbor +{ + public partial class CborWriter + { + // Implements major type 7 encoding per https://tools.ietf.org/html/rfc7049#section-2.1 + + /// Writes a half-precision floating point number (major type 7). + /// The value to write. + /// Writing a new value exceeds the definite length of the parent data item. + /// -or- + /// The major type of the encoded value is not permitted in the parent data item. + /// -or- + /// The written data is not accepted under the current conformance mode. + private void WriteHalf(ushort value) + { + EnsureWriteCapacity(1 + sizeof(ushort)); + WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional16BitData)); + CborHelpers.WriteHalfBigEndian(_buffer.AsSpan(_offset), value); + _offset += sizeof(ushort); + AdvanceDataItemCounters(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool TryConvertSingleToHalf(float value, out ushort result) + { + result = HalfHelpers.FloatToHalf(value); + return CborHelpers.SingleToInt32Bits(HalfHelpers.HalfToFloat(result)) == CborHelpers.SingleToInt32Bits(value); + } + } +} diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.String.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.String.cs index 379163789c832..2e600d99dad32 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.String.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.String.cs @@ -131,7 +131,7 @@ public void WriteTextString(ReadOnlySpan value) int length; try { - length = utf8Encoding.GetByteCount(value); + length = CborHelpers.GetByteCount(utf8Encoding, value); } catch (EncoderFallbackException e) { @@ -150,7 +150,7 @@ public void WriteTextString(ReadOnlySpan value) _currentIndefiniteLengthStringRanges.Add((_offset, value.Length)); } - utf8Encoding.GetBytes(value, _buffer.AsSpan(_offset, length)); + CborHelpers.GetBytes(utf8Encoding, value, _buffer.AsSpan(_offset, length)); _offset += length; AdvanceDataItemCounters(); } diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs index bd94ca2acd15f..6ce58ec11d8e7 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs @@ -88,7 +88,7 @@ public void WriteBigInteger(BigInteger value) { bool isUnsigned = value.Sign >= 0; BigInteger unsignedValue = isUnsigned ? value : -1 - value; - byte[] unsignedBigEndianEncoding = unsignedValue.ToByteArray(isUnsigned: true, isBigEndian: true); + byte[] unsignedBigEndianEncoding = CborHelpers.CreateUnsignedBigEndianBytesFromBigInteger(unsignedValue); WriteTag(isUnsigned ? CborTag.UnsignedBigNum : CborTag.NegativeBigNum); WriteByteString(unsignedBigEndianEncoding); @@ -142,7 +142,7 @@ internal static class DecimalHelpers public static void Deconstruct(decimal value, out decimal mantissa, out byte scale) { Span buf = stackalloc int[4]; - decimal.GetBits(value, buf); + CborHelpers.GetBitsFromDecimal(value, buf); int flags = buf[3]; bool isNegative = (flags & SignMask) == SignMask; @@ -154,7 +154,7 @@ public static void Deconstruct(decimal value, out decimal mantissa, out byte sca private static decimal ReconstructFromNegativeScale(decimal mantissa, byte scale) { Span buf = stackalloc int[4]; - decimal.GetBits(mantissa, buf); + CborHelpers.GetBitsFromDecimal(mantissa, buf); int flags = buf[3]; bool isNegative = (flags & SignMask) == SignMask; diff --git a/src/libraries/System.Formats.Cbor/tests/CborTestHelpers.netcoreapp.cs b/src/libraries/System.Formats.Cbor/tests/CborTestHelpers.netcoreapp.cs new file mode 100644 index 0000000000000..6aaa045512800 --- /dev/null +++ b/src/libraries/System.Formats.Cbor/tests/CborTestHelpers.netcoreapp.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. + +namespace System.Formats.Cbor.Tests +{ + internal static class CborTestHelpers + { + public static readonly DateTimeOffset UnixEpoch = DateTimeOffset.UnixEpoch; + } +} diff --git a/src/libraries/System.Formats.Cbor/tests/CborTestHelpers.netstandard.cs b/src/libraries/System.Formats.Cbor/tests/CborTestHelpers.netstandard.cs new file mode 100644 index 0000000000000..80fb9cd7db6db --- /dev/null +++ b/src/libraries/System.Formats.Cbor/tests/CborTestHelpers.netstandard.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. + +namespace System.Formats.Cbor.Tests +{ + internal static class CborTestHelpers + { + private const long UnixEpochTicks = 719162L /*Number of days from 1/1/0001 to 12/31/1969*/ * 10000 * 1000 * 60 * 60 * 24; /* Ticks per day.*/ + public static readonly DateTimeOffset UnixEpoch = new DateTimeOffset(UnixEpochTicks, TimeSpan.Zero); + } +} diff --git a/src/libraries/System.Formats.Cbor/tests/CoseKeyHelpers.cs b/src/libraries/System.Formats.Cbor/tests/CoseKeyHelpers.cs index a3cfca3069e07..944b86ae7b336 100644 --- a/src/libraries/System.Formats.Cbor/tests/CoseKeyHelpers.cs +++ b/src/libraries/System.Formats.Cbor/tests/CoseKeyHelpers.cs @@ -90,7 +90,13 @@ private static void WriteECParametersAsCosePublicKey(CborWriter writer, ECParame throw new ArgumentException("Unrecognized named curve", curve.Oid.Value); - bool MatchesOid(ECCurve namedCurve) => curve.Oid.Value == namedCurve.Oid.Value; + bool MatchesOid(ECCurve namedCurve) => curve.Oid.Value == namedCurve.Oid.Value +#if NETFRAMEWORK + // If this check fails, resolve the OID Value yourself. + // See https://github.com/dotnet/runtime/issues/62813#issuecomment-994114540 + || (curve.Oid.Value is null && curve.Oid.FriendlyName == namedCurve.Oid.FriendlyName) +#endif + ; } static CoseKeyAlgorithm MapHashAlgorithmNameToCoseKeyAlg(HashAlgorithmName name) diff --git a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.ByteString.cs b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.ByteString.cs index 1e06314986d78..567740818915a 100644 --- a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.ByteString.cs +++ b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.ByteString.cs @@ -38,7 +38,7 @@ public static void TryReadByteString_SingleValue_HappyPath(string hexExpectedVal bool result = reader.TryReadByteString(buffer, out int bytesWritten); Assert.True(result); Assert.Equal(expectedValue.Length, bytesWritten); - Assert.Equal(expectedValue, buffer[..bytesWritten]); + Assert.Equal(expectedValue, buffer.Take(bytesWritten)); Assert.Equal(CborReaderState.Finished, reader.PeekState()); } diff --git a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Map.cs b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Map.cs index 126cae1b500a9..b94d01a23e2e3 100644 --- a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Map.cs +++ b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Map.cs @@ -226,7 +226,7 @@ public static void ReadMap_UnsortedKeys_ConformanceRequiringSortedKeys_ShouldThr { var reader = new CborReader(hexEncoding.HexToByteArray(), mode); reader.ReadStartMap(); - foreach (object key in keySequence.SkipLast(1)) + foreach (object key in keySequence.Take(keySequence.Length - 1)) { Helpers.VerifyValue(reader, key); // verify key reader.ReadInt32(); // value is always an integer diff --git a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Simple.cs b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Simple.cs index 53075439bdf9c..1c71ba3b8668a 100644 --- a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Simple.cs +++ b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Simple.cs @@ -12,28 +12,7 @@ public partial class CborReaderTests // Additional pairs generated using http://cbor.me/ [Theory] - [InlineData(0.0, "f90000")] - [InlineData(-0.0, "f98000")] - [InlineData(1.0, "f93c00")] - [InlineData(1.5, "f93e00")] - [InlineData(65504.0, "f97bff")] - [InlineData(5.960464477539063e-8, "f90001")] - [InlineData(0.00006103515625, "f90400")] - [InlineData(-4.0, "f9c400")] - [InlineData(double.PositiveInfinity, "f97c00")] - [InlineData(double.NaN, "f97e00")] - [InlineData(double.NegativeInfinity, "f9fc00")] - public static void ReadHalf_SingleValue_HappyPath(float expectedResult, string hexEncoding) - { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - Assert.Equal(CborReaderState.HalfPrecisionFloat, reader.PeekState()); - Half actualResult = reader.ReadHalf(); - AssertHelpers.Equal((Half)expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.PeekState()); - } - - [Theory] + [InlineData(1.0, "fa3f800000")] [InlineData(100000.0, "fa47c35000")] [InlineData(3.4028234663852886e+38, "fa7f7fffff")] [InlineData(float.PositiveInfinity, "fa7f800000")] @@ -247,25 +226,6 @@ public static void ReadNull_InvalidTypes_ShouldThrowInvalidOperationException(st Assert.Equal(encoding.Length, reader.BytesRemaining); } - [Theory] - [InlineData("01")] // integer - [InlineData("40")] // empty text string - [InlineData("60")] // empty byte string - [InlineData("80")] // [] - [InlineData("a0")] // {} - [InlineData("f6")] // null - [InlineData("f4")] // false - [InlineData("c202")] // tagged value - [InlineData("fa47c35000")] // single-precision float encoding - [InlineData("fb7ff0000000000000")] // double-precision float encoding - public static void ReadHalf_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) - { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - Assert.Throws(() => reader.ReadHalf()); - Assert.Equal(encoding.Length, reader.BytesRemaining); - } - [Theory] [InlineData("01")] // integer [InlineData("40")] // empty text string @@ -300,21 +260,5 @@ public static void ReadDouble_InvalidTypes_ShouldThrowInvalidOperationException( Assert.Throws(() => reader.ReadDouble()); Assert.Equal(encoding.Length, reader.BytesRemaining); } - - public static class AssertHelpers - { - // temporary workaround for xunit's lack of support for Half equality assertions - public static void Equal(Half expected, Half actual) - { - if (Half.IsNaN(expected)) - { - Assert.True(Half.IsNaN(actual), $"Expected: {expected}\nActual: {actual}"); - } - else - { - Assert.Equal(expected, actual); - } - } - } } } diff --git a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Simple.netcoreapp.cs b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Simple.netcoreapp.cs new file mode 100644 index 0000000000000..8a11121bbb1a8 --- /dev/null +++ b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Simple.netcoreapp.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Test.Cryptography; +using Xunit; + +namespace System.Formats.Cbor.Tests +{ + public partial class CborReaderTests + { + [Theory] + [InlineData(0.0, "f90000")] + [InlineData(-0.0, "f98000")] + [InlineData(1.0, "f93c00")] + [InlineData(1.5, "f93e00")] + [InlineData(65504.0, "f97bff")] + [InlineData(5.960464477539063e-8, "f90001")] + [InlineData(0.00006103515625, "f90400")] + [InlineData(-4.0, "f9c400")] + [InlineData(double.PositiveInfinity, "f97c00")] + [InlineData(double.NaN, "f97e00")] + [InlineData(double.NegativeInfinity, "f9fc00")] + public static void ReadHalf_SingleValue_HappyPath(float expectedResult, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Equal(CborReaderState.HalfPrecisionFloat, reader.PeekState()); + Half actualResult = reader.ReadHalf(); + AssertHelpers.Equal((Half)expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData("01")] // integer + [InlineData("40")] // empty text string + [InlineData("60")] // empty byte string + [InlineData("80")] // [] + [InlineData("a0")] // {} + [InlineData("f6")] // null + [InlineData("f4")] // false + [InlineData("c202")] // tagged value + [InlineData("fa47c35000")] // single-precision float encoding + [InlineData("fb7ff0000000000000")] // double-precision float encoding + public static void ReadHalf_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadHalf()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + public static class AssertHelpers + { + + // temporary workaround for xunit's lack of support for Half equality assertions + public static void Equal(Half expected, Half actual) + { + if (Half.IsNaN(expected)) + { + Assert.True(Half.IsNaN(actual), $"Expected: {expected}\nActual: {actual}"); + } + else + { + Assert.Equal(expected, actual); + } + } + } + } +} diff --git a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Tag.cs b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Tag.cs index f09e89115541e..af9adfbe67b50 100644 --- a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Tag.cs +++ b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.Tag.cs @@ -557,7 +557,7 @@ private static (object value, string hexEncoding)[] TaggedValues => (new object[] { CborTag.MimeMessage, 42 }, "d824182a"), (42.0m, "c482201901a4"), ((BigInteger)1, "c24101"), - (DateTimeOffset.UnixEpoch, "c0781c313937302d30312d30315430303a30303a30302e303030303030305a"), + (CborTestHelpers.UnixEpoch, "c0781c313937302d30312d30315430303a30303a30302e303030303030305a"), }; } } diff --git a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.TextString.cs b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.TextString.cs index b06b36696f750..4f6acad8e5287 100644 --- a/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.TextString.cs +++ b/src/libraries/System.Formats.Cbor/tests/Reader/CborReaderTests.TextString.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Linq; using System.Text; using Test.Cryptography; using Xunit; @@ -44,7 +45,7 @@ public static void TryReadTextString_SingleValue_HappyPath(string expectedValue, bool result = reader.TryReadTextString(buffer, out int charsWritten); Assert.True(result); Assert.Equal(expectedValue.Length, charsWritten); - Assert.Equal(expectedValue.ToCharArray(), buffer[..charsWritten]); + Assert.Equal(expectedValue.ToCharArray(), buffer.Take(charsWritten)); Assert.Equal(CborReaderState.Finished, reader.PeekState()); } @@ -104,7 +105,11 @@ public static void TryReadTextString_IndefiniteLengthConcatenated_SingleValue__H Assert.True(result); Assert.Equal(expectedValue.Length, charsWritten); - Assert.Equal(expectedValue, new string(buffer.Slice(0, charsWritten))); + Assert.Equal(expectedValue, new string(buffer.Slice(0, charsWritten) +#if !NETCOREAPP +.ToArray() +#endif + )); Assert.Equal(CborReaderState.Finished, reader.PeekState()); } @@ -130,7 +135,11 @@ public static void TryReadTextString_BufferTooSmall_ShouldReturnFalse(string act result = reader.TryReadTextString(buffer, out charsWritten); Assert.True(result); Assert.Equal(actualValue.Length, charsWritten); - Assert.Equal(actualValue, new string(buffer.AsSpan(0, charsWritten))); + Assert.Equal(actualValue, new string(buffer.AsSpan(0, charsWritten) +#if !NETCOREAPP +.ToArray() +#endif + )); } [Theory] @@ -152,7 +161,11 @@ public static void TryReadTextString_IndefiniteLengthConcatenated_BufferTooSmall result = reader.TryReadTextString(buffer, out charsWritten); Assert.True(result); Assert.Equal(expectedValue.Length, charsWritten); - Assert.Equal(expectedValue, new string(buffer.AsSpan(0, charsWritten))); + Assert.Equal(expectedValue, new string(buffer.AsSpan(0, charsWritten) +#if !NETCOREAPP +.ToArray() +#endif + )); } [Theory] @@ -170,7 +183,11 @@ public static void ReadDefiniteLengthTextStringBytes_SingleValue_HappyPath(strin var reader = new CborReader(encoding); ReadOnlyMemory resultBytes = reader.ReadDefiniteLengthTextStringBytes(); - string result = System.Text.Encoding.UTF8.GetString(resultBytes.Span); + string result = Encoding.UTF8.GetString(resultBytes.Span +#if !NETCOREAPP +.ToArray() +#endif + ); Assert.Equal(expectedValue, result); Assert.Equal(0, reader.BytesRemaining); } diff --git a/src/libraries/System.Formats.Cbor/tests/System.Formats.Cbor.Tests.csproj b/src/libraries/System.Formats.Cbor/tests/System.Formats.Cbor.Tests.csproj index c2211d72e5b19..d6337713f665d 100644 --- a/src/libraries/System.Formats.Cbor/tests/System.Formats.Cbor.Tests.csproj +++ b/src/libraries/System.Formats.Cbor/tests/System.Formats.Cbor.Tests.csproj @@ -1,6 +1,6 @@ - + - $(NetCoreAppCurrent) + $(NetCoreAppCurrent);net48 enable CS8002 @@ -9,8 +9,6 @@ CommonTest\System\Security\Cryptography\ByteUtils.cs - - @@ -32,10 +30,25 @@ + + + + + + + + + + + + + + + + - diff --git a/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Simple.cs b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Simple.cs index d6ef2d89aacda..8a0130cdf03f7 100644 --- a/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Simple.cs +++ b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Simple.cs @@ -11,26 +11,6 @@ public partial class CborWriterTests // Data points taken from https://tools.ietf.org/html/rfc7049#appendix-A // Additional pairs generated using http://cbor.me/ - [Theory] - [InlineData(0.0, "f90000")] - [InlineData(-0.0, "f98000")] - [InlineData(1.0, "f93c00")] - [InlineData(1.5, "f93e00")] - [InlineData(65504.0, "f97bff")] - [InlineData(5.960464477539063e-8, "f90001")] - [InlineData(0.00006103515625, "f90400")] - [InlineData(-4.0, "f9c400")] - [InlineData(float.PositiveInfinity, "f97c00")] - [InlineData(float.NaN, "f9fe00")] - [InlineData(float.NegativeInfinity, "f9fc00")] - public static void WriteHalf_SingleValue_HappyPath(float input, string hexExpectedEncoding) - { - byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); - var writer = new CborWriter(); - writer.WriteHalf((Half)input); - AssertHelper.HexEqual(expectedEncoding, writer.Encode()); - } - [Theory] [InlineData(100000.0, "fa47c35000")] [InlineData(3.4028234663852886e+38, "fa7f7fffff")] diff --git a/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Simple.netcoreapp.cs b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Simple.netcoreapp.cs new file mode 100644 index 0000000000000..3ef7ad9655176 --- /dev/null +++ b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Simple.netcoreapp.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. + +using Test.Cryptography; +using Xunit; + +namespace System.Formats.Cbor.Tests +{ + public partial class CborWriterTests + { + [Theory] + [InlineData(0.0, "f90000")] + [InlineData(-0.0, "f98000")] + [InlineData(1.0, "f93c00")] + [InlineData(1.5, "f93e00")] + [InlineData(65504.0, "f97bff")] + [InlineData(5.960464477539063e-8, "f90001")] + [InlineData(0.00006103515625, "f90400")] + [InlineData(-4.0, "f9c400")] + [InlineData(float.PositiveInfinity, "f97c00")] + [InlineData(float.NaN, "f9fe00")] + [InlineData(float.NegativeInfinity, "f9fc00")] + public static void WriteHalf_SingleValue_HappyPath(float input, string hexExpectedEncoding) + { + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + var writer = new CborWriter(); + writer.WriteHalf((Half)input); + AssertHelper.HexEqual(expectedEncoding, writer.Encode()); + } + } +} diff --git a/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Tag.cs b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Tag.cs index b9cc53ceb237b..3413eadc84cc3 100644 --- a/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Tag.cs +++ b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.Tag.cs @@ -206,7 +206,7 @@ from v in TaggedValues new object[] { CborTag.MimeMessage, 42 }, 42.0m, (BigInteger)1, - DateTimeOffset.UnixEpoch, + CborTestHelpers.UnixEpoch, }; } } diff --git a/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.TextString.cs b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.TextString.cs index 70c7232412bf1..15292330a1573 100644 --- a/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.TextString.cs +++ b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.TextString.cs @@ -54,7 +54,7 @@ public static void WriteTextString_IndefiniteLength_WithPatching_SingleValue_Hap public static void WriteTextString_NullValue_ShouldThrowArgumentNullException() { var writer = new CborWriter(); - Assert.Throws(() => writer.WriteTextString(null!)); + Assert.Throws(() => writer.WriteTextString((string)null!)); } [Theory] From 9bc443942c15e5bfc71253477af8083a40e2daa6 Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Thu, 20 Jan 2022 21:01:33 +0300 Subject: [PATCH 094/308] Exception sets: debug checker & fixes (#63539) * Add a simple exception sets checker * Add asserts to catch missing nodes * Fix normal VN printing * Fix JTRUE VNs * Fix PHI VNs * Update VNs for "this" ARGPLACE node * Tolerate missing VNs on PHI_ARGs We do not update them after numbering the loops. (Though perhaps we should) * Tolerate unreachable blocks * Fix exception sets for VNF_PtrTo VNFuncs * Add VNUniqueWithExc * Add VNPUniqueWithExc * Fix arrays * Consistently give location nodes VNForVoid And always add exception sets for them. This will simplify the exception set propagation code for assignments. * Fix CSE * Fix GT_RETURN * Fix LCLHEAP * Fix GT_ARR_ELEM * Fix unique HWI * Fix unique SIMD * Fix GT_SWITCH * Fix CKFINITE * Fix HWI loads * Fix fgValueNumberAddExceptionSetForIndirection The method does not need to add the exception set for the base address. Additionally, the way it did add the sets, by unioning with normal value numbers, lost all exceptions not coming from the base address. This was fine for the unary loads, but broke the HWI loads that could have exceptions coming from not just the address. * Fix GT_RETFILT * Fix INIT_VAL * Fix DYN_BLK * Fix FIELD_LIST * De-pessimize CkFinite * Add a test for HWIs * Add a test for LCLHEAP --- src/coreclr/jit/compiler.h | 12 +- src/coreclr/jit/optcse.cpp | 3 +- src/coreclr/jit/valuenum.cpp | 550 +++++++++++------- src/coreclr/jit/valuenum.h | 8 + .../ExceptionSetsPropagation_Hwi.cs | 40 ++ .../ExceptionSetsPropagation_Hwi.csproj | 13 + .../ExceptionSetsPropagation_LclHeap.il | 75 +++ .../ExceptionSetsPropagation_LclHeap.ilproj | 13 + 8 files changed, 500 insertions(+), 214 deletions(-) create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.cs create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.csproj create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.il create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.ilproj diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index d5dcf4cd92c81..ea29174e05769 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5432,7 +5432,7 @@ class Compiler // Requires that "tree" is a GT_IND marked as an array index, and that its address argument // has been parsed to yield the other input arguments. If evaluation of the address - // can raise exceptions, those should be captured in the exception set "excVN." + // can raise exceptions, those should be captured in the exception set "addrXvnp". // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type. // Marks "tree" with the VN for H[elemTypeEq][arrVN][inx][fldSeq] (for the liberal VN; a new unique // VN for the conservative VN.) Also marks the tree's argument as the address of an array element. @@ -5443,14 +5443,14 @@ class Compiler CORINFO_CLASS_HANDLE elemTypeEq, ValueNum arrVN, ValueNum inxVN, - ValueNum excVN, + ValueNumPair addrXvnp, FieldSeqNode* fldSeq); - // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvn" to represent the exception set thrown + // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvnp" to represent the exception set thrown // by evaluating the array index expression "tree". Returns the value number resulting from // dereferencing the array in the current GcHeap state. If "tree" is non-null, it must be the // "GT_IND" that does the dereference, and it is given the returned value number. - ValueNum fgValueNumberArrIndexVal(GenTree* tree, struct VNFuncApp* funcApp, ValueNum addrXvn); + ValueNum fgValueNumberArrIndexVal(GenTree* tree, VNFuncApp* funcApp, ValueNumPair addrXvnp); // Compute the value number for a byref-exposed load of the given type via the given pointerVN. ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN); @@ -5560,6 +5560,10 @@ class Compiler // Adds the exception sets for the current tree node void fgValueNumberAddExceptionSet(GenTree* tree); +#ifdef DEBUG + void fgDebugCheckExceptionSets(); +#endif + // These are the current value number for the memory implicit variables while // doing value numbering. These are the value numbers under the "liberal" interpretation // of memory values; the "conservative" interpretation needs no VN, since every access of diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index f16fb917a589d..805e5b7d2eb3f 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -829,7 +829,8 @@ bool Compiler::optValnumCSE_Locate() continue; } - if (ValueNumStore::isReservedVN(tree->GetVN(VNK_Liberal))) + ValueNum valueVN = vnStore->VNNormalValue(tree->GetVN(VNK_Liberal)); + if (ValueNumStore::isReservedVN(valueVN) && (valueVN != ValueNumStore::VNForNull())) { continue; } diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index cc9fb0f38d249..9fc0cefa30089 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -1266,6 +1266,17 @@ bool ValueNumStore::VNExcIsSubset(ValueNum vnFullSet, ValueNum vnCandidateSet) } } +//---------------------------------------------------------------------------------------- +// VNPExcIsSubset - Given two exception sets, returns true when both the liberal and +// conservative value numbers of vnpCandidateSet represent subsets of +// the corresponding numbers in vnpFullSet (see VNExcIsSubset). +// +bool ValueNumStore::VNPExcIsSubset(ValueNumPair vnpFullSet, ValueNumPair vnpCandidateSet) +{ + return VNExcIsSubset(vnpFullSet.GetLiberal(), vnpCandidateSet.GetLiberal()) && + VNExcIsSubset(vnpFullSet.GetConservative(), vnpCandidateSet.GetConservative()); +} + //------------------------------------------------------------------------------------- // VNUnpackExc: - Given a ValueNum 'vnWx, return via write back parameters both // the normal and the exception set components. @@ -1423,6 +1434,64 @@ ValueNumPair ValueNumStore::VNPMakeNormalUniquePair(ValueNumPair vnp) return ValueNumPair(VNMakeNormalUnique(vnp.GetLiberal()), VNMakeNormalUnique(vnp.GetConservative())); } +//------------------------------------------------------------------------------------ +// VNUniqueWithExc: +// +// Arguments: +// type - The type for the unique Value Number +// vnExcSet - The Value Number for the exception set. +// +// Return Value: +// - VN representing a "new, unique" value, with +// the exceptions contained in "vnExcSet". +// +ValueNum ValueNumStore::VNUniqueWithExc(var_types type, ValueNum vnExcSet) +{ + ValueNum normVN = VNForExpr(m_pComp->compCurBB, type); + + if (vnExcSet == VNForEmptyExcSet()) + { + return normVN; + } + +#ifdef DEBUG + VNFuncApp excSetFunc; + assert(GetVNFunc(vnExcSet, &excSetFunc) && (excSetFunc.m_func == VNF_ExcSetCons)); +#endif // DEBUG + + return VNWithExc(normVN, vnExcSet); +} + +//------------------------------------------------------------------------------------ +// VNPUniqueWithExc: +// +// Arguments: +// type - The type for the unique Value Numbers +// vnExcSet - The Value Number Pair for the exception set. +// +// Return Value: +// - VN Pair representing a "new, unique" value (liberal and conservative +// values will be equal), with the exceptions contained in "vnpExcSet". +// +// Notes: - We use the same unique value number both for liberal and conservative +// portions of the pair to save memory (it would not be useful to make +// them different). +// +ValueNumPair ValueNumStore::VNPUniqueWithExc(var_types type, ValueNumPair vnpExcSet) +{ +#ifdef DEBUG + VNFuncApp excSetFunc; + assert((GetVNFunc(vnpExcSet.GetLiberal(), &excSetFunc) && (excSetFunc.m_func == VNF_ExcSetCons)) || + (vnpExcSet.GetLiberal() == VNForEmptyExcSet())); + assert((GetVNFunc(vnpExcSet.GetConservative(), &excSetFunc) && (excSetFunc.m_func == VNF_ExcSetCons)) || + (vnpExcSet.GetConservative() == VNForEmptyExcSet())); +#endif // DEBUG + + ValueNum normVN = VNForExpr(m_pComp->compCurBB, type); + + return VNPWithExc(ValueNumPair(normVN, normVN), vnpExcSet); +} + //-------------------------------------------------------------------------------- // VNNormalValue: - Returns a Value Number that represents the result for the // normal (non-exceptional) evaluation for the expression. @@ -4338,21 +4407,21 @@ ValueNum Compiler::fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq, return vnStore->VNForMapStore(fgCurMemoryVN[GcHeap], elemTypeEqVN, newValAtArrType); } -ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, VNFuncApp* pFuncApp, ValueNum addrXvn) +ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, VNFuncApp* pFuncApp, ValueNumPair addrXvnp) { assert(vnStore->IsVNHandle(pFuncApp->m_args[0])); CORINFO_CLASS_HANDLE arrElemTypeEQ = CORINFO_CLASS_HANDLE(vnStore->ConstantValue(pFuncApp->m_args[0])); ValueNum arrVN = pFuncApp->m_args[1]; ValueNum inxVN = pFuncApp->m_args[2]; FieldSeqNode* fldSeq = vnStore->FieldSeqVNToFieldSeq(pFuncApp->m_args[3]); - return fgValueNumberArrIndexVal(tree, arrElemTypeEQ, arrVN, inxVN, addrXvn, fldSeq); + return fgValueNumberArrIndexVal(tree, arrElemTypeEQ, arrVN, inxVN, addrXvnp, fldSeq); } ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, CORINFO_CLASS_HANDLE elemTypeEq, ValueNum arrVN, ValueNum inxVN, - ValueNum excVN, + ValueNumPair addrXvnp, FieldSeqNode* fldSeq) { assert(tree == nullptr || tree->OperIsIndir()); @@ -4372,7 +4441,7 @@ ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, JITDUMP(" *** Not a proper arrray access encountered in fgValueNumberArrIndexVal\n"); // a new unique value number - selectedElem = vnStore->VNForExpr(compCurBB, elemTyp); + selectedElem = vnStore->VNForExpr(compCurBB, indType); #ifdef DEBUG if (verbose) @@ -4383,7 +4452,7 @@ ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, if (tree != nullptr) { - tree->gtVNPair.SetBoth(selectedElem); + tree->gtVNPair = vnStore->VNPWithExc(ValueNumPair(selectedElem, selectedElem), addrXvnp); } } else @@ -4422,7 +4491,7 @@ ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, elemTyp = vnStore->TypeOfVN(selectedElem); } selectedElem = vnStore->VNApplySelectorsTypeCheck(selectedElem, indType, elemStructSize); - selectedElem = vnStore->VNWithExc(selectedElem, excVN); + selectedElem = vnStore->VNWithExc(selectedElem, addrXvnp.GetLiberal()); #ifdef DEBUG if (verbose && (selectedElem != wholeElem)) @@ -4434,10 +4503,7 @@ ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, if (tree != nullptr) { tree->gtVNPair.SetLiberal(selectedElem); - - // TODO-CQ: what to do here about exceptions? We don't have the array and ind conservative - // values, so we don't have their exceptions. Maybe we should. - tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet())); + tree->gtVNPair.SetConservative(vnStore->VNUniqueWithExc(tree->TypeGet(), addrXvnp.GetConservative())); } } @@ -5952,8 +6018,7 @@ void ValueNumStore::vnDumpValWithExc(Compiler* comp, VNFuncApp* valWithExc) GetVNFunc(excVN, &excSeq); printf("norm="); - printf(FMT_VN, normVN); - vnDump(comp, normVN); + comp->vnPrint(normVN, 1); printf(", exc="); printf(FMT_VN, excVN); vnDumpExcSeq(comp, &excSeq, true); @@ -6793,6 +6858,7 @@ void Compiler::fgValueNumber() #ifdef DEBUG JitTestCheckVN(); + fgDebugCheckExceptionSets(); #endif // DEBUG fgVNPassesCompleted++; @@ -6812,10 +6878,11 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk) assert(asg->OperIs(GT_ASG)); GenTreeLclVar* newSsaDef = asg->AsOp()->gtGetOp1()->AsLclVar(); + GenTreePhi* phiNode = asg->AsOp()->gtGetOp2()->AsPhi(); ValueNumPair phiVNP; ValueNumPair sameVNP; - for (GenTreePhi::Use& use : asg->AsOp()->gtGetOp2()->AsPhi()->Uses()) + for (GenTreePhi::Use& use : phiNode->Uses()) { GenTreePhiArg* phiArg = use.GetNode()->AsPhiArg(); ValueNum phiArgSsaNumVN = vnStore->VNForIntCon(phiArg->GetSsaNum()); @@ -6880,6 +6947,10 @@ void Compiler::fgValueNumberBlock(BasicBlock* blk) printf(" %s.\n", sameVNP.BothDefined() ? "(all same)" : ""); } #endif // DEBUG + + newSsaDef->gtVNPair = vnStore->VNPForVoid(); + phiNode->gtVNPair = newSsaDefVNP; + asg->gtVNPair = vnStore->VNPForVoid(); } // Now do the same for each MemoryKind. @@ -7465,13 +7536,7 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) } // We have to handle the case where the LHS is a comma. In that case, we don't evaluate the comma, - // so we give it VNForVoid, and we're really interested in the effective value. - GenTree* lhsCommaIter = lhs; - while (lhsCommaIter->OperGet() == GT_COMMA) - { - lhsCommaIter->gtVNPair.SetBoth(vnStore->VNForVoid()); - lhsCommaIter = lhsCommaIter->AsOp()->gtOp2; - } + // and we're really just interested in the effective value. lhs = lhs->gtEffectiveVal(); // Now, record the new VN for an assignment (performing the indicated "state update"). @@ -7628,8 +7693,6 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) // Indicates whether the argument of the IND is the address of a local. bool wasLocal = false; - lhs->gtVNPair = rhsVNPair; - VNFuncApp funcApp; ValueNum argVN = arg->gtVNPair.GetLiberal(); @@ -7855,10 +7918,6 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) storeVal, indType); } - // It is not strictly necessary to set the lhs value number, - // but the dumps read better with it set to the 'storeVal' that we just computed - lhs->gtVNPair.SetBoth(storeVal); - // Update the GcHeap value. recordGcHeapStore(tree, newHeapVN DEBUGARG("StoreField")); } @@ -8156,7 +8215,7 @@ void Compiler::fgValueNumberBlockAssignment(GenTree* tree) else if (srcAddrFuncApp.m_func == VNF_PtrToArrElem) { ValueNum elemLib = - fgValueNumberArrIndexVal(nullptr, &srcAddrFuncApp, vnStore->VNForEmptyExcSet()); + fgValueNumberArrIndexVal(nullptr, &srcAddrFuncApp, vnStore->VNPForEmptyExcSet()); rhsVNPair.SetLiberal(elemLib); rhsVNPair.SetConservative(vnStore->VNForExpr(compCurBB, lclVarTree->TypeGet())); } @@ -8312,43 +8371,8 @@ bool Compiler::fgValueNumberIsStructReinterpretation(GenTreeLclVarCommon* lhsLcl void Compiler::fgValueNumberTree(GenTree* tree) { genTreeOps oper = tree->OperGet(); + var_types typ = tree->TypeGet(); -#ifdef FEATURE_SIMD - if ((JitConfig.JitDisableSimdVN() & 1) == 1) - { - // This Jit Config forces the previous behavior of value numbering for SIMD nodes - if (oper == GT_SIMD) - { - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN)); - return; - } - } -#endif // FEATURE_SIMD - -#ifdef FEATURE_HW_INTRINSICS - if ((JitConfig.JitDisableSimdVN() & 2) == 2) - { - // This Jit Config forces the previous behavior of value numbering for HW Intrinsic nodes - if (oper == GT_HWINTRINSIC) - { - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN)); - - GenTreeHWIntrinsic* hwIntrinsicNode = tree->AsHWIntrinsic(); - assert(hwIntrinsicNode != nullptr); - - // For safety/correctness we must mutate the global heap valuenumber - // for any HW intrinsic that performs a memory store operation - if (hwIntrinsicNode->OperIsMemoryStore()) - { - fgMutateGcHeap(tree DEBUGARG("HWIntrinsic - MemoryStore")); - } - - return; - } - } -#endif // FEATURE_HW_INTRINSICS - - var_types typ = tree->TypeGet(); if (GenTree::OperIsConst(oper)) { // If this is a struct assignment, with a constant rhs, (i,.e. an initBlk), @@ -8505,19 +8529,18 @@ void Compiler::fgValueNumberTree(GenTree* tree) { // We have a Def (write) of the LclVar - // TODO-Review: For the short term, we have a workaround for copyblk/initblk. Those that use - // addrSpillTemp will have a statement like "addrSpillTemp = addr(local)." If we previously decided - // that this block operation defines the local, we will have labeled the "local" node as a DEF - // This flag propagates to the "local" on the RHS. So we'll assume that this is correct, - // and treat it as a def (to a new, unique VN). - // + // The below block ensures we give VNs to the fields of + // "CanBeReplacedWithItsField" struct locals. To the numbering + // of block assignments, those appear as untracked locals, but + // we need to give the SSA defs they represent a VN. if (lcl->GetSsaNum() != SsaConfig::RESERVED_SSA_NUM) { ValueNum uniqVN = vnStore->VNForExpr(compCurBB, lcl->TypeGet()); varDsc->GetPerSsaData(lcl->GetSsaNum())->m_vnPair.SetBoth(uniqVN); } - lcl->gtVNPair = ValueNumPair(); // Avoid confusion -- we don't set the VN of a lcl being defined. + // Location nodes get VNForVoid (no exceptions needed). + lcl->gtVNPair = vnStore->VNPForVoid(); } } break; @@ -8559,6 +8582,11 @@ void Compiler::fgValueNumberTree(GenTree* tree) tree->gtVNPair = vnStore->VNPairApplySelectors(lclVNPair, lclFld->GetFieldSeq(), indType); } } + else + { + // A location node (LHS). + lclFld->gtVNPair = vnStore->VNPForVoid(); + } } break; @@ -8643,6 +8671,11 @@ void Compiler::fgValueNumberTree(GenTree* tree) } tree->gtVNPair = clsVarVNPair; } + else + { + // Location nodes get the "Void" VN. + tree->gtVNPair = vnStore->VNPForVoid(); + } break; case GT_MEMORYBARRIER: // Leaf @@ -8839,61 +8872,65 @@ void Compiler::fgValueNumberTree(GenTree* tree) // Try to parse it. GenTree* arr = nullptr; addr->ParseArrayAddress(this, &arrInfo, &arr, &inxVN, &fldSeq); - if (arr == nullptr) - { - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); - return; - } - assert(fldSeq != FieldSeqStore::NotAField()); - - // Otherwise... - // Need to form H[arrType][arr][ind][fldSeq] - // Get the array element type equivalence class rep. - CORINFO_CLASS_HANDLE elemTypeEq = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType); - ValueNum elemTypeEqVN = vnStore->VNForHandle(ssize_t(elemTypeEq), GTF_ICON_CLASS_HDL); - JITDUMP(" VNForHandle(arrElemType: %s) is " FMT_VN "\n", - (arrInfo.m_elemType == TYP_STRUCT) ? eeGetClassName(arrInfo.m_elemStructType) - : varTypeName(arrInfo.m_elemType), - elemTypeEqVN) - - // We take the "VNNormalValue"s here, because if either has exceptional outcomes, they will be captured - // as part of the value of the composite "addr" operation... - ValueNum arrVN = vnStore->VNLiberalNormalValue(arr->gtVNPair); - inxVN = vnStore->VNNormalValue(inxVN); - - // Additionally, relabel the address with a PtrToArrElem value number. - ValueNum fldSeqVN = vnStore->VNForFieldSeq(fldSeq); - ValueNum elemAddr = - vnStore->VNForFunc(TYP_BYREF, VNF_PtrToArrElem, elemTypeEqVN, arrVN, inxVN, fldSeqVN); - - // The aggregate "addr" VN should have had all the exceptions bubble up... - elemAddr = vnStore->VNWithExc(elemAddr, addrXvnp.GetLiberal()); - addr->gtVNPair.SetBoth(elemAddr); + if (arr != nullptr) + { + assert(fldSeq != FieldSeqStore::NotAField()); + + // Need to form H[arrType][arr][ind][fldSeq] + // Get the array element type equivalence class rep. + CORINFO_CLASS_HANDLE elemTypeEq = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType); + ValueNum elemTypeEqVN = vnStore->VNForHandle(ssize_t(elemTypeEq), GTF_ICON_CLASS_HDL); + JITDUMP(" VNForHandle(arrElemType: %s) is " FMT_VN "\n", + (arrInfo.m_elemType == TYP_STRUCT) ? eeGetClassName(arrInfo.m_elemStructType) + : varTypeName(arrInfo.m_elemType), + elemTypeEqVN); + + // We take the "VNNormalValue"s here, because if either has exceptional outcomes, they will + // be captured as part of the value of the composite "addr" operation... + ValueNum arrVN = vnStore->VNLiberalNormalValue(arr->gtVNPair); + inxVN = vnStore->VNNormalValue(inxVN); + + // Additionally, relabel the address with a PtrToArrElem value number. + ValueNum fldSeqVN = vnStore->VNForFieldSeq(fldSeq); + ValueNum elemAddr = + vnStore->VNForFunc(TYP_BYREF, VNF_PtrToArrElem, elemTypeEqVN, arrVN, inxVN, fldSeqVN); + + // The aggregate "addr" VN should have had all the exceptions bubble up... + addr->gtVNPair = vnStore->VNPWithExc(ValueNumPair(elemAddr, elemAddr), addrXvnp); #ifdef DEBUG - if (verbose) - { - printf(" Relabeled IND_ARR_INDEX address node "); - Compiler::printTreeID(addr); - printf(" with l:" FMT_VN ": ", elemAddr); - vnStore->vnDump(this, elemAddr); - printf("\n"); - if (vnStore->VNNormalValue(elemAddr) != elemAddr) + ValueNum elemAddrWithExc = addr->gtVNPair.GetLiberal(); + if (verbose) { - printf(" [" FMT_VN " is: ", vnStore->VNNormalValue(elemAddr)); - vnStore->vnDump(this, vnStore->VNNormalValue(elemAddr)); - printf("]\n"); + printf(" Relabeled IND_ARR_INDEX address node "); + Compiler::printTreeID(addr); + printf(" with l:" FMT_VN ": ", elemAddrWithExc); + vnStore->vnDump(this, elemAddrWithExc); + printf("\n"); + if (elemAddrWithExc != elemAddr) + { + printf(" [" FMT_VN " is: ", elemAddr); + vnStore->vnDump(this, elemAddr); + printf("]\n"); + } } - } #endif // DEBUG - // We now need to retrieve the value number for the array element value - // and give this value number to the GT_IND node 'tree' - // We do this whenever we have an rvalue, but we don't do it for a - // normal LHS assignment into an array element. - // - if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0) + // We now need to retrieve the value number for the array element value + // and give this value number to the GT_IND node 'tree' + // We do this whenever we have an rvalue, but we don't do it for a + // normal LHS assignment into an array element. + // + if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0) + { + fgValueNumberArrIndexVal(tree, elemTypeEq, arrVN, inxVN, addrXvnp, fldSeq); + } + } + else // An unparseable array expression. { - fgValueNumberArrIndexVal(tree, elemTypeEq, arrVN, inxVN, addrXvnp.GetLiberal(), fldSeq); + if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0) + { + tree->gtVNPair = vnStore->VNPUniqueWithExc(tree->TypeGet(), addrXvnp); + } } } // In general we skip GT_IND nodes on that are the LHS of an assignment. (We labeled these earlier.) @@ -8952,7 +8989,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) } else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem)) { - fgValueNumberArrIndexVal(tree, &funcApp, addrXvnp.GetLiberal()); + fgValueNumberArrIndexVal(tree, &funcApp, addrXvnp); } else if (addr->IsFieldAddr(this, &baseAddr, &fldSeq)) { @@ -9006,6 +9043,12 @@ void Compiler::fgValueNumberTree(GenTree* tree) tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp); } } + + // To be able to propagate exception sets, we give location nodes the "Void" VN. + if ((tree->gtFlags & GTF_IND_ASG_LHS) != 0) + { + tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), addrXvnp); + } } else if (tree->OperGet() == GT_CAST) { @@ -9102,8 +9145,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) if (newVN != ValueNumStore::NoVN) { // We don't care about differences between liberal and conservative for pointer values. - newVN = vnStore->VNWithExc(newVN, excSetPair.GetLiberal()); - tree->gtVNPair.SetBoth(newVN); + tree->gtVNPair = vnStore->VNPWithExc(ValueNumPair(newVN, newVN), excSetPair); } else { @@ -9122,28 +9164,8 @@ void Compiler::fgValueNumberTree(GenTree* tree) { case GT_COMMA: { - ValueNumPair op1vnp; - ValueNumPair op1Xvnp; - vnStore->VNPUnpackExc(tree->AsOp()->gtOp1->gtVNPair, &op1vnp, &op1Xvnp); - ValueNumPair op2vnp; - ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet(); - GenTree* op2 = tree->gtGetOp2(); - - if (op2->OperIsIndir() && ((op2->gtFlags & GTF_IND_ASG_LHS) != 0)) - { - // If op2 represents the lhs of an assignment then we give a VNForVoid for the lhs - op2vnp = ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()); - } - else if ((op2->OperGet() == GT_CLS_VAR) && (op2->gtFlags & GTF_CLS_VAR_ASG_LHS)) - { - // If op2 represents the lhs of an assignment then we give a VNForVoid for the lhs - op2vnp = ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid()); - } - else - { - vnStore->VNPUnpackExc(op2->gtVNPair, &op2vnp, &op2Xvnp); - } - tree->gtVNPair = vnStore->VNPWithExc(op2vnp, vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp)); + ValueNumPair op1Xvnp = vnStore->VNPExceptionSet(tree->AsOp()->gtOp1->gtVNPair); + tree->gtVNPair = vnStore->VNPWithExc(tree->AsOp()->gtOp2->gtVNPair, op1Xvnp); } break; @@ -9174,18 +9196,6 @@ void Compiler::fgValueNumberTree(GenTree* tree) } break; - case GT_NULLCHECK: - { - // An Explicit null check, produces no value - // But we do persist any execeptions produced by op1 - // - tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), - vnStore->VNPExceptionSet(tree->AsOp()->gtOp1->gtVNPair)); - // The exception set with VNF_NullPtrExc will be added below - // by fgValueNumberAddExceptionSet - } - break; - case GT_LOCKADD: // Binop noway_assert("LOCKADD should not appear before lowering"); break; @@ -9220,20 +9230,41 @@ void Compiler::fgValueNumberTree(GenTree* tree) break; } + // These unary nodes do not produce values. Note that for NULLCHECK the + // additional exception will be added below by "fgValueNumberAddExceptionSet". case GT_JTRUE: - // These nodes never need to have a ValueNumber - tree->gtVNPair.SetBoth(ValueNumStore::NoVN); + case GT_SWITCH: + case GT_RETURN: + case GT_RETFILT: + case GT_NULLCHECK: + if (tree->gtGetOp1() != nullptr) + { + tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), + vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); + } + else + { + tree->gtVNPair = vnStore->VNPForVoid(); + } break; + // BOX and CKFINITE are passthrough nodes (like NOP). We'll add the exception for the latter later. case GT_BOX: - // BOX doesn't do anything at this point, the actual object allocation - // and initialization happens separately (and not numbering BOX correctly - // prevents seeing allocation related assertions through it) + case GT_CKFINITE: tree->gtVNPair = tree->gtGetOp1()->gtVNPair; break; + // These unary nodes will receive a unique VN. + // TODO-CQ: model INIT_VAL properly. + case GT_LCLHEAP: + case GT_INIT_VAL: + tree->gtVNPair = + vnStore->VNPUniqueWithExc(tree->TypeGet(), + vnStore->VNPExceptionSet(tree->gtGetOp1()->gtVNPair)); + break; + default: - // The default action is to give the node a new, unique VN. + assert(!"Unhandled node in fgValueNumberTree"); tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); break; } @@ -9300,8 +9331,49 @@ void Compiler::fgValueNumberTree(GenTree* tree) break; } + // ARR_ELEM is a bounds-checked address. TODO-CQ: model it precisely. + case GT_ARR_ELEM: + { + GenTreeArrElem* arrElem = tree->AsArrElem(); + + ValueNumPair vnpExcSet = vnStore->VNPExceptionSet(arrElem->gtArrObj->gtVNPair); + for (size_t i = 0; i < arrElem->gtArrRank; i++) + { + vnpExcSet = vnStore->VNPUnionExcSet(arrElem->gtArrInds[i]->gtVNPair, vnpExcSet); + } + + arrElem->gtVNPair = vnStore->VNPUniqueWithExc(arrElem->TypeGet(), vnpExcSet); + + // TODO: model the IndexOutOfRangeException for this node. + fgValueNumberAddExceptionSetForIndirection(arrElem, arrElem->gtArrObj); + } + break; + + // DYN_BLK is always an L-value. + case GT_DYN_BLK: + assert(!tree->CanCSE()); + tree->gtVNPair = vnStore->VNPForVoid(); + tree->gtVNPair = + vnStore->VNPWithExc(tree->gtVNPair, vnStore->VNPExceptionSet(tree->AsDynBlk()->Addr()->gtVNPair)); + tree->gtVNPair = + vnStore->VNPWithExc(tree->gtVNPair, + vnStore->VNPExceptionSet(tree->AsDynBlk()->gtDynamicSize->gtVNPair)); + break; + + // FIELD_LIST is an R-value that we currently don't model. + case GT_FIELD_LIST: + tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); + for (GenTreeFieldList::Use& use : tree->AsFieldList()->Uses()) + { + tree->gtVNPair = + vnStore->VNPWithExc(tree->gtVNPair, vnStore->VNPExceptionSet(use.GetNode()->gtVNPair)); + } + break; + default: + assert(!"Unhandled special node in fgValueNumberTree"); tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); + break; } } #ifdef DEBUG @@ -9375,19 +9447,25 @@ void Compiler::fgValueNumberSimd(GenTreeSIMD* tree) ValueNumPair excSetPair; ValueNumPair normalPair; + if ((tree->GetOperandCount() > 2) || ((JitConfig.JitDisableSimdVN() & 1) == 1)) + { + // We have a SIMD node with 3 or more args. To retain the + // previous behavior, we will generate a unique VN for this case. + excSetPair = ValueNumStore::VNPForEmptyExcSet(); + for (GenTree* operand : tree->Operands()) + { + excSetPair = vnStore->VNPUnionExcSet(operand->gtVNPair, excSetPair); + } + tree->gtVNPair = vnStore->VNPUniqueWithExc(tree->TypeGet(), excSetPair); + return; + } + // There are some SIMD operations that have zero args, i.e. NI_Vector128_Zero if (tree->GetOperandCount() == 0) { excSetPair = ValueNumStore::VNPForEmptyExcSet(); normalPair = vnStore->VNPairForFunc(tree->TypeGet(), simdFunc); } - else if (tree->GetOperandCount() > 2) - { - // We have a SIMD node with 3 or more args. To retain the - // previous behavior, we will generate a unique VN for this case. - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); - return; - } else // SIMD unary or binary operator. { ValueNumPair resvnp = ValueNumPair(); @@ -9512,12 +9590,17 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree) fgMutateGcHeap(tree DEBUGARG("HWIntrinsic - MemoryStore")); } - if (tree->GetOperandCount() > 2) + if ((tree->GetOperandCount() > 2) || ((JitConfig.JitDisableSimdVN() & 2) == 2)) { // TODO-CQ: allow intrinsics with > 2 operands to be properly VN'ed, it will // allow use to process things like Vector128.Create(1,2,3,4) etc. - // Generate unique VN for now to retaing previois behavior. - tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); + // Generate unique VN for now to retaing previous behavior. + ValueNumPair vnpExcSet = vnStore->VNPForEmptyExcSet(); + for (GenTree* operand : tree->Operands()) + { + vnpExcSet = vnStore->VNPUnionExcSet(operand->gtVNPair, vnpExcSet); + } + tree->gtVNPair = vnStore->VNPUniqueWithExc(tree->TypeGet(), vnpExcSet); return; } @@ -9529,15 +9612,13 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree) // if (isMemoryLoad) { - ValueNumPair op1vnp; - ValueNumPair op1Xvnp; - vnStore->VNPUnpackExc(tree->Op(1)->gtVNPair, &op1vnp, &op1Xvnp); + ValueNumPair op1vnp = vnStore->VNPNormalPair(tree->Op(1)->gtVNPair); // The addrVN incorporates both op1's ValueNumber and the func operation // The func is used because operations such as LoadLow and LoadHigh perform // different operations, thus need to compute different ValueNumbers // We don't need to encode the result type as it will be encoded by the opcode in 'func' - // + // TODO-Bug: some HWI loads have more than one operand, we need to encode the rest. ValueNum addrVN = vnStore->VNForFunc(TYP_BYREF, func, op1vnp.GetLiberal()); // The address could point anywhere, so it is an ByrefExposed load. @@ -9545,7 +9626,11 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree) ValueNum loadVN = fgValueNumberByrefExposedLoad(tree->TypeGet(), addrVN); tree->gtVNPair.SetLiberal(loadVN); tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet())); - tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, op1Xvnp); + + for (GenTree* operand : tree->Operands()) + { + tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, vnStore->VNPExceptionSet(operand->gtVNPair)); + } fgValueNumberAddExceptionSetForIndirection(tree, tree->Op(1)); return; } @@ -9932,14 +10017,12 @@ void Compiler::fgValueNumberCall(GenTreeCall* call) { // First: do value numbering of any argument placeholder nodes in the argument list // (by transferring from the VN of the late arg that they are standing in for...) - unsigned i = 0; - for (GenTreeCall::Use& use : call->Args()) - { - GenTree* arg = use.GetNode(); + + auto updateArgVN = [=](GenTree* arg, unsigned argIndex) { if (arg->OperGet() == GT_ARGPLACE) { // Find the corresponding late arg. - GenTree* lateArg = call->fgArgInfo->GetArgNode(i); + GenTree* lateArg = call->fgArgInfo->GetArgNode(argIndex); assert(lateArg->gtVNPair.BothDefined()); arg->gtVNPair = lateArg->gtVNPair; #ifdef DEBUG @@ -9953,7 +10036,19 @@ void Compiler::fgValueNumberCall(GenTreeCall* call) } #endif } - i++; + }; + + unsigned argIndex = 0; + if (call->gtCallThisArg != nullptr) + { + updateArgVN(call->gtCallThisArg->GetNode(), argIndex); + argIndex++; + } + + for (GenTreeCall::Use& use : call->Args()) + { + updateArgVN(use.GetNode(), argIndex); + argIndex++; } if (call->gtCallType == CT_HELPER) @@ -10497,27 +10592,16 @@ void Compiler::fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree // Create baseVNP, from the values we just computed, baseVNP = ValueNumPair(baseLVN, baseCVN); - // Unpack, Norm,Exc for the tree's op1 VN - ValueNumPair vnpBaseNorm; - ValueNumPair vnpBaseExc; - vnStore->VNPUnpackExc(baseVNP, &vnpBaseNorm, &vnpBaseExc); + // The exceptions in "baseVNP" should have been added to the "tree"'s set already. + assert(vnStore->VNPExcIsSubset(vnStore->VNPExceptionSet(tree->gtVNPair), vnStore->VNPExceptionSet(baseVNP))); - // The Norm VN for op1 is used to create the NullPtrExc - ValueNumPair excChkSet = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NullPtrExc, vnpBaseNorm)); - - // Combine the excChkSet with exception set of op1 - ValueNumPair excSetBoth = vnStore->VNPExcSetUnion(excChkSet, vnpBaseExc); + // The normal VN for base address is used to create the NullPtrExc + ValueNumPair vnpBaseNorm = vnStore->VNPNormalPair(baseVNP); - // Retrieve the Normal VN for tree, note that it may be NoVN, so we handle that case - ValueNumPair vnpNorm = vnStore->VNPNormalPair(tree->gtVNPair); + ValueNumPair excChkSet = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NullPtrExc, vnpBaseNorm)); - // For as GT_IND on the lhs of an assignment we will get a NoVN value - if (vnpNorm.GetLiberal() == ValueNumStore::NoVN) - { - // Use the special Void VN value instead. - vnpNorm = vnStore->VNPForVoid(); - } - tree->gtVNPair = vnStore->VNPWithExc(vnpNorm, excSetBoth); + // Add the NullPtrExc to "tree"'s value numbers. + tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, excChkSet); } //-------------------------------------------------------------------------------- @@ -10898,14 +10982,7 @@ void Compiler::fgValueNumberAddExceptionSet(GenTree* tree) // ToDo: model the exceptions for Intrinsics break; - case GT_IND: // Implicit null check. - if ((tree->gtFlags & GTF_IND_ASG_LHS) != 0) - { - // Don't add exception set on LHS of assignment - break; - } - FALLTHROUGH; - + case GT_IND: case GT_BLK: case GT_OBJ: case GT_DYN_BLK: @@ -10947,6 +11024,61 @@ void Compiler::fgValueNumberAddExceptionSet(GenTree* tree) } #ifdef DEBUG +//------------------------------------------------------------------------ +// fgDebugCheckExceptionSets: Verify the exception sets on trees. +// +// This function checks that the node's exception set is a superset of +// the exception sets of its operands. +// +void Compiler::fgDebugCheckExceptionSets() +{ + struct ExceptionSetsChecker + { + static void CheckTree(GenTree* tree, ValueNumStore* vnStore) + { + // We will fail to VN some PHI_ARGs - their values may not + // be known at the point we number them because of loops. + assert(tree->gtVNPair.BothDefined() || tree->OperIs(GT_PHI_ARG)); + + ValueNumPair operandsExcSet = vnStore->VNPForEmptyExcSet(); + tree->VisitOperands([&](GenTree* operand) -> GenTree::VisitResult { + + CheckTree(operand, vnStore); + + ValueNumPair operandVNP = operand->gtVNPair.BothDefined() ? operand->gtVNPair : vnStore->VNPForVoid(); + operandsExcSet = vnStore->VNPUnionExcSet(operandVNP, operandsExcSet); + + return GenTree::VisitResult::Continue; + }); + + // Currently, we fail to properly maintain the exception sets for trees with user + // calls or assignments. + if ((tree->gtFlags & (GTF_ASG | GTF_CALL)) != 0) + { + return; + } + + ValueNumPair nodeExcSet = vnStore->VNPExceptionSet(tree->gtVNPair); + assert(vnStore->VNExcIsSubset(nodeExcSet.GetLiberal(), operandsExcSet.GetLiberal())); + assert(vnStore->VNExcIsSubset(nodeExcSet.GetConservative(), operandsExcSet.GetConservative())); + } + }; + + for (BasicBlock* const block : Blocks()) + { + for (Statement* const stmt : block->Statements()) + { + // Exclude statements VN hasn't visited for whichever reason... + if (stmt->GetRootNode()->GetVN(VNK_Liberal) == ValueNumStore::NoVN) + { + continue; + } + + ExceptionSetsChecker::CheckTree(stmt->GetRootNode(), vnStore); + } + } +} + // This method asserts that SSA name constraints specified are satisfied. // Until we figure out otherwise, all VN's are assumed to be liberal. // TODO-Cleanup: new JitTestLabels for lib vs cons vs both VN classes? diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index 289e09fb688b1..6c19327c80037 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -494,6 +494,8 @@ class ValueNumStore // Both arguments must be either VNForEmptyExcSet() or applications of VNF_ExcSetCons. bool VNExcIsSubset(ValueNum vnFullSet, ValueNum vnCandidateSet); + bool VNPExcIsSubset(ValueNumPair vnpFullSet, ValueNumPair vnpCandidateSet); + // Returns "true" iff "vn" is an application of "VNF_ValWithExc". bool VNHasExc(ValueNum vn) { @@ -528,6 +530,12 @@ class ValueNumStore // Keeps any Exception set values ValueNumPair VNPMakeNormalUniquePair(ValueNumPair vnp); + // A new unique value with the given exception set. + ValueNum VNUniqueWithExc(var_types type, ValueNum vnExcSet); + + // A new unique VN pair with the given exception set pair. + ValueNumPair VNPUniqueWithExc(var_types type, ValueNumPair vnpExcSet); + // If "vn" is a "VNF_ValWithExc(norm, excSet)" value, returns the "norm" argument; otherwise, // just returns "vn". // The Normal value is the value number of the expression when no exceptions occurred diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.cs b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.cs new file mode 100644 index 0000000000000..103f6b6c8547c --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.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. + +using System; +using System.Runtime.Intrinsics; +using System.Runtime.CompilerServices; + +// We're testing whether HWI nodes with > 2 operands propagate exception sets correctly. +// +class ExceptionSetsPropagation_Hwi +{ + public static int Main() + { + try + { + Problem(-1, false, false); + } + catch (OverflowException) + { + return 100; + } + + return 101; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool Problem(int a, bool c1, bool c2) + { + var zero = 0; + c1 = a == 0; + c2 = c1; + + if ((Vector128.Create((int)checked((uint)a), a, a, a).GetElement(0) * zero) + a == 0) + { + return false; + } + + return c2; + } +} diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.csproj b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.csproj new file mode 100644 index 0000000000000..5d8fe22529764 --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_Hwi.csproj @@ -0,0 +1,13 @@ + + + Exe + 1 + + + None + True + + + + + diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.il b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.il new file mode 100644 index 0000000000000..312eb5dcb545e --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.il @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern xunit.core { } +.assembly extern System.Runtime { } +.assembly extern System.Console { } + +.assembly ExceptionSetsPropagation_LclHeap { } + +.class ExceptionSetsPropagation_LclHeap extends [System.Runtime]System.Object +{ + .method public static int32 Main() + { + .custom instance void [xunit.core]Xunit.FactAttribute::.ctor() = (01 00 00 00) + .entrypoint + + .try + { + ldc.i4 300 + conv.i + call bool ExceptionSetsPropagation_LclHeap::Problem(native int) + pop + leave FAIL + } + catch [System.Runtime]System.OverflowException + { + pop + leave SUCCESS + } + + SUCCESS: + ldc.i4 100 + ret + + FAIL: + ldc.i4 101 + ret + } + + .method private static bool Problem(native int a) + { + .locals (bool c1, bool c2) + + ldarg a + localloc + ldc.i4 0 + conv.i + and + ldarg a + ceq + stloc c1 + + ldloc c1 + stloc c2 + + ldarg a + conv.ovf.i1 + conv.i + localloc + ldc.i4 0 + conv.i + and + ldarg a + ceq + brtrue RET + + ldstr "The expected OverflowException was not thrown!" + call void [System.Console]System.Console::WriteLine(string) + + RET: + ldloc c2 + ret + } +} + diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.ilproj b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.ilproj new file mode 100644 index 0000000000000..477cccfe1def0 --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSetsPropagation_LclHeap.ilproj @@ -0,0 +1,13 @@ + + + Exe + 1 + + + None + True + + + + + From 18b05407173ae8b36c6303d813d6011a488992ab Mon Sep 17 00:00:00 2001 From: yowl Date: Thu, 20 Jan 2022 13:04:58 -0500 Subject: [PATCH 095/308] Change test to check for store block operators (#60878) --- src/coreclr/jit/gentree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 8cab63e505b5f..7eeb3b0f57bd2 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -7490,7 +7490,7 @@ struct GenTreeCC final : public GenTree inline bool GenTree::OperIsBlkOp() { - return ((gtOper == GT_ASG) && varTypeIsStruct(AsOp()->gtOp1)) || (OperIsBlk() && (AsBlk()->Data() != nullptr)); + return ((gtOper == GT_ASG) && varTypeIsStruct(AsOp()->gtOp1)) || OperIsStoreBlk(); } inline bool GenTree::OperIsDynBlkOp() From 1d751ba8563fc099c6a75c41687d2f282a05f916 Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Thu, 20 Jan 2022 10:35:50 -0800 Subject: [PATCH 096/308] Update XUnit to 2.4.2-pre.22 (#63948) * Update to Xunit build 2.4.2-pre.13 Also pick up latest pre-release of analyzers * Disambiguate calls to Assert.Equals(double,double,int) Xunit added a new Assert overload that caused a lot of ambiguous calls. https://github.com/xunit/xunit/issues/2393 Workaround by casting to double. * Fix new instances of xUnit2000 diagnostic * Workaround xUnit2002 issue with implicit cast Works around https://github.com/xunit/xunit/issues/2395 * Disable xUnit2014 diagnostic This diagnostic forces the use of Assert.ThrowsAsync for any async method, however in our case we may want to test that a method will throw synchronously to avoid regressing that behavior by moving to the async portion of the method. * Use AssertExtensions to test for null ArgumentException.ParamName Workaround https://github.com/xunit/xunit/issues/2396 * Update to Xunit 2.4.2-pre.22 * Fix another ArugmentException.ParamName == null assert --- eng/CodeAnalysis.test.globalconfig | 2 +- eng/Versions.props | 3 +- eng/testing/xunit/xunit.props | 1 + .../CompressionStreamUnitTestBase.cs | 2 +- .../tests/RuntimeBinderExceptionTests.cs | 2 +- .../tests/ReadOnlyCollectionBaseTests.cs | 2 +- .../tests/ContainerTests.cs | 2 +- .../MemberRelationshipServiceTests.cs | 2 +- .../tests/Design/ServiceContainerTests.cs | 6 +- .../System/Data/SqlTypes/SqlBytesTest.cs | 4 +- .../System/Data/SqlTypes/SqlCharsTest.cs | 4 +- .../System/Data/SqlTypes/SqlInt32Test.cs | 164 +++++++++--------- .../tests/Drawing2D/MatrixTests.cs | 2 +- .../tests/FontFamilyTests.cs | 2 +- .../System.Drawing.Common/tests/FontTests.cs | 4 +- .../System.Drawing.Common/tests/ImageTests.cs | 28 +-- .../tests/Printing/PrinterSettingsTests.cs | 24 +-- .../tests/SystemPensTest.cs | 2 +- .../mono/System.Drawing/GraphicsTests.cs | 88 +++++----- .../tests/mono/System.Imaging/MetafileTest.cs | 24 +-- .../tests/UmsSafeBuffer.cs | 4 +- .../System.IO/tests/IndentedTextWriter.cs | 2 +- .../ExceptionHandlingExpressions.cs | 2 +- .../tests/MemoryMarshal/AsReadOnlyRef.cs | 2 +- .../tests/MemoryMarshal/AsRef.cs | 2 +- .../FunctionalTests/SocketsHttpHandlerTest.cs | 12 +- .../Functional/ContentDispositionTest.cs | 2 +- .../tests/FtpWebRequestTest.cs | 4 +- .../tests/Vector2Tests.cs | 4 +- .../tests/FunctionalTests/UriTests.cs | 4 +- .../XmlSerializerTests.RuntimeOnly.cs | 52 +++--- .../tests/RuntimeReflectionExtensionTests.cs | 2 +- .../tests/Metadata/MetadataReaderTests.cs | 20 +-- .../tests/Utilities/CompressedIntegerTests.cs | 2 +- .../tests/ParameterInfoTests.cs | 6 +- .../tests/BinaryResourceWriterUnitTest.cs | 36 ++-- .../tests/System/IO/PathTests.cs | 2 +- .../tests/System/IO/PathTests_Unix.cs | 2 +- .../tests/System/IO/PathTests_Windows.cs | 2 +- .../InteropServices/SafeBufferTests.cs | 4 +- .../DefaultContext/DefaultLoadContextTest.cs | 2 +- .../tests/DataContractJsonSerializer.cs | 52 +++--- .../tests/DataContractSerializer.cs | 24 +-- .../System/IO/EndOfStreamExceptionTests.cs | 4 +- .../System/NullReferenceExceptionTests.cs | 4 +- .../SignedCms/SignerInfoTests.netcoreapp.cs | 2 +- .../tests/DSAKeyValueTest.cs | 10 +- .../tests/XmlLicenseEncryptedRef.cs | 2 +- .../System.Text.Json.Tests/BitStackTests.cs | 2 +- .../JsonNode/JsonNodeOperatorTests.cs | 2 + .../Dataflow/DataflowBlockExtensionTests.cs | 2 +- 51 files changed, 322 insertions(+), 318 deletions(-) diff --git a/eng/CodeAnalysis.test.globalconfig b/eng/CodeAnalysis.test.globalconfig index 572310d3b86d0..f56a38cfa707c 100644 --- a/eng/CodeAnalysis.test.globalconfig +++ b/eng/CodeAnalysis.test.globalconfig @@ -1681,7 +1681,7 @@ dotnet_diagnostic.xUnit2012.severity = warning dotnet_diagnostic.xUnit2013.severity = none # xUnit2014: Do not use throws check to check for asynchronously thrown exception -dotnet_diagnostic.xUnit2014.severity = warning +dotnet_diagnostic.xUnit2014.severity = none # xUnit2015: Do not use typeof expression to check the exception type dotnet_diagnostic.xUnit2015.severity = warning diff --git a/eng/Versions.props b/eng/Versions.props index b0db712120a28..f368a31dc3c93 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -164,7 +164,8 @@ 1.0.0-prerelease.22067.1 1.0.0-prerelease.22067.1 1.0.2-alpha.0.22060.2 - 2.4.2-pre.9 + 2.4.2-pre.22 + 0.12.0-pre.20 2.4.2 3.1.0 12.0.3 diff --git a/eng/testing/xunit/xunit.props b/eng/testing/xunit/xunit.props index 3f9c4b67141a2..a2ed68f1ecbc9 100644 --- a/eng/testing/xunit/xunit.props +++ b/eng/testing/xunit/xunit.props @@ -10,6 +10,7 @@ + diff --git a/src/libraries/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs b/src/libraries/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs index 2935ef6fd3f82..ba9e6b86b092a 100644 --- a/src/libraries/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs +++ b/src/libraries/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs @@ -320,7 +320,7 @@ IEnumerable> CtorFunctions() } else { - Assert.Equal(data2[i], (byte)0); + Assert.Equal((byte)0, data2[i]); } } }); diff --git a/src/libraries/Microsoft.CSharp/tests/RuntimeBinderExceptionTests.cs b/src/libraries/Microsoft.CSharp/tests/RuntimeBinderExceptionTests.cs index d4fddedacc674..4db799a324b95 100644 --- a/src/libraries/Microsoft.CSharp/tests/RuntimeBinderExceptionTests.cs +++ b/src/libraries/Microsoft.CSharp/tests/RuntimeBinderExceptionTests.cs @@ -57,7 +57,7 @@ public void InstanceArgumentInsteadOfTypeForStaticCall() CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) })); Func target = site.Target; - Assert.Throws(null, () => target.Invoke(site, "Ceci n'est pas un type", 2, 2)); + AssertExtensions.Throws(null, () => target.Invoke(site, "Ceci n'est pas un type", 2, 2)); } [Fact] diff --git a/src/libraries/System.Collections.NonGeneric/tests/ReadOnlyCollectionBaseTests.cs b/src/libraries/System.Collections.NonGeneric/tests/ReadOnlyCollectionBaseTests.cs index 426a0bad6f565..f4f0820f18725 100644 --- a/src/libraries/System.Collections.NonGeneric/tests/ReadOnlyCollectionBaseTests.cs +++ b/src/libraries/System.Collections.NonGeneric/tests/ReadOnlyCollectionBaseTests.cs @@ -139,7 +139,7 @@ public static void IListProperties() public static void VirtualMethods() { VirtualTestReadOnlyCollection collectionBase = new VirtualTestReadOnlyCollection(); - Assert.Equal(collectionBase.Count, int.MinValue); + Assert.Equal(int.MinValue, collectionBase.Count); Assert.Null(collectionBase.GetEnumerator()); } diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/ContainerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/ContainerTests.cs index 418d0c1c270d7..f1f331994a934 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/ContainerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/ContainerTests.cs @@ -400,7 +400,7 @@ public void Add_SetSiteNameDuplicate_ThrowsArgumentException() container.Add(component1, "Name1"); container.Add(component2, "Name2"); - Assert.Throws(null, () => component1.Site.Name = "Name2"); + AssertExtensions.Throws(null, () => component1.Site.Name = "Name2"); } [Fact] diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/Serialization/MemberRelationshipServiceTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/Serialization/MemberRelationshipServiceTests.cs index 9519d2f8b3918..2ef721735a12a 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/Serialization/MemberRelationshipServiceTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/Serialization/MemberRelationshipServiceTests.cs @@ -84,7 +84,7 @@ public void Indexer_SetNotSupported_ThrowsArgumentException(object owner) MemberRelationship source = new MemberRelationship(owner, member); var service = new NotSupportingMemberRelationshipService(); - Assert.Throws(null, () => service[source] = source); + AssertExtensions.Throws(null, () => service[source] = source); } private class TestClass diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/ServiceContainerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/ServiceContainerTests.cs index 3fa5aa15c50b9..001abff49fa2d 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/ServiceContainerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/ServiceContainerTests.cs @@ -224,9 +224,9 @@ public void AddService_NullServiceInstance_ThrowsArgumentNullException() public void AddService_ServiceInstanceNotInstanceOfType_ThrowsArgumentException() { var container = new ServiceContainer(); - Assert.Throws(null, () => container.AddService(typeof(int), new object())); - Assert.Throws(null, () => container.AddService(typeof(int), new object(), true)); - Assert.Throws(null, () => container.AddService(typeof(int), new object(), false)); + AssertExtensions.Throws(null, () => container.AddService(typeof(int), new object())); + AssertExtensions.Throws(null, () => container.AddService(typeof(int), new object(), true)); + AssertExtensions.Throws(null, () => container.AddService(typeof(int), new object(), false)); } [Fact] diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBytesTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBytesTest.cs index b0f498c276676..4b65884b86c74 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBytesTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBytesTest.cs @@ -66,9 +66,9 @@ public void SqlBytesMaxLength() { byte[] b = null; SqlBytes bytes = new SqlBytes(); - Assert.Equal(bytes.MaxLength, -1); + Assert.Equal(-1, bytes.MaxLength); bytes = new SqlBytes(b); - Assert.Equal(bytes.MaxLength, -1); + Assert.Equal(-1, bytes.MaxLength); b = new byte[10]; bytes = new SqlBytes(b); Assert.Equal(10, bytes.MaxLength); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlCharsTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlCharsTest.cs index cdfe5988dc494..dfc9e95769a3e 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlCharsTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlCharsTest.cs @@ -72,9 +72,9 @@ public void SqlCharsMaxLength() { char[] b = null; SqlChars chars = new SqlChars(); - Assert.Equal(chars.MaxLength, -1); + Assert.Equal(-1, chars.MaxLength); chars = new SqlChars(b); - Assert.Equal(chars.MaxLength, -1); + Assert.Equal(-1, chars.MaxLength); b = new char[10]; chars = new SqlChars(b); Assert.Equal(10, chars.MaxLength); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt32Test.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt32Test.cs index 6198c3a7ac9bc..e3466d60e63e9 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt32Test.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt32Test.cs @@ -56,9 +56,9 @@ public void Add() x = new SqlInt32(a); y = new SqlInt32(b); z = x + y; - Assert.Equal(z.Value, a + b); + Assert.Equal(a + b, z.Value); z = SqlInt32.Add(x, y); - Assert.Equal(z.Value, a + b); + Assert.Equal(a + b, z.Value); } [Fact] @@ -70,9 +70,9 @@ public void BitwiseAnd() SqlInt32 x = new SqlInt32(a); SqlInt32 y = new SqlInt32(b); SqlInt32 z = x & y; - Assert.Equal(z.Value, a & b); + Assert.Equal(a & b, z.Value); z = SqlInt32.BitwiseAnd(x, y); - Assert.Equal(z.Value, a & b); + Assert.Equal(a & b, z.Value); } [Fact] @@ -84,9 +84,9 @@ public void BitwiseOr() SqlInt32 x = new SqlInt32(a); SqlInt32 y = new SqlInt32(b); SqlInt32 z = x | y; - Assert.Equal(z.Value, a | b); + Assert.Equal(a | b, z.Value); z = SqlInt32.BitwiseOr(x, y); - Assert.Equal(z.Value, a | b); + Assert.Equal(a | b, z.Value); } [Fact] @@ -98,9 +98,9 @@ public void Divide() SqlInt32 x = new SqlInt32(a); SqlInt32 y = new SqlInt32(b); SqlInt32 z = x / y; - Assert.Equal(z.Value, a / b); + Assert.Equal(a / b, z.Value); z = SqlInt32.Divide(x, y); - Assert.Equal(z.Value, a / b); + Assert.Equal(a / b, z.Value); } [Fact] @@ -112,25 +112,25 @@ public void EqualsTest() // Case 1: either is SqlInt32.Null x = SqlInt32.Null; y = new SqlInt32(5); - Assert.Equal(x == y, SqlBoolean.Null); - Assert.Equal(SqlInt32.Equals(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x == y); + Assert.Equal(SqlBoolean.Null, SqlInt32.Equals(x, y)); // Case 2: both are SqlInt32.Null y = SqlInt32.Null; - Assert.Equal(x == y, SqlBoolean.Null); - Assert.Equal(SqlInt32.Equals(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x == y); + Assert.Equal(SqlBoolean.Null, SqlInt32.Equals(x, y)); // Case 3: both are equal x = new SqlInt32(5); y = new SqlInt32(5); - Assert.Equal(x == y, SqlBoolean.True); - Assert.Equal(SqlInt32.Equals(x, y), SqlBoolean.True); + Assert.Equal(SqlBoolean.True, x == y); + Assert.Equal(SqlBoolean.True, SqlInt32.Equals(x, y)); // Case 4: inequality x = new SqlInt32(5); y = new SqlInt32(6); - Assert.Equal(x == y, SqlBoolean.False); - Assert.Equal(SqlInt32.Equals(x, y), SqlBoolean.False); + Assert.Equal(SqlBoolean.False, x == y); + Assert.Equal(SqlBoolean.False, SqlInt32.Equals(x, y)); } [Fact] @@ -142,25 +142,25 @@ public void GreaterThan() // Case 1: either is SqlInt32.Null x = SqlInt32.Null; y = new SqlInt32(5); - Assert.Equal(x > y, SqlBoolean.Null); - Assert.Equal(SqlInt32.GreaterThan(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x > y); + Assert.Equal(SqlBoolean.Null, SqlInt32.GreaterThan(x, y)); // Case 2: both are SqlInt32.Null y = SqlInt32.Null; - Assert.Equal(x > y, SqlBoolean.Null); - Assert.Equal(SqlInt32.GreaterThan(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x > y); + Assert.Equal(SqlBoolean.Null, SqlInt32.GreaterThan(x, y)); // Case 3: x > y x = new SqlInt32(5); y = new SqlInt32(4); - Assert.Equal(x > y, SqlBoolean.True); - Assert.Equal(SqlInt32.GreaterThan(x, y), SqlBoolean.True); + Assert.Equal(SqlBoolean.True, x > y); + Assert.Equal(SqlBoolean.True, SqlInt32.GreaterThan(x, y)); // Case 4: x < y x = new SqlInt32(5); y = new SqlInt32(6); - Assert.Equal(x > y, SqlBoolean.False); - Assert.Equal(SqlInt32.GreaterThan(x, y), SqlBoolean.False); + Assert.Equal(SqlBoolean.False, x > y); + Assert.Equal(SqlBoolean.False, SqlInt32.GreaterThan(x, y)); } [Fact] @@ -172,31 +172,31 @@ public void GreaterThanOrEqual() // Case 1: either is SqlInt32.Null x = SqlInt32.Null; y = new SqlInt32(5); - Assert.Equal(x >= y, SqlBoolean.Null); - Assert.Equal(SqlInt32.GreaterThanOrEqual(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x >= y); + Assert.Equal(SqlBoolean.Null, SqlInt32.GreaterThanOrEqual(x, y)); // Case 2: both are SqlInt32.Null y = SqlInt32.Null; - Assert.Equal(x >= y, SqlBoolean.Null); - Assert.Equal(SqlInt32.GreaterThanOrEqual(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x >= y); + Assert.Equal(SqlBoolean.Null, SqlInt32.GreaterThanOrEqual(x, y)); // Case 3: x > y x = new SqlInt32(5); y = new SqlInt32(4); - Assert.Equal(x >= y, SqlBoolean.True); - Assert.Equal(SqlInt32.GreaterThanOrEqual(x, y), SqlBoolean.True); + Assert.Equal(SqlBoolean.True, x >= y); + Assert.Equal(SqlBoolean.True, SqlInt32.GreaterThanOrEqual(x, y)); // Case 4: x < y x = new SqlInt32(5); y = new SqlInt32(6); - Assert.Equal(x >= y, SqlBoolean.False); - Assert.Equal(SqlInt32.GreaterThanOrEqual(x, y), SqlBoolean.False); + Assert.Equal(SqlBoolean.False, x >= y); + Assert.Equal(SqlBoolean.False, SqlInt32.GreaterThanOrEqual(x, y)); // Case 5: x == y x = new SqlInt32(5); y = new SqlInt32(5); - Assert.Equal(x >= y, SqlBoolean.True); - Assert.Equal(SqlInt32.GreaterThanOrEqual(x, y), SqlBoolean.True); + Assert.Equal(SqlBoolean.True, x >= y); + Assert.Equal(SqlBoolean.True, SqlInt32.GreaterThanOrEqual(x, y)); } [Fact] @@ -208,25 +208,25 @@ public void LessThan() // Case 1: either is SqlInt32.Null x = SqlInt32.Null; y = new SqlInt32(5); - Assert.Equal(x < y, SqlBoolean.Null); - Assert.Equal(SqlInt32.LessThan(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x < y); + Assert.Equal(SqlBoolean.Null, SqlInt32.LessThan(x, y)); // Case 2: both are SqlInt32.Null y = SqlInt32.Null; - Assert.Equal(x < y, SqlBoolean.Null); - Assert.Equal(SqlInt32.LessThan(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x < y); + Assert.Equal(SqlBoolean.Null, SqlInt32.LessThan(x, y)); // Case 3: x > y x = new SqlInt32(5); y = new SqlInt32(4); - Assert.Equal(x < y, SqlBoolean.False); - Assert.Equal(SqlInt32.LessThan(x, y), SqlBoolean.False); + Assert.Equal(SqlBoolean.False, x < y); + Assert.Equal(SqlBoolean.False, SqlInt32.LessThan(x, y)); // Case 4: x < y x = new SqlInt32(5); y = new SqlInt32(6); - Assert.Equal(x < y, SqlBoolean.True); - Assert.Equal(SqlInt32.LessThan(x, y), SqlBoolean.True); + Assert.Equal(SqlBoolean.True, x < y); + Assert.Equal(SqlBoolean.True, SqlInt32.LessThan(x, y)); } [Fact] @@ -238,31 +238,31 @@ public void LessThanOrEqual() // Case 1: either is SqlInt32.Null x = SqlInt32.Null; y = new SqlInt32(5); - Assert.Equal(x <= y, SqlBoolean.Null); - Assert.Equal(SqlInt32.LessThanOrEqual(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x <= y); + Assert.Equal(SqlBoolean.Null, SqlInt32.LessThanOrEqual(x, y)); // Case 2: both are SqlInt32.Null y = SqlInt32.Null; - Assert.Equal(x <= y, SqlBoolean.Null); - Assert.Equal(SqlInt32.LessThanOrEqual(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x <= y); + Assert.Equal(SqlBoolean.Null, SqlInt32.LessThanOrEqual(x, y)); // Case 3: x > y x = new SqlInt32(5); y = new SqlInt32(4); - Assert.Equal(x <= y, SqlBoolean.False); - Assert.Equal(SqlInt32.LessThanOrEqual(x, y), SqlBoolean.False); + Assert.Equal(SqlBoolean.False, x <= y); + Assert.Equal(SqlBoolean.False, SqlInt32.LessThanOrEqual(x, y)); // Case 4: x < y x = new SqlInt32(5); y = new SqlInt32(6); - Assert.Equal(x <= y, SqlBoolean.True); - Assert.Equal(SqlInt32.LessThanOrEqual(x, y), SqlBoolean.True); + Assert.Equal(SqlBoolean.True, x <= y); + Assert.Equal(SqlBoolean.True, SqlInt32.LessThanOrEqual(x, y)); // Case 5: x == y x = new SqlInt32(5); y = new SqlInt32(5); - Assert.Equal(x <= y, SqlBoolean.True); - Assert.Equal(SqlInt32.LessThanOrEqual(x, y), SqlBoolean.True); + Assert.Equal(SqlBoolean.True, x <= y); + Assert.Equal(SqlBoolean.True, SqlInt32.LessThanOrEqual(x, y)); } [Fact] @@ -274,9 +274,9 @@ public void Mod() SqlInt32 x = new SqlInt32(a); SqlInt32 y = new SqlInt32(b); SqlInt32 z = x % y; - Assert.Equal(z.Value, a % b); + Assert.Equal(a % b, z.Value); z = SqlInt32.Mod(x, y); - Assert.Equal(z.Value, a % b); + Assert.Equal(a % b, z.Value); } [Fact] @@ -287,9 +287,9 @@ public void Modulus() SqlInt32 x = new SqlInt32(a); SqlInt32 y = new SqlInt32(b); SqlInt32 z = x % y; - Assert.Equal(z.Value, a % b); + Assert.Equal(a % b, z.Value); z = SqlInt32.Modulus(x, y); - Assert.Equal(z.Value, a % b); + Assert.Equal(a % b, z.Value); } [Fact] @@ -301,9 +301,9 @@ public void Multiply() SqlInt32 x = new SqlInt32(a); SqlInt32 y = new SqlInt32(b); SqlInt32 z = x * y; - Assert.Equal(z.Value, a * b); + Assert.Equal(a * b, z.Value); z = SqlInt32.Multiply(x, y); - Assert.Equal(z.Value, a * b); + Assert.Equal(a * b, z.Value); } [Fact] @@ -315,16 +315,16 @@ public void NotEquals() x = new SqlInt32(5); y = SqlInt32.Null; - Assert.Equal(x != y, SqlBoolean.Null); - Assert.Equal(SqlInt32.NotEquals(x, y), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x != y); + Assert.Equal(SqlBoolean.Null, SqlInt32.NotEquals(x, y)); y = new SqlInt32(5); - Assert.Equal(x != y, SqlBoolean.False); - Assert.Equal(SqlInt32.NotEquals(x, y), SqlBoolean.False); + Assert.Equal(SqlBoolean.False, x != y); + Assert.Equal(SqlBoolean.False, SqlInt32.NotEquals(x, y)); y = new SqlInt32(6); - Assert.Equal(x != y, SqlBoolean.True); - Assert.Equal(SqlInt32.NotEquals(x, y), SqlBoolean.True); + Assert.Equal(SqlBoolean.True, x != y); + Assert.Equal(SqlBoolean.True, SqlInt32.NotEquals(x, y)); } [Fact] @@ -334,9 +334,9 @@ public void OnesComplement() SqlInt32 x = new SqlInt32(a); SqlInt32 z = ~x; - Assert.Equal(z.Value, ~a); + Assert.Equal(~a, z.Value); z = SqlInt32.OnesComplement(x); - Assert.Equal(z.Value, ~a); + Assert.Equal(~a, z.Value); } [Fact] @@ -355,9 +355,9 @@ public void Subtract() SqlInt32 x = new SqlInt32(a); SqlInt32 y = new SqlInt32(b); SqlInt32 z = x - y; - Assert.Equal(z.Value, a - b); + Assert.Equal(a - b, z.Value); z = SqlInt32.Subtract(x, y); - Assert.Equal(z.Value, a - b); + Assert.Equal(a - b, z.Value); } [Fact] @@ -367,27 +367,27 @@ public void ConversionMethods() // Case 1: SqlInt32.Null -> SqlBoolean == SqlBoolean.Null x = SqlInt32.Null; - Assert.Equal(x.ToSqlBoolean(), SqlBoolean.Null); + Assert.Equal(SqlBoolean.Null, x.ToSqlBoolean()); // Case 2: SqlInt32.Zero -> SqlBoolean == False x = SqlInt32.Zero; - Assert.Equal(x.ToSqlBoolean(), SqlBoolean.False); + Assert.Equal(SqlBoolean.False, x.ToSqlBoolean()); // Case 3: SqlInt32(nonzero) -> SqlBoolean == True x = new SqlInt32(27); - Assert.Equal(x.ToSqlBoolean(), SqlBoolean.True); + Assert.Equal(SqlBoolean.True, x.ToSqlBoolean()); // Case 4: SqlInt32.Null -> SqlByte == SqlByte.Null x = SqlInt32.Null; - Assert.Equal(x.ToSqlByte(), SqlByte.Null); + Assert.Equal(SqlByte.Null, x.ToSqlByte()); // Case 5: Test non-null conversion to SqlByte x = new SqlInt32(27); - Assert.Equal(x.ToSqlByte().Value, (byte)27); + Assert.Equal((byte)27, x.ToSqlByte().Value); // Case 6: SqlInt32.Null -> SqlDecimal == SqlDecimal.Null x = SqlInt32.Null; - Assert.Equal(x.ToSqlDecimal(), SqlDecimal.Null); + Assert.Equal(SqlDecimal.Null, x.ToSqlDecimal()); // Case 7: Test non-null conversion to SqlDecimal x = new SqlInt32(27); @@ -395,7 +395,7 @@ public void ConversionMethods() // Case 8: SqlInt32.Null -> SqlDouble == SqlDouble.Null x = SqlInt32.Null; - Assert.Equal(x.ToSqlDouble(), SqlDouble.Null); + Assert.Equal(SqlDouble.Null, x.ToSqlDouble()); // Case 9: Test non-null conversion to SqlDouble x = new SqlInt32(27); @@ -403,15 +403,15 @@ public void ConversionMethods() // Case 10: SqlInt32.Null -> SqlInt16 == SqlInt16.Null x = SqlInt32.Null; - Assert.Equal(x.ToSqlInt16(), SqlInt16.Null); + Assert.Equal(SqlInt16.Null, x.ToSqlInt16()); // Case 11: Test non-null conversion to SqlInt16 x = new SqlInt32(27); - Assert.Equal(x.ToSqlInt16().Value, (short)27); + Assert.Equal((short)27, x.ToSqlInt16().Value); // Case 12: SqlInt32.Null -> SqlInt64 == SqlInt64.Null x = SqlInt32.Null; - Assert.Equal(x.ToSqlInt64(), SqlInt64.Null); + Assert.Equal(SqlInt64.Null, x.ToSqlInt64()); // Case 13: Test non-null conversion to SqlInt64 x = new SqlInt32(27); @@ -419,7 +419,7 @@ public void ConversionMethods() // Case 14: SqlInt32.Null -> SqlMoney == SqlMoney.Null x = SqlInt32.Null; - Assert.Equal(x.ToSqlMoney(), SqlMoney.Null); + Assert.Equal(SqlMoney.Null, x.ToSqlMoney()); // Case 15: Test non-null conversion to SqlMoney x = new SqlInt32(27); @@ -427,7 +427,7 @@ public void ConversionMethods() // Case 16: SqlInt32.Null -> SqlSingle == SqlSingle.Null x = SqlInt32.Null; - Assert.Equal(x.ToSqlSingle(), SqlSingle.Null); + Assert.Equal(SqlSingle.Null, x.ToSqlSingle()); // Case 17: Test non-null conversion to SqlSingle x = new SqlInt32(27); @@ -443,9 +443,9 @@ public void Xor() SqlInt32 x = new SqlInt32(a); SqlInt32 y = new SqlInt32(b); SqlInt32 z = x ^ y; - Assert.Equal(z.Value, a ^ b); + Assert.Equal(a ^ b, z.Value); z = SqlInt32.Xor(x, y); - Assert.Equal(z.Value, a ^ b); + Assert.Equal(a ^ b, z.Value); } [Fact] diff --git a/src/libraries/System.Drawing.Common/tests/Drawing2D/MatrixTests.cs b/src/libraries/System.Drawing.Common/tests/Drawing2D/MatrixTests.cs index 34480479f6956..e014299b88bef 100644 --- a/src/libraries/System.Drawing.Common/tests/Drawing2D/MatrixTests.cs +++ b/src/libraries/System.Drawing.Common/tests/Drawing2D/MatrixTests.cs @@ -910,7 +910,7 @@ private static void AssertEqualFloatArray(float[] expected, float[] actual) { try { - Assert.Equal(expected[i], actual[i], 3); + Assert.Equal((double)expected[i], (double)actual[i], 3); } catch { diff --git a/src/libraries/System.Drawing.Common/tests/FontFamilyTests.cs b/src/libraries/System.Drawing.Common/tests/FontFamilyTests.cs index a87895ba21303..cf6287420d3b1 100644 --- a/src/libraries/System.Drawing.Common/tests/FontFamilyTests.cs +++ b/src/libraries/System.Drawing.Common/tests/FontFamilyTests.cs @@ -69,7 +69,7 @@ public void Ctor_NoSuchFontNameInCollection_ThrowsArgumentException() { using (var fontCollection = new PrivateFontCollection()) { - Assert.Throws(null, () => new FontFamily("Times New Roman", fontCollection)); + AssertExtensions.Throws(null, () => new FontFamily("Times New Roman", fontCollection)); } } diff --git a/src/libraries/System.Drawing.Common/tests/FontTests.cs b/src/libraries/System.Drawing.Common/tests/FontTests.cs index 899bd4e3c1040..4cf0c6e690b50 100644 --- a/src/libraries/System.Drawing.Common/tests/FontTests.cs +++ b/src/libraries/System.Drawing.Common/tests/FontTests.cs @@ -557,7 +557,7 @@ public void GetHeight_Graphics_ReturnsExpected() using (var image = new Bitmap(10, 10)) using (Graphics graphics = Graphics.FromImage(image)) { - Assert.Equal(font.GetHeight(graphics.DpiY), font.GetHeight(graphics), 5); + Assert.Equal((double)font.GetHeight(graphics.DpiY), font.GetHeight(graphics), 5); } } @@ -574,7 +574,7 @@ public void GetHeight_Dpi_ReturnsExpected(float dpi, float expected) using (FontFamily family = FontFamily.GenericSansSerif) using (var font = new Font(family, 10)) { - Assert.Equal(expected, font.GetHeight(dpi), 5); + Assert.Equal((double)expected, font.GetHeight(dpi), 5); } } diff --git a/src/libraries/System.Drawing.Common/tests/ImageTests.cs b/src/libraries/System.Drawing.Common/tests/ImageTests.cs index 5357e9a48b370..00d37e7520df8 100644 --- a/src/libraries/System.Drawing.Common/tests/ImageTests.cs +++ b/src/libraries/System.Drawing.Common/tests/ImageTests.cs @@ -121,7 +121,7 @@ public void GetPropertyItem_InvokeExistsBitmapBmp_Success() public void GetPropertyItem_NoSuchPropertyItemEmptyMemoryBitmap_ThrowsArgumentException(int propid) { using var bitmap = new Bitmap(1, 1); - Assert.Throws(null, () => bitmap.GetPropertyItem(propid)); + AssertExtensions.Throws(null, () => bitmap.GetPropertyItem(propid)); } [Theory] @@ -131,7 +131,7 @@ public void GetPropertyItem_NoSuchPropertyItemEmptyMemoryBitmap_ThrowsArgumentEx public void GetPropertyItem_NoSuchPropertyItemEmptyImageBitmapBmp_ThrowsArgumentException(int propid) { using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("almogaver1bit.bmp")); - Assert.Throws(null, () => bitmap.GetPropertyItem(propid)); + AssertExtensions.Throws(null, () => bitmap.GetPropertyItem(propid)); } [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] @@ -149,17 +149,17 @@ public void RemovePropertyItem_InvokeMemoryBitmap_Success() bitmap.RemovePropertyItem(PropertyTagExifUserComment); Assert.Equal(new int[] { PropertyTagChrominanceTable, PropertyTagLuminanceTable }, bitmap.PropertyIdList); - Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagExifUserComment)); - Assert.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagExifUserComment)); + AssertExtensions.Throws(null, () => bitmap.GetPropertyItem(PropertyTagExifUserComment)); + AssertExtensions.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagExifUserComment)); bitmap.RemovePropertyItem(PropertyTagLuminanceTable); Assert.Equal(new int[] { PropertyTagChrominanceTable }, bitmap.PropertyIdList); - Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagLuminanceTable)); - Assert.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagLuminanceTable)); + AssertExtensions.Throws(null, () => bitmap.GetPropertyItem(PropertyTagLuminanceTable)); + AssertExtensions.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagLuminanceTable)); bitmap.RemovePropertyItem(PropertyTagChrominanceTable); Assert.Empty(bitmap.PropertyIdList); - Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagChrominanceTable)); + AssertExtensions.Throws(null, () => bitmap.GetPropertyItem(PropertyTagChrominanceTable)); Assert.Throws(() => bitmap.RemovePropertyItem(PropertyTagChrominanceTable)); } @@ -170,17 +170,17 @@ public void RemovePropertyItem_InvokeBitmapJpg_Success() using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg")); bitmap.RemovePropertyItem(PropertyTagExifUserComment); Assert.Equal(new int[] { PropertyTagChrominanceTable, PropertyTagLuminanceTable }, bitmap.PropertyIdList); - Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagExifUserComment)); - Assert.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagExifUserComment)); + AssertExtensions.Throws(null, () => bitmap.GetPropertyItem(PropertyTagExifUserComment)); + AssertExtensions.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagExifUserComment)); bitmap.RemovePropertyItem(PropertyTagLuminanceTable); Assert.Equal(new int[] { PropertyTagChrominanceTable }, bitmap.PropertyIdList); - Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagLuminanceTable)); - Assert.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagLuminanceTable)); + AssertExtensions.Throws(null, () => bitmap.GetPropertyItem(PropertyTagLuminanceTable)); + AssertExtensions.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagLuminanceTable)); bitmap.RemovePropertyItem(PropertyTagChrominanceTable); Assert.Empty(bitmap.PropertyIdList); - Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagChrominanceTable)); + AssertExtensions.Throws(null, () => bitmap.GetPropertyItem(PropertyTagChrominanceTable)); Assert.Throws(() => bitmap.RemovePropertyItem(PropertyTagChrominanceTable)); } @@ -222,7 +222,7 @@ public void RemovePropertyItem_NoSuchPropertyNotEmptyMemoryBitmap_ThrowsArgument bitmap.SetPropertyItem(item2); bitmap.SetPropertyItem(item3); - Assert.Throws(null, () => bitmap.RemovePropertyItem(propid)); + AssertExtensions.Throws(null, () => bitmap.RemovePropertyItem(propid)); } [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] @@ -233,7 +233,7 @@ public void RemovePropertyItem_NoSuchPropertyNotEmptyMemoryBitmap_ThrowsArgument public void RemovePropertyItem_NoSuchPropertyNotEmptyBitmapJpg_ThrowsArgumentException(int propid) { using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg")); - Assert.Throws(null, () => bitmap.RemovePropertyItem(propid)); + AssertExtensions.Throws(null, () => bitmap.RemovePropertyItem(propid)); } [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] diff --git a/src/libraries/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs b/src/libraries/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs index 137ea1d48d31b..0a2fae6c0fd9d 100644 --- a/src/libraries/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs +++ b/src/libraries/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs @@ -479,10 +479,10 @@ public void CreateMeasurementGraphics_Default_ReturnsExpected() using (Graphics graphic = printerSettings.CreateMeasurementGraphics()) { Assert.NotNull(graphic); - Assert.Equal(printerSettings.DefaultPageSettings.Bounds.X, graphic.VisibleClipBounds.X, 0); - Assert.Equal(printerSettings.DefaultPageSettings.Bounds.Y, graphic.VisibleClipBounds.Y, 0); - Assert.Equal(printerSettings.DefaultPageSettings.PrintableArea.Height, graphic.VisibleClipBounds.Height, 0); - Assert.Equal(printerSettings.DefaultPageSettings.PrintableArea.Width, graphic.VisibleClipBounds.Width, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.Bounds.X, graphic.VisibleClipBounds.X, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.Bounds.Y, graphic.VisibleClipBounds.Y, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.PrintableArea.Height, graphic.VisibleClipBounds.Height, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.PrintableArea.Width, graphic.VisibleClipBounds.Width, 0); } } @@ -494,8 +494,8 @@ public void CreateMeasurementGraphics_Bool_ReturnsExpected() using (Graphics graphic = printerSettings.CreateMeasurementGraphics(true)) { Assert.NotNull(graphic); - Assert.Equal(printerSettings.DefaultPageSettings.PrintableArea.Height, graphic.VisibleClipBounds.Height, 0); - Assert.Equal(printerSettings.DefaultPageSettings.PrintableArea.Width, graphic.VisibleClipBounds.Width, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.PrintableArea.Height, graphic.VisibleClipBounds.Height, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.PrintableArea.Width, graphic.VisibleClipBounds.Width, 0); } } @@ -508,10 +508,10 @@ public void CreateMeasurementGraphics_PageSettings_ReturnsExpected() using (Graphics graphic = printerSettings.CreateMeasurementGraphics(pageSettings)) { Assert.NotNull(graphic); - Assert.Equal(printerSettings.DefaultPageSettings.Bounds.X, graphic.VisibleClipBounds.X, 0); - Assert.Equal(printerSettings.DefaultPageSettings.Bounds.Y, graphic.VisibleClipBounds.Y, 0); - Assert.Equal(printerSettings.DefaultPageSettings.PrintableArea.Height, graphic.VisibleClipBounds.Height, 0); - Assert.Equal(printerSettings.DefaultPageSettings.PrintableArea.Width, graphic.VisibleClipBounds.Width, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.Bounds.X, graphic.VisibleClipBounds.X, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.Bounds.Y, graphic.VisibleClipBounds.Y, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.PrintableArea.Height, graphic.VisibleClipBounds.Height, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.PrintableArea.Width, graphic.VisibleClipBounds.Width, 0); } } @@ -524,8 +524,8 @@ public void CreateMeasurementGraphics_PageSettingsBool_ReturnsExpected() using (Graphics graphic = printerSettings.CreateMeasurementGraphics(pageSettings, true)) { Assert.NotNull(graphic); - Assert.Equal(printerSettings.DefaultPageSettings.PrintableArea.Height, graphic.VisibleClipBounds.Height, 0); - Assert.Equal(printerSettings.DefaultPageSettings.PrintableArea.Width, graphic.VisibleClipBounds.Width, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.PrintableArea.Height, graphic.VisibleClipBounds.Height, 0); + Assert.Equal((double)printerSettings.DefaultPageSettings.PrintableArea.Width, graphic.VisibleClipBounds.Width, 0); } } diff --git a/src/libraries/System.Drawing.Common/tests/SystemPensTest.cs b/src/libraries/System.Drawing.Common/tests/SystemPensTest.cs index 046231cdf50f7..225800bd167d4 100644 --- a/src/libraries/System.Drawing.Common/tests/SystemPensTest.cs +++ b/src/libraries/System.Drawing.Common/tests/SystemPensTest.cs @@ -77,7 +77,7 @@ public void SystemPens_Get_ReturnsExpected(Func getPen, Color expectedColor AssertExtensions.Throws(null, () => pen.StartCap = LineCap.RoundAnchor); using (var matrix = new Matrix()) { - Assert.Throws(null, () => pen.Transform = matrix); + AssertExtensions.Throws(null, () => pen.Transform = matrix); } AssertExtensions.Throws(null, () => pen.Width = 10); } diff --git a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing/GraphicsTests.cs b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing/GraphicsTests.cs index 756e860a2a644..a274b13d74120 100644 --- a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing/GraphicsTests.cs +++ b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing/GraphicsTests.cs @@ -1794,11 +1794,11 @@ public void MeasureString_StringFormat_Alignment() string_format.Alignment = StringAlignment.Far; SizeF far = g.MeasureString(text, font, int.MaxValue, string_format); - Assert.Equal(near.Width, center.Width, 1); - Assert.Equal(near.Height, center.Height, 1); + Assert.Equal((double)near.Width, center.Width, 1); + Assert.Equal((double)near.Height, center.Height, 1); - Assert.Equal(center.Width, far.Width, 1); - Assert.Equal(center.Height, far.Height, 1); + Assert.Equal((double)center.Width, far.Width, 1); + Assert.Equal((double)center.Height, far.Height, 1); } } @@ -1821,11 +1821,11 @@ public void MeasureString_StringFormat_Alignment_DirectionVertical() string_format.Alignment = StringAlignment.Far; SizeF far = g.MeasureString(text, font, int.MaxValue, string_format); - Assert.Equal(near.Width, center.Width, 0); - Assert.Equal(near.Height, center.Height, 0); + Assert.Equal((double)near.Width, center.Width, 0); + Assert.Equal((double)near.Height, center.Height, 0); - Assert.Equal(center.Width, far.Width, 0); - Assert.Equal(center.Height, far.Height, 0); + Assert.Equal((double)center.Width, far.Width, 0); + Assert.Equal((double)center.Height, far.Height, 0); } } @@ -1846,11 +1846,11 @@ public void MeasureString_StringFormat_LineAlignment() string_format.LineAlignment = StringAlignment.Far; SizeF far = g.MeasureString(text, font, int.MaxValue, string_format); - Assert.Equal(near.Width, center.Width, 1); - Assert.Equal(near.Height, center.Height, 1); + Assert.Equal((double)near.Width, center.Width, 1); + Assert.Equal((double)near.Height, center.Height, 1); - Assert.Equal(center.Width, far.Width, 1); - Assert.Equal(center.Height, far.Height, 1); + Assert.Equal((double)center.Width, far.Width, 1); + Assert.Equal((double)center.Height, far.Height, 1); } } @@ -1873,11 +1873,11 @@ public void MeasureString_StringFormat_LineAlignment_DirectionVertical() string_format.LineAlignment = StringAlignment.Far; SizeF far = g.MeasureString(text, font, int.MaxValue, string_format); - Assert.Equal(near.Width, center.Width, 1); - Assert.Equal(near.Height, center.Height, 1); + Assert.Equal((double)near.Width, center.Width, 1); + Assert.Equal((double)near.Height, center.Height, 1); - Assert.Equal(center.Width, far.Width, 1); - Assert.Equal(center.Height, far.Height, 1); + Assert.Equal((double)center.Width, far.Width, 1); + Assert.Equal((double)center.Height, far.Height, 1); } } @@ -1895,7 +1895,7 @@ public void MeasureString_CharactersFitted() // in pixels Assert.True(size2.Width < size.Width); - Assert.Equal(size2.Height, size.Height); + Assert.Equal((double)size2.Height, size.Height); Assert.Equal(1, lines); // documentation seems to suggest chars is total length @@ -1920,8 +1920,8 @@ public void MeasureString_Whitespace() { s += " "; size = g.MeasureString(s, font); - Assert.Equal(expected.Height, size.Height, 1); - Assert.Equal(expected.Width, size.Width, 1); + Assert.Equal((double)expected.Height, size.Height, 1); + Assert.Equal((double)expected.Width, size.Width, 1); } s = "a"; @@ -1932,8 +1932,8 @@ public void MeasureString_Whitespace() for (int i = 1; i < 10; i++) { size = g.MeasureString(s, font); - Assert.Equal(expected.Height, size.Height, 1); - Assert.Equal(expected.Width + i * space_width, size.Width, 1); + Assert.Equal((double)expected.Height, size.Height, 1); + Assert.Equal((double)expected.Width + i * space_width, size.Width, 1); s = " " + s; } @@ -1943,8 +1943,8 @@ public void MeasureString_Whitespace() { s = s + " "; size = g.MeasureString(s, font); - Assert.Equal(expected.Height, size.Height, 1); - Assert.Equal(expected.Width, size.Width, 1); + Assert.Equal((double)expected.Height, size.Height, 1); + Assert.Equal((double)expected.Width, size.Width, 1); } } } @@ -2076,7 +2076,7 @@ public void MeasureCharacterRanges_Prefix() string_format.HotkeyPrefix = HotkeyPrefix.Hide; regions = g.MeasureCharacterRanges(text, font, layout_rect, string_format); RectangleF bounds_hide = regions[0].GetBounds(g); - Assert.Equal(bounds_hide.Width, bounds_show.Width); + Assert.Equal((double)bounds_hide.Width, bounds_show.Width); } } @@ -2125,8 +2125,8 @@ public void Measure() RectangleF sb = small[i].GetBounds(gfx); Assert.Equal(sb.X, zb.X); Assert.Equal(sb.Y, zb.Y); - Assert.Equal(sb.Width, zb.Width); - Assert.Equal(sb.Height, zb.Height); + Assert.Equal((double)sb.Width, zb.Width); + Assert.Equal((double)sb.Height, zb.Height); } Region[] max = Measure_Helper(gfx, new RectangleF(0, 0, float.MaxValue, float.MaxValue)); @@ -2137,8 +2137,8 @@ public void Measure() RectangleF mb = max[i].GetBounds(gfx); Assert.Equal(mb.X, zb.X); Assert.Equal(mb.Y, zb.Y); - Assert.Equal(mb.Width, zb.Width); - Assert.Equal(mb.Height, zb.Height); + Assert.Equal((double)mb.Width, zb.Width); + Assert.Equal((double)mb.Height, zb.Height); } } } @@ -2316,15 +2316,15 @@ public void VisibleClipBound() RectangleF clip = g.VisibleClipBounds; Assert.Equal(0, clip.X); Assert.Equal(0, clip.Y); - Assert.Equal(32, clip.Width, 4); - Assert.Equal(32, clip.Height, 4); + Assert.Equal(32.0, clip.Width, 4); + Assert.Equal(32.0, clip.Height, 4); g.RotateTransform(90); RectangleF rotclip = g.VisibleClipBounds; Assert.Equal(0, rotclip.X); - Assert.Equal(-32, rotclip.Y, 4); - Assert.Equal(32, rotclip.Width, 4); - Assert.Equal(32, rotclip.Height, 4); + Assert.Equal(-32.0, rotclip.Y, 4); + Assert.Equal(32.0, rotclip.Width, 4); + Assert.Equal(32.0, rotclip.Height, 4); } } @@ -2363,15 +2363,15 @@ public void VisibleClipBound_BigClip() g.RotateTransform(90); RectangleF rotclipbound = g.ClipBounds; Assert.Equal(0, rotclipbound.X); - Assert.Equal(-200, rotclipbound.Y, 4); - Assert.Equal(200, rotclipbound.Width, 4); - Assert.Equal(200, rotclipbound.Height, 4); + Assert.Equal(-200.0, rotclipbound.Y, 4); + Assert.Equal(200.0, rotclipbound.Width, 4); + Assert.Equal(200.0, rotclipbound.Height, 4); RectangleF rotclip = g.VisibleClipBounds; Assert.Equal(0, rotclip.X); - Assert.Equal(-100, rotclip.Y, 4); - Assert.Equal(100, rotclip.Width, 4); - Assert.Equal(100, rotclip.Height, 4); + Assert.Equal(-100.0, rotclip.Y, 4); + Assert.Equal(100.0, rotclip.Width, 4); + Assert.Equal(100.0, rotclip.Height, 4); } } @@ -2390,15 +2390,15 @@ public void Rotate() RectangleF vcb = g.VisibleClipBounds; Assert.Equal(0, vcb.X); Assert.Equal(0, vcb.Y); - Assert.Equal(100, vcb.Width, 4); - Assert.Equal(50, vcb.Height, 4); + Assert.Equal(100.0, vcb.Width, 4); + Assert.Equal(50.0, vcb.Height, 4); g.RotateTransform(90); RectangleF rvcb = g.VisibleClipBounds; Assert.Equal(0, rvcb.X); - Assert.Equal(-100, rvcb.Y, 4); - Assert.Equal(50.0f, rvcb.Width, 4); - Assert.Equal(100, rvcb.Height, 4); + Assert.Equal(-100.0, rvcb.Y, 4); + Assert.Equal(50.0, rvcb.Width, 4); + Assert.Equal(100.0, rvcb.Height, 4); } } diff --git a/src/libraries/System.Drawing.Common/tests/mono/System.Imaging/MetafileTest.cs b/src/libraries/System.Drawing.Common/tests/mono/System.Imaging/MetafileTest.cs index a50622aa57edd..6fe608464542e 100644 --- a/src/libraries/System.Drawing.Common/tests/mono/System.Imaging/MetafileTest.cs +++ b/src/libraries/System.Drawing.Common/tests/mono/System.Imaging/MetafileTest.cs @@ -441,21 +441,21 @@ public void WorldTransforms() g.MultiplyTransform(m); // check float[] elements = g.Transform.Elements; - Assert.Equal(-1f, elements[0], 5); - Assert.Equal(0f, elements[1], 5); - Assert.Equal(0f, elements[2], 5); - Assert.Equal(-1f, elements[3], 5); - Assert.Equal(-2f, elements[4], 5); - Assert.Equal(-3f, elements[5], 5); + Assert.Equal(-1.0, elements[0], 5); + Assert.Equal(0.0, elements[1], 5); + Assert.Equal(0.0, elements[2], 5); + Assert.Equal(-1.0, elements[3], 5); + Assert.Equal(-2.0, elements[4], 5); + Assert.Equal(-3.0, elements[5], 5); g.Transform = m; elements = g.Transform.Elements; - Assert.Equal(0f, elements[0], 5); - Assert.Equal(0.5f, elements[1], 5); - Assert.Equal(-2f, elements[2], 5); - Assert.Equal(0f, elements[3], 5); - Assert.Equal(-4f, elements[4], 5); - Assert.Equal(-1f, elements[5], 5); + Assert.Equal(0.0, elements[0], 5); + Assert.Equal(0.5, elements[1], 5); + Assert.Equal(-2.0, elements[2], 5); + Assert.Equal(0.0, elements[3], 5); + Assert.Equal(-4.0, elements[4], 5); + Assert.Equal(-1.0, elements[5], 5); g.ResetTransform(); Assert.True(g.Transform.IsIdentity); diff --git a/src/libraries/System.IO.UnmanagedMemoryStream/tests/UmsSafeBuffer.cs b/src/libraries/System.IO.UnmanagedMemoryStream/tests/UmsSafeBuffer.cs index f5afb82342a63..cec8bb9ee15f1 100644 --- a/src/libraries/System.IO.UnmanagedMemoryStream/tests/UmsSafeBuffer.cs +++ b/src/libraries/System.IO.UnmanagedMemoryStream/tests/UmsSafeBuffer.cs @@ -95,7 +95,7 @@ public static void WriteSafeBuffer() using (var buffer = new TestSafeBuffer(length)) { var stream = new UnmanagedMemoryStream(buffer, 0, (long)buffer.ByteLength, FileAccess.Write); - Assert.Equal(stream.Length, length); + Assert.Equal(length, stream.Length); var bytes = ArrayHelpers.CreateByteArray(length); var copy = bytes.Copy(); @@ -116,7 +116,7 @@ public static void ReadWriteByteSafeBuffer() using (var buffer = new TestSafeBuffer(length)) { var stream = new UnmanagedMemoryStream(buffer, 0, (long)buffer.ByteLength, FileAccess.ReadWrite); - Assert.Equal(stream.Length, length); + Assert.Equal(length, stream.Length); var bytes = ArrayHelpers.CreateByteArray(length); for (int index = 0; index < length; index++) diff --git a/src/libraries/System.IO/tests/IndentedTextWriter.cs b/src/libraries/System.IO/tests/IndentedTextWriter.cs index 96a973ba375bb..78d9a8db49d01 100644 --- a/src/libraries/System.IO/tests/IndentedTextWriter.cs +++ b/src/libraries/System.IO/tests/IndentedTextWriter.cs @@ -312,7 +312,7 @@ public static void Ctor_ExpectedDefaults() Assert.Same(sw, itw.InnerWriter); Assert.Equal(sw.NewLine, itw.NewLine); - Assert.Equal(new string(' ', 4), IndentedTextWriter.DefaultTabString); + Assert.Equal(" ", IndentedTextWriter.DefaultTabString); } [Fact] diff --git a/src/libraries/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs b/src/libraries/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs index 40e794a5f6935..ac7715a193c65 100644 --- a/src/libraries/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs +++ b/src/libraries/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs @@ -1402,7 +1402,7 @@ public void CanReturnAnythingFromExplicitVoidCatch(bool useInterpreter) [Fact] public void CatchesMustReturnVoidWithVoidBody() { - Assert.Throws(null, () => + AssertExtensions.Throws(null, () => Expression.TryCatch( Expression.Empty(), Expression.Catch(typeof(InvocationExpression), Expression.Constant("hello")), diff --git a/src/libraries/System.Memory/tests/MemoryMarshal/AsReadOnlyRef.cs b/src/libraries/System.Memory/tests/MemoryMarshal/AsReadOnlyRef.cs index 1a654bdff8d20..e48790231b288 100644 --- a/src/libraries/System.Memory/tests/MemoryMarshal/AsReadOnlyRef.cs +++ b/src/libraries/System.Memory/tests/MemoryMarshal/AsReadOnlyRef.cs @@ -22,7 +22,7 @@ public static void AsReadOnlyRef() Array.Fill(array, 0x42); ref readonly TestHelpers.TestStructExplicit asStruct = ref MemoryMarshal.AsRef(new ReadOnlySpan(array)); - Assert.Equal(asStruct.UI1, (uint)0x42424242); + Assert.Equal((uint)0x42424242, asStruct.UI1); } [Fact] diff --git a/src/libraries/System.Memory/tests/MemoryMarshal/AsRef.cs b/src/libraries/System.Memory/tests/MemoryMarshal/AsRef.cs index 39d4cace81035..a51b41051957c 100644 --- a/src/libraries/System.Memory/tests/MemoryMarshal/AsRef.cs +++ b/src/libraries/System.Memory/tests/MemoryMarshal/AsRef.cs @@ -22,7 +22,7 @@ public static void AsRef() Array.Fill(array, 0x42); ref TestHelpers.TestStructExplicit asStruct = ref MemoryMarshal.AsRef(new Span(array)); - Assert.Equal(asStruct.UI1, (uint)0x42424242); + Assert.Equal((uint)0x42424242, asStruct.UI1); } [Fact] diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index 3c011b669ca9a..8431f2565e819 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -2254,9 +2254,9 @@ public async Task Http2_MultipleConnectionsEnabled_OpenAndCloseMultipleConnectio await Task.WhenAll(handleRequestTasks).WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); - Assert.Equal(handleRequestTasks[0].Result.Count, MaxConcurrentStreams); - Assert.Equal(handleRequestTasks[1].Result.Count, MaxConcurrentStreams); - Assert.Equal(handleRequestTasks[2].Result.Count, MaxConcurrentStreams); + Assert.Equal(MaxConcurrentStreams, handleRequestTasks[0].Result.Count); + Assert.Equal(MaxConcurrentStreams, handleRequestTasks[1].Result.Count); + Assert.Equal(MaxConcurrentStreams, handleRequestTasks[2].Result.Count); await connection0.ShutdownIgnoringErrorsAsync(handleRequestTasks[0].Result.LastStreamId).ConfigureAwait(false); await connection2.ShutdownIgnoringErrorsAsync(handleRequestTasks[2].Result.LastStreamId).ConfigureAwait(false); @@ -2277,9 +2277,9 @@ public async Task Http2_MultipleConnectionsEnabled_OpenAndCloseMultipleConnectio await Task.WhenAll(finalHandleTasks).WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); - Assert.Equal(finalHandleTasks[0].Result.Count, MaxConcurrentStreams); - Assert.Equal(finalHandleTasks[1].Result.Count, MaxConcurrentStreams); - Assert.Equal(finalHandleTasks[2].Result.Count, MaxConcurrentStreams); + Assert.Equal(MaxConcurrentStreams, finalHandleTasks[0].Result.Count); + Assert.Equal(MaxConcurrentStreams, finalHandleTasks[1].Result.Count); + Assert.Equal(MaxConcurrentStreams, finalHandleTasks[2].Result.Count); await Task.WhenAll(sendTasks).WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); diff --git a/src/libraries/System.Net.Mail/tests/Functional/ContentDispositionTest.cs b/src/libraries/System.Net.Mail/tests/Functional/ContentDispositionTest.cs index d6d6db3623494..2f25ed2bf8f12 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/ContentDispositionTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/ContentDispositionTest.cs @@ -261,7 +261,7 @@ public void GetViaDateTimeProperty_WithLocalTime_ShouldSetDateTimeKindAppropriat cd.Parameters["creation-date"] = ValidDateTimeLocal; Assert.Equal(DateTimeKind.Local, cd.CreationDate.Kind); - Assert.Equal(cd.Parameters["creation-date"], ValidDateTimeLocal); + Assert.Equal(ValidDateTimeLocal, cd.Parameters["creation-date"]); } [Fact] diff --git a/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs b/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs index ff439513b116b..6cf0d7d7740ee 100644 --- a/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs +++ b/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs @@ -40,9 +40,9 @@ public void Ctor_VerifyDefaults_Success() Assert.NotNull(request.Headers); Assert.Equal(0, request.Headers.Count); Assert.True(request.KeepAlive); - Assert.Equal(request.Method, WebRequestMethods.Ftp.DownloadFile); + Assert.Equal(WebRequestMethods.Ftp.DownloadFile, request.Method); Assert.Null(request.Proxy); - Assert.Equal(request.ReadWriteTimeout, 5 * 60 * 1000); + Assert.Equal(5 * 60 * 1000, request.ReadWriteTimeout); Assert.Null(request.RenameTo); Assert.Equal("ftp", request.RequestUri.Scheme); Assert.Equal("foo.com", request.RequestUri.Host); diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs index 8106173a6378e..13a4c44616993 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs @@ -873,8 +873,8 @@ public void Vector2ConstructorTest2() public void Vector2ConstructorTest3() { Vector2 target = new Vector2(float.NaN, float.MaxValue); - Assert.Equal(target.X, float.NaN); - Assert.Equal(target.Y, float.MaxValue); + Assert.Equal(float.NaN, target.X); + Assert.Equal(float.MaxValue, target.Y); } // A test for Vector2f (float) diff --git a/src/libraries/System.Private.Uri/tests/FunctionalTests/UriTests.cs b/src/libraries/System.Private.Uri/tests/FunctionalTests/UriTests.cs index 2656fe960b708..ca302b4be1c1c 100644 --- a/src/libraries/System.Private.Uri/tests/FunctionalTests/UriTests.cs +++ b/src/libraries/System.Private.Uri/tests/FunctionalTests/UriTests.cs @@ -546,13 +546,13 @@ public static void TestCompare() int i; i = Uri.Compare(uri1, uri2, UriComponents.AbsoluteUri, UriFormat.UriEscaped, StringComparison.CurrentCulture); - Assert.Equal(i, -1); + Assert.Equal(-1, i); i = Uri.Compare(uri1, uri2, UriComponents.Query, UriFormat.UriEscaped, StringComparison.CurrentCulture); Assert.Equal(0, i); i = Uri.Compare(uri1, uri2, UriComponents.Query | UriComponents.Fragment, UriFormat.UriEscaped, StringComparison.CurrentCulture); - Assert.Equal(i, -1); + Assert.Equal(-1, i); Assert.False(uri1.Equals(uri2)); diff --git a/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.RuntimeOnly.cs b/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.RuntimeOnly.cs index cb50258f7fa27..592f6254d8c51 100644 --- a/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.RuntimeOnly.cs +++ b/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.RuntimeOnly.cs @@ -58,12 +58,12 @@ public static void Xml_ByteArrayNull() [Fact] public static void Xml_CharAsRoot() { - Assert.StrictEqual(SerializeAndDeserialize(char.MinValue, + Assert.StrictEqual(char.MinValue, SerializeAndDeserialize(char.MinValue, @" -0"), char.MinValue); - Assert.StrictEqual(SerializeAndDeserialize(char.MaxValue, +0")); + Assert.StrictEqual(char.MaxValue, SerializeAndDeserialize(char.MaxValue, @" -65535"), char.MaxValue); +65535")); Assert.StrictEqual('a', SerializeAndDeserialize('a', @" 97")); @@ -81,12 +81,12 @@ public static void Xml_ByteAsRoot() Assert.StrictEqual(10, SerializeAndDeserialize(10, @" 10")); - Assert.StrictEqual(SerializeAndDeserialize(byte.MinValue, + Assert.StrictEqual(byte.MinValue, SerializeAndDeserialize(byte.MinValue, @" -0"), byte.MinValue); - Assert.StrictEqual(SerializeAndDeserialize(byte.MaxValue, +0")); + Assert.StrictEqual(byte.MaxValue, SerializeAndDeserialize(byte.MaxValue, @" -255"), byte.MaxValue); +255")); } [Fact] @@ -128,46 +128,46 @@ public static void Xml_DecimalAsRoot() [Fact] public static void Xml_DoubleAsRoot() { - Assert.StrictEqual(SerializeAndDeserialize(-1.2, + Assert.StrictEqual(-1.2, SerializeAndDeserialize(-1.2, @" --1.2"), -1.2); +-1.2")); Assert.StrictEqual(0, SerializeAndDeserialize(0, @" 0")); Assert.StrictEqual(2.3, SerializeAndDeserialize(2.3, @" 2.3")); - Assert.StrictEqual(SerializeAndDeserialize(double.MinValue, + Assert.StrictEqual(double.MinValue, SerializeAndDeserialize(double.MinValue, @" --1.7976931348623157E+308"), double.MinValue); - Assert.StrictEqual(SerializeAndDeserialize(double.MaxValue, +-1.7976931348623157E+308")); + Assert.StrictEqual(double.MaxValue, SerializeAndDeserialize(double.MaxValue, @" -1.7976931348623157E+308"), double.MaxValue); +1.7976931348623157E+308")); } [Fact] public static void Xml_FloatAsRoot() { - Assert.StrictEqual(SerializeAndDeserialize((float)-1.2, + Assert.StrictEqual((float)-1.2, SerializeAndDeserialize((float)-1.2, @" --1.2"), (float)-1.2); - Assert.StrictEqual(SerializeAndDeserialize((float)0, +-1.2")); + Assert.StrictEqual((float)0, SerializeAndDeserialize((float)0, @" -0"), (float)0); - Assert.StrictEqual(SerializeAndDeserialize((float)2.3, +0")); + Assert.StrictEqual((float)2.3, SerializeAndDeserialize((float)2.3, @" -2.3"), (float)2.3); +2.3")); } [Fact] public static void Xml_FloatAsRoot_NotNetFramework() { - Assert.StrictEqual(SerializeAndDeserialize(float.MinValue, + Assert.StrictEqual(float.MinValue, SerializeAndDeserialize(float.MinValue, @" --3.4028235E+38"), float.MinValue); - Assert.StrictEqual(SerializeAndDeserialize(float.MaxValue, +-3.4028235E+38")); + Assert.StrictEqual(float.MaxValue, SerializeAndDeserialize(float.MaxValue, @" -3.4028235E+38"), float.MaxValue); +3.4028235E+38")); } [Fact] @@ -229,8 +229,8 @@ public static void Xml_XmlQualifiedNameAsRoot() Assert.StrictEqual(SerializeAndDeserialize(new XmlQualifiedName("abc", "def"), @" q1:abc"), new XmlQualifiedName("abc", "def")); - Assert.StrictEqual(SerializeAndDeserialize(XmlQualifiedName.Empty, -@""), XmlQualifiedName.Empty); + Assert.StrictEqual(XmlQualifiedName.Empty, SerializeAndDeserialize(XmlQualifiedName.Empty, +@"")); } [Fact] diff --git a/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs b/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs index 21ee42cf39176..6934766e36392 100644 --- a/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs +++ b/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs @@ -249,7 +249,7 @@ public void GetRuntimeField() }); - Assert.Throws(null, () => + AssertExtensions.Throws(null, () => { typeof(RuntimeReflectionExtensionsTests).GetRuntimeField(null); }); diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs index bba7976b646df..f02b3e292b413 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs @@ -127,7 +127,7 @@ public unsafe void InvalidFindMscorlibAssemblyRefNoProjection() //find index for mscorlib int mscorlibIndex = IndexOf(peImage, Encoding.ASCII.GetBytes("mscorlib"), headers.MetadataStartOffset); - Assert.NotEqual(mscorlibIndex, -1); + Assert.NotEqual(-1, mscorlibIndex); //mutate mscorlib peImage[mscorlibIndex + headers.MetadataStartOffset] = 0xFF; @@ -146,10 +146,10 @@ public unsafe void InvalidStreamHeaderLengths() // mutate CLR to reach MetadataKind.WindowsMetadata // find CLR int clrIndex = IndexOf(peImage, Encoding.ASCII.GetBytes("CLR"), headers.MetadataStartOffset); - Assert.NotEqual(clrIndex, -1); + Assert.NotEqual(-1, clrIndex); //find 5, This is the streamcount and is the last thing that should be read befor the test. int fiveIndex = IndexOf(peImage, new byte[] {5}, headers.MetadataStartOffset + clrIndex); - Assert.NotEqual(fiveIndex, -1); + Assert.NotEqual(-1, fiveIndex); peImage[clrIndex + headers.MetadataStartOffset] = 0xFF; @@ -173,7 +173,7 @@ public unsafe void InvalidSpaceForStreams() //find 5, This is the streamcount we'll change to one to leave out loops. int fiveIndex = IndexOf(peImage, new byte[] { 5 }, headers.MetadataStartOffset); - Assert.NotEqual(fiveIndex, -1); + Assert.NotEqual(-1, fiveIndex); Array.Copy(BitConverter.GetBytes((ushort)1), 0, peImage, fiveIndex + headers.MetadataStartOffset, BitConverter.GetBytes((ushort)1).Length); string[] streamNames= new string[] @@ -206,7 +206,7 @@ public unsafe void InvalidExternalTableMask() //0x900001447 is the external table mask from PortablePdbs.DocumentsPdb int externalTableMaskIndex = IndexOf(peImage, new byte[] { 0x47, 0x14, 0, 0, 9, 0, 0, 0 }, 0); - Assert.NotEqual(externalTableMaskIndex, -1); + Assert.NotEqual(-1, externalTableMaskIndex); Array.Copy(new byte[] { 0x48, 0x14, 0, 0, 9, 0, 0, 0 }, 0, peImage, externalTableMaskIndex, 8); Assert.Throws(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject(), peImage.Length)); @@ -219,13 +219,13 @@ public unsafe void IsMinimalDelta() GCHandle pinned = GetPinnedPEImage(peImage); //Find COR20Constants.StringStreamName to be changed to COR20Constants.MinimalDeltaMetadataTableStreamName int stringIndex = IndexOf(peImage, Encoding.ASCII.GetBytes(COR20Constants.StringStreamName), 0); - Assert.NotEqual(stringIndex, -1); + Assert.NotEqual(-1, stringIndex); //find remainingBytes to be increased because we are changing to uncompressed int remainingBytesIndex = IndexOf(peImage, BitConverter.GetBytes(180), 0); - Assert.NotEqual(remainingBytesIndex, -1); + Assert.NotEqual(-1, remainingBytesIndex); //find compressed to change to uncompressed int compressedIndex = IndexOf(peImage, Encoding.ASCII.GetBytes(COR20Constants.CompressedMetadataTableStreamName), 0); - Assert.NotEqual(compressedIndex, -1); + Assert.NotEqual(-1, compressedIndex); Array.Copy(Encoding.ASCII.GetBytes(COR20Constants.MinimalDeltaMetadataTableStreamName), 0, peImage, stringIndex, Encoding.ASCII.GetBytes(COR20Constants.MinimalDeltaMetadataTableStreamName).Length); peImage[stringIndex + COR20Constants.MinimalDeltaMetadataTableStreamName.Length] = (byte)0; @@ -248,10 +248,10 @@ public unsafe void InvalidMetaDataTableHeaders() //0x0570 is the remaining bytes from NetModule.AppCS int remainingBytesIndex = IndexOf(peImage, new byte[] { 0x70, 0x05, 0, 0 }, headers.MetadataStartOffset); - Assert.NotEqual(remainingBytesIndex, -1); + Assert.NotEqual(-1, remainingBytesIndex); //0xcc90da21757 is the presentTables from NetModule.AppCS, must be after remainingBytesIndex int presentTablesIndex = IndexOf(peImage, new byte[] { 0x57, 0x17, 0xa2, 0x0d, 0xc9, 0x0c, 0, 0 }, headers.MetadataStartOffset + remainingBytesIndex); - Assert.NotEqual(presentTablesIndex, -1); + Assert.NotEqual(-1, presentTablesIndex); //Set this.ModuleTable.NumberOfRows to 0 Array.Copy(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, peImage, presentTablesIndex + remainingBytesIndex + headers.MetadataStartOffset + 16, 8); diff --git a/src/libraries/System.Reflection.Metadata/tests/Utilities/CompressedIntegerTests.cs b/src/libraries/System.Reflection.Metadata/tests/Utilities/CompressedIntegerTests.cs index f6d7b5bb9044e..fbd523ca9b124 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Utilities/CompressedIntegerTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Utilities/CompressedIntegerTests.cs @@ -323,7 +323,7 @@ private unsafe int ReadCompressedInteger(byte[] bytes, TryReadFunc tryRead, Read { Assert.Equal(0, reader.Offset); Assert.Throws(() => reader.ReadCompressedInteger()); - Assert.Equal(value, BlobReader.InvalidCompressedInteger); + Assert.Equal(BlobReader.InvalidCompressedInteger, value); Assert.Equal(0, reader.Offset); } diff --git a/src/libraries/System.Reflection/tests/ParameterInfoTests.cs b/src/libraries/System.Reflection/tests/ParameterInfoTests.cs index b5acc81f999c0..f6285546a8713 100644 --- a/src/libraries/System.Reflection/tests/ParameterInfoTests.cs +++ b/src/libraries/System.Reflection/tests/ParameterInfoTests.cs @@ -104,7 +104,7 @@ public void RawDefaultValue_Enum() ParameterInfo p = GetParameterInfo(typeof(ParameterInfoMetadata), "Foo1", 0); object raw = p.RawDefaultValue; Assert.Equal(typeof(int), raw.GetType()); - Assert.Equal((int)raw, (int)BindingFlags.DeclaredOnly); + Assert.Equal((int)BindingFlags.DeclaredOnly, (int)raw); } [Fact] @@ -114,7 +114,7 @@ public void RawDefaultValueFromAttribute() ParameterInfo p = GetParameterInfo(typeof(ParameterInfoMetadata), "Foo2", 0); object raw = p.RawDefaultValue; Assert.Equal(typeof(int), raw.GetType()); - Assert.Equal((int)raw, (int)BindingFlags.IgnoreCase); + Assert.Equal((int)BindingFlags.IgnoreCase, (int)raw); } [Fact] @@ -123,7 +123,7 @@ public void RawDefaultValue_MetadataTrumpsAttribute() ParameterInfo p = GetParameterInfo(typeof(ParameterInfoMetadata), "Foo3", 0); object raw = p.RawDefaultValue; Assert.Equal(typeof(int), raw.GetType()); - Assert.Equal((int)raw, (int)BindingFlags.FlattenHierarchy); + Assert.Equal((int)BindingFlags.FlattenHierarchy, (int)raw); } [Theory] diff --git a/src/libraries/System.Resources.Extensions/tests/BinaryResourceWriterUnitTest.cs b/src/libraries/System.Resources.Extensions/tests/BinaryResourceWriterUnitTest.cs index 378a416210d62..47e6299b373e2 100644 --- a/src/libraries/System.Resources.Extensions/tests/BinaryResourceWriterUnitTest.cs +++ b/src/libraries/System.Resources.Extensions/tests/BinaryResourceWriterUnitTest.cs @@ -69,36 +69,36 @@ public static void ExceptionforDuplicateKey() { writer.AddResource("duplicate", "value"); - Assert.Throws(null, () => writer.AddResource("duplicate", "value")); - Assert.Throws(null, () => writer.AddResource("duplicate", new object())); - Assert.Throws(null, () => writer.AddResource("duplicate", new byte[0])); + AssertExtensions.Throws(null, () => writer.AddResource("duplicate", "value")); + AssertExtensions.Throws(null, () => writer.AddResource("duplicate", new object())); + AssertExtensions.Throws(null, () => writer.AddResource("duplicate", new byte[0])); using (var stream = new MemoryStream()) { - Assert.Throws(null, () => writer.AddResource("duplicate", stream)); - Assert.Throws(null, () => writer.AddResource("duplicate", stream, true)); - Assert.Throws(null, () => writer.AddActivatorResource("duplicate", stream, "System.DayOfWeek", false)); + AssertExtensions.Throws(null, () => writer.AddResource("duplicate", stream)); + AssertExtensions.Throws(null, () => writer.AddResource("duplicate", stream, true)); + AssertExtensions.Throws(null, () => writer.AddActivatorResource("duplicate", stream, "System.DayOfWeek", false)); } - Assert.Throws(null, () => writer.AddBinaryFormattedResource("duplicate", new byte[1], "System.DayOfWeek")); - Assert.Throws(null, () => writer.AddTypeConverterResource("duplicate", new byte[1], "System.DayOfWeek")); - Assert.Throws(null, () => writer.AddResource("duplicate", "Monday", "System.DayOfWeek")); + AssertExtensions.Throws(null, () => writer.AddBinaryFormattedResource("duplicate", new byte[1], "System.DayOfWeek")); + AssertExtensions.Throws(null, () => writer.AddTypeConverterResource("duplicate", new byte[1], "System.DayOfWeek")); + AssertExtensions.Throws(null, () => writer.AddResource("duplicate", "Monday", "System.DayOfWeek")); - Assert.Throws(null, () => writer.AddResource("Duplicate", "value")); - Assert.Throws(null, () => writer.AddResource("dUplicate", new object())); - Assert.Throws(null, () => writer.AddResource("duPlicate", new byte[0])); + AssertExtensions.Throws(null, () => writer.AddResource("Duplicate", "value")); + AssertExtensions.Throws(null, () => writer.AddResource("dUplicate", new object())); + AssertExtensions.Throws(null, () => writer.AddResource("duPlicate", new byte[0])); using (var stream = new MemoryStream()) { - Assert.Throws(null, () => writer.AddResource("dupLicate", stream)); - Assert.Throws(null, () => writer.AddResource("duplIcate", stream, true)); - Assert.Throws(null, () => writer.AddActivatorResource("dupliCate", stream, "System.DayOfWeek", false)); + AssertExtensions.Throws(null, () => writer.AddResource("dupLicate", stream)); + AssertExtensions.Throws(null, () => writer.AddResource("duplIcate", stream, true)); + AssertExtensions.Throws(null, () => writer.AddActivatorResource("dupliCate", stream, "System.DayOfWeek", false)); } - Assert.Throws(null, () => writer.AddBinaryFormattedResource("duplicAte", new byte[1], "System.DayOfWeek")); - Assert.Throws(null, () => writer.AddTypeConverterResource("duplicaTe", new byte[1], "System.DayOfWeek")); - Assert.Throws(null, () => writer.AddResource("duplicatE", "Monday", "System.DayOfWeek")); + AssertExtensions.Throws(null, () => writer.AddBinaryFormattedResource("duplicAte", new byte[1], "System.DayOfWeek")); + AssertExtensions.Throws(null, () => writer.AddTypeConverterResource("duplicaTe", new byte[1], "System.DayOfWeek")); + AssertExtensions.Throws(null, () => writer.AddResource("duplicatE", "Monday", "System.DayOfWeek")); } } diff --git a/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests.cs index 2ef46ada0d0b6..45f3b048c92a3 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests.cs @@ -157,7 +157,7 @@ public void GetRandomFileName() for (int i = 0; i < 100; i++) { string s = Path.GetRandomFileName(); - Assert.Equal(s.Length, 8 + 1 + 3); + Assert.Equal(8 + 1 + 3, s.Length); Assert.Equal('.', s[8]); Assert.Equal(-1, s.IndexOfAny(invalidChars)); Assert.True(fileNames.Add(s)); diff --git a/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests_Unix.cs b/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests_Unix.cs index 3f9cb8775d704..2012c1f09cd91 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests_Unix.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests_Unix.cs @@ -158,7 +158,7 @@ public static void GePathRoot_Unix(string path) [Fact] public void GetFullPath_ThrowsOnEmbeddedNulls() { - Assert.Throws(null, () => Path.GetFullPath("/gi\0t", "/foo/bar")); + AssertExtensions.Throws(null, () => Path.GetFullPath("/gi\0t", "/foo/bar")); } public static TheoryData TestData_TrimEndingDirectorySeparator => new TheoryData diff --git a/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.cs b/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.cs index 949e44c6a1723..9f53541319f9a 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.cs @@ -616,7 +616,7 @@ public void GetFullPath_CommonUnRooted_Windows(string path, string basePath, str [Fact] public void GetFullPath_ThrowsOnEmbeddedNulls() { - Assert.Throws(null, () => Path.GetFullPath("/gi\0t", @"C:\foo\bar")); + AssertExtensions.Throws(null, () => Path.GetFullPath("/gi\0t", @"C:\foo\bar")); } public static TheoryData TestData_TrimEndingDirectorySeparator => new TheoryData diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/SafeBufferTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/SafeBufferTests.cs index d60da1fc34ba8..303c2250b538f 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/SafeBufferTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/SafeBufferTests.cs @@ -76,8 +76,8 @@ public void ReadWrite_NotEnoughSpaceInBuffer_ThrowsArgumentException(ulong byteO var buffer = new SubBuffer(true); buffer.Initialize(4); - Assert.Throws(null, () => buffer.Read(byteOffset)); - Assert.Throws(null, () => buffer.Write(byteOffset, 2)); + AssertExtensions.Throws(null, () => buffer.Read(byteOffset)); + AssertExtensions.Throws(null, () => buffer.Write(byteOffset, 2)); } [Fact] diff --git a/src/libraries/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs index 8f7ecc5dc71bd..420f24fa625f7 100644 --- a/src/libraries/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs @@ -151,7 +151,7 @@ public void LoadInDefaultContext() Assert.Equal(assemblyExpected, assemblyExpectedFromLoad); // And make sure the simple name matches - Assert.Equal(assemblyExpected.GetName().Name, TestAssemblyName); + Assert.Equal(TestAssemblyName, assemblyExpected.GetName().Name); // Unwire the Resolving event. AssemblyLoadContext.Default.Resolving -= ResolveAssemblyAgain; diff --git a/src/libraries/System.Runtime.Serialization.Json/tests/DataContractJsonSerializer.cs b/src/libraries/System.Runtime.Serialization.Json/tests/DataContractJsonSerializer.cs index 3cbae8430c207..018565ccacf3b 100644 --- a/src/libraries/System.Runtime.Serialization.Json/tests/DataContractJsonSerializer.cs +++ b/src/libraries/System.Runtime.Serialization.Json/tests/DataContractJsonSerializer.cs @@ -50,47 +50,47 @@ public static void DCJS_ByteArrayAsRoot() public static void DCJS_CharAsRoot() { // Special characters - Assert.StrictEqual(SerializeAndDeserialize((char)0x2f, @"""\/"""), (char)0x2f); // Expected output string is: \/ - Assert.StrictEqual(SerializeAndDeserialize((char)0x5c, @"""\\"""), (char)0x5c); // \\ - Assert.StrictEqual(SerializeAndDeserialize((char)0x27, @"""'"""), (char)0x27); // ' - Assert.StrictEqual(SerializeAndDeserialize((char)0x22, @"""\"""""), (char)0x22); // \" + Assert.StrictEqual((char)0x2f, SerializeAndDeserialize((char)0x2f, @"""\/""")); // Expected output string is: \/ + Assert.StrictEqual((char)0x5c, SerializeAndDeserialize((char)0x5c, @"""\\""")); // \\ + Assert.StrictEqual((char)0x27, SerializeAndDeserialize((char)0x27, @"""'""")); // ' + Assert.StrictEqual((char)0x22, SerializeAndDeserialize((char)0x22, @"""\""""")); // \" // There are 5 ranges of characters that have output in the form of "\u". // The following tests the start and end character and at least one character in each range // and also in between the ranges. // #1. 0x0000 - 0x001F - Assert.StrictEqual(SerializeAndDeserialize(char.MinValue, @"""\u0000"""), char.MinValue); - Assert.StrictEqual(SerializeAndDeserialize((char)0x10, @"""\u0010"""), (char)0x10); - Assert.StrictEqual(SerializeAndDeserialize((char)0x1f, @"""\u001f"""), (char)0x1f); + Assert.StrictEqual(char.MinValue, SerializeAndDeserialize(char.MinValue, @"""\u0000""")); + Assert.StrictEqual((char)0x10, SerializeAndDeserialize((char)0x10, @"""\u0010""")); + Assert.StrictEqual((char)0x1f, SerializeAndDeserialize((char)0x1f, @"""\u001f""")); // Between #1 and #2 Assert.StrictEqual('a', SerializeAndDeserialize('a', @"""a""")); // 0x0061 // #2. 0x0085 - Assert.StrictEqual(SerializeAndDeserialize((char)0x85, @"""\u0085"""), (char)0x85); + Assert.StrictEqual((char)0x85, SerializeAndDeserialize((char)0x85, @"""\u0085""")); // Between #2 and #3 Assert.StrictEqual('\u00F1', SerializeAndDeserialize('\u00F1', "\"\u00F1\"")); // 0x00F1 // #3. 0x2028 - 0x2029 - Assert.StrictEqual(SerializeAndDeserialize((char)0x2028, @"""\u2028"""), (char)0x2028); - Assert.StrictEqual(SerializeAndDeserialize((char)0x2029, @"""\u2029"""), (char)0x2029); + Assert.StrictEqual((char)0x2028, SerializeAndDeserialize((char)0x2028, @"""\u2028""")); + Assert.StrictEqual((char)0x2029, SerializeAndDeserialize((char)0x2029, @"""\u2029""")); // Between #3 and #4 Assert.StrictEqual('?', SerializeAndDeserialize('?', @"""?""")); // 0x6F22 // #4. 0xD800 - 0xDFFF - Assert.StrictEqual(SerializeAndDeserialize((char)0xd800, @"""\ud800"""), (char)0xd800); - Assert.StrictEqual(SerializeAndDeserialize((char)0xdabc, @"""\udabc"""), (char)0xdabc); - Assert.StrictEqual(SerializeAndDeserialize((char)0xdfff, @"""\udfff"""), (char)0xdfff); + Assert.StrictEqual((char)0xd800, SerializeAndDeserialize((char)0xd800, @"""\ud800""")); + Assert.StrictEqual((char)0xdabc, SerializeAndDeserialize((char)0xdabc, @"""\udabc""")); + Assert.StrictEqual((char)0xdfff, SerializeAndDeserialize((char)0xdfff, @"""\udfff""")); // Between #4 and #5 - Assert.StrictEqual(SerializeAndDeserialize((char)0xeabc, "\"\uEABC\""), (char)0xeabc); + Assert.StrictEqual((char)0xeabc, SerializeAndDeserialize((char)0xeabc, "\"\uEABC\"")); // #5. 0xFFFE - 0xFFFF - Assert.StrictEqual(SerializeAndDeserialize((char)0xfffe, @"""\ufffe"""), (char)0xfffe); - Assert.StrictEqual(SerializeAndDeserialize(char.MaxValue, @"""\uffff"""), char.MaxValue); + Assert.StrictEqual((char)0xfffe, SerializeAndDeserialize((char)0xfffe, @"""\ufffe""")); + Assert.StrictEqual(char.MaxValue, SerializeAndDeserialize(char.MaxValue, @"""\uffff""")); } [Fact] @@ -108,8 +108,8 @@ public static void DCJS_NewLineChars() public static void DCJS_ByteAsRoot() { Assert.StrictEqual(10, SerializeAndDeserialize(10, "10")); - Assert.StrictEqual(SerializeAndDeserialize(byte.MinValue, "0"), byte.MinValue); - Assert.StrictEqual(SerializeAndDeserialize(byte.MaxValue, "255"), byte.MaxValue); + Assert.StrictEqual(byte.MinValue, SerializeAndDeserialize(byte.MinValue, "0")); + Assert.StrictEqual(byte.MaxValue, SerializeAndDeserialize(byte.MaxValue, "255")); } [Fact] @@ -139,26 +139,26 @@ public static void DCJS_DecimalAsRoot() [Fact] public static void DCJS_DoubleAsRoot() { - Assert.StrictEqual(SerializeAndDeserialize(-1.2, "-1.2"), -1.2); + Assert.StrictEqual(-1.2, SerializeAndDeserialize(-1.2, "-1.2")); Assert.StrictEqual(0, SerializeAndDeserialize(0, "0")); Assert.StrictEqual(2.3, SerializeAndDeserialize(2.3, "2.3")); - Assert.StrictEqual(SerializeAndDeserialize(double.MinValue, "-1.7976931348623157E+308"), double.MinValue); - Assert.StrictEqual(SerializeAndDeserialize(double.MaxValue, "1.7976931348623157E+308"), double.MaxValue); + Assert.StrictEqual(double.MinValue, SerializeAndDeserialize(double.MinValue, "-1.7976931348623157E+308")); + Assert.StrictEqual(double.MaxValue, SerializeAndDeserialize(double.MaxValue, "1.7976931348623157E+308")); } [Fact] public static void DCJS_FloatAsRoot() { - Assert.StrictEqual(SerializeAndDeserialize((float)-1.2, "-1.2"), (float)-1.2); - Assert.StrictEqual(SerializeAndDeserialize((float)0, "0"), (float)0); - Assert.StrictEqual(SerializeAndDeserialize((float)2.3, "2.3"), (float)2.3); + Assert.StrictEqual((float)-1.2, SerializeAndDeserialize((float)-1.2, "-1.2")); + Assert.StrictEqual((float)0, SerializeAndDeserialize((float)0, "0")); + Assert.StrictEqual((float)2.3, SerializeAndDeserialize((float)2.3, "2.3")); } [Fact] public static void DCJS_FloatAsRoot_NotNetFramework() { - Assert.StrictEqual(SerializeAndDeserialize(float.MinValue, "-3.4028235E+38"), float.MinValue); - Assert.StrictEqual(SerializeAndDeserialize(float.MaxValue, "3.4028235E+38"), float.MaxValue); + Assert.StrictEqual(float.MinValue, SerializeAndDeserialize(float.MinValue, "-3.4028235E+38")); + Assert.StrictEqual(float.MaxValue, SerializeAndDeserialize(float.MaxValue, "3.4028235E+38")); } [Fact] diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs index d841d36fb244f..6ab67b426a35b 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs @@ -85,8 +85,8 @@ public static void DCS_ByteArrayAsRoot() [Fact] public static void DCS_CharAsRoot() { - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize(char.MinValue, @"0"), char.MinValue); - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize(char.MaxValue, @"65535"), char.MaxValue); + Assert.StrictEqual(char.MinValue, DataContractSerializerHelper.SerializeAndDeserialize(char.MinValue, @"0")); + Assert.StrictEqual(char.MaxValue, DataContractSerializerHelper.SerializeAndDeserialize(char.MaxValue, @"65535")); Assert.StrictEqual('a', DataContractSerializerHelper.SerializeAndDeserialize('a', @"97")); Assert.StrictEqual('\u00F1', DataContractSerializerHelper.SerializeAndDeserialize('\u00F1', @"241")); Assert.StrictEqual('\u6F22', DataContractSerializerHelper.SerializeAndDeserialize('\u6F22', @"28450")); @@ -96,8 +96,8 @@ public static void DCS_CharAsRoot() public static void DCS_ByteAsRoot() { Assert.StrictEqual(10, DataContractSerializerHelper.SerializeAndDeserialize(10, @"10")); - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize(byte.MinValue, @"0"), byte.MinValue); - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize(byte.MaxValue, @"255"), byte.MaxValue); + Assert.StrictEqual(byte.MinValue, DataContractSerializerHelper.SerializeAndDeserialize(byte.MinValue, @"0")); + Assert.StrictEqual(byte.MaxValue, DataContractSerializerHelper.SerializeAndDeserialize(byte.MaxValue, @"255")); } [Fact] @@ -124,26 +124,26 @@ public static void DCS_DecimalAsRoot() [Fact] public static void DCS_DoubleAsRoot() { - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize(-1.2, @"-1.2"), -1.2); + Assert.StrictEqual(-1.2, DataContractSerializerHelper.SerializeAndDeserialize(-1.2, @"-1.2")); Assert.StrictEqual(0, DataContractSerializerHelper.SerializeAndDeserialize(0, @"0")); Assert.StrictEqual(2.3, DataContractSerializerHelper.SerializeAndDeserialize(2.3, @"2.3")); - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize(double.MinValue, @"-1.7976931348623157E+308"), double.MinValue); - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize(double.MaxValue, @"1.7976931348623157E+308"), double.MaxValue); + Assert.StrictEqual(double.MinValue, DataContractSerializerHelper.SerializeAndDeserialize(double.MinValue, @"-1.7976931348623157E+308")); + Assert.StrictEqual(double.MaxValue, DataContractSerializerHelper.SerializeAndDeserialize(double.MaxValue, @"1.7976931348623157E+308")); } [Fact] public static void DCS_FloatAsRoot() { - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize((float)-1.2, @"-1.2"), (float)-1.2); - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize((float)0, @"0"), (float)0); - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize((float)2.3, @"2.3"), (float)2.3); + Assert.StrictEqual((float)-1.2, DataContractSerializerHelper.SerializeAndDeserialize((float)-1.2, @"-1.2")); + Assert.StrictEqual((float)0, DataContractSerializerHelper.SerializeAndDeserialize((float)0, @"0")); + Assert.StrictEqual((float)2.3, DataContractSerializerHelper.SerializeAndDeserialize((float)2.3, @"2.3")); } [Fact] public static void DCS_FloatAsRoot_NotNetFramework() { - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize(float.MinValue, @"-3.4028235E+38"), float.MinValue); - Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize(float.MaxValue, @"3.4028235E+38"), float.MaxValue); + Assert.StrictEqual(float.MinValue, DataContractSerializerHelper.SerializeAndDeserialize(float.MinValue, @"-3.4028235E+38")); + Assert.StrictEqual(float.MaxValue, DataContractSerializerHelper.SerializeAndDeserialize(float.MaxValue, @"3.4028235E+38")); } [Fact] diff --git a/src/libraries/System.Runtime/tests/System/IO/EndOfStreamExceptionTests.cs b/src/libraries/System.Runtime/tests/System/IO/EndOfStreamExceptionTests.cs index c80eab91b3226..fe734e4c95ae0 100644 --- a/src/libraries/System.Runtime/tests/System/IO/EndOfStreamExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/EndOfStreamExceptionTests.cs @@ -35,8 +35,8 @@ public static void EndOfStreamException_Ctor_String_Exception() EndOfStreamException i = new EndOfStreamException(exceptionMessage, ex); Assert.Equal(exceptionMessage, i.Message); - Assert.Equal(i.InnerException.Message, innerExceptionMessage); - Assert.Equal(i.InnerException.HResult, ex.HResult); + Assert.Equal(innerExceptionMessage, i.InnerException.Message); + Assert.Equal(ex.HResult, i.InnerException.HResult); Assert.Equal(COR_E_ENDOFSTREAM, unchecked((uint)i.HResult)); } } diff --git a/src/libraries/System.Runtime/tests/System/NullReferenceExceptionTests.cs b/src/libraries/System.Runtime/tests/System/NullReferenceExceptionTests.cs index 1e852df6281a3..94f5396778d4e 100644 --- a/src/libraries/System.Runtime/tests/System/NullReferenceExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/NullReferenceExceptionTests.cs @@ -36,8 +36,8 @@ public static void NullReferenceException_Ctor_String_Exception() NullReferenceException i = new NullReferenceException(exceptionMessage, ex); Assert.Equal(exceptionMessage, i.Message); - Assert.Equal(i.InnerException.Message, innerExceptionMessage); - Assert.Equal(i.InnerException.HResult, ex.HResult); + Assert.Equal(innerExceptionMessage, i.InnerException.Message); + Assert.Equal(ex.HResult, i.InnerException.HResult); Assert.Equal(E_POINTER, unchecked((uint)i.HResult)); } } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.netcoreapp.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.netcoreapp.cs index cda2262f78205..32adea8510ef4 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.netcoreapp.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.netcoreapp.cs @@ -547,7 +547,7 @@ private static void VerifyAttributesAreEqual(AsnEncodedData actual, AsnEncodedDa Assert.Equal(expectedToken.GetSerialNumber().ByteArrayToHex(), actualToken.GetSerialNumber().ByteArrayToHex()); Assert.Equal(expectedToken.Timestamp, actualToken.Timestamp); - Assert.Equal(expectedToken.HashAlgorithmId.Value, Oids.Sha256); + Assert.Equal(Oids.Sha256, expectedToken.HashAlgorithmId.Value); Assert.Equal(expectedToken.HashAlgorithmId.Value, actualToken.HashAlgorithmId.Value); } diff --git a/src/libraries/System.Security.Cryptography.Xml/tests/DSAKeyValueTest.cs b/src/libraries/System.Security.Cryptography.Xml/tests/DSAKeyValueTest.cs index 14863aff90810..464895d338fef 100644 --- a/src/libraries/System.Security.Cryptography.Xml/tests/DSAKeyValueTest.cs +++ b/src/libraries/System.Security.Cryptography.Xml/tests/DSAKeyValueTest.cs @@ -108,16 +108,16 @@ public void LoadXml() dsaKeyValue.LoadXml(xmlDoc.DocumentElement); var parameters = dsaKeyValue.Key.ExportParameters(false); - Assert.Equal(Convert.ToBase64String(parameters.P), pValue); - Assert.Equal(Convert.ToBase64String(parameters.Q), qValue); - Assert.Equal(Convert.ToBase64String(parameters.G), gValue); - Assert.Equal(Convert.ToBase64String(parameters.Y), yValue); + Assert.Equal(pValue, Convert.ToBase64String(parameters.P)); + Assert.Equal(qValue, Convert.ToBase64String(parameters.Q)); + Assert.Equal(gValue, Convert.ToBase64String(parameters.G)); + Assert.Equal(yValue, Convert.ToBase64String(parameters.Y)); // Not all providers support round-tripping the seed value. // Seed and PGenCounter are round-tripped together. if (parameters.Seed != null) { - Assert.Equal(Convert.ToBase64String(parameters.Seed), seedValue); + Assert.Equal(seedValue, Convert.ToBase64String(parameters.Seed)); Assert.Equal(BitConverter.GetBytes(parameters.Counter)[0], Convert.FromBase64String(pgenCounterValue)[0]); } } diff --git a/src/libraries/System.Security.Cryptography.Xml/tests/XmlLicenseEncryptedRef.cs b/src/libraries/System.Security.Cryptography.Xml/tests/XmlLicenseEncryptedRef.cs index a10050c652f7d..5da12f940d60f 100644 --- a/src/libraries/System.Security.Cryptography.Xml/tests/XmlLicenseEncryptedRef.cs +++ b/src/libraries/System.Security.Cryptography.Xml/tests/XmlLicenseEncryptedRef.cs @@ -49,7 +49,7 @@ public Stream Decrypt(EncryptionMethod encryptionMethod, KeyInfo keyInfo, Stream KeyInfoEncryptedKey encryptedKeyInfo = clause as KeyInfoEncryptedKey; EncryptedKey encryptedKey = encryptedKeyInfo.EncryptedKey; - Assert.Equal(encryptedKey.EncryptionMethod.KeyAlgorithm, EncryptedXml.XmlEncRSAOAEPUrl); + Assert.Equal(EncryptedXml.XmlEncRSAOAEPUrl, encryptedKey.EncryptionMethod.KeyAlgorithm); Assert.Equal(1, encryptedKey.KeyInfo.Count); Assert.NotEqual(0, _asymmetricKeys.Count); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/BitStackTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/BitStackTests.cs index 48d36677359df..08b47fc04cdce 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/BitStackTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/BitStackTests.cs @@ -128,7 +128,7 @@ public static void BitStackPushPopLarge(int bitLength) Assert.Equal(expectedDepth, bitStack.CurrentDepth); } - Assert.Equal(expectedDepth, IterationCapacity * 2); + Assert.Equal(IterationCapacity * 2, expectedDepth); // Loop backwards when popping. for (int i = bitLength - 1; i >= bitLength - IterationCapacity; i--) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonNodeOperatorTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonNodeOperatorTests.cs index 0a3e130a317dc..27a565561c5e6 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonNodeOperatorTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonNodeOperatorTests.cs @@ -181,6 +181,7 @@ public static void ImplicitOperators_FromNullValues() [Fact] public static void ImplicitOperators_FromNullableValues() { + #pragma warning disable xUnit2002 Assert.NotNull((JsonValue?)(byte?)42); Assert.NotNull((JsonValue?)(short?)42); Assert.NotNull((JsonValue?)(int?)42); @@ -194,6 +195,7 @@ public static void ImplicitOperators_FromNullableValues() Assert.NotNull((JsonValue?)(float?)42); Assert.NotNull((JsonValue?)(double?)42); Assert.NotNull((JsonValue?)(decimal?)42); + #pragma warning restore xUnit2002 Assert.NotNull((JsonValue?)(DateTime?)new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc)); Assert.NotNull((JsonValue?)(DateTimeOffset?)new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0))); Assert.NotNull((JsonValue?)(Guid?)new Guid("1B33498A-7B7D-4DDA-9C13-F6AA4AB449A6")); 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 2d59951cad66e..a8b9e355e314e 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/tests/Dataflow/DataflowBlockExtensionTests.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/tests/Dataflow/DataflowBlockExtensionTests.cs @@ -1762,7 +1762,7 @@ public async Task TestEncapsulate_EncapsulateBoundedTarget() source.Complete(); await encapsulated.Completion; - Assert.Equal(messagesReceived, messagesSent); + Assert.Equal(messagesSent, messagesReceived); } [Fact] From 5d1cb4f30477d1229ed92f4d35ccf388ea6d7fa8 Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Thu, 20 Jan 2022 23:46:24 +0300 Subject: [PATCH 097/308] Preserve OBJ/BLK on the RHS of ASG (#63268) One of my upcoming changes will need this information to accurately detect type mismatch in "fgValueNumberBlockAssignment". --- src/coreclr/jit/lower.cpp | 10 +++++++++- src/coreclr/jit/morph.cpp | 11 ++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 06d42a37f986f..51b7a51eb1005 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -6922,6 +6922,14 @@ void Lowering::TransformUnusedIndirection(GenTreeIndir* ind, Compiler* comp, Bas void Lowering::LowerBlockStoreCommon(GenTreeBlk* blkNode) { assert(blkNode->OperIs(GT_STORE_BLK, GT_STORE_DYN_BLK, GT_STORE_OBJ)); + + // Lose the type information stored in the source - we no longer need it. + if (blkNode->Data()->OperIs(GT_OBJ, GT_BLK)) + { + blkNode->Data()->SetOper(GT_IND); + LowerIndir(blkNode->Data()->AsIndir()); + } + if (TryTransformStoreObjAsStoreInd(blkNode)) { return; @@ -6996,7 +7004,7 @@ bool Lowering::TryTransformStoreObjAsStoreInd(GenTreeBlk* blkNode) return false; } - JITDUMP("Replacing STORE_OBJ with STOREIND for [06%u]", blkNode->gtTreeID); + JITDUMP("Replacing STORE_OBJ with STOREIND for [%06u]\n", blkNode->gtTreeID); blkNode->ChangeOper(GT_STOREIND); blkNode->ChangeType(regType); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index f1210b1741dcc..138e46358065e 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -10431,15 +10431,8 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne { if (indirTree != nullptr) { - if (indirTree->OperIsBlk() && !isBlkReqd) - { - effectiveVal->SetOper(GT_IND); - } - else - { - // If we have an indirection and a block is required, it should already be a block. - assert(indirTree->OperIsBlk() || !isBlkReqd); - } + // If we have an indirection and a block is required, it should already be a block. + assert(indirTree->OperIsBlk() || !isBlkReqd); effectiveVal->gtType = asgType; } else From 3e6eda669cbd389a83cc2b48567dd4af7faef3b8 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 20 Jan 2022 12:51:28 -0800 Subject: [PATCH 098/308] Revert "Temporarily disable coredumps during library testing on macOS (#63742)" (#64057) This reverts commit 2c28e63f9360280011a3b03c1ca6dc0edce1fae4. Fixes #63761 --- eng/testing/RunnerTemplate.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eng/testing/RunnerTemplate.sh b/eng/testing/RunnerTemplate.sh index 0fb8260a0b9bc..bfaa743ef6f41 100644 --- a/eng/testing/RunnerTemplate.sh +++ b/eng/testing/RunnerTemplate.sh @@ -132,8 +132,7 @@ if [[ "$(uname -s)" == "Darwin" ]]; then # files already in /cores/ at this point. This is being done to prevent # inadvertently flooding the CI machines with dumps. if [[ ! -d "/cores" || ! "$(ls -A /cores)" ]]; then - # FIXME: temporarily disable core dumps - ulimit -c 0 + ulimit -c unlimited fi elif [[ "$(uname -s)" == "Linux" ]]; then From 6d56d4851da1095d1d9b2746fe0f9324e7fbf657 Mon Sep 17 00:00:00 2001 From: Parker Bibus Date: Thu, 20 Jan 2022 15:07:08 -0600 Subject: [PATCH 099/308] Performance: Fix Browser Wasm job not being found for dependent jobs (#64058) * Figure out the name that browser wasm now uses. * linux to the Browser wasm depends on name. Update the browser wasm dependson name to match the new one found in the pipeline. --- eng/pipelines/coreclr/templates/perf-job.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/coreclr/templates/perf-job.yml b/eng/pipelines/coreclr/templates/perf-job.yml index dd1ff0ebd3b24..627d42fd7add1 100644 --- a/eng/pipelines/coreclr/templates/perf-job.yml +++ b/eng/pipelines/coreclr/templates/perf-job.yml @@ -57,7 +57,7 @@ jobs: - ${{ if and(eq(parameters.runtimeType, 'mono'), ne(parameters.codeGenType, 'AOT')) }}: - ${{ format('mono_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - ${{ if eq(parameters.runtimeType, 'wasm')}}: - - ${{ format('build_{0}{1}_{2}_{3}_{4}', 'Browser', '', 'wasm', parameters.buildConfig, parameters.runtimeType) }} + - ${{ format('build_{0}{1}_{2}_{3}_{4}_{5}', 'Browser', '', 'wasm', 'Linux', parameters.buildConfig, parameters.runtimeType) }} - ${{ if and(eq(parameters.codeGenType, 'AOT'), ne(parameters.runtimeType, 'wasm'))}}: - ${{ format('build_{0}{1}_{2}_{3}_{4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.codeGenType) }} - ${{ if eq(parameters.runtimeType, 'AndroidMono')}}: From 830c6dee0789abbd0abf5bf714ff35555d85af4a Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 20 Jan 2022 22:15:03 +0100 Subject: [PATCH 100/308] Fix exception propagation over HW exception frame on macOS arm64 (#63596) * Fix exception propagation over HW exception frame on macOS arm64 There is a problem unwinding over the PAL_DispatchExceptionWrapper to the actual hardware exception location. The unwinder is unable to get distinct LR and PC in that frame and sets both of them to the same value. This is caused by the fact that the PAL_DispatchExceptionWrapper is just an injected fake frame and there was no real call. Calls always return with LR and PC set to the same value. The fix unifies the hardware exception frame unwinding with Linux where we had problems unwinding over signal handler trampoline, so PAL_VirtualUnwind skips the trampoline and now also the PAL_DispatchExceptionWrapper frame by copying the context of the exception as the unwound context. * Reenable DllImportGenerator.Unit.Tests --- .../pal/src/exception/machexception.cpp | 18 ++---- src/coreclr/pal/src/exception/seh-unwind.cpp | 16 ++--- src/coreclr/pal/src/exception/signal.cpp | 7 +-- src/coreclr/pal/src/include/pal/seh.hpp | 5 ++ src/libraries/tests.proj | 5 -- .../coreclr/GitHub_62058/test62058.cs | 60 +++++++++++++++++++ .../coreclr/GitHub_62058/test62058.csproj | 9 +++ 7 files changed, 90 insertions(+), 30 deletions(-) create mode 100644 src/tests/Regressions/coreclr/GitHub_62058/test62058.cs create mode 100644 src/tests/Regressions/coreclr/GitHub_62058/test62058.csproj diff --git a/src/coreclr/pal/src/exception/machexception.cpp b/src/coreclr/pal/src/exception/machexception.cpp index e5aebdf652c6a..eca89e0a204c6 100644 --- a/src/coreclr/pal/src/exception/machexception.cpp +++ b/src/coreclr/pal/src/exception/machexception.cpp @@ -369,19 +369,13 @@ void PAL_DispatchException(PCONTEXT pContext, PEXCEPTION_RECORD pExRecord, MachE { CPalThread *pThread = InternalGetCurrentThread(); - CONTEXT *contextRecord; - EXCEPTION_RECORD *exceptionRecord; - AllocateExceptionRecords(&exceptionRecord, &contextRecord); + CONTEXT *contextRecord = pContext; + g_hardware_exception_context_locvar_offset = (int)((char*)&contextRecord - (char*)__builtin_frame_address(0)); - *contextRecord = *pContext; - *exceptionRecord = *pExRecord; - - contextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; + pContext->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; bool continueExecution; - { - // The exception object takes ownership of the exceptionRecord and contextRecord - PAL_SEHException exception(exceptionRecord, contextRecord); + PAL_SEHException exception(pExRecord, pContext, true); TRACE("PAL_DispatchException(EC %08x EA %p)\n", pExRecord->ExceptionCode, pExRecord->ExceptionAddress); @@ -389,8 +383,8 @@ void PAL_DispatchException(PCONTEXT pContext, PEXCEPTION_RECORD pExRecord, MachE if (continueExecution) { // Make a copy of the exception records so that we can free them before restoring the context - *pContext = *contextRecord; - *pExRecord = *exceptionRecord; + *pContext = *exception.ExceptionPointers.ContextRecord; + *pExRecord = *exception.ExceptionPointers.ExceptionRecord; } // The exception records are destroyed by the PAL_SEHException destructor now. diff --git a/src/coreclr/pal/src/exception/seh-unwind.cpp b/src/coreclr/pal/src/exception/seh-unwind.cpp index 750f19109fbaa..3091650ec5faa 100644 --- a/src/coreclr/pal/src/exception/seh-unwind.cpp +++ b/src/coreclr/pal/src/exception/seh-unwind.cpp @@ -496,7 +496,9 @@ void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOL #ifndef HOST_WINDOWS -extern int g_common_signal_handler_context_locvar_offset; +// Frame pointer relative offset of a local containing a pointer to the windows style context of a location +// where a hardware exception occured. +int g_hardware_exception_context_locvar_offset = 0; BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers) { @@ -506,19 +508,17 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP DWORD64 curPc = CONTEXTGetPC(context); -#ifndef __APPLE__ - // Check if the PC is the return address from the SEHProcessException in the common_signal_handler. - // If that's the case, extract its local variable containing the windows style context of the hardware + // Check if the PC is the return address from the SEHProcessException. + // If that's the case, extract its local variable containing a pointer to the windows style context of the hardware // exception and return that. This skips the hardware signal handler trampoline that the libunwind - // cannot cross on some systems. + // cannot cross on some systems. On macOS, it skips a similar trampoline we create in HijackFaultingThread. if ((void*)curPc == g_SEHProcessExceptionReturnAddress) { - CONTEXT* signalContext = (CONTEXT*)(CONTEXTGetFP(context) + g_common_signal_handler_context_locvar_offset); - memcpy_s(context, sizeof(CONTEXT), signalContext, sizeof(CONTEXT)); + CONTEXT* exceptionContext = *(CONTEXT**)(CONTEXTGetFP(context) + g_hardware_exception_context_locvar_offset); + memcpy_s(context, sizeof(CONTEXT), exceptionContext, sizeof(CONTEXT)); return TRUE; } -#endif if ((context->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) != 0) { diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp index 58fc78ef357e8..63b7ef115f26d 100644 --- a/src/coreclr/pal/src/exception/signal.cpp +++ b/src/coreclr/pal/src/exception/signal.cpp @@ -116,10 +116,6 @@ struct sigaction g_previous_sigabrt; #if !HAVE_MACH_EXCEPTIONS -// Offset of the local variable containing pointer to windows style context in the common_signal_handler function. -// This offset is relative to the frame pointer. -int g_common_signal_handler_context_locvar_offset = 0; - // TOP of special stack for handling stack overflow volatile void* g_stackOverflowHandlerStack = NULL; @@ -942,11 +938,12 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext #if !HAVE_MACH_EXCEPTIONS sigset_t signal_set; CONTEXT signalContextRecord; + CONTEXT* signalContextRecordPtr = &signalContextRecord; EXCEPTION_RECORD exceptionRecord; native_context_t *ucontext; ucontext = (native_context_t *)sigcontext; - g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0)); + g_hardware_exception_context_locvar_offset = (int)((char*)&signalContextRecordPtr - (char*)__builtin_frame_address(0)); if (code == (SIGSEGV | StackOverflowFlag)) { diff --git a/src/coreclr/pal/src/include/pal/seh.hpp b/src/coreclr/pal/src/include/pal/seh.hpp index 6ad89df0fdd65..327fe0d7fb03e 100644 --- a/src/coreclr/pal/src/include/pal/seh.hpp +++ b/src/coreclr/pal/src/include/pal/seh.hpp @@ -145,5 +145,10 @@ CorUnix::PAL_ERROR SEHDisable(CorUnix::CPalThread *pthrCurrent); } +// Offset of the local variable containing pointer to windows style context in the common_signal_handler / PAL_DispatchException function. +// This offset is relative to the frame pointer. +extern int g_hardware_exception_context_locvar_offset; + + #endif /* _PAL_SEH_HPP_ */ diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index d9391e0ec2c9d..8d6a97b157d41 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -334,11 +334,6 @@ Roslyn4.0.Tests.csproj" /> - - - - - diff --git a/src/tests/Regressions/coreclr/GitHub_62058/test62058.cs b/src/tests/Regressions/coreclr/GitHub_62058/test62058.cs new file mode 100644 index 0000000000000..bffbf999e7396 --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_62058/test62058.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +public class Program +{ + private interface IFoo + { + bool IsValid { get; } + } + + private class Foo : IFoo + { + public bool IsValid { get; set; } + } + + public static int Main(string[] args) + { + bool warmup = new Foo().IsValid; + CatchIgnore(() => + CatchRethrow(() => + { + IFoo[] foos = {new Foo(), null}; + foreach (var foo in foos) + { + bool check = foo.IsValid; + } + })); + + return 100; + } + + public static void CatchRethrow(Action action) + { + try + { + action.Invoke(); + } + catch (Exception e) + { + Console.Out.WriteLine("catch"); + Console.Out.Flush(); + throw new Exception("catch", e); + } + } + + public static void CatchIgnore(Action action) + { + try + { + action.Invoke(); + } + catch (Exception) + { + Console.Out.WriteLine("ignore"); + Console.Out.Flush(); + } + } +} diff --git a/src/tests/Regressions/coreclr/GitHub_62058/test62058.csproj b/src/tests/Regressions/coreclr/GitHub_62058/test62058.csproj new file mode 100644 index 0000000000000..0fce5a0556f40 --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_62058/test62058.csproj @@ -0,0 +1,9 @@ + + + Exe + 1 + + + + + From 0e6837744b1e5a97e6dfecf53328944a15b482a5 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 20 Jan 2022 16:28:17 -0500 Subject: [PATCH 101/308] Add StringSyntax attribute to Regex.pattern field (#64063) I missed adding this one in my initial audit. It'll be exceedingly rare for a developer to manually write code that assigns a string to this protected field, but every source-generated regex does so, and thus any colorization VS provides will benefit looking at the source-generated code. --- .../src/System/Text/RegularExpressions/Regex.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs index f34cc2329d291..08793ce85ca68 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs @@ -22,6 +22,7 @@ public partial class Regex : ISerializable { internal const int MaxOptionShift = 11; + [StringSyntax(StringSyntaxAttribute.Regex)] protected internal string? pattern; // The string pattern provided protected internal RegexOptions roptions; // the top-level options from the options string protected internal RegexRunnerFactory? factory; // Factory used to create runner instances for executing the regex From d885105d5ee04eec69d3e088c5b52a10beeac9b2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 21 Jan 2022 11:17:24 +1300 Subject: [PATCH 102/308] Sync shared code from aspnetcore (#64059) Co-authored-by: JamesNK --- .../Net/Http/aspnetcore/Http3/QPack/H3StaticTable.Http3.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/H3StaticTable.Http3.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/H3StaticTable.Http3.cs index 6e109d6f8c547..e254c3a1ef0bc 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/H3StaticTable.Http3.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/H3StaticTable.Http3.cs @@ -48,7 +48,7 @@ public static bool TryGetStatusIndex(int status, out int index) // TODO: just use Dictionary directly to avoid interface dispatch. public static IReadOnlyDictionary MethodIndex => s_methodIndex; - public static ref HeaderField Get(int index) => ref s_staticTable[index]; + public static ref readonly HeaderField Get(int index) => ref s_staticTable[index]; private static readonly HeaderField[] s_staticTable = new HeaderField[] { From 338fa9f3c55af3669631218ffc07e99ba4223061 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Thu, 20 Jan 2022 14:23:19 -0800 Subject: [PATCH 103/308] Read the System.GC.CpuGroup settings in runtimeconfig.json (#64067) --- src/coreclr/utilcode/util.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index afc0c057d3ee5..44b5250547689 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -19,6 +19,7 @@ #include "corinfo.h" #include "volatile.h" #include "mdfileformat.h" +#include #ifndef DACCESS_COMPILE UINT32 g_nClrInstanceId = 0; @@ -827,7 +828,7 @@ DWORD LCM(DWORD u, DWORD v) CONTRACTL_END; #if !defined(FEATURE_REDHAWK) && (defined(TARGET_AMD64) || defined(TARGET_ARM64)) - BOOL enableGCCPUGroups = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_GCCpuGroup) != 0; + BOOL enableGCCPUGroups = Configuration::GetKnobBooleanValue(W("System.GC.CpuGroup"), CLRConfig::EXTERNAL_GCCpuGroup); if (!enableGCCPUGroups) return; From e2da32c1f327b586dfcbda173f720d2c68726a2f Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Thu, 20 Jan 2022 17:14:54 -0700 Subject: [PATCH 104/308] Log message of unexpected exception in ThrowsAny (#64064) * Log message of unexpected exception in ThrowsAny * Update AssertExtensions.cs --- .../Common/tests/TestUtilities/System/AssertExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs index 8f97aa5ea31ce..c56fdae2d8979 100644 --- a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs +++ b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs @@ -209,7 +209,7 @@ private static void ThrowsAnyInternal(Action action, params Type[] exceptionType if (exceptionTypes.Any(t => t.Equals(exceptionType))) return; - throw new XunitException($"Expected one of: ({string.Join(", ", exceptionTypes)}) -> Actual: ({exceptionType})"); + throw new XunitException($"Expected one of: ({string.Join(", ", exceptionTypes)}) -> Actual: ({exceptionType}): {e}"); // Log message and callstack to help diagnosis } throw new XunitException($"Expected one of: ({string.Join(", ", exceptionTypes)}) -> Actual: No exception thrown"); From 50f42976116c7b3a335e332e2366f94778d59af8 Mon Sep 17 00:00:00 2001 From: Santiago Fernandez Madero Date: Thu, 20 Jan 2022 16:47:27 -0800 Subject: [PATCH 105/308] Enable some browser legs on the extra-platforms pipeline (#64065) * Enable some browser legs on the extra-platforms pipeline * Flow platform parameter from helix queues templates * Fix another condition --- eng/pipelines/common/global-build-job.yml | 2 +- .../coreclr/templates/helix-queues-setup.yml | 1 + eng/pipelines/libraries/helix-queues-setup.yml | 1 + eng/pipelines/runtime-extra-platforms.yml | 18 ++++++------------ 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/eng/pipelines/common/global-build-job.yml b/eng/pipelines/common/global-build-job.yml index 12d56d00e2d64..c9015681d1e17 100644 --- a/eng/pipelines/common/global-build-job.yml +++ b/eng/pipelines/common/global-build-job.yml @@ -141,7 +141,7 @@ jobs: df -h displayName: Disk Usage before Build - - ${{ if contains(parameters.nameSuffix, 'Windows_wasm') }}: + - ${{ if eq(parameters.platform, 'Browser_wasm_win') }}: # Update machine certs - task: PowerShell@2 displayName: Update machine certs diff --git a/eng/pipelines/coreclr/templates/helix-queues-setup.yml b/eng/pipelines/coreclr/templates/helix-queues-setup.yml index 1a5a346758702..0b2e6f7f80ed2 100644 --- a/eng/pipelines/coreclr/templates/helix-queues-setup.yml +++ b/eng/pipelines/coreclr/templates/helix-queues-setup.yml @@ -21,6 +21,7 @@ jobs: archType: ${{ parameters.archType }} container: ${{ parameters.container }} pool: ${{ parameters.pool }} + platform: ${{ parameters.platform }} shouldContinueOnError: ${{ parameters.shouldContinueOnError }} dependOnEvaluatePaths: ${{ parameters.dependOnEvaluatePaths}} runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }} diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index 644c64d975bac..dec87138ed456 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -21,6 +21,7 @@ jobs: archType: ${{ parameters.archType }} container: ${{ parameters.container }} pool: ${{ parameters.pool }} + platform: ${{ parameters.platform }} shouldContinueOnError: ${{ parameters.shouldContinueOnError }} dependOnEvaluatePaths: ${{ parameters.dependOnEvaluatePaths}} runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }} diff --git a/eng/pipelines/runtime-extra-platforms.yml b/eng/pipelines/runtime-extra-platforms.yml index 844666bdea5dc..d9121f4b8027a 100644 --- a/eng/pipelines/runtime-extra-platforms.yml +++ b/eng/pipelines/runtime-extra-platforms.yml @@ -130,8 +130,7 @@ jobs: platforms: # BuildWasmApps should only happen on the extra platforms build as we already have coverage for this build on PRs. - Browser_wasm - # disable until https://github.com/dotnet/runtime/issues/63987 is fixed - # - Browser_wasm_win + - Browser_wasm_win variables: # map dependencies variables to local variables - name: wasmbuildtestsContainsChange @@ -169,8 +168,7 @@ jobs: buildConfig: release runtimeFlavor: mono platforms: - # disable until https://github.com/dotnet/runtime/issues/63987 is fixed - # - Browser_wasm_win + - Browser_wasm_win variables: # map dependencies variables to local variables - name: librariesContainsChange @@ -257,8 +255,7 @@ jobs: runtimeFlavor: mono platforms: - Browser_wasm - # disable until https://github.com/dotnet/runtime/issues/63987 is fixed - # - Browser_wasm_win + - Browser_wasm_win variables: # map dependencies variables to local variables - name: librariesContainsChange @@ -541,8 +538,7 @@ jobs: condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -559,8 +555,7 @@ jobs: buildConfig: Release runtimeFlavor: mono platforms: - # disable until https://github.com/dotnet/runtime/issues/63987 is fixed - # - Browser_wasm_win + - Browser_wasm_win variables: # map dependencies variables to local variables - name: wasmdebuggertestsContainsChange @@ -573,8 +568,7 @@ jobs: condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) + eq(variables['isRollingBuild'], true)) # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: From b75b558e12176750b386c263986ec3f76f938ca6 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 20 Jan 2022 17:23:24 -0800 Subject: [PATCH 106/308] Allow CreateScalarUnsafe to be directly contained by hwintrinsics that support scalar loads (#62407) * Ensure that floating-point constants can be contained by hardware intrinsics * Allow CreateScalarUnsafe to be directly contained by hwintrinsics that support scalar loads * Rename IsContainableHWIntrinsicOp to TryGetContainableHWIntrinsicOp and improve handling * Ensure that NI_AVX2_BroadcastScalarToVector128/256 are properly tracked as MaybeMemoryLoad * Applying formatting patch * Ensure a few other "maybe memory" and special memory operand size cases are handled * Applying formatting patch --- src/coreclr/jit/emit.h | 128 ++++++++- src/coreclr/jit/emitxarch.cpp | 16 +- src/coreclr/jit/gentree.cpp | 45 ++- src/coreclr/jit/hwintrinsic.cpp | 35 +++ src/coreclr/jit/hwintrinsiccodegenxarch.cpp | 55 +++- src/coreclr/jit/hwintrinsiclistxarch.h | 12 +- src/coreclr/jit/instr.cpp | 37 ++- src/coreclr/jit/lower.h | 4 +- src/coreclr/jit/lowerxarch.cpp | 297 ++++++++++++++------ 9 files changed, 485 insertions(+), 144 deletions(-) diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index bee6a159e0042..66706ecaf488e 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -2883,19 +2883,12 @@ inline unsigned emitter::emitGetInsCIargs(instrDesc* id) /* static */ emitAttr emitter::emitGetMemOpSize(instrDesc* id) { emitAttr defaultSize = id->idOpSize(); - emitAttr newSize = defaultSize; + switch (id->idIns()) { - case INS_vextractf128: - case INS_vextracti128: - case INS_vinsertf128: - case INS_vinserti128: - { - return EA_16BYTE; - } - case INS_pextrb: case INS_pinsrb: + case INS_vpbroadcastb: { return EA_1BYTE; } @@ -2903,27 +2896,142 @@ inline unsigned emitter::emitGetInsCIargs(instrDesc* id) case INS_pextrw: case INS_pextrw_sse41: case INS_pinsrw: + case INS_pmovsxbq: + case INS_pmovzxbq: + case INS_vpbroadcastw: { return EA_2BYTE; } + case INS_addss: + case INS_cmpss: + case INS_comiss: + case INS_cvtss2sd: + case INS_cvtss2si: + case INS_cvttss2si: + case INS_divss: case INS_extractps: case INS_insertps: + case INS_maxss: + case INS_minss: + case INS_movss: + case INS_mulss: case INS_pextrd: case INS_pinsrd: + case INS_pmovsxbd: + case INS_pmovsxwq: + case INS_pmovzxbd: + case INS_pmovzxwq: + case INS_rcpss: + case INS_roundss: + case INS_rsqrtss: + case INS_sqrtss: + case INS_subss: + case INS_ucomiss: + case INS_vbroadcastss: + case INS_vfmadd132ss: + case INS_vfmadd213ss: + case INS_vfmadd231ss: + case INS_vfmsub132ss: + case INS_vfmsub213ss: + case INS_vfmsub231ss: + case INS_vfnmadd132ss: + case INS_vfnmadd213ss: + case INS_vfnmadd231ss: + case INS_vfnmsub132ss: + case INS_vfnmsub213ss: + case INS_vfnmsub231ss: + case INS_vpbroadcastd: { return EA_4BYTE; } + case INS_addsd: + case INS_cmpsd: + case INS_comisd: + case INS_cvtsd2si: + case INS_cvtsd2ss: + case INS_cvttsd2si: + case INS_divsd: + case INS_maxsd: + case INS_minsd: + case INS_movhpd: + case INS_movhps: + case INS_movlpd: + case INS_movlps: + case INS_movq: + case INS_movsd: + case INS_mulsd: case INS_pextrq: case INS_pinsrq: + case INS_pmovsxbw: + case INS_pmovsxdq: + case INS_pmovsxwd: + case INS_pmovzxbw: + case INS_pmovzxdq: + case INS_pmovzxwd: + case INS_roundsd: + case INS_sqrtsd: + case INS_subsd: + case INS_ucomisd: + case INS_vbroadcastsd: + case INS_vfmadd132sd: + case INS_vfmadd213sd: + case INS_vfmadd231sd: + case INS_vfmsub132sd: + case INS_vfmsub213sd: + case INS_vfmsub231sd: + case INS_vfnmadd132sd: + case INS_vfnmadd213sd: + case INS_vfnmadd231sd: + case INS_vfnmsub132sd: + case INS_vfnmsub213sd: + case INS_vfnmsub231sd: + case INS_vpbroadcastq: { return EA_8BYTE; } + case INS_cvtdq2pd: + case INS_cvtps2pd: + { + if (defaultSize == 32) + { + return EA_16BYTE; + } + else + { + assert(defaultSize == 16); + return EA_8BYTE; + } + } + + case INS_vbroadcastf128: + case INS_vbroadcasti128: + case INS_vextractf128: + case INS_vextracti128: + case INS_vinsertf128: + case INS_vinserti128: + { + return EA_16BYTE; + } + + case INS_movddup: + { + if (defaultSize == 32) + { + return EA_32BYTE; + } + else + { + assert(defaultSize == 16); + return EA_8BYTE; + } + } + default: { - return id->idOpSize(); + return defaultSize; } } } diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 1075c4ccd97d0..d90c5771ce1a9 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -8965,9 +8965,8 @@ void emitter::emitDispIns( } else { - attr = emitGetMemOpSize(id); - - sstr = codeGen->genSizeStr(attr); + attr = id->idOpSize(); + sstr = codeGen->genSizeStr(emitGetMemOpSize(id)); if (ins == INS_lea) { @@ -11743,17 +11742,6 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) #ifdef DEBUG int byteSize = EA_SIZE_IN_BYTES(emitGetMemOpSize(id)); - // this instruction has a fixed size (4) src. - if (ins == INS_cvttss2si || ins == INS_cvtss2sd || ins == INS_vbroadcastss) - { - byteSize = 4; - } - // This has a fixed size (8) source. - if (ins == INS_vbroadcastsd) - { - byteSize = 8; - } - // Check that the offset is properly aligned (i.e. the ddd in [ddd]) // When SMALL_CODE is set, we only expect 4-byte alignment, otherwise // we expect the same alignment as the size of the constant. diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 3ba0b8a8c9095..be664b41d8cfc 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -21414,7 +21414,9 @@ GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode( bool GenTreeHWIntrinsic::OperIsMemoryLoad() const { #if defined(TARGET_XARCH) || defined(TARGET_ARM64) - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(GetHWIntrinsicId()); + NamedIntrinsic intrinsicId = GetHWIntrinsicId(); + HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); + if (category == HW_Category_MemoryLoad) { return true; @@ -21423,17 +21425,42 @@ bool GenTreeHWIntrinsic::OperIsMemoryLoad() const else if (HWIntrinsicInfo::MaybeMemoryLoad(GetHWIntrinsicId())) { // Some intrinsics (without HW_Category_MemoryLoad) also have MemoryLoad semantics + // This is generally because they have both vector and pointer overloads, e.g., + // * Vector128 BroadcastScalarToVector128(Vector128 value) + // * Vector128 BroadcastScalarToVector128(byte* source) + // So, we need to check the argument's type is memory-reference or Vector128 - if (category == HW_Category_SIMDScalar) + if ((category == HW_Category_SimpleSIMD) || (category == HW_Category_SIMDScalar)) { - // Avx2.BroadcastScalarToVector128/256 have vector and pointer overloads both, e.g., - // Vector128 BroadcastScalarToVector128(Vector128 value) - // Vector128 BroadcastScalarToVector128(byte* source) - // So, we need to check the argument's type is memory-reference or Vector128 assert(GetOperandCount() == 1); - return (GetHWIntrinsicId() == NI_AVX2_BroadcastScalarToVector128 || - GetHWIntrinsicId() == NI_AVX2_BroadcastScalarToVector256) && - !Op(1)->TypeIs(TYP_SIMD16); + + switch (intrinsicId) + { + case NI_SSE41_ConvertToVector128Int16: + case NI_SSE41_ConvertToVector128Int32: + case NI_SSE41_ConvertToVector128Int64: + case NI_AVX2_BroadcastScalarToVector128: + case NI_AVX2_BroadcastScalarToVector256: + case NI_AVX2_ConvertToVector256Int16: + case NI_AVX2_ConvertToVector256Int32: + case NI_AVX2_ConvertToVector256Int64: + { + CorInfoType auxiliaryType = GetAuxiliaryJitType(); + + if (auxiliaryType == CORINFO_TYPE_PTR) + { + return true; + } + + assert(auxiliaryType == CORINFO_TYPE_UNDEF); + return false; + } + + default: + { + unreached(); + } + } } else if (category == HW_Category_IMM) { diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index dfde343fe52cb..0a5559dfd4122 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1007,6 +1007,41 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, retNode = isScalar ? gtNewScalarHWIntrinsicNode(retType, op1, intrinsic) : gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, simdBaseJitType, simdSize); + +#if defined(TARGET_XARCH) + switch (intrinsic) + { + case NI_SSE41_ConvertToVector128Int16: + case NI_SSE41_ConvertToVector128Int32: + case NI_SSE41_ConvertToVector128Int64: + case NI_AVX2_BroadcastScalarToVector128: + case NI_AVX2_BroadcastScalarToVector256: + case NI_AVX2_ConvertToVector256Int16: + case NI_AVX2_ConvertToVector256Int32: + case NI_AVX2_ConvertToVector256Int64: + { + // These intrinsics have both pointer and vector overloads + // We want to be able to differentiate between them so lets + // just track the aux type as a ptr or undefined, depending + + CorInfoType auxiliaryType = CORINFO_TYPE_UNDEF; + + if (!varTypeIsSIMD(op1->TypeGet())) + { + auxiliaryType = CORINFO_TYPE_PTR; + } + + retNode->AsHWIntrinsic()->SetAuxiliaryJitType(auxiliaryType); + break; + } + + default: + { + break; + } + } +#endif // TARGET_XARCH + break; case 2: diff --git a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp index cd9e0f8f8fc3d..d6490c59b2e36 100644 --- a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp @@ -27,11 +27,13 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // assertIsContainableHWIntrinsicOp: Asserts that op is containable by node // // Arguments: -// lowering - The lowering phase from the compiler -// node - The HWIntrinsic node that has the contained node -// op - The op that is contained +// lowering - The lowering phase from the compiler +// containingNode - The HWIntrinsic node that has the contained node +// containedNode - The node that is contained // -static void assertIsContainableHWIntrinsicOp(Lowering* lowering, GenTreeHWIntrinsic* node, GenTree* op) +static void assertIsContainableHWIntrinsicOp(Lowering* lowering, + GenTreeHWIntrinsic* containingNode, + GenTree* containedNode) { #if DEBUG // The Lowering::IsContainableHWIntrinsicOp call is not quite right, since it follows pre-register allocation @@ -39,14 +41,15 @@ static void assertIsContainableHWIntrinsicOp(Lowering* lowering, GenTreeHWIntrin // // We use isContainable to track the special HWIntrinsic node containment rules (for things like LoadAligned and // LoadUnaligned) and we use the supportsRegOptional check to support general-purpose loads (both from stack - // spillage - // and for isUsedFromMemory contained nodes, in the case where the register allocator decided to not allocate a - // register - // in the first place). + // spillage and for isUsedFromMemory contained nodes, in the case where the register allocator decided to not + // allocate a register in the first place). + + GenTree* node = containedNode; + bool supportsRegOptional = false; + bool isContainable = lowering->TryGetContainableHWIntrinsicOp(containingNode, &node, &supportsRegOptional); - bool supportsRegOptional = false; - bool isContainable = lowering->IsContainableHWIntrinsicOp(node, op, &supportsRegOptional); assert(isContainable || supportsRegOptional); + assert(node == containedNode); #endif // DEBUG } @@ -521,6 +524,14 @@ void CodeGen::genHWIntrinsic_R_RM( break; } + case GT_CNS_DBL: + { + GenTreeDblCon* cns = rmOp->AsDblCon(); + CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(cns->gtDconVal, emitTypeSize(cns)); + emit->emitIns_R_C(ins, attr, reg, hnd, 0); + return; + } + default: { unreached(); @@ -737,6 +748,14 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, break; } + case GT_CNS_DBL: + { + GenTreeDblCon* cns = op2->AsDblCon(); + CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(cns->gtDconVal, emitTypeSize(cns)); + emit->emitIns_SIMD_R_R_C_I(ins, simdSize, targetReg, op1Reg, hnd, 0, ival); + return; + } + default: unreached(); break; @@ -886,6 +905,14 @@ void CodeGen::genHWIntrinsic_R_R_RM_R(GenTreeHWIntrinsic* node, instruction ins, break; } + case GT_CNS_DBL: + { + GenTreeDblCon* cns = op2->AsDblCon(); + CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(cns->gtDconVal, emitTypeSize(cns)); + emit->emitIns_SIMD_R_R_C_R(ins, simdSize, targetReg, op1Reg, op3Reg, hnd, 0); + return; + } + default: unreached(); break; @@ -1012,6 +1039,14 @@ void CodeGen::genHWIntrinsic_R_R_R_RM( break; } + case GT_CNS_DBL: + { + GenTreeDblCon* cns = op3->AsDblCon(); + CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(cns->gtDconVal, emitTypeSize(cns)); + emit->emitIns_SIMD_R_R_R_C(ins, attr, targetReg, op1Reg, op2Reg, hnd, 0); + return; + } + default: unreached(); break; diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 95ab714ae6334..b0571e1f40f0c 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -494,9 +494,9 @@ HARDWARE_INTRINSIC(SSE41, BlendVariable, HARDWARE_INTRINSIC(SSE41, Ceiling, 16, 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(SSE41, CeilingScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE41, CompareEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE41, ConvertToVector128Int16, 16, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41, ConvertToVector128Int32, 16, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41, ConvertToVector128Int64, 16, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, ConvertToVector128Int16, 16, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics|HW_Flag_MaybeMemoryLoad) +HARDWARE_INTRINSIC(SSE41, ConvertToVector128Int32, 16, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics|HW_Flag_MaybeMemoryLoad) +HARDWARE_INTRINSIC(SSE41, ConvertToVector128Int64, 16, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics|HW_Flag_MaybeMemoryLoad) HARDWARE_INTRINSIC(SSE41, DotProduct, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_dpps, INS_dppd}, HW_Category_IMM, HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(SSE41, Extract, 16, 2, {INS_pextrb, INS_pextrb, INS_invalid, INS_invalid, INS_pextrd, INS_pextrd, INS_invalid, INS_invalid, INS_extractps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_BaseTypeFromFirstArg|HW_Flag_MultiIns|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE41, Floor, 16, 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) @@ -649,9 +649,9 @@ HARDWARE_INTRINSIC(AVX2, CompareLessThan, HARDWARE_INTRINSIC(AVX2, ExtractVector128, 32, 2, {INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(AVX2, ConvertToInt32, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX2, ConvertToUInt32, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX2, ConvertToVector256Int16, 32, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX2, ConvertToVector256Int32, 32, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX2, ConvertToVector256Int64, 32, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2, ConvertToVector256Int16, 32, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_MaybeMemoryLoad) +HARDWARE_INTRINSIC(AVX2, ConvertToVector256Int32, 32, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_MaybeMemoryLoad) +HARDWARE_INTRINSIC(AVX2, ConvertToVector256Int64, 32, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_MaybeMemoryLoad) HARDWARE_INTRINSIC(AVX2, GatherVector128, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_NoContainment) HARDWARE_INTRINSIC(AVX2, GatherVector256, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_NoContainment) HARDWARE_INTRINSIC(AVX2, GatherMaskVector128, 16, 5, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport|HW_Flag_NoContainment) diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index bbf204c74caa8..1cbe07cb69b1c 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -1017,7 +1017,8 @@ void CodeGen::inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regN // void CodeGen::inst_RV_TT_IV(instruction ins, emitAttr attr, regNumber reg1, GenTree* rmOp, int ival) { - noway_assert(GetEmitter()->emitVerifyEncodable(ins, EA_SIZE(attr), reg1)); + emitter* emit = GetEmitter(); + noway_assert(emit->emitVerifyEncodable(ins, EA_SIZE(attr), reg1)); if (rmOp->isContained() || rmOp->isUsedFromSpillTemp()) { @@ -1069,7 +1070,7 @@ void CodeGen::inst_RV_TT_IV(instruction ins, emitAttr attr, regNumber reg1, GenT case GT_CLS_VAR_ADDR: { - GetEmitter()->emitIns_R_C_I(ins, attr, reg1, addr->AsClsVar()->gtClsVarHnd, 0, ival); + emit->emitIns_R_C_I(ins, attr, reg1, addr->AsClsVar()->gtClsVarHnd, 0, ival); return; } @@ -1084,7 +1085,7 @@ void CodeGen::inst_RV_TT_IV(instruction ins, emitAttr attr, regNumber reg1, GenT // temporary GT_IND to generate code with. memIndir = &load; } - GetEmitter()->emitIns_R_A_I(ins, attr, reg1, memIndir, ival); + emit->emitIns_R_A_I(ins, attr, reg1, memIndir, ival); return; } } @@ -1106,6 +1107,14 @@ void CodeGen::inst_RV_TT_IV(instruction ins, emitAttr attr, regNumber reg1, GenT break; } + case GT_CNS_DBL: + { + GenTreeDblCon* cns = rmOp->AsDblCon(); + CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(cns->gtDconVal, emitTypeSize(cns)); + emit->emitIns_R_C_I(ins, attr, reg1, hnd, 0, ival); + return; + } + default: unreached(); } @@ -1117,12 +1126,12 @@ void CodeGen::inst_RV_TT_IV(instruction ins, emitAttr attr, regNumber reg1, GenT assert((varNum != BAD_VAR_NUM) || (tmpDsc != nullptr)); assert(offset != (unsigned)-1); - GetEmitter()->emitIns_R_S_I(ins, attr, reg1, varNum, offset, ival); + emit->emitIns_R_S_I(ins, attr, reg1, varNum, offset, ival); } else { regNumber rmOpReg = rmOp->GetRegNum(); - GetEmitter()->emitIns_SIMD_R_R_I(ins, attr, reg1, rmOpReg, ival); + emit->emitIns_SIMD_R_R_I(ins, attr, reg1, rmOpReg, ival); } } @@ -1142,7 +1151,8 @@ void CodeGen::inst_RV_TT_IV(instruction ins, emitAttr attr, regNumber reg1, GenT void CodeGen::inst_RV_RV_TT( instruction ins, emitAttr size, regNumber targetReg, regNumber op1Reg, GenTree* op2, bool isRMW) { - noway_assert(GetEmitter()->emitVerifyEncodable(ins, EA_SIZE(size), targetReg)); + emitter* emit = GetEmitter(); + noway_assert(emit->emitVerifyEncodable(ins, EA_SIZE(size), targetReg)); // TODO-XArch-CQ: Commutative operations can have op1 be contained // TODO-XArch-CQ: Non-VEX encoded instructions can have both ops contained @@ -1197,7 +1207,7 @@ void CodeGen::inst_RV_RV_TT( case GT_CLS_VAR_ADDR: { - GetEmitter()->emitIns_SIMD_R_R_C(ins, size, targetReg, op1Reg, addr->AsClsVar()->gtClsVarHnd, 0); + emit->emitIns_SIMD_R_R_C(ins, size, targetReg, op1Reg, addr->AsClsVar()->gtClsVarHnd, 0); return; } @@ -1212,7 +1222,7 @@ void CodeGen::inst_RV_RV_TT( // temporary GT_IND to generate code with. memIndir = &load; } - GetEmitter()->emitIns_SIMD_R_R_A(ins, size, targetReg, op1Reg, memIndir); + emit->emitIns_SIMD_R_R_A(ins, size, targetReg, op1Reg, memIndir); return; } } @@ -1238,10 +1248,9 @@ void CodeGen::inst_RV_RV_TT( case GT_CNS_DBL: { - GenTreeDblCon* dblCns = op2->AsDblCon(); - CORINFO_FIELD_HANDLE cnsDblHnd = - GetEmitter()->emitFltOrDblConst(dblCns->gtDconVal, emitTypeSize(dblCns)); - GetEmitter()->emitIns_SIMD_R_R_C(ins, size, targetReg, op1Reg, cnsDblHnd, 0); + GenTreeDblCon* cns = op2->AsDblCon(); + CORINFO_FIELD_HANDLE hnd = emit->emitFltOrDblConst(cns->gtDconVal, emitTypeSize(cns)); + emit->emitIns_SIMD_R_R_C(ins, size, targetReg, op1Reg, hnd, 0); return; } @@ -1258,7 +1267,7 @@ void CodeGen::inst_RV_RV_TT( assert((varNum != BAD_VAR_NUM) || (tmpDsc != nullptr)); assert(offset != (unsigned)-1); - GetEmitter()->emitIns_SIMD_R_R_S(ins, size, targetReg, op1Reg, varNum, offset); + emit->emitIns_SIMD_R_R_S(ins, size, targetReg, op1Reg, varNum, offset); } else { @@ -1277,7 +1286,7 @@ void CodeGen::inst_RV_RV_TT( op1Reg = targetReg; } - GetEmitter()->emitIns_SIMD_R_R_R(ins, size, targetReg, op1Reg, op2Reg); + emit->emitIns_SIMD_R_R_R(ins, size, targetReg, op1Reg, op2Reg); } } #endif // TARGET_XARCH diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h index ed0ecc5661970..92a4ef43f2370 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -564,8 +564,8 @@ class Lowering final : public Phase } #ifdef FEATURE_HW_INTRINSICS - // Return true if 'node' is a containable HWIntrinsic op. - bool IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, GenTree* node, bool* supportsRegOptional); + // Tries to get a containable node for a given HWIntrinsic + bool TryGetContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, GenTree** pNode, bool* supportsRegOptional); #endif // FEATURE_HW_INTRINSICS static void TransformUnusedIndirection(GenTreeIndir* ind, Compiler* comp, BasicBlock* block); diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index c8076c4525f2d..0d2acef315a98 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -832,8 +832,8 @@ void Lowering::LowerHWIntrinsicCC(GenTreeHWIntrinsic* node, NamedIntrinsic newIn bool op1SupportsRegOptional = false; bool op2SupportsRegOptional = false; - if (!IsContainableHWIntrinsicOp(node, node->Op(2), &op2SupportsRegOptional) && - IsContainableHWIntrinsicOp(node, node->Op(1), &op1SupportsRegOptional)) + if (!TryGetContainableHWIntrinsicOp(node, &node->Op(2), &op2SupportsRegOptional) && + TryGetContainableHWIntrinsicOp(node, &node->Op(1), &op1SupportsRegOptional)) { // Swap operands if op2 cannot be contained but op1 can. swapOperands = true; @@ -5158,21 +5158,34 @@ void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode) #ifdef FEATURE_HW_INTRINSICS //---------------------------------------------------------------------------------------------- -// IsContainableHWIntrinsicOp: Return true if 'node' is a containable HWIntrinsic op. +// TryGetContainableHWIntrinsicOp: Tries to get a containable node for a given HWIntrinsic // // Arguments: -// containingNode - The hardware intrinsic node which contains 'node' -// node - The node to check -// [Out] supportsRegOptional - On return, this will be true if 'containingNode' supports regOptional operands; +// [In] containingNode - The hardware intrinsic node which contains 'node' +// [In/Out] pNode - The node to check and potentially replace with the containable node +// [Out] supportsRegOptional - On return, this will be true if 'containingNode' supports regOptional operands // otherwise, false. // // Return Value: -// true if 'node' is a containable hardware intrinsic node; otherwise, false. +// true if 'node' is a containable by containingNode; otherwise, false. // -bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, GenTree* node, bool* supportsRegOptional) +// When true is returned 'node' (and by extension the relevant op of 'containingNode') may be modified +// to handle special scenarios such as CreateScalarUnsafe which exist to bridge the type system with +// the actual registers. +// +// When false is returned 'node' is not modified. +// +bool Lowering::TryGetContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, + GenTree** pNode, + bool* supportsRegOptional) { + assert(containingNode != nullptr); + assert((pNode != nullptr) && (*pNode != nullptr)); + assert(supportsRegOptional != nullptr); + NamedIntrinsic containingIntrinsicId = containingNode->GetHWIntrinsicId(); HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(containingIntrinsicId); + GenTree*& node = *pNode; // We shouldn't have called in here if containingNode doesn't support containment assert(HWIntrinsicInfo::SupportsContainment(containingIntrinsicId)); @@ -5213,8 +5226,10 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge switch (category) { case HW_Category_MemoryLoad: - supportsGeneralLoads = (!node->OperIsHWIntrinsic()); + { + supportsGeneralLoads = !node->OperIsHWIntrinsic(); break; + } case HW_Category_SimpleSIMD: { @@ -5227,26 +5242,90 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge case NI_AVX2_ConvertToVector256Int32: case NI_AVX2_ConvertToVector256Int64: { - supportsGeneralLoads = (!node->OperIsHWIntrinsic()); + assert(!supportsSIMDScalarLoads); + + if (!containingNode->OperIsMemoryLoad()) + { + // The containable form is the one that takes a SIMD value, that may be in memory. + + if (!comp->canUseVexEncoding()) + { + supportsAlignedSIMDLoads = true; + supportsUnalignedSIMDLoads = !supportsAlignedSIMDLoads; + } + else + { + supportsAlignedSIMDLoads = !comp->opts.MinOpts(); + supportsUnalignedSIMDLoads = true; + } + + // General loads are a bit special where we need at least `sizeof(simdType) / (sizeof(baseType) + // * 2)` elements + // For example: + // * ConvertToVector128Int16 - sizeof(simdType) = 16; sizeof(baseType) = 1; expectedSize = 8 + // * ConvertToVector128Int32 - sizeof(simdType) = 16; sizeof(baseType) = 1 | 2; + // expectedSize = 8 | 4 + // * ConvertToVector128Int64 - sizeof(simdType) = 16; sizeof(baseType) = 1 | 2 | 4; + // expectedSize = 8 | 4 | 2 + // * ConvertToVector256Int16 - sizeof(simdType) = 32; sizeof(baseType) = 1; expectedSize = 16 + // * ConvertToVector256Int32 - sizeof(simdType) = 32; sizeof(baseType) = 1 | 2; + // expectedSize = 16 | 8 + // * ConvertToVector256Int64 - sizeof(simdType) = 32; sizeof(baseType) = 1 | 2 | 4; + // expectedSize = 16 | 8 | 4 + + const unsigned sizeof_simdType = genTypeSize(containingNode->TypeGet()); + const unsigned sizeof_baseType = genTypeSize(containingNode->GetSimdBaseType()); + + assert((sizeof_simdType == 16) || (sizeof_simdType == 32)); + assert((sizeof_baseType == 1) || (sizeof_baseType == 2) || (sizeof_baseType == 4)); + + const unsigned expectedSize = sizeof_simdType / (sizeof_baseType * 2); + const unsigned operandSize = genTypeSize(node->TypeGet()); + + assert((sizeof_simdType != 16) || (expectedSize == 8) || (expectedSize == 4) || + (expectedSize == 2)); + assert((sizeof_simdType != 32) || (expectedSize == 16) || (expectedSize == 8) || + (expectedSize == 4)); + + supportsGeneralLoads = (operandSize >= expectedSize); + } + else + { + // The memory form of this already takes a pointer and should be treated like a MemoryLoad + supportsGeneralLoads = !node->OperIsHWIntrinsic(); + } + break; + } + + case NI_SSE2_ConvertToVector128Double: + case NI_SSE3_MoveAndDuplicate: + case NI_AVX_ConvertToVector256Double: + { + assert(!supportsSIMDScalarLoads); + + // Most instructions under the non-VEX encoding require aligned operands. + // Those used for Sse2.ConvertToVector128Double (CVTDQ2PD and CVTPS2PD) + // and Sse3.MoveAndDuplicate (MOVDDUP) are exceptions and don't fail for + // unaligned inputs as they read mem64 (half the vector width) instead + + supportsAlignedSIMDLoads = !comp->opts.MinOpts(); + supportsUnalignedSIMDLoads = true; + + const unsigned expectedSize = genTypeSize(containingNode->TypeGet()) / 2; + const unsigned operandSize = genTypeSize(node->TypeGet()); + + supportsGeneralLoads = supportsUnalignedSIMDLoads && (operandSize >= expectedSize); break; } default: { - if ((genTypeSize(node->TypeGet()) != 16) && (genTypeSize(node->TypeGet()) != 32)) - { - // These intrinsics only expect 16 or 32-byte nodes for containment - break; - } + assert(!supportsSIMDScalarLoads); if (!comp->canUseVexEncoding()) { - // Most instructions under the non-VEX encoding require aligned operands. - // Those used for Sse2.ConvertToVector128Double (CVTDQ2PD and CVTPS2PD) - // are exceptions and don't fail for unaligned inputs. - - supportsAlignedSIMDLoads = (containingIntrinsicId != NI_SSE2_ConvertToVector128Double); - supportsUnalignedSIMDLoads = !supportsAlignedSIMDLoads; + assert(!supportsUnalignedSIMDLoads); + supportsAlignedSIMDLoads = true; } else { @@ -5254,7 +5333,10 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge supportsUnalignedSIMDLoads = true; } - supportsGeneralLoads = supportsUnalignedSIMDLoads; + const unsigned expectedSize = genTypeSize(containingNode->TypeGet()); + const unsigned operandSize = genTypeSize(node->TypeGet()); + + supportsGeneralLoads = supportsUnalignedSIMDLoads && (operandSize >= expectedSize); break; } } @@ -5283,11 +5365,9 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge case NI_AVX_Blend: case NI_AVX_Compare: case NI_AVX_DotProduct: - case NI_AVX_InsertVector128: case NI_AVX_Permute: case NI_AVX_Permute2x128: case NI_AVX2_Blend: - case NI_AVX2_InsertVector128: case NI_AVX2_MultipleSumAbsoluteDifferences: case NI_AVX2_Permute2x128: case NI_AVX2_Permute4x64: @@ -5297,17 +5377,29 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge case NI_AVX2_ShuffleHigh: case NI_AVX2_ShuffleLow: { - if ((genTypeSize(node->TypeGet()) != 16) && (genTypeSize(node->TypeGet()) != 32)) - { - // These intrinsics only expect 16 or 32-byte nodes for containment - break; - } assert(!supportsSIMDScalarLoads); + const unsigned expectedSize = genTypeSize(containingNode->GetSimdBaseType()); + const unsigned operandSize = genTypeSize(node->TypeGet()); + supportsAlignedSIMDLoads = !comp->canUseVexEncoding() || !comp->opts.MinOpts(); supportsUnalignedSIMDLoads = comp->canUseVexEncoding(); - supportsGeneralLoads = supportsUnalignedSIMDLoads; + supportsGeneralLoads = supportsUnalignedSIMDLoads && (operandSize >= expectedSize); + break; + } + + case NI_AVX_InsertVector128: + case NI_AVX2_InsertVector128: + { + // InsertVector128 is special in that that it returns a TYP_SIMD32 but takes a TYP_SIMD16 + assert(!supportsSIMDScalarLoads); + const unsigned expectedSize = 16; + const unsigned operandSize = genTypeSize(node->TypeGet()); + + supportsAlignedSIMDLoads = !comp->canUseVexEncoding() || !comp->opts.MinOpts(); + supportsUnalignedSIMDLoads = comp->canUseVexEncoding(); + supportsGeneralLoads = supportsUnalignedSIMDLoads && (operandSize >= expectedSize); break; } @@ -5315,16 +5407,13 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge case NI_SSE41_Insert: case NI_SSE41_X64_Insert: { + assert(supportsAlignedSIMDLoads == false); + assert(supportsUnalignedSIMDLoads == false); + if (containingNode->GetSimdBaseType() == TYP_FLOAT) { assert(containingIntrinsicId == NI_SSE41_Insert); - if (genTypeSize(node->TypeGet()) != 16) - { - // These intrinsics only expect 16-byte nodes for containment - break; - } - // Sse41.Insert(V128, V128, byte) is a bit special // in that it has different behavior depending on whether the // second operand is coming from a register or memory. When coming @@ -5333,8 +5422,6 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge // from memory, it only works with the lowest element and is effectively // a `SIMDScalar`. - assert(supportsAlignedSIMDLoads == false); - assert(supportsUnalignedSIMDLoads == false); assert(supportsGeneralLoads == false); assert(supportsSIMDScalarLoads == false); @@ -5342,8 +5429,6 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge GenTree* op2 = containingNode->Op(2); GenTree* op3 = containingNode->Op(3); - assert(node == op2); - // The upper two bits of the immediate value are ignored if // op2 comes from memory. In order to support using the upper // bits, we need to disable containment support if op3 is not @@ -5363,9 +5448,6 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge // We should only get here for integral nodes. assert(varTypeIsIntegral(node->TypeGet())); - - assert(supportsAlignedSIMDLoads == false); - assert(supportsUnalignedSIMDLoads == false); assert(supportsSIMDScalarLoads == false); const unsigned expectedSize = genTypeSize(containingNode->GetSimdBaseType()); @@ -5377,12 +5459,6 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge case NI_AVX_CompareScalar: { - if ((genTypeSize(node->TypeGet()) != 16) && (genTypeSize(node->TypeGet()) != 32)) - { - // These intrinsics only expect 16 or 32-byte nodes for containment - break; - } - assert(supportsAlignedSIMDLoads == false); assert(supportsUnalignedSIMDLoads == false); @@ -5413,21 +5489,38 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge case NI_Vector128_CreateScalarUnsafe: case NI_Vector256_CreateScalarUnsafe: { + if (!varTypeIsIntegral(node->TypeGet())) + { + // The floating-point overload doesn't require any special semantics + supportsSIMDScalarLoads = true; + supportsGeneralLoads = supportsSIMDScalarLoads; + break; + } + + // The integral overloads only take GPR/mem assert(supportsSIMDScalarLoads == false); const unsigned expectedSize = genTypeSize(genActualType(containingNode->GetSimdBaseType())); const unsigned operandSize = genTypeSize(node->TypeGet()); - supportsGeneralLoads = (operandSize == expectedSize); + supportsGeneralLoads = (operandSize >= expectedSize); break; } case NI_AVX2_BroadcastScalarToVector128: case NI_AVX2_BroadcastScalarToVector256: { - // The memory form of this already takes a pointer, and cannot be further contained. - // The containable form is the one that takes a SIMD value, that may be in memory. - supportsGeneralLoads = (node->TypeGet() == TYP_SIMD16); + if (!containingNode->OperIsMemoryLoad()) + { + // The containable form is the one that takes a SIMD value, that may be in memory. + supportsSIMDScalarLoads = true; + supportsGeneralLoads = supportsSIMDScalarLoads; + } + else + { + // The memory form of this already takes a pointer and should be treated like a MemoryLoad + supportsGeneralLoads = !node->OperIsHWIntrinsic(); + } break; } @@ -5449,23 +5542,18 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge break; } + // The integral overloads only take GPR/mem assert(supportsSIMDScalarLoads == false); const unsigned expectedSize = genTypeSize(genActualType(containingNode->GetSimdBaseType())); const unsigned operandSize = genTypeSize(node->TypeGet()); - supportsGeneralLoads = (operandSize == expectedSize); + supportsGeneralLoads = (operandSize >= expectedSize); break; } default: { - if ((genTypeSize(node->TypeGet()) != 16) && (genTypeSize(node->TypeGet()) != 32)) - { - // These intrinsics only expect 16 or 32-byte nodes for containment - break; - } - supportsSIMDScalarLoads = true; supportsGeneralLoads = supportsSIMDScalarLoads; break; @@ -5508,20 +5596,55 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge } } - noway_assert(supportsRegOptional != nullptr); *supportsRegOptional = supportsGeneralLoads; if (!node->OperIsHWIntrinsic()) { - return supportsGeneralLoads && IsContainableMemoryOp(node); + return supportsGeneralLoads && (IsContainableMemoryOp(node) || node->IsCnsNonZeroFltOrDbl()); } // TODO-XArch: Update this to be table driven, if possible. - NamedIntrinsic intrinsicId = node->AsHWIntrinsic()->GetHWIntrinsicId(); + GenTreeHWIntrinsic* hwintrinsic = node->AsHWIntrinsic(); + NamedIntrinsic intrinsicId = hwintrinsic->GetHWIntrinsicId(); switch (intrinsicId) { + case NI_Vector128_CreateScalarUnsafe: + case NI_Vector256_CreateScalarUnsafe: + { + if (!supportsSIMDScalarLoads) + { + return false; + } + + GenTree* op1 = hwintrinsic->Op(1); + bool op1SupportsRegOptional = false; + + if (!TryGetContainableHWIntrinsicOp(containingNode, &op1, &op1SupportsRegOptional)) + { + return false; + } + + LIR::Use use; + if (!BlockRange().TryGetUse(node, &use) || (use.User() != containingNode)) + { + return false; + } + + // We have CreateScalarUnsafe where the underlying scalar is directly containable + // by containingNode. As such, we'll just remove CreateScalarUnsafe and consume + // the value directly. + + use.ReplaceWith(op1); + BlockRange().Remove(node); + + node = op1; + node->ClearContained(); + + return true; + } + case NI_SSE_LoadAlignedVector128: case NI_SSE2_LoadAlignedVector128: case NI_AVX_LoadAlignedVector256: @@ -5709,7 +5832,22 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) bool supportsRegOptional = false; - if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional)) + if (node->OperIsMemoryLoad()) + { + // We have a few cases that can be potential memory loads + + assert((intrinsicId == NI_SSE41_ConvertToVector128Int16) || + (intrinsicId == NI_SSE41_ConvertToVector128Int32) || + (intrinsicId == NI_SSE41_ConvertToVector128Int64) || + (intrinsicId == NI_AVX2_BroadcastScalarToVector128) || + (intrinsicId == NI_AVX2_BroadcastScalarToVector256) || + (intrinsicId == NI_AVX2_ConvertToVector256Int16) || + (intrinsicId == NI_AVX2_ConvertToVector256Int32) || + (intrinsicId == NI_AVX2_ConvertToVector256Int64)); + + ContainCheckHWIntrinsicAddr(node, op1); + } + else if (TryGetContainableHWIntrinsicOp(node, &op1, &supportsRegOptional)) { MakeSrcContained(node, op1); } @@ -5765,13 +5903,13 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) { bool supportsRegOptional = false; - if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional)) + if (TryGetContainableHWIntrinsicOp(node, &op2, &supportsRegOptional)) { MakeSrcContained(node, op2); } else if ((isCommutative || (intrinsicId == NI_BMI2_MultiplyNoFlags) || (intrinsicId == NI_BMI2_X64_MultiplyNoFlags)) && - IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional)) + TryGetContainableHWIntrinsicOp(node, &op1, &supportsRegOptional)) { MakeSrcContained(node, op1); @@ -5817,7 +5955,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) if (!HWIntrinsicInfo::isImmOp(intrinsicId, op2)) { - if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional)) + if (TryGetContainableHWIntrinsicOp(node, &op2, &supportsRegOptional)) { MakeSrcContained(node, op2); } @@ -5839,7 +5977,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) { // These intrinsics have op2 as an imm and op1 as a reg/mem - if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional)) + if (TryGetContainableHWIntrinsicOp(node, &op1, &supportsRegOptional)) { MakeSrcContained(node, op1); } @@ -5866,7 +6004,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) if (HWIntrinsicInfo::isImmOp(intrinsicId, op2)) { - if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional)) + if (TryGetContainableHWIntrinsicOp(node, &op1, &supportsRegOptional)) { MakeSrcContained(node, op1); } @@ -5875,7 +6013,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) op1->SetRegOptional(); } } - else if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional)) + else if (TryGetContainableHWIntrinsicOp(node, &op2, &supportsRegOptional)) { MakeSrcContained(node, op2); } @@ -5888,7 +6026,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) case NI_AES_KeygenAssist: { - if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional)) + if (TryGetContainableHWIntrinsicOp(node, &op1, &supportsRegOptional)) { MakeSrcContained(node, op1); } @@ -6016,18 +6154,19 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) // Set op regOptional only if none of them is containable. // Prefer to make op3 contained, - if (resultOpNum != 3 && IsContainableHWIntrinsicOp(node, op3, &supportsOp3RegOptional)) + if (resultOpNum != 3 && TryGetContainableHWIntrinsicOp(node, &op3, &supportsOp3RegOptional)) { // result = (op1 * op2) + [op3] MakeSrcContained(node, op3); } - else if (resultOpNum != 2 && IsContainableHWIntrinsicOp(node, op2, &supportsOp2RegOptional)) + else if (resultOpNum != 2 && + TryGetContainableHWIntrinsicOp(node, &op2, &supportsOp2RegOptional)) { // result = (op1 * [op2]) + op3 MakeSrcContained(node, op2); } else if (resultOpNum != 1 && !HWIntrinsicInfo::CopiesUpperBits(intrinsicId) && - IsContainableHWIntrinsicOp(node, op1, &supportsOp1RegOptional)) + TryGetContainableHWIntrinsicOp(node, &op1, &supportsOp1RegOptional)) { // result = ([op1] * op2) + op3 MakeSrcContained(node, op1); @@ -6057,7 +6196,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) case NI_AVX_BlendVariable: case NI_AVX2_BlendVariable: { - if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional)) + if (TryGetContainableHWIntrinsicOp(node, &op2, &supportsRegOptional)) { MakeSrcContained(node, op2); } @@ -6070,7 +6209,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) case NI_AVXVNNI_MultiplyWideningAndAdd: case NI_AVXVNNI_MultiplyWideningAndAddSaturate: { - if (IsContainableHWIntrinsicOp(node, op3, &supportsRegOptional)) + if (TryGetContainableHWIntrinsicOp(node, &op3, &supportsRegOptional)) { MakeSrcContained(node, op3); } @@ -6083,11 +6222,11 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) case NI_BMI2_MultiplyNoFlags: case NI_BMI2_X64_MultiplyNoFlags: { - if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional)) + if (TryGetContainableHWIntrinsicOp(node, &op2, &supportsRegOptional)) { MakeSrcContained(node, op2); } - else if (IsContainableHWIntrinsicOp(node, op1, &supportsRegOptional)) + else if (TryGetContainableHWIntrinsicOp(node, &op1, &supportsRegOptional)) { MakeSrcContained(node, op1); // MultiplyNoFlags is a Commutative operation, so swap the first two operands here @@ -6141,7 +6280,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) case NI_AVX2_Permute2x128: case NI_PCLMULQDQ_CarrylessMultiply: { - if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional)) + if (TryGetContainableHWIntrinsicOp(node, &op2, &supportsRegOptional)) { MakeSrcContained(node, op2); } From 24348f061f724b55950bbbed4e4a9004c26a1d79 Mon Sep 17 00:00:00 2001 From: Wrzucher Date: Fri, 21 Jan 2022 07:44:30 +0600 Subject: [PATCH 107/308] Remove commented code (#63869) --- .../System.Drawing.Common/src/System/Drawing/GdiplusNative.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs index a435640a795c1..8fef9cbc472b2 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs @@ -1399,7 +1399,6 @@ internal struct StartupInput { public int GdiplusVersion; // Must be 1 - // public DebugEventProc DebugEventCallback; // Ignored on free builds public IntPtr DebugEventCallback; public bool SuppressBackgroundThread; // FALSE unless you're prepared to call @@ -1416,7 +1415,6 @@ public static StartupInput GetDefault() // In Windows 7 GDI+1.1 story is different as there are different binaries per GDI+ version. bool isWindows7 = os.Platform == PlatformID.Win32NT && os.Version.Major == 6 && os.Version.Minor == 1; result.GdiplusVersion = isWindows7 ? 1 : 2; - // result.DebugEventCallback = null; result.SuppressBackgroundThread = false; result.SuppressExternalCodecs = false; return result; From f3e4e768d10dc502b0a7e9c417ae269dcf75dbc7 Mon Sep 17 00:00:00 2001 From: Egor Chesakov Date: Thu, 20 Jan 2022 19:23:21 -0800 Subject: [PATCH 108/308] Add pmi_path argument to superpmi.py script and use it in the superpmi-collect pipeline. (#63983) * Add -pmi_path argument to superpmi.py collect command and use it to set PMIPATH environment variable in src/coreclr/scripts/superpmi.py * Set pmi_path to $(SuperPMIDirectory)\crossgen2 * Print a warning if -pmi_path or -pmi_location is specified while --pmi is not in src/coreclr/scripts/superpmi.py * Move setting of PMIPATH environment variable under `if self.coreclr_args.pmi is True:` in src/coreclr/scripts/superpmi.py * Move pmi argument validation to setup_args() in src/coreclr/scripts/superpmi.py * Clone root_env if we are going to set PMIPATH environment variable in src/coreclr/scripts/superpmi.py --- src/coreclr/scripts/superpmi-collect.proj | 4 ++-- src/coreclr/scripts/superpmi.py | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/coreclr/scripts/superpmi-collect.proj b/src/coreclr/scripts/superpmi-collect.proj index 963e117688f57..046a699917fc6 100644 --- a/src/coreclr/scripts/superpmi-collect.proj +++ b/src/coreclr/scripts/superpmi-collect.proj @@ -54,7 +54,7 @@ %HELIX_WORKITEM_UPLOAD_ROOT% $(BUILD_SOURCESDIRECTORY)\artifacts\helixresults - $(SuperPMIDirectory)\superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)\pmi.dll + $(SuperPMIDirectory)\superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)\pmi.dll -pmi_path $(SuperPMIDirectory)\crossgen2 $HELIX_PYTHONPATH @@ -68,7 +68,7 @@ $HELIX_WORKITEM_UPLOAD_ROOT $(BUILD_SOURCESDIRECTORY)/artifacts/helixresults - $(SuperPMIDirectory)/superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)/pmi.dll + $(SuperPMIDirectory)/superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)/pmi.dll -pmi_path $(SuperPMIDirectory)/crossgen2 diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index 8433294a146d8..3c9d417f81cc0 100755 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -276,6 +276,7 @@ collect_parser.add_argument("-assemblies", dest="assemblies", nargs="+", default=[], help="A list of managed dlls or directories to recursively use while collecting with PMI or crossgen2. Required if --pmi or --crossgen2 is specified.") collect_parser.add_argument("-exclude", dest="exclude", nargs="+", default=[], help="A list of files or directories to exclude from the files and directories specified by `-assemblies`.") collect_parser.add_argument("-pmi_location", help="Path to pmi.dll to use during PMI run. Optional; pmi.dll will be downloaded from Azure Storage if necessary.") +collect_parser.add_argument("-pmi_path", metavar="PMIPATH_DIR", nargs='*', help="Specify a \"load path\" where assemblies can be found during pmi.dll run. Optional; the argument values are translated to PMIPATH environment variable.") collect_parser.add_argument("-output_mch_path", help="Location to place the final MCH file.") collect_parser.add_argument("--merge_mch_files", action="store_true", help="Merge multiple MCH files. Use the -mch_files flag to pass a list of MCH files to merge.") collect_parser.add_argument("-mch_files", metavar="MCH_FILE", nargs='+', help="Pass a sequence of MCH files which will be merged. Required by --merge_mch_files.") @@ -831,7 +832,14 @@ async def run_pmi(print_prefix, assembly, self): pmi_command_env = env_copy.copy() pmi_complus_env = complus_env.copy() pmi_complus_env["JitName"] = self.collection_shim_name - set_and_report_env(pmi_command_env, root_env, pmi_complus_env) + + if self.coreclr_args.pmi_path is not None: + pmi_root_env = root_env.copy() + pmi_root_env["PMIPATH"] = ";".join(self.coreclr_args.pmi_path) + else: + pmi_root_env = root_env + + set_and_report_env(pmi_command_env, pmi_root_env, pmi_complus_env) old_env = os.environ.copy() os.environ.update(pmi_command_env) @@ -3105,6 +3113,11 @@ def verify_replay_common_args(): lambda unused: True, "Unable to set tiered_compilation") + coreclr_args.verify(args, + "pmi_path", + lambda unused: True, + "Unable to set pmi_path") + if (args.collection_command is None) and (args.pmi is False) and (args.crossgen2 is False): print("Either a collection command or `--pmi` or `--crossgen2` must be specified") sys.exit(1) @@ -3121,6 +3134,12 @@ def verify_replay_common_args(): print("Specify `-assemblies` if `--pmi` or `--crossgen2` is given") sys.exit(1) + if not args.pmi: + if args.pmi_path is not None: + logging.warning("Warning: -pmi_path is set but --pmi is not.") + if args.pmi_location is not None: + logging.warning("Warning: -pmi_location is set but --pmi is not.") + if args.collection_command is None and args.merge_mch_files is not True: assert args.collection_args is None assert (args.pmi is True) or (args.crossgen2 is True) From 22e2db1228da5da1df4a6bcfd8340c9a66146a13 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Fri, 21 Jan 2022 02:26:05 -0500 Subject: [PATCH 109/308] Update the macOS CoreCLR building documentation. (#63932) This updates the documentation to refer to the up-to-date location of requirements and prerequisites. --- .../building/coreclr/osx-instructions.md | 43 ++----------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/docs/workflow/building/coreclr/osx-instructions.md b/docs/workflow/building/coreclr/osx-instructions.md index d8bf4fe604fcb..41e8d87de1a7e 100644 --- a/docs/workflow/building/coreclr/osx-instructions.md +++ b/docs/workflow/building/coreclr/osx-instructions.md @@ -1,49 +1,12 @@ -Build CoreCLR on OS X +Build CoreCLR on macOS ===================== -This guide will walk you through building CoreCLR on OS X. We'll start by showing how to set up your environment from scratch. +This guide will walk you through building CoreCLR on macOS. We'll start by showing how to set up your environment from scratch. Environment =========== -These instructions were validated on macOS 10.12. Sierra. On older versions coreFX will fail to build properly because of SSL API changes. - -If your machine has Command Line Tools for XCode 6.3 installed, you'll need to update them to the 6.3.1 version or higher in order to successfully build. There was an issue with the headers that shipped with version 6.3 that was subsequently fixed in 6.3.1. - -Git Setup ---------- - -Clone the CoreCLR and CoreFX repositories (either upstream or a fork). - -```sh -git clone https://github.com/dotnet/runtime -# Cloning into 'runtime'... -``` - -CMake ------ - -CoreCLR has a dependency on CMake for the build. You can install it with [Homebrew](https://brew.sh/). - -```sh -brew install cmake -``` - -ICU ---- -ICU (International Components for Unicode) is also required to build and run. It can be obtained via [Homebrew](https://brew.sh/). - -```sh -brew install icu4c -``` - -pkg-config ----------- -pkg-config is also required to build. It can be obtained via [Homebrew](https://brew.sh/). - -```sh -brew install pkg-config -``` +Ensure you have all of the prerequisites installed from the [macOS Requirements](/docs/workflow/requirements/macos-requirements.md). Build the Runtime and System.Private.CoreLib ============================================ From 8c9451e66ad5c54c95aaf5b84b2f27e6a9d72883 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Fri, 21 Jan 2022 09:06:46 +0100 Subject: [PATCH 110/308] Introduce RandomAccess.SetLength (#63992) --- .../tests/RandomAccess/SetLength.cs | 65 +++++++++++++++++++ .../Win32/SafeHandles/SafeFileHandle.Unix.cs | 8 ++- .../SafeHandles/SafeFileHandle.Windows.cs | 12 ++-- .../src/System/IO/RandomAccess.Unix.cs | 3 + .../src/System/IO/RandomAccess.Windows.cs | 21 ++++++ .../src/System/IO/RandomAccess.cs | 22 +++++++ .../IO/Strategies/FileStreamHelpers.Unix.cs | 3 - .../Strategies/FileStreamHelpers.Windows.cs | 31 --------- .../IO/Strategies/OSFileStreamStrategy.cs | 6 +- .../System.Runtime/ref/System.Runtime.cs | 1 + 10 files changed, 127 insertions(+), 45 deletions(-) create mode 100644 src/libraries/System.IO.FileSystem/tests/RandomAccess/SetLength.cs diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/SetLength.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/SetLength.cs new file mode 100644 index 0000000000000..95d4bc2497018 --- /dev/null +++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/SetLength.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. + +using Microsoft.Win32.SafeHandles; +using Xunit; + +namespace System.IO.Tests +{ + public class RandomAccess_SetLength : RandomAccess_Base + { + private const long FileSize = 123; + + protected override long MethodUnderTest(SafeFileHandle handle, byte[] bytes, long fileOffset) + { + RandomAccess.SetLength(handle, fileOffset); + + return 0; + } + + protected override bool UsesOffsets => false; + + [Theory] + [MemberData(nameof(GetSyncAsyncOptions))] + public void ModifiesTheActualFileSize(FileOptions options) + { + using (SafeFileHandle handle = File.OpenHandle(GetTestFilePath(), FileMode.CreateNew, FileAccess.Write, options: options)) + { + RandomAccess.SetLength(handle, FileSize); + + Assert.Equal(FileSize, RandomAccess.GetLength(handle)); + } + } + + [Theory] + [MemberData(nameof(GetSyncAsyncOptions))] + public void AllowsForShrinking(FileOptions options) + { + using (SafeFileHandle handle = File.OpenHandle(GetTestFilePath(), FileMode.CreateNew, FileAccess.Write, options: options)) + { + RandomAccess.SetLength(handle, FileSize); + Assert.Equal(FileSize, RandomAccess.GetLength(handle)); + + RandomAccess.SetLength(handle, FileSize / 2); + Assert.Equal(FileSize / 2, RandomAccess.GetLength(handle)); + + RandomAccess.SetLength(handle, 0); + Assert.Equal(0, RandomAccess.GetLength(handle)); + } + } + + [Theory] + [MemberData(nameof(GetSyncAsyncOptions))] + public void ZeroesTheFileContentsWhenExtendingTheFile(FileOptions options) + { + using (SafeFileHandle handle = File.OpenHandle(GetTestFilePath(), FileMode.CreateNew, FileAccess.Write, options: options)) + { + RandomAccess.SetLength(handle, FileSize); + + byte[] buffer = new byte[FileSize + 1]; + Assert.Equal(FileSize, RandomAccess.Read(handle, buffer, 0)); + Assert.All(buffer, @byte => Assert.Equal(0, @byte)); + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs index 6bfd650a0d2fc..348c7762ec901 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs @@ -57,9 +57,11 @@ internal bool SupportsRandomAccess internal void EnsureThreadPoolBindingInitialized() { /* nop */ } - internal bool LengthCanBeCached => false; - - internal bool HasCachedFileLength => false; + internal bool TryGetCachedLength(out long cachedLength) + { + cachedLength = -1; + return false; + } private static SafeFileHandle Open(string path, Interop.Sys.OpenFlags flags, int mode, Func? createOpenException) diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs index a4ecc686513cb..d6bbfdd166bf0 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs @@ -29,9 +29,11 @@ public SafeFileHandle() : base(true) internal ThreadPoolBoundHandle? ThreadPoolBinding { get; set; } - internal bool LengthCanBeCached => _lengthCanBeCached; - - internal bool HasCachedFileLength => _lengthCanBeCached && _length >= 0; + internal bool TryGetCachedLength(out long cachedLength) + { + cachedLength = _length; + return _lengthCanBeCached && cachedLength >= 0; + } internal static unsafe SafeFileHandle Open(string fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, long preallocationSize) { @@ -261,7 +263,7 @@ internal int GetFileType() return fileType; } - internal unsafe long GetFileLength() + internal long GetFileLength() { if (!_lengthCanBeCached) { @@ -277,7 +279,7 @@ internal unsafe long GetFileLength() return _length; - long GetFileLengthCore() + unsafe long GetFileLengthCore() { Interop.Kernel32.FILE_STANDARD_INFO info; diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs index d9739e3082dfd..fcbf862ec91c4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs @@ -19,6 +19,9 @@ public static partial class RandomAccess // that get stackalloced in the Linux kernel. private const int IovStackThreshold = 8; + internal static unsafe void SetFileLength(SafeFileHandle handle, long length) => + FileStreamHelpers.CheckFileCall(Interop.Sys.FTruncate(handle, length), handle.Path); + internal static unsafe int ReadAtOffset(SafeFileHandle handle, Span buffer, long fileOffset) { fixed (byte* bufPtr = &MemoryMarshal.GetReference(buffer)) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs index 4e79f02de4081..2cb2f984904a6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs @@ -18,6 +18,27 @@ public static partial class RandomAccess { private static readonly IOCompletionCallback s_callback = AllocateCallback(); + internal static unsafe void SetFileLength(SafeFileHandle handle, long length) + { + var eofInfo = new Interop.Kernel32.FILE_END_OF_FILE_INFO + { + EndOfFile = length + }; + + if (!Interop.Kernel32.SetFileInformationByHandle( + handle, + Interop.Kernel32.FileEndOfFileInfo, + &eofInfo, + (uint)sizeof(Interop.Kernel32.FILE_END_OF_FILE_INFO))) + { + int errorCode = Marshal.GetLastPInvokeError(); + + throw errorCode == Interop.Errors.ERROR_INVALID_PARAMETER + ? new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_FileLengthTooBig) + : Win32Marshal.GetExceptionForWin32Error(errorCode, handle.Path); + } + } + internal static unsafe int ReadAtOffset(SafeFileHandle handle, Span buffer, long fileOffset) { if (handle.IsAsync) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.cs index 5c4ede7ff408b..7aaaace1e3e47 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.cs @@ -27,6 +27,28 @@ public static long GetLength(SafeFileHandle handle) return handle.GetFileLength(); } + /// + /// Sets the length of the file to the given value. + /// + /// The file handle. + /// A long value representing the length of the file in bytes. + /// is . + /// is invalid. + /// The file is closed. + /// The file does not support seeking (pipe or socket). + /// is negative. + public static void SetLength(SafeFileHandle handle, long length) + { + ValidateInput(handle, fileOffset: 0); + + if (length < 0) + { + ThrowHelper.ThrowArgumentOutOfRangeException_NeedNonNegNum(nameof(length)); + } + + SetFileLength(handle, length); + } + /// /// Reads a sequence of bytes from given file at given offset. /// diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Unix.cs index 0f91702c00cc6..a0aa31bb89713 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Unix.cs @@ -34,9 +34,6 @@ internal static long Seek(SafeFileHandle handle, long offset, SeekOrigin origin, internal static void ThrowInvalidArgument(SafeFileHandle handle) => throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(Interop.Error.EINVAL), handle.Path); - internal static unsafe void SetFileLength(SafeFileHandle handle, long length) => - CheckFileCall(Interop.Sys.FTruncate(handle, length), handle.Path); - /// Flushes the file's OS buffer. internal static void FlushToDisk(SafeFileHandle handle) { diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Windows.cs index b519b32a05ba2..3e90bf225385c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Windows.cs @@ -121,37 +121,6 @@ internal static void Unlock(SafeFileHandle handle, long position, long length) } } - internal static unsafe void SetFileLength(SafeFileHandle handle, long length) - { - if (!TrySetFileLength(handle, length, out int errorCode)) - { - throw errorCode == Interop.Errors.ERROR_INVALID_PARAMETER - ? new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_FileLengthTooBig) - : Win32Marshal.GetExceptionForWin32Error(errorCode, handle.Path); - } - } - - internal static unsafe bool TrySetFileLength(SafeFileHandle handle, long length, out int errorCode) - { - var eofInfo = new Interop.Kernel32.FILE_END_OF_FILE_INFO - { - EndOfFile = length - }; - - if (!Interop.Kernel32.SetFileInformationByHandle( - handle, - Interop.Kernel32.FileEndOfFileInfo, - &eofInfo, - (uint)sizeof(Interop.Kernel32.FILE_END_OF_FILE_INFO))) - { - errorCode = Marshal.GetLastPInvokeError(); - return false; - } - - errorCode = Interop.Errors.ERROR_SUCCESS; - return true; - } - internal static unsafe int ReadFileNative(SafeFileHandle handle, Span bytes, NativeOverlapped* overlapped, out int errorCode) { Debug.Assert(handle != null, "handle != null"); diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs index 662945c0941e9..80f1427789b6d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs @@ -195,8 +195,8 @@ protected unsafe void SetLengthCore(long value) { Debug.Assert(value >= 0, "value >= 0"); - FileStreamHelpers.SetFileLength(_fileHandle, value); - Debug.Assert(!_fileHandle.LengthCanBeCached, "If length can be cached (file opened for reading, not shared for writing), it should be impossible to modify file length"); + RandomAccess.SetFileLength(_fileHandle, value); + Debug.Assert(!_fileHandle.TryGetCachedLength(out _), "If length can be cached (file opened for reading, not shared for writing), it should be impossible to modify file length"); if (_filePosition > value) { @@ -283,7 +283,7 @@ public sealed override ValueTask ReadAsync(Memory destination, Cancel return RandomAccess.ReadAtOffsetAsync(_fileHandle, destination, fileOffset: -1, cancellationToken); } - if (_fileHandle.HasCachedFileLength && Volatile.Read(ref _filePosition) >= _fileHandle.GetFileLength()) + if (_fileHandle.TryGetCachedLength(out long cachedLength) && Volatile.Read(ref _filePosition) >= cachedLength) { // We know for sure that the file length can be safely cached and it has already been obtained. // If we have reached EOF we just return here and avoid a sys-call. diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 851f9dcc38714..4ba4ebabbb445 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -10760,6 +10760,7 @@ public PathTooLongException(string? message, System.Exception? innerException) { public static partial class RandomAccess { public static long GetLength(Microsoft.Win32.SafeHandles.SafeFileHandle handle) { throw null; } + public static void SetLength(Microsoft.Win32.SafeHandles.SafeFileHandle handle, long length) { throw null; } public static long Read(Microsoft.Win32.SafeHandles.SafeFileHandle handle, System.Collections.Generic.IReadOnlyList> buffers, long fileOffset) { throw null; } public static int Read(Microsoft.Win32.SafeHandles.SafeFileHandle handle, System.Span buffer, long fileOffset) { throw null; } public static System.Threading.Tasks.ValueTask ReadAsync(Microsoft.Win32.SafeHandles.SafeFileHandle handle, System.Collections.Generic.IReadOnlyList> buffers, long fileOffset, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } From d7b6689d79bc35ab13a13c17d4d4f98070fd985b Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Fri, 21 Jan 2022 09:08:03 +0100 Subject: [PATCH 111/308] don't Flush readonly MemoryMappedViewAccessor on disposal (#63794) * don't Flush if it's impossible to write * address code review feedback: apply same optimization to MemoryMappedViewStream --- .../src/System/IO/MemoryMappedFiles/MemoryMappedViewAccessor.cs | 2 +- .../src/System/IO/MemoryMappedFiles/MemoryMappedViewStream.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedViewAccessor.cs b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedViewAccessor.cs index 8bde897dc57e6..2321438afb1d9 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedViewAccessor.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedViewAccessor.cs @@ -34,7 +34,7 @@ protected override void Dispose(bool disposing) { // Explicitly flush the changes. The OS will do this for us anyway, but not until after the // MemoryMappedFile object itself is closed. - if (disposing && !_view.IsClosed) + if (disposing && !_view.IsClosed && CanWrite) { Flush(); } diff --git a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedViewStream.cs b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedViewStream.cs index 740db8809d928..522e784d81520 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedViewStream.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedViewStream.cs @@ -37,7 +37,7 @@ protected override void Dispose(bool disposing) { try { - if (disposing && !_view.IsClosed) + if (disposing && !_view.IsClosed && CanWrite) { Flush(); } From 358ee3c9f61d8c11f7cac067307db1b2d6690f3c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 21 Jan 2022 00:10:01 -0800 Subject: [PATCH 112/308] Implement System.Runtime.CompilerServices.DisabledRuntimeMarshallingAttribute on CoreCLR-family of runtimes/type systems (#63320) * Add the DisableRuntimeMarshallingAttribute to the build. * Add initial test suite * Implement support in IL stubs for the "disabled runtime marshalling" feature. * Add testing for inlining IL stubs. * Block SetLastError and LCID support when DisableRuntimeMarshallingAttribute is applied. * Bump NativeAOT-only R2R version header (missed previously) * Implement support in crossgen2 and NativeAOT * Clean up the test tree and update the tests to fail more reliably when bugs are present. Fix a bug that was uncovered when the tests were refactored. * Fix NativeAOT and clean up crossgen2 * Add a test for NoPreserveSig with DisableRuntimeMarshalling * Assign hr in SUCCEEDED macro. * PR feedback. * Block varargs in disabled marshalling mode. * Fix typo * Block types that have a field that is auto-layout somewhere in their layout. * Fix typo * Revert the AutoLayoutOrHasAutoLayoutFIeld check in the "marshalling enabled" case * Only set scope when it isn't null (it's null for some cases). * Fix narrowing conversion failure. * First pass simple implementation in Mono * Fix assert to still work for the built-in marshalling system * S_FALSE is a thing * Fix type load failures caused by eager type handle loading. * Get MethodILScope from the calling method when available (this covers all cases where we need it) * Add const modifier. * Try 2 to fix const modifiers * Fix compilation of NativeAOT jitinterface * Fix type lookup in Mono * Use try_get model for getting the attribute type in the case of failure. Fix mono implementation for looking up the attribute. * Handle void and generic instantiations * Update auto-layout check to check recursively in layout. * Enhance test suite with more tests for UnmanagedCallersOnly, generics, and the like. Fix AutoLayout test. * Fix IL and a few typos * Set a value in the padding for easier debugging. * Create sig->marshalling_disabled to track when marshalling is disabled, which is separate from the concept of "is this signature a P/Invoke" * Fix running test suite on Mono + Mini JIT * Fix recursive type load failure by only checking the "has auto-layout or field with auto-layout" for value types. * Fix mono windows build. * Feedback from Michal. * Fix bug in EcmaAssembly.HasAssemblyCustomAttribute * Make the runtime flavor check in the wrapper generator case-invariant * Use helper method since various different platforms/configurations throw different exceptions for these scenarios. * Fix AutoLayout test refactor and use a dummy value for the padding field in both enabled and disabled scenarios. * Add an explicit test for using enums as they're a little weird and needed some special-casing. * Fix build-time test filtering in xunit wrapper generator. * Fix some x86-specific issues * Add a nice big comment block. * Fix x86 * Refactor tests so we can skip one on Mono since Char->char lossy conversion is not supported. * Disable test in issues.targets until an alternative solution is reached. * Add another SkipOnMono attribute in the "Enabled" test suite. * Apply UnmangedFunctionPointerAttribute to help hint to the Mono LLVM AOT compiler to compile the managed->native thunks at aot-time * Unify on "runtime marshalling" terminology * Clean up unused usings. * Address Jan's feedback except for applying the attribute to CoreLib. * PR feedback. * Mono throws an InvalidProgramException for varargs * Fix copy-paste issue. * Make sure we use the P/Invoke's Module and not the caller's module when deciding if runtime marshalling is enabled for a varargs P/Invoke call. * Handle how LLVM AOT reports the failure to handle varargs (EEE) --- src/coreclr/dlls/mscorrc/mscorrc.rc | 5 + src/coreclr/dlls/mscorrc/resource.h | 5 + .../tools/Common/JitInterface/CorInfoImpl.cs | 18 +- .../TypeSystem/Common/DefType.FieldLayout.cs | 24 ++ .../TypeSystem/Common/FieldLayoutAlgorithm.cs | 1 + .../Common/MetadataFieldLayoutAlgorithm.cs | 42 +++- .../Common/TypeSystem/Ecma/EcmaAssembly.cs | 2 +- .../CalliMarshallingMethodThunk.Mangling.cs | 2 +- .../CalliMarshallingMethodThunk.Sorting.cs | 5 + .../IL/Stubs/CalliMarshallingMethodThunk.cs | 6 +- .../TypeSystem/IL/Stubs/PInvokeILEmitter.cs | 87 ++++--- .../Interop/IL/MarshalHelpers.Aot.cs | 2 +- .../TypeSystem/Interop/IL/MarshalHelpers.cs | 38 +++ .../TypeSystem/Interop/IL/Marshaller.cs | 44 +++- .../TypeSystem/Interop/InteropStateManager.cs | 30 +-- .../Common/TypeSystem/Interop/InteropTypes.cs | 5 + .../Compiler/UsageBasedInteropStubManager.cs | 2 +- .../IL/Stubs/PInvokeILProvider.cs | 4 +- .../IL/Stubs/PInvokeILEmitter.cs | 7 + .../Interop/IL/Marshaller.ReadyToRun.cs | 55 +++-- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 4 +- .../JitInterface/CorInfoImpl.RyuJit.cs | 14 +- src/coreclr/vm/ceeload.cpp | 36 +++ src/coreclr/vm/ceeload.h | 17 ++ src/coreclr/vm/class.h | 40 +++- src/coreclr/vm/classlayoutinfo.cpp | 100 +++++--- src/coreclr/vm/classnames.h | 2 + src/coreclr/vm/dllimport.cpp | 73 +++++- src/coreclr/vm/dllimport.h | 8 + src/coreclr/vm/methodtable.h | 2 + src/coreclr/vm/methodtable.inl | 7 + src/coreclr/vm/mlinfo.cpp | 137 +++++++++-- src/coreclr/vm/stubgen.cpp | 2 +- .../System.Private.CoreLib.Shared.projitems | 1 + .../DisableRuntimeMarshallingAttribute.cs | 27 +++ .../System.Runtime/ref/System.Runtime.cs | 5 + src/mono/mono/arch/s390x/tramp.c | 19 +- src/mono/mono/metadata/class-getters.h | 1 + src/mono/mono/metadata/class-init.c | 21 +- .../mono/metadata/class-private-definition.h | 1 + src/mono/mono/metadata/cominterop.c | 3 +- src/mono/mono/metadata/marshal-ilgen.c | 21 ++ src/mono/mono/metadata/marshal-noilgen.c | 6 + src/mono/mono/metadata/marshal.c | 220 ++++++++++++++++-- src/mono/mono/metadata/marshal.h | 7 +- src/mono/mono/metadata/metadata-internals.h | 3 + src/mono/mono/mini/calls.c | 2 +- src/mono/mono/mini/interp/interp.c | 16 +- src/mono/mono/mini/interp/transform.c | 8 +- src/mono/mono/mini/mini-amd64.c | 12 +- src/mono/mono/mini/mini-arm.c | 10 +- src/mono/mono/mini/mini-generic-sharing.c | 2 +- src/mono/mono/mini/mini-mips.c | 6 +- src/mono/mono/mini/mini-ppc.c | 14 +- src/mono/mono/mini/mini-s390x.c | 14 +- src/mono/mono/mini/mini-sparc.c | 4 +- src/mono/mono/mini/mini-x86.c | 6 +- .../XUnitWrapperGenerator/OptionsHelper.cs | 2 +- .../XUnitWrapperGenerator.cs | 10 +- src/tests/Common/tests.targets | 16 +- src/tests/Interop/CMakeLists.txt | 1 + .../DisabledRuntimeMarshalling/AutoLayout.cs | 54 +++++ .../DisabledRuntimeMarshalling/CMakeLists.txt | 10 + .../DisabledRuntimeMarshallingNative.cpp | 64 +++++ ...ing_Disabled_NativeAssemblyDisabled.csproj | 13 ++ ...ling_Disabled_NativeAssemblyEnabled.csproj | 13 ++ ...lling_Disabled_NativeTypeInAssembly.csproj | 11 + ...ng_Disabled_NativeTypeInAssembly_ro.csproj | 14 ++ ...eMarshalling_NativeAssemblyDisabled.csproj | 14 ++ .../FunctionPointers.cs | 29 +++ .../DisabledRuntimeMarshallingNative.cs | 153 ++++++++++++ ...ledRuntimeMarshallingNative_Default.csproj | 10 + .../DisabledRuntimeMarshallingNative.cs | 190 +++++++++++++++ ...rshallingNative_DisabledMarshalling.csproj | 11 + .../Delegates.cs | 34 +++ .../PInvokes.cs | 151 ++++++++++++ .../UnmanagedCallersOnly.cs | 23 ++ .../Delegates.cs | 35 +++ .../PInvokes.cs | 96 ++++++++ .../UnmanagedCallersOnly.cs | 27 +++ .../RuntimeMarshallingDisabledAttribute.cs | 5 + src/tests/Interop/common/xplatform.h | 14 +- src/tests/issues.targets | 4 + 83 files changed, 1997 insertions(+), 262 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/DisableRuntimeMarshallingAttribute.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/AutoLayout.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/CMakeLists.txt create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshallingNative.cpp create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyDisabled.csproj create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyEnabled.csproj create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly.csproj create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly_ro.csproj create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_NativeAssemblyDisabled.csproj create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/FunctionPointers.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/Native_Default/DisabledRuntimeMarshallingNative.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/Native_Default/DisabledRuntimeMarshallingNative_Default.csproj create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/Native_DisabledMarshalling/DisabledRuntimeMarshallingNative.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/Native_DisabledMarshalling/DisabledRuntimeMarshallingNative_DisabledMarshalling.csproj create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/Delegates.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/PInvokes.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/UnmanagedCallersOnly.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/Delegates.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/PInvokes.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/UnmanagedCallersOnly.cs create mode 100644 src/tests/Interop/DisabledRuntimeMarshalling/RuntimeMarshallingDisabledAttribute.cs diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc index 0e78c99f38d5d..d2c7bff988cc8 100644 --- a/src/coreclr/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/dlls/mscorrc/mscorrc.rc @@ -194,6 +194,10 @@ BEGIN IDS_EE_NDIRECT_GETPROCADDR_WIN_DLL "Unable to find an entry point named '%1' in DLL." IDS_EE_NDIRECT_GETPROCADDR_UNIX_SO "Unable to find an entry point named '%1' in shared library." IDS_EE_NDIRECT_GETPROCADDRESS_NONAME "A library name must be specified in a DllImport attribute applied to non-IJW methods." + IDS_EE_NDIRECT_DISABLEDMARSHAL_SETLASTERROR "Setting SetLastError to 'true' is not supported when runtime marshalling is disabled." + IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID "The LCIDConversionAttribute is not supported when runtime marshalling is disabled." + IDS_EE_NDIRECT_DISABLEDMARSHAL_PRESERVESIG "Setting PreserveSig to false for a P/Invoke is not supported when runtime marshalling is disabled." + IDS_EE_NDIRECT_DISABLEDMARSHAL_VARARGS "Using a variable argument list in a P/Invoke is not supported when runtime marshalling is disabled." IDS_EE_CLASS_CONSTRAINTS_VIOLATION "GenericArguments[%1], '%2', on '%3' violates the constraint of type parameter '%4'." IDS_EE_METHOD_CONSTRAINTS_VIOLATION "Method %1.%2: type argument '%3' violates the constraint of type parameter '%4'." IDS_EE_NOSYNCHRONIZED "Synchronized attribute cannot be used with this method type." @@ -297,6 +301,7 @@ BEGIN IDS_EE_BADMARSHAL_GENERICS_RESTRICTION "Non-blittable generic types cannot be marshaled." IDS_EE_BADMARSHAL_AUTOLAYOUT "Structures marked with [StructLayout(LayoutKind.Auto)] cannot be marshaled." IDS_EE_BADMARSHAL_STRING_OUT "Cannot marshal a string by-value with the [Out] attribute." + IDS_EE_BADMARSHAL_MARSHAL_DISABLED "Cannot marshal managed types when the runtime marshalling system is disabled." IDS_EE_BADMARSHALPARAM_STRINGBUILDER "Invalid managed/unmanaged type combination (StringBuilders must be paired with LPStr, LPWStr, or LPTStr)." IDS_EE_BADMARSHALPARAM_NO_LPTSTR "Invalid managed/unmanaged type combination (Strings cannot be paired with LPTStr for parameters and return types of methods in interfaces exposed to COM)." diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h index 05b31799ec5c4..7a8f148456a83 100644 --- a/src/coreclr/dlls/mscorrc/resource.h +++ b/src/coreclr/dlls/mscorrc/resource.h @@ -588,3 +588,8 @@ #define IDS_EE_BADMARSHAL_DELEGATE_TLB_INTERFACE 0x2649 #define IDS_EE_THREAD_APARTMENT_NOT_SUPPORTED 0x264A #define IDS_EE_NO_IINSPECTABLE 0x264B +#define IDS_EE_BADMARSHAL_MARSHAL_DISABLED 0x264C +#define IDS_EE_NDIRECT_DISABLEDMARSHAL_SETLASTERROR 0x264D +#define IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID 0x264E +#define IDS_EE_NDIRECT_DISABLEDMARSHAL_PRESERVESIG 0x264F +#define IDS_EE_NDIRECT_DISABLEDMARSHAL_VARARGS 0x2650 diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 30189ccc4cb52..cd464db795534 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -658,7 +658,7 @@ private bool Get_CORINFO_METHOD_INFO(MethodDesc method, MethodIL methodIL, CORIN methodInfo->options |= CorInfoOptions.CORINFO_GENERICS_CTXT_FROM_METHODTABLE; } methodInfo->regionKind = CorInfoRegionKind.CORINFO_REGION_NONE; - Get_CORINFO_SIG_INFO(method, sig: &methodInfo->args); + Get_CORINFO_SIG_INFO(method, sig: &methodInfo->args, methodIL); Get_CORINFO_SIG_INFO(methodIL.GetLocals(), &methodInfo->locals); return true; @@ -683,9 +683,9 @@ private bool Get_CORINFO_METHOD_INFO(MethodDesc method, MethodIL methodIL, CORIN return (CORINFO_CLASS_STRUCT_**)GetPin(jitVisibleInstantiation); } - private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, bool suppressHiddenArgument = false) + private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, MethodILScope scope, bool suppressHiddenArgument = false) { - Get_CORINFO_SIG_INFO(method.Signature, sig); + Get_CORINFO_SIG_INFO(method.Signature, sig, scope); // Does the method have a hidden parameter? bool hasHiddenParameter = !suppressHiddenArgument && method.RequiresInstArg(); @@ -845,7 +845,7 @@ private static CorInfoCallConvExtension GetMemberFunctionCallingConventionVarian var c => c }; - private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* sig) + private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* sig, MethodILScope scope) { sig->callConv = (CorInfoCallConv)(signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask); @@ -875,7 +875,7 @@ private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* s sig->pSig = null; sig->cbSig = 0; // Not used by the JIT sig->methodSignature = ObjectToHandle(signature); - sig->scope = null; + sig->scope = scope is not null ? ObjectToHandle(scope) : null; // scope can be null for internal calls and COM methods. sig->token = 0; // Not used by the JIT } @@ -1149,7 +1149,7 @@ private void getMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CO } } - Get_CORINFO_SIG_INFO(method, sig: sig); + Get_CORINFO_SIG_INFO(method, sig: sig, scope: null); } private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info) @@ -1795,7 +1795,7 @@ private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEX var methodIL = HandleToObject(module); var methodSig = (MethodSignature)methodIL.GetObject((int)sigTOK); - Get_CORINFO_SIG_INFO(methodSig, sig); + Get_CORINFO_SIG_INFO(methodSig, sig, methodIL); #if !READYTORUN // Check whether we need to report this as a fat pointer call @@ -1811,7 +1811,7 @@ private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEX private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) { var methodIL = HandleToObject(module); - Get_CORINFO_SIG_INFO(((MethodDesc)methodIL.GetObject((int)methTOK)), sig: sig); + Get_CORINFO_SIG_INFO(((MethodDesc)methodIL.GetObject((int)methTOK)), sig: sig, methodIL); } private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) @@ -3745,7 +3745,7 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) #if READYTORUN // TODO: enable this check in full AOT - if (Marshaller.IsMarshallingRequired(this.MethodBeingCompiled.Signature, Array.Empty())) // Only blittable arguments + if (Marshaller.IsMarshallingRequired(this.MethodBeingCompiled.Signature, Array.Empty(), ((MetadataType)this.MethodBeingCompiled.OwningType).Module)) // Only blittable arguments { ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramNonBlittableTypes, this.MethodBeingCompiled); } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs b/src/coreclr/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs index 71c7423b8fbb0..2190f9ac1a278 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs @@ -63,6 +63,11 @@ private static class FieldLayoutFlags /// True if type transitively has UnsafeValueTypeAttribute /// public const int IsUnsafeValueType = 0x200; + + /// + /// True if the type transitively has any types with LayoutKind.Auto in its layout. + /// + public const int IsAutoLayoutOrHasAutoLayoutFields = 0x400; } private class StaticBlockInfo @@ -115,6 +120,21 @@ public bool IsUnsafeValueType } } + /// + /// Does a type have auto-layout or transitively have any fields of a type with auto-layout. + /// + public virtual bool IsAutoLayoutOrHasAutoLayoutFields + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout)) + { + ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields); + } + return _fieldLayoutFlags.HasFlags(FieldLayoutFlags.IsAutoLayoutOrHasAutoLayoutFields); + } + } + /// /// The number of bytes required to hold a field of this type @@ -406,6 +426,10 @@ public void ComputeInstanceLayout(InstanceLayoutKind layoutKind) { _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedInstanceLayoutAbiUnstable); } + if (computedLayout.IsAutoLayoutOrHasAutoLayoutFields) + { + _fieldLayoutFlags.AddFlags(FieldLayoutFlags.IsAutoLayoutOrHasAutoLayoutFields); + } if (computedLayout.Offsets != null) { diff --git a/src/coreclr/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs index 863e857a21def..a19ec4b3603bf 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs @@ -82,6 +82,7 @@ public struct ComputedInstanceFieldLayout public LayoutInt ByteCountUnaligned; public LayoutInt ByteCountAlignment; public bool LayoutAbiStable; // Is the layout stable such that it can safely be used in function calling conventions + public bool IsAutoLayoutOrHasAutoLayoutFields; /// /// If Offsets is non-null, then all field based layout is complete. diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 249faef7cd040..9973be45ff130 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -112,7 +112,8 @@ out instanceByteSizeAndAlignment ByteCountAlignment = instanceByteSizeAndAlignment.Alignment, FieldAlignment = sizeAndAlignment.Alignment, FieldSize = sizeAndAlignment.Size, - LayoutAbiStable = true + LayoutAbiStable = true, + IsAutoLayoutOrHasAutoLayoutFields = false, }; if (numInstanceFields > 0) @@ -214,7 +215,7 @@ public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defTy } ref StaticsBlock block = ref GetStaticsBlockForField(ref result, field); - SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout: false, context.Target.DefaultPackingSize, out bool _); + SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout: false, context.Target.DefaultPackingSize, out bool _, out bool _); block.Size = LayoutInt.AlignUp(block.Size, sizeAndAlignment.Alignment, context.Target); result.Offsets[index] = new FieldAndOffset(field, block.Size); @@ -305,13 +306,16 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty var offsets = new FieldAndOffset[numInstanceFields]; int fieldOrdinal = 0; bool layoutAbiStable = true; + bool hasAutoLayoutField = false; foreach (var fieldAndOffset in layoutMetadata.Offsets) { TypeDesc fieldType = fieldAndOffset.Field.FieldType; - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType.UnderlyingType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType.UnderlyingType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable, out bool fieldHasAutoLayout); if (!fieldLayoutAbiStable) layoutAbiStable = false; + if (fieldHasAutoLayout) + hasAutoLayoutField = true; largestAlignmentRequired = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequired); @@ -354,7 +358,10 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty layoutMetadata.Size, out instanceByteSizeAndAlignment); - ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); + ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout + { + IsAutoLayoutOrHasAutoLayoutFields = hasAutoLayoutField, + }; computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; computedLayout.FieldSize = instanceSizeAndAlignment.Size; computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size; @@ -388,15 +395,18 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType int fieldOrdinal = 0; int packingSize = ComputePackingSize(type, layoutMetadata); bool layoutAbiStable = true; + bool hasAutoLayoutField = false; foreach (var field in type.GetFields()) { if (field.IsStatic) continue; - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType.UnderlyingType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType.UnderlyingType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable, out bool fieldHasAutoLayout); if (!fieldLayoutAbiStable) layoutAbiStable = false; + if (fieldHasAutoLayout) + hasAutoLayoutField = true; largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement); @@ -415,7 +425,10 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType layoutMetadata.Size, out instanceByteSizeAndAlignment); - ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); + ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout + { + IsAutoLayoutOrHasAutoLayoutFields = hasAutoLayoutField, + }; computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; computedLayout.FieldSize = instanceSizeAndAlignment.Size; computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size; @@ -470,7 +483,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, { Debug.Assert(fieldType.IsPrimitive || fieldType.IsPointer || fieldType.IsFunctionPointer || fieldType.IsEnum); - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout, packingSize, out bool _); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout, packingSize, out bool _, out bool _); instanceNonGCPointerFieldsCount[CalculateLog2(fieldSizeAndAlignment.Size.AsInt)]++; } } @@ -507,7 +520,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, TypeDesc fieldType = field.FieldType; - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout, packingSize, out bool fieldLayoutAbiStable, out bool _); if (!fieldLayoutAbiStable) layoutAbiStable = false; @@ -646,7 +659,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, for (int i = 0; i < instanceValueClassFieldsArr.Length; i++) { // Align the cumulative field offset to the indeterminate value - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(instanceValueClassFieldsArr[i].FieldType, hasLayout, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(instanceValueClassFieldsArr[i].FieldType, hasLayout, packingSize, out bool fieldLayoutAbiStable, out bool _); if (!fieldLayoutAbiStable) layoutAbiStable = false; @@ -694,7 +707,10 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, classLayoutSize: 0, byteCount: out instanceByteSizeAndAlignment); - ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); + ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout + { + IsAutoLayoutOrHasAutoLayoutFields = true, + }; computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; computedLayout.FieldSize = instanceSizeAndAlignment.Size; computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size; @@ -707,7 +723,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, private static void PlaceInstanceField(FieldDesc field, bool hasLayout, int packingSize, FieldAndOffset[] offsets, ref LayoutInt instanceFieldPos, ref int fieldOrdinal, LayoutInt offsetBias) { - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, hasLayout, packingSize, out bool _); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, hasLayout, packingSize, out bool _, out bool _); instanceFieldPos = AlignUpInstanceFieldOffset(field.OwningType, instanceFieldPos, fieldSizeAndAlignment.Alignment, field.Context.Target); offsets[fieldOrdinal] = new FieldAndOffset(field, instanceFieldPos + offsetBias); @@ -767,10 +783,11 @@ public LayoutInt CalculateFieldBaseOffset(MetadataType type, bool requiresAlign8 return cumulativeInstanceFieldPos; } - private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, bool hasLayout, int packingSize, out bool layoutAbiStable) + private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, bool hasLayout, int packingSize, out bool layoutAbiStable, out bool fieldTypeHasAutoLayout) { SizeAndAlignment result; layoutAbiStable = true; + fieldTypeHasAutoLayout = true; if (fieldType.IsDefType) { @@ -780,6 +797,7 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, result.Size = defType.InstanceFieldSize; result.Alignment = defType.InstanceFieldAlignment; layoutAbiStable = defType.LayoutAbiStable; + fieldTypeHasAutoLayout = defType.IsAutoLayoutOrHasAutoLayoutFields; } else { diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs index 0e155fda998f3..5a281d21ba11a 100644 --- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs +++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs @@ -67,7 +67,7 @@ public override string ToString() public bool HasAssemblyCustomAttribute(string attributeNamespace, string attributeName) { - return _metadataReader.GetCustomAttributeHandle(_assemblyDefinition.GetCustomAttributes(), + return !_metadataReader.GetCustomAttributeHandle(_assemblyDefinition.GetCustomAttributes(), attributeNamespace, attributeName).IsNil; } } diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.Mangling.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.Mangling.cs index c68f9a10fe2fa..dd91b65fa9079 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.Mangling.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.Mangling.cs @@ -20,7 +20,7 @@ string IPrefixMangledSignature.Prefix { get { - return "Calli"; + return RuntimeMarshallingEnabled ? "CalliWithRuntimeMarshalling" : "Calli"; } } } diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.Sorting.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.Sorting.cs index 89be9fa3a7d88..cd6e620aa8607 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.Sorting.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.Sorting.cs @@ -13,6 +13,11 @@ partial class CalliMarshallingMethodThunk protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) { var otherMethod = (CalliMarshallingMethodThunk)other; + int result = RuntimeMarshallingEnabled.CompareTo(otherMethod.RuntimeMarshallingEnabled); + if (result != 0) + { + return result; + } return comparer.Compare(_targetSignature, otherMethod._targetSignature); } } diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.cs index bdbd7b67998f4..d0d397bafdf38 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/CalliMarshallingMethodThunk.cs @@ -21,11 +21,13 @@ public partial class CalliMarshallingMethodThunk : ILStubMethod private MethodSignature _signature; public CalliMarshallingMethodThunk(MethodSignature targetSignature, TypeDesc owningType, - InteropStateManager interopStateManager) + InteropStateManager interopStateManager, + bool runtimeMarshallingEnabled) { _targetSignature = targetSignature; _owningType = owningType; _interopStateManager = interopStateManager; + RuntimeMarshallingEnabled = runtimeMarshallingEnabled; } public MethodSignature TargetSignature @@ -87,6 +89,8 @@ public override string DiagnosticName } } + public bool RuntimeMarshallingEnabled { get; } + public override PInvokeMetadata GetPInvokeMethodMetadata() { // Return PInvokeAttributes.PreserveSig to circumvent marshalling required checks diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs index d77bb5994ec0e..81245ffe82515 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs @@ -12,11 +12,6 @@ namespace Internal.IL.Stubs { /// /// Provides method bodies for PInvoke methods - /// - /// This by no means intends to provide full PInvoke support. The intended use of this is to - /// a) prevent calls getting generated to targets that require a full marshaller - /// (this compiler doesn't provide that), and b) offer a hand in some very simple marshalling - /// situations (but support for this part might go away as the product matures). /// public struct PInvokeILEmitter { @@ -55,23 +50,27 @@ private static Marshaller[] InitializeMarshallers(MethodDesc targetMethod, Inter { MarshalDirection direction = MarshalDirection.Forward; MethodSignature methodSig; + bool runtimeMarshallingEnabled; switch (targetMethod) { case DelegateMarshallingMethodThunk delegateMethod: methodSig = delegateMethod.DelegateSignature; direction = delegateMethod.Direction; + runtimeMarshallingEnabled = MarshalHelpers.IsRuntimeMarshallingEnabled(delegateMethod.DelegateType.Module); break; case CalliMarshallingMethodThunk calliMethod: methodSig = calliMethod.TargetSignature; + runtimeMarshallingEnabled = calliMethod.RuntimeMarshallingEnabled; break; default: methodSig = targetMethod.Signature; + runtimeMarshallingEnabled = MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)targetMethod.OwningType).Module); break; } int indexOffset = 0; if (!methodSig.IsStatic && direction == MarshalDirection.Forward) { - // For instance methods(eg. Forward delegate marshalling thunk), first argument is + // For instance methods(eg. Forward delegate marshalling thunk), first argument is // the instance indexOffset = 1; } @@ -88,7 +87,7 @@ private static Marshaller[] InitializeMarshallers(MethodDesc targetMethod, Inter // if we don't have metadata for the parameter, create a dummy one parameterMetadata = new ParameterMetadata(i, ParameterMetadataAttributes.None, null); } - else + else { Debug.Assert(i == parameterMetadataArray[parameterIndex].Index); parameterMetadata = parameterMetadataArray[parameterIndex++]; @@ -104,7 +103,7 @@ private static Marshaller[] InitializeMarshallers(MethodDesc targetMethod, Inter { // PreserveSig = false can only show up an regular forward PInvokes Debug.Assert(direction == MarshalDirection.Forward); - + parameterType = methodSig.Context.GetByRefType(parameterType); isHRSwappedRetVal = true; } @@ -114,20 +113,35 @@ private static Marshaller[] InitializeMarshallers(MethodDesc targetMethod, Inter parameterType = methodSig[i - 1]; } - marshallers[i] = Marshaller.CreateMarshaller(parameterType, - parameterIndex, - methodSig.GetEmbeddedSignatureData(), - MarshallerType.Argument, - parameterMetadata.MarshalAsDescriptor, - direction, - marshallers, - interopStateManager, - indexOffset + parameterMetadata.Index, - flags, - parameterMetadata.In, - isHRSwappedRetVal ? true : parameterMetadata.Out, - isHRSwappedRetVal ? false : parameterMetadata.Return - ); + if (runtimeMarshallingEnabled) + { + marshallers[i] = Marshaller.CreateMarshaller(parameterType, + parameterIndex, + methodSig.GetEmbeddedSignatureData(), + MarshallerType.Argument, + parameterMetadata.MarshalAsDescriptor, + direction, + marshallers, + interopStateManager, + indexOffset + parameterMetadata.Index, + flags, + parameterMetadata.In, + isHRSwappedRetVal ? true : parameterMetadata.Out, + isHRSwappedRetVal ? false : parameterMetadata.Return + ); + } + else + { + marshallers[i] = Marshaller.CreateDisabledMarshaller( + parameterType, + parameterIndex, + MarshallerType.Argument, + direction, + marshallers, + indexOffset + parameterMetadata.Index, + flags, + parameterMetadata.Return); + } } return marshallers; @@ -146,10 +160,10 @@ private void EmitDelegateCall(DelegateMarshallingMethodThunk delegateMethod, PIn if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind.ReverseOpenStatic) { // - // For Open static delegates call + // For Open static delegates call // InteropHelpers.GetCurrentCalleeOpenStaticDelegateFunctionPointer() // which returns a function pointer. Just call the function pointer and we are done. - // + // TypeDesc[] parameters = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { @@ -193,7 +207,7 @@ private void EmitDelegateCall(DelegateMarshallingMethodThunk delegateMethod, PIn else if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind .ForwardNativeFunctionWrapper) { - // if the SetLastError flag is set in UnmanagedFunctionPointerAttribute, clear the error code before doing P/Invoke + // if the SetLastError flag is set in UnmanagedFunctionPointerAttribute, clear the error code before doing P/Invoke if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( @@ -225,7 +239,7 @@ private void EmitDelegateCall(DelegateMarshallingMethodThunk delegateMethod, PIn MethodSignatureFlags unmanagedCallingConvention = _flags.UnmanagedCallingConvention; if (unmanagedCallingConvention == MethodSignatureFlags.None) unmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConvention; - + MethodSignature nativeSig = new MethodSignature( MethodSignatureFlags.Static | unmanagedCallingConvention, 0, nativeReturnType, nativeParameterTypes); @@ -257,9 +271,16 @@ private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) TypeDesc nativeReturnType = _flags.PreserveSig ? _marshallers[0].NativeParameterType : context.GetWellKnownType(WellKnownType.Int32); TypeDesc[] nativeParameterTypes = new TypeDesc[isHRSwappedRetVal ? _marshallers.Length : _marshallers.Length - 1]; - // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke + bool runtimeMarshallingEnabled = MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)_targetMethod.OwningType).Module); + + // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_flags.SetLastError) { + if (!runtimeMarshallingEnabled) + { + // When runtime marshalling is disabled, we don't support SetLastError + throw new NotSupportedException(); + } callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastError", null))); } @@ -271,6 +292,11 @@ private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) if (isHRSwappedRetVal) { + if (!runtimeMarshallingEnabled) + { + // When runtime marshalling is disabled, we don't support HResult-return-swapping + throw new NotSupportedException(); + } nativeParameterTypes[_marshallers.Length - 1] = _marshallers[0].NativeParameterType; } @@ -364,6 +390,9 @@ private void EmitCalli(PInvokeILCodeStreams ilCodeStreams, CalliMarshallingMetho private MethodIL EmitIL() { + if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute")) + throw new NotSupportedException(); + PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream marshallingCodestream = pInvokeILCodeStreams.MarshallingCodeStream; @@ -417,8 +446,8 @@ private MethodIL EmitIL() return new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired()); } - public static MethodIL EmitIL(MethodDesc method, - PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration, + public static MethodIL EmitIL(MethodDesc method, + PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration, InteropStateManager interopStateManager) { try diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.Aot.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.Aot.cs index 8925f9964b093..b047f29e9ec64 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.Aot.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.Aot.cs @@ -126,7 +126,7 @@ public static MethodIL EmitExceptionBody(string message, MethodDesc method) TypeSystemContext context = method.Context; MethodSignature ctorSignature = new MethodSignature(0, 0, context.GetWellKnownType(WellKnownType.Void), new TypeDesc[] { context.GetWellKnownType(WellKnownType.String) }); - MethodDesc exceptionCtor = method.Context.GetWellKnownType(WellKnownType.Exception).GetKnownMethod(".ctor", ctorSignature); + MethodDesc exceptionCtor = InteropTypes.GetMarshalDirectiveException(context).GetKnownMethod(".ctor", ctorSignature); ILCodeStream codeStream = emitter.NewCodeStream(); codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(message)); diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs index f23a4479634a9..b50d0406129ba 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs @@ -5,6 +5,7 @@ using Internal.IL; using Debug = System.Diagnostics.Debug; using Internal.IL.Stubs; +using Internal.TypeSystem.Ecma; namespace Internal.TypeSystem.Interop { @@ -75,6 +76,7 @@ internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type, #if !READYTORUN case MarshallerKind.Struct: case MarshallerKind.LayoutClass: + Debug.Assert(interopStateManager is not null, "An InteropStateManager is required to look up the native representation of a non-blittable struct or class with layout."); return interopStateManager.GetStructMarshallingNativeType((MetadataType)type); #endif @@ -844,6 +846,37 @@ private static MarshallerKind GetArrayElementMarshallerKind( } } + internal static MarshallerKind GetDisabledMarshallerKind( + TypeDesc type) + { + if (type.Category == TypeFlags.Void) + { + return MarshallerKind.VoidReturn; + } + else if (type.IsByRef) + { + // Managed refs are not supported when runtime marshalling is disabled. + return MarshallerKind.Invalid; + } + else if (type.IsPrimitive) + { + return MarshallerKind.BlittableValue; + } + else if (type.IsPointer || type.IsFunctionPointer) + { + return MarshallerKind.BlittableValue; + } + else if (type.IsValueType) + { + var defType = (DefType)type; + if (!defType.ContainsGCPointers && !defType.IsAutoLayoutOrHasAutoLayoutFields) + { + return MarshallerKind.BlittableValue; + } + } + return MarshallerKind.Invalid; + } + internal static bool ShouldCheckForPendingException(TargetDetails target, PInvokeMetadata metadata) { if (!target.IsOSX) @@ -861,5 +894,10 @@ internal static bool ShouldCheckForPendingException(TargetDetails target, PInvok return metadata.Module.Equals(ObjectiveCLibrary) && metadata.Name.StartsWith(ObjectiveCMsgSend); } + + public static bool IsRuntimeMarshallingEnabled(ModuleDesc module) + { + return module.Assembly is not EcmaAssembly assembly || !assembly.HasAssemblyCustomAttribute("System.Runtime.CompilerServices", "DisableRuntimeMarshallingAttribute"); + } } } diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs index ea0494643a14a..7b7e3a24d9813 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs @@ -329,6 +329,44 @@ public static Marshaller CreateMarshaller(TypeDesc parameterType, return marshaller; } + + /// + /// Create a marshaller + /// + /// type of the parameter to marshal + /// The created Marshaller + public static Marshaller CreateDisabledMarshaller(TypeDesc parameterType, + int? parameterIndex, + MarshallerType marshallerType, + MarshalDirection direction, + Marshaller[] marshallers, + int index, + PInvokeFlags flags, + bool isReturn) + { + MarshallerKind marshallerKind = MarshalHelpers.GetDisabledMarshallerKind(parameterType); + + TypeSystemContext context = parameterType.Context; + // Create the marshaller based on MarshallerKind + Marshaller marshaller = CreateMarshaller(marshallerKind); + marshaller.Context = context; + marshaller.MarshallerKind = marshallerKind; + marshaller.MarshallerType = marshallerType; + marshaller.ElementMarshallerKind = MarshallerKind.Unknown; + marshaller.ManagedParameterType = parameterType; + marshaller.ManagedType = parameterType; + marshaller.Return = isReturn; + marshaller.IsManagedByRef = false; + marshaller.IsNativeByRef = false; + marshaller.MarshalDirection = direction; + marshaller.MarshalAsDescriptor = null; + marshaller.Marshallers = marshallers; + marshaller.Index = index; + marshaller.PInvokeFlags = flags; + marshaller.In = true; + marshaller.Out = false; + return marshaller; + } #endregion @@ -1560,7 +1598,7 @@ protected override void EmitCleanupManaged(ILCodeStream codeStream) class AnsiStringMarshaller : Marshaller { #if READYTORUN - const int MAX_LOCAL_BUFFER_LENGTH = 260 + 1; // MAX_PATH + 1 + const int MAX_LOCAL_BUFFER_LENGTH = 260 + 1; // MAX_PATH + 1 private ILLocalVariable? _localBuffer = null; #endif @@ -1597,7 +1635,7 @@ protected override void TransformManagedToNative(ILCodeStream codeStream) .GetKnownMethod("ConvertToNative", null); bool bPassByValueInOnly = In && !Out && !IsManagedByRef; - + if (bPassByValueInOnly) { var bufSize = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); @@ -1632,7 +1670,7 @@ protected override void TransformManagedToNative(ILCodeStream codeStream) codeStream.EmitStLoc(bufSize); // if (MAX_LOCAL_BUFFER_LENGTH < BufSize ) goto NoOptimize - codeStream.EmitLdc(MAX_LOCAL_BUFFER_LENGTH + 1); + codeStream.EmitLdc(MAX_LOCAL_BUFFER_LENGTH + 1); codeStream.EmitLdLoc(bufSize); codeStream.Emit(ILOpcode.clt); codeStream.Emit(ILOpcode.brtrue, noOptimize); diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/InteropStateManager.cs b/src/coreclr/tools/Common/TypeSystem/Interop/InteropStateManager.cs index 202fcce90bece..0d594010328e6 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/InteropStateManager.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/InteropStateManager.cs @@ -38,7 +38,7 @@ public InteropStateManager(ModuleDesc generatedAssembly) // // Delegate Marshalling Stubs // - + /// /// Generates marshalling stubs for open static delegates /// @@ -105,9 +105,9 @@ public PInvokeDelegateWrapper GetPInvokeDelegateWrapper(TypeDesc delegateType) } // - // Struct Marshalling + // Struct Marshalling // To support struct marshalling compiler needs to generate a native type which - // imitates the original struct being passed to managed side with corresponding + // imitates the original struct being passed to managed side with corresponding // fields of marshalled types. Additionally it needs to generate three thunks // 1. Managed to Native Thunk: For forward marshalling // 2. Native to Managed Thunk: For reverse marshalling @@ -186,9 +186,9 @@ public FieldDesc GetPInvokeLazyFixupField(MethodDesc method) return _pInvokeLazyFixupFieldHashtable.GetOrCreateValue(method); } - public MethodDesc GetPInvokeCalliStub(MethodSignature signature) + public MethodDesc GetPInvokeCalliStub(MethodSignature signature, ModuleDesc moduleContext) { - return _pInvokeCalliHashtable.GetOrCreateValue(signature); + return _pInvokeCalliHashtable.GetOrCreateValue(new CalliMarshallingMethodThunkKey(signature, MarshalHelpers.IsRuntimeMarshallingEnabled(moduleContext))); } private class NativeStructTypeHashtable : LockFreeReaderHashtable @@ -355,7 +355,7 @@ protected override bool CompareValueToValue(DelegateMarshallingMethodThunk value protected override DelegateMarshallingMethodThunk CreateValueFromKey(DelegateMarshallingStubHashtableKey key) { - return new DelegateMarshallingMethodThunk(key.DelegateType, _owningType, + return new DelegateMarshallingMethodThunk(key.DelegateType, _owningType, _interopStateManager, key.Kind); } @@ -478,34 +478,36 @@ public PInvokeLazyFixupFieldHashtable(DefType owningType) } } - private class PInvokeCalliHashtable : LockFreeReaderHashtable + private readonly record struct CalliMarshallingMethodThunkKey(MethodSignature Signature, bool RuntimeMarshallingEnabled); + + private class PInvokeCalliHashtable : LockFreeReaderHashtable { private readonly InteropStateManager _interopStateManager; private readonly TypeDesc _owningType; - protected override int GetKeyHashCode(MethodSignature key) + protected override int GetKeyHashCode(CalliMarshallingMethodThunkKey key) { return key.GetHashCode(); } protected override int GetValueHashCode(CalliMarshallingMethodThunk value) { - return value.TargetSignature.GetHashCode(); + return new CalliMarshallingMethodThunkKey(value.TargetSignature, value.RuntimeMarshallingEnabled).GetHashCode(); } - protected override bool CompareKeyToValue(MethodSignature key, CalliMarshallingMethodThunk value) + protected override bool CompareKeyToValue(CalliMarshallingMethodThunkKey key, CalliMarshallingMethodThunk value) { - return key.Equals(value.TargetSignature); + return key.Signature.Equals(value.TargetSignature) && key.RuntimeMarshallingEnabled == value.RuntimeMarshallingEnabled; } protected override bool CompareValueToValue(CalliMarshallingMethodThunk value1, CalliMarshallingMethodThunk value2) { - return value1.TargetSignature.Equals(value2.TargetSignature); + return value1.TargetSignature.Equals(value2.TargetSignature) && value1.RuntimeMarshallingEnabled == value2.RuntimeMarshallingEnabled; } - protected override CalliMarshallingMethodThunk CreateValueFromKey(MethodSignature key) + protected override CalliMarshallingMethodThunk CreateValueFromKey(CalliMarshallingMethodThunkKey key) { - return new CalliMarshallingMethodThunk(key, _owningType, _interopStateManager); + return new CalliMarshallingMethodThunk(key.Signature, _owningType, _interopStateManager, key.RuntimeMarshallingEnabled); } public PInvokeCalliHashtable(InteropStateManager interopStateManager, TypeDesc owningType) diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs b/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs index 96ffe8868422d..ac32fbbe54647 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs @@ -54,6 +54,11 @@ public static MetadataType GetNativeFunctionPointerWrapper(TypeSystemContext con return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "NativeFunctionPointerWrapper"); } + public static MetadataType GetMarshalDirectiveException(TypeSystemContext context) + { + return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "MarshalDirectiveException"); + } + public static MetadataType GetVariant(TypeSystemContext context) { return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "Variant"); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedInteropStubManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedInteropStubManager.cs index fe42b62526b77..e1c1362e109c0 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedInteropStubManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedInteropStubManager.cs @@ -30,7 +30,7 @@ public UsageBasedInteropStubManager(InteropStateManager interopStateManager, PIn public override void AddDependeciesDueToPInvoke(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { - if (method.IsPInvoke) + if (method.IsPInvoke && method.OwningType is MetadataType type && MarshalHelpers.IsRuntimeMarshallingEnabled(type.Module)) { dependencies = dependencies ?? new DependencyList(); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/PInvokeILProvider.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/PInvokeILProvider.cs index 830fb11d1ef21..93fb4cc376c07 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/PInvokeILProvider.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/PInvokeILProvider.cs @@ -30,9 +30,9 @@ public override MethodIL GetMethodIL(MethodDesc method) return PInvokeILEmitter.EmitIL(method, _pInvokeILEmitterConfiguration, _interopStateManager); } - public MethodDesc GetCalliStub(MethodSignature signature) + public MethodDesc GetCalliStub(MethodSignature signature, ModuleDesc moduleContext) { - return _interopStateManager.GetPInvokeCalliStub(signature); + return _interopStateManager.GetPInvokeCalliStub(signature, moduleContext); } public string GetDirectCallExternName(MethodDesc method) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/Stubs/PInvokeILEmitter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/Stubs/PInvokeILEmitter.cs index a8e42ec37b9bc..6fc1687d7a7f9 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/Stubs/PInvokeILEmitter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/Stubs/PInvokeILEmitter.cs @@ -46,6 +46,13 @@ private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_importMetadata.Flags.SetLastError) { + if (!MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)_targetMethod.OwningType).Module)) + { + // When runtime marshalling is disabled, we don't support generating the stub IL + // in Ready-to-Run so we can correctly throw an exception at runtime when the user tries to + // use SetLastError=true when marshalling is disabled. + throw new NotSupportedException(); + } callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( stubHelpersType.GetKnownMethod("ClearLastError", null))); } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs index 927148cf006e2..ddb1d24c1b535 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs @@ -43,7 +43,8 @@ protected static Marshaller CreateMarshaller(MarshallerKind kind) private static Marshaller[] GetMarshallers( MethodSignature methodSig, PInvokeFlags flags, - ParameterMetadata[] parameterMetadataArray) + ParameterMetadata[] parameterMetadataArray, + bool runtimeMarshallingEnabled) { Marshaller[] marshallers = new Marshaller[methodSig.Length + 1]; @@ -64,39 +65,55 @@ private static Marshaller[] GetMarshallers( } TypeDesc parameterType = (i == 0) ? methodSig.ReturnType : methodSig[i - 1]; //first item is the return type - marshallers[i] = CreateMarshaller(parameterType, - parameterIndex, - methodSig.GetEmbeddedSignatureData(), - MarshallerType.Argument, - parameterMetadata.MarshalAsDescriptor, - MarshalDirection.Forward, - marshallers, - parameterMetadata.Index, - flags, - parameterMetadata.In, - parameterMetadata.Out, - parameterMetadata.Return); + if (runtimeMarshallingEnabled) + { + marshallers[i] = CreateMarshaller(parameterType, + parameterIndex, + methodSig.GetEmbeddedSignatureData(), + MarshallerType.Argument, + parameterMetadata.MarshalAsDescriptor, + MarshalDirection.Forward, + marshallers, + parameterMetadata.Index, + flags, + parameterMetadata.In, + parameterMetadata.Out, + parameterMetadata.Return); + } + else + { + marshallers[i] = CreateDisabledMarshaller( + parameterType, + parameterIndex, + MarshallerType.Argument, + MarshalDirection.Forward, + marshallers, + parameterMetadata.Index, + flags, + parameterMetadata.Return); + } } return marshallers; } - public static Marshaller[] GetMarshallersForMethod(MethodDesc targetMethod) { Debug.Assert(targetMethod.IsPInvoke); return GetMarshallers( targetMethod.Signature, targetMethod.GetPInvokeMethodMetadata().Flags, - targetMethod.GetParameterMetadata()); + targetMethod.GetParameterMetadata(), + MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)targetMethod.OwningType).Module)); } - public static Marshaller[] GetMarshallersForSignature(MethodSignature methodSig, ParameterMetadata[] paramMetadata) + public static Marshaller[] GetMarshallersForSignature(MethodSignature methodSig, ParameterMetadata[] paramMetadata, ModuleDesc moduleContext) { return GetMarshallers( methodSig, new PInvokeFlags(PInvokeAttributes.None), - paramMetadata); + paramMetadata, + MarshalHelpers.IsRuntimeMarshallingEnabled(moduleContext)); } public static bool IsMarshallingRequired(MethodDesc targetMethod) @@ -128,9 +145,9 @@ public static bool IsMarshallingRequired(MethodDesc targetMethod) return false; } - public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMetadata[] paramMetadata) + public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMetadata[] paramMetadata, ModuleDesc moduleContext) { - Marshaller[] marshallers = GetMarshallersForSignature(methodSig, paramMetadata); + Marshaller[] marshallers = GetMarshallersForSignature(methodSig, paramMetadata, moduleContext); for (int i = 0; i < marshallers.Length; i++) { if (marshallers[i].IsMarshallingRequired()) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index f8282ab82cd27..c2dcc6b397016 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -1811,7 +1811,7 @@ private void ceeInfoGetCallInfo( pResult->wrapperDelegateInvoke = false; - Get_CORINFO_SIG_INFO(methodToCall, &pResult->sig, useInstantiatingStub); + Get_CORINFO_SIG_INFO(methodToCall, &pResult->sig, scope: null, useInstantiatingStub); } private uint getMethodAttribs(CORINFO_METHOD_STRUCT_* ftn) @@ -2579,7 +2579,7 @@ private bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* handle, CORINFO_S else { var sig = HandleToObject(callSiteSig->methodSignature); - return Marshaller.IsMarshallingRequired(sig, Array.Empty()); + return Marshaller.IsMarshallingRequired(sig, Array.Empty(), ((MetadataType)HandleToObject(callSiteSig->scope).OwningMethod.OwningType).Module); } } diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index 5966efead0066..1b1fbdf550777 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -1027,7 +1027,7 @@ private CorInfoHelpFunc getNewHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, TypeDesc type = HandleToObject(pResolvedToken.hClass); Debug.Assert(!type.IsString && !type.IsArray && !type.IsCanonicalDefinitionType(CanonicalFormKind.Any)); - + pHasSideEffects = type.HasFinalizer; if (type.RequiresAlign8()) @@ -1520,7 +1520,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO targetIsFatFunctionPointer |= (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_CALLVIRT) != 0 && !(pResult->kind == CORINFO_CALL_KIND.CORINFO_CALL); - Get_CORINFO_SIG_INFO(targetMethod, &pResult->sig, targetIsFatFunctionPointer); + Get_CORINFO_SIG_INFO(targetMethod, &pResult->sig, scope: null, targetIsFatFunctionPointer); if (useFatCallTransform) { pResult->sig.flags |= CorInfoSigInfoFlags.CORINFO_SIGFLAG_FAT_CALL; @@ -1531,7 +1531,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO if (pResult->hMethod != pResolvedToken.hMethod) { pResult->verMethodFlags = getMethodAttribsInternal(targetMethod); - Get_CORINFO_SIG_INFO(targetMethod, &pResult->verSig); + Get_CORINFO_SIG_INFO(targetMethod, &pResult->verSig, scope: null); } else { @@ -1791,7 +1791,9 @@ private bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* handle, CORINFO_S #if DEBUG MethodSignature methodSignature = (MethodSignature)HandleToObject((IntPtr)callSiteSig->pSig); - MethodDesc stub = _compilation.PInvokeILProvider.GetCalliStub(methodSignature); + MethodDesc stub = _compilation.PInvokeILProvider.GetCalliStub( + methodSignature, + ((MetadataType)HandleToObject(callSiteSig->scope).OwningMethod.OwningType).Module); Debug.Assert(!IsPInvokeStubRequired(stub)); #endif @@ -1825,7 +1827,9 @@ private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken if ((signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask) == 0) return false; - MethodDesc stub = _compilation.PInvokeILProvider.GetCalliStub(signature); + MethodDesc stub = _compilation.PInvokeILProvider.GetCalliStub( + signature, + ((MetadataType)methodIL.OwningMethod.OwningType).Module); if (!mustConvert && !IsPInvokeStubRequired(stub)) return false; diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 72a2e1152210b..87876cded4d57 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -1775,6 +1775,42 @@ BOOL Module::IsRuntimeWrapExceptions() return !!(m_dwPersistedFlags & WRAP_EXCEPTIONS); } +BOOL Module::IsRuntimeMarshallingEnabled() +{ + CONTRACTL + { + THROWS; + if (IsRuntimeMarshallingEnabledCached()) GC_NOTRIGGER; else GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END + + if (IsRuntimeMarshallingEnabledCached()) + { + return !!(m_dwPersistedFlags & RUNTIME_MARSHALLING_ENABLED); + } + + HRESULT hr; + + IMDInternalImport *mdImport = GetAssembly()->GetManifestImport(); + + mdToken token; + if (SUCCEEDED(hr = mdImport->GetAssemblyFromScope(&token))) + { + const BYTE *pVal; + ULONG cbVal; + + hr = mdImport->GetCustomAttributeByName(token, + g_DisableRuntimeMarshallingAttribute, + (const void**)&pVal, &cbVal); + } + + FastInterlockOr(&m_dwPersistedFlags, RUNTIME_MARSHALLING_ENABLED_IS_CACHED | + (hr == S_OK ? 0 : RUNTIME_MARSHALLING_ENABLED)); + + return hr != S_OK; +} + BOOL Module::IsPreV4Assembly() { CONTRACTL diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 8a3caaddc7dbf..2b9198b811732 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -834,6 +834,11 @@ class Module // Low level system assembly. Used by preferred zap module computation. LOW_LEVEL_SYSTEM_ASSEMBLY_BY_NAME = 0x00004000, + + //If setting has been cached + RUNTIME_MARSHALLING_ENABLED_IS_CACHED = 0x00008000, + //If runtime marshalling is enabled for this assembly + RUNTIME_MARSHALLING_ENABLED = 0x00010000, }; Volatile m_dwTransientFlags; @@ -2059,6 +2064,18 @@ class Module //----------------------------------------------------------------------------------------- BOOL IsRuntimeWrapExceptions(); + //----------------------------------------------------------------------------------------- + // If true, the built-in runtime-generated marshalling subsystem will be used for + // P/Invokes, function pointer invocations, and delegates defined in this module + //----------------------------------------------------------------------------------------- + BOOL IsRuntimeMarshallingEnabled(); + + BOOL IsRuntimeMarshallingEnabledCached() + { + LIMITED_METHOD_CONTRACT; + return (m_dwPersistedFlags & RUNTIME_MARSHALLING_ENABLED_IS_CACHED); + } + BOOL HasDefaultDllImportSearchPathsAttribute(); BOOL IsDefaultDllImportSearchPathsAttributeCached() diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 0ccacd36a9f91..9aa6c6994e726 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -363,19 +363,21 @@ class EEClassLayoutInfo private: enum { // TRUE if the GC layout of the class is bit-for-bit identical - // to its unmanaged counterpart (i.e. no internal reference fields, - // no ansi-unicode char conversions required, etc.) Used to - // optimize marshaling. - e_BLITTABLE = 0x01, - // Post V1.0 addition: Is this type also sequential in managed memory? - e_MANAGED_SEQUENTIAL = 0x02, + // to its unmanaged counterpart with the runtime marshalling system + // (i.e. no internal reference fields, no ansi-unicode char conversions required, etc.) + // Used to optimize marshaling. + e_BLITTABLE = 0x01, + // Is this type also sequential in managed memory? + e_MANAGED_SEQUENTIAL = 0x02, // When a sequential/explicit type has no fields, it is conceptually // zero-sized, but actually is 1 byte in length. This holds onto this // fact and allows us to revert the 1 byte of padding when another // explicit type inherits from this type. - e_ZERO_SIZED = 0x04, + e_ZERO_SIZED = 0x04, // The size of the struct is explicitly specified in the meta-data. - e_HAS_EXPLICIT_SIZE = 0x08 + e_HAS_EXPLICIT_SIZE = 0x08, + // The type recursively has a field that is LayoutKind.Auto and not an enum. + e_HAS_AUTO_LAYOUT_FIELD_IN_LAYOUT = 0x10 }; BYTE m_bFlags; @@ -419,6 +421,12 @@ class EEClassLayoutInfo return (m_bFlags & e_HAS_EXPLICIT_SIZE) == e_HAS_EXPLICIT_SIZE; } + BOOL HasAutoLayoutField() const + { + LIMITED_METHOD_CONTRACT; + return (m_bFlags & e_HAS_AUTO_LAYOUT_FIELD_IN_LAYOUT) == e_HAS_AUTO_LAYOUT_FIELD_IN_LAYOUT; + } + BYTE GetPackingSize() const { LIMITED_METHOD_CONTRACT; @@ -453,6 +461,13 @@ class EEClassLayoutInfo m_bFlags = hasExplicitSize ? (m_bFlags | e_HAS_EXPLICIT_SIZE) : (m_bFlags & ~e_HAS_EXPLICIT_SIZE); } + + void SetHasAutoLayoutField(BOOL hasAutoLayoutField) + { + LIMITED_METHOD_CONTRACT; + m_bFlags = hasAutoLayoutField ? (m_bFlags | e_HAS_AUTO_LAYOUT_FIELD_IN_LAYOUT) + : (m_bFlags & ~e_HAS_AUTO_LAYOUT_FIELD_IN_LAYOUT); + } }; // @@ -1395,6 +1410,8 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW! BOOL HasExplicitSize(); + BOOL IsAutoLayoutOrHasAutoLayoutField(); + static void GetBestFitMapping(MethodTable * pMT, BOOL *pfBestFitMapping, BOOL *pfThrowOnUnmappableChar); /* @@ -2082,6 +2099,13 @@ inline BOOL EEClass::HasExplicitSize() return HasLayout() && GetLayoutInfo()->HasExplicitSize(); } +inline BOOL EEClass::IsAutoLayoutOrHasAutoLayoutField() +{ + LIMITED_METHOD_CONTRACT; + // If this type is not auto + return !HasLayout() || GetLayoutInfo()->HasAutoLayoutField(); +} + //========================================================================== // These routines manage the prestub (a bootstrapping stub that all // FunctionDesc's are initialized with.) diff --git a/src/coreclr/vm/classlayoutinfo.cpp b/src/coreclr/vm/classlayoutinfo.cpp index 90315764cfbc5..b95c6d4108ed4 100644 --- a/src/coreclr/vm/classlayoutinfo.cpp +++ b/src/coreclr/vm/classlayoutinfo.cpp @@ -226,23 +226,18 @@ namespace *pLargestAlignmentRequirementOut = LargestAlignmentRequirement; } - //======================================================================= - // This function returns TRUE if the provided corElemType disqualifies - // the structure from being a managed-sequential structure. - // The fsig parameter is used when the corElemType doesn't contain enough information - // to successfully determine if this field disqualifies the type from being - // managed-sequential. - // This function also fills in the pManagedPlacementInfo structure for this field. - //======================================================================= - BOOL CheckIfDisqualifiedFromManagedSequential(CorElementType corElemType, MetaSig& fsig, RawFieldPlacementInfo* pManagedPlacementInfo) + RawFieldPlacementInfo GetFieldPlacementInfo(CorElementType corElemType, TypeHandle pNestedType) { - pManagedPlacementInfo->m_alignment = TARGET_POINTER_SIZE; - pManagedPlacementInfo->m_size = TARGET_POINTER_SIZE; + RawFieldPlacementInfo placementInfo; + // Initialize offset to a dummy value as we set it to the correct value later. + placementInfo.m_offset = (UINT32)-1; + placementInfo.m_size = TARGET_POINTER_SIZE; + placementInfo.m_alignment = TARGET_POINTER_SIZE; // This type may qualify for ManagedSequential. Collect managed size and alignment info. if (CorTypeInfo::IsPrimitiveType(corElemType)) { // Safe cast - no primitive type is larger than 4gb! - pManagedPlacementInfo->m_size = ((UINT32)CorTypeInfo::Size(corElemType)); + placementInfo.m_size = ((UINT32)CorTypeInfo::Size(corElemType)); #if defined(TARGET_X86) && defined(UNIX_X86_ABI) switch (corElemType) { @@ -251,67 +246,87 @@ namespace case ELEMENT_TYPE_U8: case ELEMENT_TYPE_R8: { - pManagedPlacementInfo->m_alignment = 4; + placementInfo.m_alignment = 4; break; } default: { - pManagedPlacementInfo->m_alignment = pManagedPlacementInfo->m_size; + placementInfo.m_alignment = placementInfo.m_size; break; } } #else // TARGET_X86 && UNIX_X86_ABI - pManagedPlacementInfo->m_alignment = pManagedPlacementInfo->m_size; + placementInfo.m_alignment = placementInfo.m_size; #endif - return FALSE; } else if (corElemType == ELEMENT_TYPE_PTR || corElemType == ELEMENT_TYPE_FNPTR) { - pManagedPlacementInfo->m_size = TARGET_POINTER_SIZE; - pManagedPlacementInfo->m_alignment = TARGET_POINTER_SIZE; - - return FALSE; + placementInfo.m_size = TARGET_POINTER_SIZE; + placementInfo.m_alignment = TARGET_POINTER_SIZE; } else if (corElemType == ELEMENT_TYPE_VALUETYPE) { - TypeHandle pNestedType = fsig.GetLastTypeHandleThrowing(ClassLoader::LoadTypes, - CLASS_LOAD_APPROXPARENTS, - TRUE); + _ASSERTE(!pNestedType.IsNull()); - pManagedPlacementInfo->m_size = (pNestedType.GetMethodTable()->GetNumInstanceFieldBytes()); + placementInfo.m_size = (pNestedType.GetMethodTable()->GetNumInstanceFieldBytes()); #if !defined(TARGET_64BIT) && (DATA_ALIGNMENT > 4) - if (pManagedPlacementInfo->m_size >= DATA_ALIGNMENT) + if (placementInfo.m_size >= DATA_ALIGNMENT) { - pManagedPlacementInfo->m_alignment = DATA_ALIGNMENT; + placementInfo.m_alignment = DATA_ALIGNMENT; } else #elif defined(FEATURE_64BIT_ALIGNMENT) if (pNestedType.RequiresAlign8()) { - pManagedPlacementInfo->m_alignment = 8; + placementInfo.m_alignment = 8; } else #endif // FEATURE_64BIT_ALIGNMENT if (pNestedType.GetMethodTable()->ContainsPointers()) { // this field type has GC pointers in it, which need to be pointer-size aligned - // so do this if it has not been done already - pManagedPlacementInfo->m_alignment = TARGET_POINTER_SIZE; + placementInfo.m_alignment = TARGET_POINTER_SIZE; } else { - pManagedPlacementInfo->m_alignment = pNestedType.GetMethodTable()->GetFieldAlignmentRequirement(); + placementInfo.m_alignment = pNestedType.GetMethodTable()->GetFieldAlignmentRequirement(); } - // Types that have GC Pointer fields (objects or byrefs) are disqualified from ManagedSequential layout. - return pNestedType.GetMethodTable()->ContainsPointers() != FALSE; } // No other type permitted for ManagedSequential. + return placementInfo; + } + + BOOL TypeHasGCPointers(CorElementType corElemType, TypeHandle pNestedType) + { + if (CorTypeInfo::IsPrimitiveType(corElemType) || corElemType == ELEMENT_TYPE_PTR || corElemType == ELEMENT_TYPE_FNPTR) + { + return FALSE; + } + if (corElemType == ELEMENT_TYPE_VALUETYPE) + { + _ASSERTE(!pNestedType.IsNull()); + return pNestedType.GetMethodTable()->ContainsPointers() != FALSE; + } return TRUE; } + BOOL TypeHasAutoLayoutField(CorElementType corElemType, TypeHandle pNestedType) + { + if (CorTypeInfo::IsPrimitiveType(corElemType) || corElemType == ELEMENT_TYPE_PTR || corElemType == ELEMENT_TYPE_FNPTR) + { + return FALSE; + } + if (corElemType == ELEMENT_TYPE_VALUETYPE) + { + _ASSERTE(!pNestedType.IsNull()); + return pNestedType.IsEnum() || pNestedType.GetMethodTable()->IsAutoLayoutOrHasAutoLayoutField(); + } + return FALSE; + } + #ifdef UNIX_AMD64_ABI void SystemVAmd64CheckForPassNativeStructInRegister(MethodTable* pMT, EEClassNativeLayoutInfo* pNativeLayoutInfo) { @@ -437,6 +452,7 @@ namespace ParseNativeTypeFlags nativeTypeFlags, const SigTypeContext* pTypeContext, BOOL* fDisqualifyFromManagedSequential, + BOOL* fHasAutoLayoutField, LayoutRawFieldInfo* pFieldInfoArrayOut, BOOL* pIsBlittableOut, ULONG* cInstanceFields @@ -505,7 +521,16 @@ namespace #endif MetaSig fsig(pCOMSignature, cbCOMSignature, pModule, pTypeContext, MetaSig::sigField); CorElementType corElemType = fsig.NextArgNormalized(); - *fDisqualifyFromManagedSequential |= CheckIfDisqualifiedFromManagedSequential(corElemType, fsig, &pFieldInfoArrayOut->m_placement); + TypeHandle typeHandleMaybe; + if (corElemType == ELEMENT_TYPE_VALUETYPE) // Only look up the next element in the signature if it is a value type to avoid causing recursive type loads in valid scenarios. + { + typeHandleMaybe = fsig.GetLastTypeHandleThrowing(ClassLoader::LoadTypes, + CLASS_LOAD_APPROXPARENTS, + TRUE); + } + pFieldInfoArrayOut->m_placement = GetFieldPlacementInfo(corElemType, typeHandleMaybe); + *fDisqualifyFromManagedSequential |= TypeHasGCPointers(corElemType, typeHandleMaybe); + *fHasAutoLayoutField |= TypeHasAutoLayoutField(corElemType, typeHandleMaybe); if (!IsFieldBlittable(pModule, fd, fsig.GetArgProps(), pTypeContext, nativeTypeFlags)) *pIsBlittableOut = FALSE; @@ -598,6 +623,7 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the the time // function exits. BOOL fDisqualifyFromManagedSequential; + BOOL hasAutoLayoutField = FALSE; // Check if this type might be ManagedSequential. Only valuetypes marked Sequential can be // ManagedSequential. Other issues checked below might also disqualify the type. @@ -612,6 +638,11 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( fDisqualifyFromManagedSequential = TRUE; } + if (pParentMT && !pParentMT->IsValueTypeClass() && pParentMT->IsAutoLayoutOrHasAutoLayoutField()) + { + hasAutoLayoutField = TRUE; + } + BOOL fHasNonTrivialParent = pParentMT && !pParentMT->IsObjectClass() && @@ -659,6 +690,7 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( nativeTypeFlags, pTypeContext, &fDisqualifyFromManagedSequential, + &hasAutoLayoutField, pInfoArrayOut, &isBlittable, &cInstanceFields @@ -671,6 +703,8 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( isBlittable = isBlittable && (fHasNonTrivialParent ? pParentMT->IsBlittable() : TRUE); pEEClassLayoutInfoOut->SetIsBlittable(isBlittable); + pEEClassLayoutInfoOut->SetHasAutoLayoutField(hasAutoLayoutField); + S_UINT32 cbSortArraySize = S_UINT32(cTotalFields) * S_UINT32(sizeof(LayoutRawFieldInfo*)); if (cbSortArraySize.IsOverflow()) { diff --git a/src/coreclr/vm/classnames.h b/src/coreclr/vm/classnames.h index 94e9b1025c7a4..7d71ce2c7d891 100644 --- a/src/coreclr/vm/classnames.h +++ b/src/coreclr/vm/classnames.h @@ -113,4 +113,6 @@ #define g_CriticalFinalizerObjectName "CriticalFinalizerObject" +#define g_DisableRuntimeMarshallingAttribute "System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute" + #endif //!__CLASSNAMES_H__ diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index b9b86e3708cbd..3a35a8e108fa4 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -107,6 +107,7 @@ StubSigDesc::StubSigDesc(MethodDesc *pMD) m_tkMethodDef = pMD->GetMemberDef(); SigTypeContext::InitTypeContext(pMD, &m_typeContext); + m_pMetadataModule = pMD->GetModule(); m_pLoaderModule = pMD->GetLoaderModule(); // Used for ILStubCache selection and MethodTable creation. INDEBUG(InitDebugNames()); @@ -133,11 +134,13 @@ StubSigDesc::StubSigDesc(MethodDesc* pMD, const Signature& sig, Module* pModule) { m_tkMethodDef = pMD->GetMemberDef(); SigTypeContext::InitTypeContext(pMD, &m_typeContext); + m_pMetadataModule = pMD->GetModule(); m_pLoaderModule = pMD->GetLoaderModule(); // Used for ILStubCache selection and MethodTable creation. } else { m_tkMethodDef = mdMethodDefNil; + m_pMetadataModule = m_pModule; m_pLoaderModule = m_pModule; } @@ -166,7 +169,8 @@ StubSigDesc::StubSigDesc(MethodTable* pMT, const Signature& sig, Module* pModule if (pMT != NULL) { SigTypeContext::InitTypeContext(pMT, &m_typeContext); - m_pLoaderModule = pMT->GetLoaderModule(); // Used for ILStubCache selection and MethodTable creation. + m_pMetadataModule = pMT->GetModule(); + m_pLoaderModule = pMT->GetLoaderModule(); } else { @@ -193,6 +197,7 @@ StubSigDesc::StubSigDesc(const Signature& sig, Module* pModule) m_sig = sig; m_pModule = pModule; m_tkMethodDef = mdMethodDefNil; + m_pMetadataModule = m_pModule; m_pLoaderModule = m_pModule; INDEBUG(InitDebugNames()); @@ -3287,6 +3292,15 @@ BOOL NDirect::MarshalingRequired( } CollateParamTokens(pMDImport, methodToken, numArgs - 1, pParamTokenArray); + // We enable the runtime marshalling system whenever it is enabled on the module as a whole + // or when the call is a COM interop call. COM interop calls are already using a significant portion of the runtime + // marshalling system just to function at all, so we aren't going to disable the parameter marshalling; + // we'd rather have developers use the feature flag to diable the whole COM interop subsystem at once. + bool runtimeMarshallingEnabled = pModule->IsRuntimeMarshallingEnabled(); +#ifdef FEATURE_COMINTEROP + runtimeMarshallingEnabled |= pMD && pMD->IsComPlusCall(); +#endif + for (ULONG i = 0; i < numArgs; i++) { SigPointer arg = ptr; @@ -3300,7 +3314,7 @@ BOOL NDirect::MarshalingRequired( IfFailThrow(arg.GetElemType(NULL)); // skip ELEMENT_TYPE_PTR IfFailThrow(arg.PeekElemType(&type)); - if (type == ELEMENT_TYPE_VALUETYPE) + if (runtimeMarshallingEnabled && type == ELEMENT_TYPE_VALUETYPE) { if ((arg.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", @@ -3331,11 +3345,21 @@ BOOL NDirect::MarshalingRequired( { TypeHandle hndArgType = arg.GetTypeHandleThrowing(pModule, &emptyTypeContext); - // JIT can handle internal blittable value types - if (!hndArgType.IsBlittable() && !hndArgType.IsEnum()) + // When the runtime runtime marshalling system is disabled, we don't support + // any types that contain gc pointers, but all "unmanaged" types are treated as blittable + // as long as they aren't auto-layout and don't have any auto-layout fields. + if (!runtimeMarshallingEnabled && + (hndArgType.GetMethodTable()->ContainsPointers() + || hndArgType.GetMethodTable()->IsAutoLayoutOrHasAutoLayoutField())) { return TRUE; } + else if (runtimeMarshallingEnabled && !hndArgType.IsBlittable() && !hndArgType.IsEnum()) + { + // When the runtime runtime marshalling system is enabled, we do special handling + // for any types that aren't blittable or enums. + return TRUE; + } if (i > 0) { @@ -3348,10 +3372,15 @@ BOOL NDirect::MarshalingRequired( case ELEMENT_TYPE_BOOLEAN: case ELEMENT_TYPE_CHAR: { + // When runtime marshalling is enabled: // Bool requires marshaling // Char may require marshaling (MARSHAL_TYPE_ANSICHAR) - return TRUE; + if (runtimeMarshallingEnabled) + { + return TRUE; + } } + FALLTHROUGH; default: { @@ -3376,7 +3405,10 @@ BOOL NDirect::MarshalingRequired( // check for explicit MarshalAs NativeTypeParamInfo paramInfo; - if (pParamTokenArray[i] != mdParamDefNil) + // We only check the MarshalAs info when the runtime marshalling system is enabled. + // We ignore MarshalAs when the system is disabled, so no reason to disqualify from inlining + // when it is present. + if (runtimeMarshallingEnabled && pParamTokenArray[i] != mdParamDefNil) { if (!ParseNativeTypeInfo(pParamTokenArray[i], pMDImport, ¶mInfo) || paramInfo.m_NativeType != NATIVE_TYPE_DEFAULT) @@ -3594,6 +3626,7 @@ static void CreateNDirectStubWorker(StubState* pss, CONSISTENCY_CHECK_MSGF(false, ("BreakOnInteropStubSetup: '%s' ", pSigDesc->m_pDebugName)); #endif // _DEBUG + bool runtimeMarshallingEnabled = SF_IsCOMStub(dwStubFlags) || pSigDesc->m_pMetadataModule->IsRuntimeMarshallingEnabled(); if (SF_IsCOMStub(dwStubFlags)) { _ASSERTE(0 == nlType); @@ -3615,26 +3648,48 @@ static void CreateNDirectStubWorker(StubState* pss, &pSigDesc->m_typeContext); if (SF_IsVarArgStub(dwStubFlags)) + { + if (!runtimeMarshallingEnabled) + { + COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_DISABLEDMARSHAL_VARARGS); + } msig.SetTreatAsVarArg(); + } bool fThisCall = (unmgdCallConv == CorInfoCallConvExtension::Thiscall); - pss->SetLastError(nlFlags & nlfLastError); + if (nlFlags & nlfLastError) + { + if (!runtimeMarshallingEnabled) + { + COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_DISABLEDMARSHAL_SETLASTERROR); + } + pss->SetLastError(TRUE); + } // This has been in the product since forward P/Invoke via delegates was // introduced. It's wrong, but please keep it for backward compatibility. - if (SF_IsDelegateStub(dwStubFlags)) + if (runtimeMarshallingEnabled && SF_IsDelegateStub(dwStubFlags)) pss->SetLastError(TRUE); pss->BeginEmit(dwStubFlags); if (-1 != iLCIDArg) { - // The code to handle the LCID will call MarshalLCID before calling MarshalArgument + if (!runtimeMarshallingEnabled) + { + COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID); + } + // The code to handle the LCID will call MarshalLCID before calling MarshalArgument // on the argument the LCID should go after. So we just bump up the index here. iLCIDArg++; } + if (!runtimeMarshallingEnabled && SF_IsHRESULTSwapping(dwStubFlags)) + { + COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_DISABLEDMARSHAL_PRESERVESIG); + } + int numArgs = msig.NumFixedArgs(); // thiscall must have at least one parameter (the "this") diff --git a/src/coreclr/vm/dllimport.h b/src/coreclr/vm/dllimport.h index f731823ff4a0b..8b472e3a0aafb 100644 --- a/src/coreclr/vm/dllimport.h +++ b/src/coreclr/vm/dllimport.h @@ -23,7 +23,15 @@ struct StubSigDesc MethodDesc *m_pMD; MethodTable *m_pMT; Signature m_sig; + // Module to use for signature reading. Module *m_pModule; + // Module that owns any metadata that influences interop behavior. + // This is usually the same as m_pModule, but can differ with vararg + // P/Invokes, where the calling assembly's module is assigned to m_pModule + // since the specific caller signature is defined in that assembly, not the + // assembly that defined the P/Invoke. + Module *m_pMetadataModule; + // Used for ILStubCache selection and MethodTable creation. Module *m_pLoaderModule; mdMethodDef m_tkMethodDef; SigTypeContext m_typeContext; diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 86a033a0593a2..76c552a304284 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -1517,6 +1517,8 @@ class MethodTable inline BOOL HasExplicitSize(); + inline BOOL IsAutoLayoutOrHasAutoLayoutField(); + UINT32 GetNativeSize(); DWORD GetBaseSize() diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index d14a73532b6e1..72b628dae9545 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -947,6 +947,13 @@ inline BOOL MethodTable::HasExplicitSize() return GetClass()->HasExplicitSize(); } +//========================================================================================== +inline BOOL MethodTable::IsAutoLayoutOrHasAutoLayoutField() +{ + LIMITED_METHOD_CONTRACT; + return GetClass()->IsAutoLayoutOrHasAutoLayoutField(); +} + //========================================================================================== inline DWORD MethodTable::GetPerInstInfoSize() { diff --git a/src/coreclr/vm/mlinfo.cpp b/src/coreclr/vm/mlinfo.cpp index c573184012284..5a071c2b9f8f9 100644 --- a/src/coreclr/vm/mlinfo.cpp +++ b/src/coreclr/vm/mlinfo.cpp @@ -1056,6 +1056,78 @@ OleColorMarshalingInfo *EEMarshalingData::GetOleColorMarshalingInfo() } #endif // FEATURE_COMINTEROP +namespace +{ + MarshalInfo::MarshalType GetDisabledMarshallerType( + Module* pModule, + SigPointer sig, + const SigTypeContext * pTypeContext, + MethodTable** pMTOut, + UINT* errorResIDOut) + { + switch (sig.PeekElemTypeNormalized(pModule, pTypeContext)) + { + case ELEMENT_TYPE_BOOLEAN: + case ELEMENT_TYPE_U1: + return MarshalInfo::MARSHAL_TYPE_GENERIC_U1; + case ELEMENT_TYPE_I1: + return MarshalInfo::MARSHAL_TYPE_GENERIC_1; + case ELEMENT_TYPE_CHAR: + case ELEMENT_TYPE_U2: + return MarshalInfo::MARSHAL_TYPE_GENERIC_U2; + case ELEMENT_TYPE_I2: + return MarshalInfo::MARSHAL_TYPE_GENERIC_2; + case ELEMENT_TYPE_U4: + return MarshalInfo::MARSHAL_TYPE_GENERIC_U4; + case ELEMENT_TYPE_I4: + return MarshalInfo::MARSHAL_TYPE_GENERIC_4; + case ELEMENT_TYPE_U8: + case ELEMENT_TYPE_I8: + return MarshalInfo::MARSHAL_TYPE_GENERIC_8; +#ifdef TARGET_64BIT + case ELEMENT_TYPE_U: + case ELEMENT_TYPE_PTR: + case ELEMENT_TYPE_FNPTR: + case ELEMENT_TYPE_I: + return MarshalInfo::MARSHAL_TYPE_GENERIC_8; +#else + case ELEMENT_TYPE_U: + return MarshalInfo::MARSHAL_TYPE_GENERIC_U4; + case ELEMENT_TYPE_PTR: + case ELEMENT_TYPE_FNPTR: + case ELEMENT_TYPE_I: + return MarshalInfo::MARSHAL_TYPE_GENERIC_4; +#endif + case ELEMENT_TYPE_R4: + return MarshalInfo::MARSHAL_TYPE_FLOAT; + case ELEMENT_TYPE_R8: + return MarshalInfo::MARSHAL_TYPE_DOUBLE; + case ELEMENT_TYPE_VAR: + case ELEMENT_TYPE_VALUETYPE: + { + TypeHandle sigTH = sig.GetTypeHandleThrowing(pModule, pTypeContext); + MethodTable* pMT = sigTH.GetMethodTable(); + + if (!pMT->IsValueType() || pMT->ContainsPointers()) + { + *errorResIDOut = IDS_EE_BADMARSHAL_MARSHAL_DISABLED; + return MarshalInfo::MARSHAL_TYPE_UNKNOWN; + } + if (pMT->IsAutoLayoutOrHasAutoLayoutField()) + { + *errorResIDOut = IDS_EE_BADMARSHAL_AUTOLAYOUT; + return MarshalInfo::MARSHAL_TYPE_UNKNOWN; + } + *pMTOut = pMT; + return MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS; + } + default: + *errorResIDOut = IDS_EE_BADMARSHAL_MARSHAL_DISABLED; + return MarshalInfo::MARSHAL_TYPE_UNKNOWN; + } + } +} + //========================================================================== // Constructs MarshalInfo. //========================================================================== @@ -1163,7 +1235,30 @@ MarshalInfo::MarshalInfo(Module* pModule, m_byref = TRUE; #endif + // For COM IL-stub scenarios, we do not support disabling the runtime marshalling support. + // The runtime-integrated COM support uses a significant portion of the marshalling infrastructure as well as + // quite a bit of its own custom marshalling infrastructure to function in basically any aspect. + // As a result, disabling marshalling in COM scenarios isn't useful. Instead, we recommend that people set the + // feature switch to false to disable the runtime COM support if they want it disabled. + // For field marshalling scenarios, we also don't disable runtime marshalling. If we're already in a field + // marshalling scenario, we've already decided that the context for the owning type is using runtime marshalling, + // so the fields of the struct should also use runtime marshalling. + const bool useRuntimeMarshalling = ms != MARSHAL_SCENARIO_NDIRECT || pModule->IsRuntimeMarshallingEnabled(); + if (!useRuntimeMarshalling) + { + m_in = TRUE; + m_out = FALSE; + m_byref = FALSE; + m_type = GetDisabledMarshallerType( + pModule, + sig, + pTypeContext, + &m_pMT, + &m_resID); + m_args.m_pMT = m_pMT; + return; + } // Retrieve the native type for the current parameter. if (!ParseNativeTypeInfo(token, pModule->GetMDImport(), &ParamInfo)) @@ -1322,6 +1417,7 @@ MarshalInfo::MarshalInfo(Module* pModule, switch (mtype) { case ELEMENT_TYPE_BOOLEAN: + switch (nativeType) { case NATIVE_TYPE_BOOLEAN: @@ -1482,10 +1578,6 @@ MarshalInfo::MarshalInfo(Module* pModule, break; case ELEMENT_TYPE_I: - // Technically the "native int" and "native uint" types aren't supported in the WinRT scenario, - // but we need to not block ourselves from using them to enable accurate managed->native marshalling of - // projected types such as NotifyCollectionChangedEventArgs and NotifyPropertyChangedEventArgs. - if (!(nativeType == NATIVE_TYPE_INT || nativeType == NATIVE_TYPE_UINT || nativeType == NATIVE_TYPE_DEFAULT)) { m_resID = IDS_EE_BADMARSHAL_I; @@ -1499,7 +1591,6 @@ MarshalInfo::MarshalInfo(Module* pModule, break; case ELEMENT_TYPE_U: - if (!(nativeType == NATIVE_TYPE_UINT || nativeType == NATIVE_TYPE_INT || nativeType == NATIVE_TYPE_DEFAULT)) { m_resID = IDS_EE_BADMARSHAL_I; @@ -1564,6 +1655,21 @@ MarshalInfo::MarshalInfo(Module* pModule, { TypeHandle sigTH = sig.GetTypeHandleThrowing(pModule, pTypeContext); + if (sigTH.GetMethodTable()->IsValueType()) + { + // For value types, we need to handle the "value type marshalled as a COM interface" + // case here for back-compat. + // Otherwise, we can go to the value-type case. +#ifdef FEATURE_COMINTEROP + if (nativeType != NATIVE_TYPE_INTF) + { + goto lValueClass; + } +#else + goto lValueClass; +#endif + } + // Disallow marshaling generic types. if (sigTH.HasInstantiation()) { @@ -1968,14 +2074,13 @@ MarshalInfo::MarshalInfo(Module* pModule, } } - else if (m_pMT->IsArray()) { _ASSERTE(!"This invalid signature should never be hit!"); IfFailGoto(E_FAIL, lFail); } #endif // FEATURE_COMINTEROP - else if (!m_pMT->IsValueType()) + else { if (!(nativeType == NATIVE_TYPE_INTF || nativeType == NATIVE_TYPE_DEFAULT)) { @@ -1990,12 +2095,6 @@ MarshalInfo::MarshalInfo(Module* pModule, IfFailGoto(E_FAIL, lFail); #endif // FEATURE_COMINTEROP } - - else - { - _ASSERTE(m_pMT->IsValueType()); - goto lValueClass; - } } break; } @@ -2166,8 +2265,7 @@ MarshalInfo::MarshalInfo(Module* pModule, || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR64T)) || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR128T)) || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR256T)) - // Crossgen scenarios block Vector from even being loaded - || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTORT)) + || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTORT)) ))) { m_resID = IDS_EE_BADMARSHAL_GENERICS_RESTRICTION; @@ -2902,6 +3000,15 @@ UINT16 MarshalInfo::GetNativeSize(MarshalType mtype) if (nativeSize == VARIABLESIZE) { _ASSERTE(IsValueClass(mtype)); + // For blittable types, use the GetNumInstanceFieldBytes method. + // When we generate IL stubs when marshalling is disabled, + // we reuse the blittable value class marshalling mechanism. + // In that scenario, only GetNumInstanceFieldBytes will return the correct value. + // GetNativeSize will return the size for when runtime marshalling is enabled. + if (mtype == MARSHAL_TYPE_BLITTABLEVALUECLASS) + { + return (UINT16) m_pMT->GetNumInstanceFieldBytes(); + } return (UINT16) m_pMT->GetNativeSize(); } diff --git a/src/coreclr/vm/stubgen.cpp b/src/coreclr/vm/stubgen.cpp index f829212a8ef6e..2249756c3358a 100644 --- a/src/coreclr/vm/stubgen.cpp +++ b/src/coreclr/vm/stubgen.cpp @@ -2669,7 +2669,7 @@ void ILStubLinker::TransformArgForJIT(LocalDesc *pLoc) // JIT will handle structures if (pLoc->InternalToken.IsValueType()) { - _ASSERTE(pLoc->InternalToken.IsBlittable()); + _ASSERTE(pLoc->InternalToken.IsNativeValueType() || !pLoc->InternalToken.GetMethodTable()->ContainsPointers()); break; } FALLTHROUGH; 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 6272743925a92..ebbc2d77b6a93 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 @@ -713,6 +713,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/DisableRuntimeMarshallingAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/DisableRuntimeMarshallingAttribute.cs new file mode 100644 index 0000000000000..6ed3018d2479e --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/DisableRuntimeMarshallingAttribute.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. + +namespace System.Runtime.CompilerServices +{ + /// + /// Disables the built-in runtime managed/unmanaged marshalling subsystem for + /// P/Invokes, Delegate types, and unmanaged function pointer invocations. + /// + /// + /// The built-in marshalling subsystem has some behaviors that cannot be changed due to + /// backward-compatibility requirements. This attribute allows disabling the built-in + /// subsystem and instead uses the following rules for P/Invokes, Delegates, + /// and unmanaged function pointer invocations: + /// + /// - All value types that do not contain reference type fields recursively (unmanaged in C#) are blittable + /// - Value types that recursively have any fields that have [StructLayout(LayoutKind.Auto)] are disallowed from interop. + /// - All reference types are disallowed from usage in interop scenarios. + /// - SetLastError support in P/Invokes is disabled. + /// - varargs support is disabled. + /// - LCIDConversionAttribute support is disabled. + /// + [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] + public sealed class DisableRuntimeMarshallingAttribute : Attribute + { + } +} diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 4ba4ebabbb445..256f032352baa 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -13009,6 +13009,11 @@ public sealed partial class DisablePrivateReflectionAttribute : System.Attribute { public DisablePrivateReflectionAttribute() { } } + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] + public sealed class DisableRuntimeMarshallingAttribute : Attribute + { + public DisableRuntimeMarshallingAttribute() { } + } [System.AttributeUsageAttribute(System.AttributeTargets.All)] public partial class DiscardableAttribute : System.Attribute { diff --git a/src/mono/mono/arch/s390x/tramp.c b/src/mono/mono/arch/s390x/tramp.c index 376970c4ab60b..451511dfc53e5 100644 --- a/src/mono/mono/arch/s390x/tramp.c +++ b/src/mono/mono/arch/s390x/tramp.c @@ -166,7 +166,7 @@ calculate_sizes (MonoMethodSignature *sig, size_data *sz, goto enum_retvalue; } gr++; - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size (sig->ret->data.klass, &align); else size = mono_class_value_size (sig->ret->data.klass, &align); @@ -235,7 +235,7 @@ calculate_sizes (MonoMethodSignature *sig, size_data *sz, simpletype = sig->params [i]->data.klass->enum_basetype->type; goto enum_calc_size; } - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size (sig->params [i]->data.klass, &align); else size = mono_class_value_size (sig->params [i]->data.klass, &align); @@ -423,7 +423,7 @@ emit_save_parameters (guint8 *p, MonoMethodSignature *sig, size_data *sz) simpletype = sig->params [i]->data.klass->enum_basetype->type; goto enum_calc_size; } - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size (sig->params [i]->data.klass, &align); else size = mono_class_value_size (sig->params [i]->data.klass, &align); @@ -625,7 +625,7 @@ emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, simpletype = sig->ret->data.klass->enum_basetype->type; goto enum_retvalue; } - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) retSize = mono_class_native_size (sig->ret->data.klass, &align); else retSize = mono_class_value_size (sig->ret->data.klass, &align); @@ -848,7 +848,7 @@ mono_arch_create_method_pointer (MonoMethod *method) /* area. If necessary save this hidden parameter for later */ /*----------------------------------------------------------*/ if (MONO_TYPE_ISSTRUCT(sig->ret)) { - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) retSize = mono_class_native_size (sig->ret->data.klass, &align); else retSize = mono_class_value_size (sig->ret->data.klass, &align); @@ -904,7 +904,10 @@ mono_arch_create_method_pointer (MonoMethod *method) if (klass->enumtype) continue; - size = mono_class_native_size (klass, &align); + if (sig->pinvoke && !sig->marshalling_disabled) + size = mono_class_native_size (sig->ret->data.klass, &align); + else + size = mono_class_value_size (sig->ret->data.klass, &align); cpos += align - 1; cpos &= ~(align - 1); vtbuf [i] = cpos; @@ -947,7 +950,7 @@ mono_arch_create_method_pointer (MonoMethod *method) simple_type = sig->params [i]->data.klass->enum_basetype->type; goto enum_savechk; } - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) parSize = mono_class_native_size (sig->params [i]->data.klass, &align); else parSize = mono_class_value_size (sig->params [i]->data.klass, &align); @@ -996,7 +999,7 @@ mono_arch_create_method_pointer (MonoMethod *method) /* fixme: alignment */ DEBUG (printf ("arg_pos %d --> ", arg_pos)); - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) arg_pos += mono_type_native_stack_size (sig->params [i], &align); else arg_pos += mono_type_stack_size (sig->params [i], &align); diff --git a/src/mono/mono/metadata/class-getters.h b/src/mono/mono/metadata/class-getters.h index 0dc97fca5807d..7f88b78780142 100644 --- a/src/mono/mono/metadata/class-getters.h +++ b/src/mono/mono/metadata/class-getters.h @@ -24,6 +24,7 @@ MONO_CLASS_GETTER(m_class_is_size_inited, gboolean, , MonoClass, size_inited) MONO_CLASS_GETTER(m_class_is_valuetype, gboolean, , MonoClass, valuetype) MONO_CLASS_GETTER(m_class_is_enumtype, gboolean, , MonoClass, enumtype) MONO_CLASS_GETTER(m_class_is_blittable, gboolean, , MonoClass, blittable) +MONO_CLASS_GETTER(m_class_any_field_has_auto_layout, gboolean, , MonoClass, any_field_has_auto_layout) MONO_CLASS_GETTER(m_class_is_unicode, gboolean, , MonoClass, unicode) MONO_CLASS_GETTER(m_class_was_typebuilder, gboolean, , MonoClass, wastypebuilder) MONO_CLASS_GETTER(m_class_is_array_special_interface, gboolean, , MonoClass, is_array_special_interface) diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 750dcff22d70b..58b95248ba828 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -1974,6 +1974,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ gboolean has_static_refs = FALSE; MonoClassField *field; gboolean blittable; + gboolean any_field_has_auto_layout; int instance_size = base_instance_size; int element_size = -1; int class_size, min_align; @@ -2045,12 +2046,17 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ gc_aware_layout = TRUE; } - /* Compute klass->blittable */ + /* Compute klass->blittable and klass->any_field_has_auto_layout */ blittable = TRUE; - if (klass->parent) + any_field_has_auto_layout = FALSE; + if (klass->parent) { blittable = klass->parent->blittable; - if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top) + any_field_has_auto_layout = klass->parent->any_field_has_auto_layout; + } + if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top) { blittable = FALSE; + any_field_has_auto_layout = TRUE; // If a type is auto-layout, treat it as having an auto-layout field in its layout. + } for (i = 0; i < top; i++) { field = &klass->fields [i]; @@ -2080,8 +2086,12 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ blittable = FALSE; } } - if (klass->enumtype) - blittable = klass->element_class->blittable; + if (!any_field_has_auto_layout && field->type->type == MONO_TYPE_VALUETYPE && m_class_any_field_has_auto_layout (mono_class_from_mono_type_internal (field->type))) + any_field_has_auto_layout = TRUE; + } + if (klass->enumtype) { + blittable = klass->element_class->blittable; + any_field_has_auto_layout = klass->element_class->any_field_has_auto_layout; } if (mono_class_has_failure (klass)) return; @@ -2308,6 +2318,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ klass->has_references = has_references; klass->packing_size = packing_size; klass->min_align = min_align; + klass->any_field_has_auto_layout = any_field_has_auto_layout; for (i = 0; i < top; ++i) { field = &klass->fields [i]; if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) diff --git a/src/mono/mono/metadata/class-private-definition.h b/src/mono/mono/metadata/class-private-definition.h index 4724df84b7f8c..a1b8432d690ce 100644 --- a/src/mono/mono/metadata/class-private-definition.h +++ b/src/mono/mono/metadata/class-private-definition.h @@ -80,6 +80,7 @@ struct _MonoClass { guint has_failure : 1; /* See mono_class_get_exception_data () for a MonoErrorBoxed with the details */ guint has_weak_fields : 1; /* class has weak reference fields */ guint has_dim_conflicts : 1; /* Class has conflicting default interface methods */ + guint any_field_has_auto_layout : 1; /* a field in this type's layout uses auto-layout */ MonoClass *parent; MonoClass *nested_in; diff --git a/src/mono/mono/metadata/cominterop.c b/src/mono/mono/metadata/cominterop.c index ddeeaccb73502..7084b5feb81fb 100644 --- a/src/mono/mono/metadata/cominterop.c +++ b/src/mono/mono/metadata/cominterop.c @@ -1012,7 +1012,7 @@ cominterop_get_native_wrapper_adjusted (MonoMethod *method) } } - mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS); + mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS | EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED); res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16); @@ -2103,6 +2103,7 @@ cominterop_get_ccw_method (MonoClass *iface, MonoMethod *method, MonoError *erro cominterop_setup_marshal_context (&m, adjust_method); m.mb = mb; + m.runtime_marshalling_enabled = TRUE; mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0); mono_cominterop_lock (); wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16); diff --git a/src/mono/mono/metadata/marshal-ilgen.c b/src/mono/mono/metadata/marshal-ilgen.c index b8a12826aac4b..2290c438125c9 100644 --- a/src/mono/mono/metadata/marshal-ilgen.c +++ b/src/mono/mono/metadata/marshal-ilgen.c @@ -1991,6 +1991,7 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi gboolean func_param = (flags & EMIT_NATIVE_WRAPPER_FUNC_PARAM) != 0; gboolean func_param_unboxed = (flags & EMIT_NATIVE_WRAPPER_FUNC_PARAM_UNBOXED) != 0; gboolean skip_gc_trans = (flags & EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS) != 0; + gboolean runtime_marshalling_enabled = (flags & EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED) != 0; EmitMarshalContext m; MonoMethodSignature *csig; MonoClass *klass; @@ -2001,6 +2002,7 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi GCSafeTransitionBuilder gc_safe_transition_builder; memset (&m, 0, sizeof (m)); + m.runtime_marshalling_enabled = runtime_marshalling_enabled; m.mb = mb; m.sig = sig; m.piinfo = piinfo; @@ -2016,6 +2018,8 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi } csig = mono_metadata_signature_dup_full (get_method_image (mb->method), sig); csig->pinvoke = 1; + if (!runtime_marshalling_enabled) + csig->marshalling_disabled = 1; m.csig = csig; m.image = image; @@ -2102,6 +2106,10 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi csig->ret = int_type; } + // Check if SetLastError usage is valid early so we don't try to throw an exception after transitioning GC modes. + if (piinfo && (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) && !m.runtime_marshalling_enabled) + mono_mb_emit_exception_marshal_directive(mb, g_strdup("Setting SetLastError=true is not supported when runtime marshalling is disabled.")); + /* we first do all conversions */ tmp_locals = g_newa (int, sig->param_count); m.orig_conv_args = g_newa (int, sig->param_count + 1); @@ -6762,6 +6770,18 @@ mb_emit_exception_for_error_ilgen (MonoMethodBuilder *mb, const MonoError *error mono_mb_emit_exception_for_error (mb, (MonoError*)error); } +static void +emit_marshal_directive_exception_ilgen (EmitMarshalContext *m, int argnum, const char* msg) +{ + char* fullmsg = NULL; + if (argnum == 0) + fullmsg = g_strdup_printf("Error marshalling return value: %s", msg); + else + fullmsg = g_strdup_printf("Error marshalling parameter #%d: %s", argnum, msg); + + mono_mb_emit_exception_marshal_directive (m->mb, fullmsg); +} + static void emit_vtfixup_ftnptr_ilgen (MonoMethodBuilder *mb, MonoMethod *method, int param_count, guint16 type) { @@ -6850,6 +6870,7 @@ mono_marshal_ilgen_init (void) cb.mb_emit_exception = mb_emit_exception_ilgen; cb.mb_emit_exception_for_error = mb_emit_exception_for_error_ilgen; cb.mb_emit_byte = mb_emit_byte_ilgen; + cb.emit_marshal_directive_exception = emit_marshal_directive_exception_ilgen; #ifdef DISABLE_NONBLITTABLE mono_marshal_noilgen_init_blittable (&cb); #endif diff --git a/src/mono/mono/metadata/marshal-noilgen.c b/src/mono/mono/metadata/marshal-noilgen.c index 0cc81a3e5744b..7a004458bbfb7 100644 --- a/src/mono/mono/metadata/marshal-noilgen.c +++ b/src/mono/mono/metadata/marshal-noilgen.c @@ -246,6 +246,11 @@ mb_emit_exception_noilgen (MonoMethodBuilder *mb, const char *exc_nspace, const { } +static void +emit_marshal_directive_exception_noilgen (EmitMarshalContext *m, int argnum, const char* msg) +{ +} + static void mb_emit_exception_for_error_noilgen (MonoMethodBuilder *mb, const MonoError *error) { @@ -404,6 +409,7 @@ mono_marshal_noilgen_init (void) cb.mb_set_dynamic = mb_set_dynamic_noilgen; cb.mb_emit_exception = mb_emit_exception_noilgen; cb.mb_emit_exception_for_error = mb_emit_exception_for_error_noilgen; + cb.emit_marshal_directive_exception = emit_marshal_directive_exception_noilgen; cb.mb_emit_byte = mb_emit_byte_noilgen; mono_install_marshal_callbacks (&cb); } diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 498f3ff563f10..4f57d238e16a8 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -2985,6 +2985,51 @@ mono_pinvoke_is_unicode (MonoMethodPInvoke *piinfo) } } +static GENERATE_TRY_GET_CLASS_WITH_CACHE (disable_runtime_marshalling_attr, "System.Runtime.CompilerServices", "DisableRuntimeMarshallingAttribute") + +/* + * runtime_marshalling_enabled: + * + * Determine whenever M's assembly has the runtime marshalling subsystem enabled. + */ +static gboolean +runtime_marshalling_enabled (MonoImage *img) +{ + ERROR_DECL (error); + MonoAssembly *ass = img->assembly; + MonoCustomAttrInfo* attrs; + MonoClass *klass; + int i; + gboolean runtime_marshalling_enabled = TRUE; + + g_assert (ass); + if (ass->runtime_marshalling_enabled_inited) + return ass->runtime_marshalling_enabled; + + klass = mono_class_try_get_disable_runtime_marshalling_attr_class (); + attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, error); + mono_error_cleanup (error); /* FIXME don't swallow the error */ + if (attrs && klass) { + for (i = 0; i < attrs->num_attrs; ++i) { + MonoCustomAttrEntry *attr = &attrs->attrs [i]; + if (attr->ctor && attr->ctor->klass == klass) { + runtime_marshalling_enabled = FALSE; + break; + } + } + } + + if (attrs) + mono_custom_attrs_free (attrs); + + ass->runtime_marshalling_enabled = runtime_marshalling_enabled; + mono_memory_barrier (); + ass->runtime_marshalling_enabled_inited = TRUE; + + return ass->runtime_marshalling_enabled; +} + + MonoType* mono_marshal_boolean_conv_in_get_local_type (MonoMarshalSpec *spec, guint8 *ldc_op /*out*/) { @@ -3031,6 +3076,76 @@ mono_marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec *spec, return conv_arg_class; } +static int +mono_emit_disabled_marshal (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + // Some phases like MARSHAL_ACTION_PUSH need to still emit "correct" IL for the IL stack to be valid. + // For those phases, we won't emit the exception throw. + // In all other phases we'll emit the exception throw. + gboolean emit_exception = action == MARSHAL_ACTION_CONV_IN || action == MARSHAL_ACTION_CONV_RESULT; + + if (m_type_is_byref(t)) { + if (emit_exception) + get_marshal_cb ()->emit_marshal_directive_exception (m, argnum, "Cannot marshal managed references when the runtime marshalling system is disabled."); + else + get_marshal_cb ()->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); + return conv_arg; + } + + switch (t->type) { + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (t)) + break; + // fallthrough + case MONO_TYPE_VALUETYPE: { + MonoClass* c = mono_class_from_mono_type_internal (t); + if (m_class_has_references(c)) { + if (emit_exception) + get_marshal_cb ()->emit_marshal_directive_exception (m, argnum, "Cannot marshal managed types when the runtime marshalling system is disabled."); + else + get_marshal_cb ()->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); + return conv_arg; + } + if (m_class_any_field_has_auto_layout(c)) { + if (emit_exception) + get_marshal_cb ()->emit_marshal_directive_exception (m, argnum, "Structures marked with [StructLayout(LayoutKind.Auto)] cannot be marshaled."); + else + get_marshal_cb ()->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); + return conv_arg; + } + } + // fallthrough + case MONO_TYPE_VOID: + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_PTR: + case MONO_TYPE_CHAR: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_FNPTR: + return get_marshal_cb ()->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); + default: + break; + } + + if (emit_exception) + get_marshal_cb ()->emit_marshal_directive_exception (m, argnum, "Cannot marshal managed types when the runtime marshalling system is disabled."); + else + get_marshal_cb ()->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); + return conv_arg; +} + int mono_emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, @@ -3039,6 +3154,9 @@ mono_emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, /* Ensure that we have marshalling info for this param */ mono_marshal_load_type_info (mono_class_from_mono_type_internal (t)); + if (!m->runtime_marshalling_enabled) + return mono_emit_disabled_marshal (m, argnum, t, spec, conv_arg, conv_arg_type, action); + if (spec && spec->native == MONO_NATIVE_CUSTOM) return get_marshal_cb ()->emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action); @@ -3480,6 +3598,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, MonoNativeWrapperFlags flags = aot ? EMIT_NATIVE_WRAPPER_AOT : (MonoNativeWrapperFlags)0; flags |= check_exceptions ? EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS : (MonoNativeWrapperFlags)0; flags |= skip_gc_trans ? EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS : (MonoNativeWrapperFlags)0; + flags |= runtime_marshalling_enabled (get_method_image (method)) ? EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED : (MonoNativeWrapperFlags)0; mono_marshal_emit_native_wrapper (get_method_image (mb->method), mb, csig, piinfo, mspecs, piinfo->addr, flags); info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_PINVOKE); @@ -3521,6 +3640,7 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig GHashTable *cache; gboolean found; char *name; + MonoNativeWrapperFlags flags; key.sig = sig; key.pointer = func; @@ -3536,7 +3656,10 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE); mb->method->save_lmf = 1; - mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS); + flags = EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS; + flags |= runtime_marshalling_enabled (image) ? EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED : (MonoNativeWrapperFlags)0; + + mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, flags); csig = mono_metadata_signature_dup_full (image, sig); csig->pinvoke = 0; @@ -3575,6 +3698,7 @@ mono_marshal_get_native_func_wrapper_aot (MonoClass *klass) MonoMethod *invoke = mono_get_delegate_invoke_internal (klass); MonoImage *image = get_method_image (invoke); int i; + MonoNativeWrapperFlags flags; // FIXME: include UnmanagedFunctionPointerAttribute info @@ -3599,7 +3723,9 @@ mono_marshal_get_native_func_wrapper_aot (MonoClass *klass) mb = mono_mb_new (invoke->klass, name, MONO_WRAPPER_MANAGED_TO_NATIVE); mb->method->save_lmf = 1; - mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, NULL, EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS | EMIT_NATIVE_WRAPPER_FUNC_PARAM); + flags = EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS | EMIT_NATIVE_WRAPPER_FUNC_PARAM; + flags |= runtime_marshalling_enabled (image) ? EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED : (MonoNativeWrapperFlags)0; + mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, NULL, flags); info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT); info->d.managed_to_native.method = invoke; @@ -3683,6 +3809,7 @@ mono_marshal_get_native_func_wrapper_indirect (MonoClass *caller_class, MonoMeth MonoMarshalSpec **mspecs = g_new0 (MonoMarshalSpec *, 1 + sig->param_count); MonoNativeWrapperFlags flags = aot ? EMIT_NATIVE_WRAPPER_AOT : (MonoNativeWrapperFlags)0; flags |= EMIT_NATIVE_WRAPPER_FUNC_PARAM | EMIT_NATIVE_WRAPPER_FUNC_PARAM_UNBOXED; + flags |= runtime_marshalling_enabled (image) ? EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED : (MonoNativeWrapperFlags)0; mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, /*func*/NULL, flags); g_free (mspecs); @@ -3745,19 +3872,70 @@ type_is_blittable (MonoType *type) } static gboolean -method_signature_is_blittable (MonoMethodSignature *sig) +check_all_types_in_method_signature (MonoMethodSignature *sig, gboolean (*validate) (MonoType *type)) { - if (!type_is_blittable (sig->ret)) + if (!validate (sig->ret)) return FALSE; for (int i = 0; i < sig->param_count; ++i) { MonoType *type = sig->params [i]; - if (!type_is_blittable (type)) + if (!validate (type)) return FALSE; } return TRUE; } +static gboolean +method_signature_is_blittable (MonoMethodSignature *sig) +{ + return check_all_types_in_method_signature (sig, &type_is_blittable); +} + +static gboolean +type_is_usable_when_marshalling_disabled (MonoType *type) +{ + switch (type->type) { + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (type)) + return FALSE; + // fallthrough + case MONO_TYPE_VALUETYPE: { + MonoClass* c = mono_class_from_mono_type_internal (type); + if (m_class_has_references(c) || (m_class_is_auto_layout(c) && !m_class_is_enumtype(c))) { + return FALSE; + } + } + // fallthrough + case MONO_TYPE_VOID: + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_PTR: + case MONO_TYPE_CHAR: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_FNPTR: + return TRUE; + default: + return FALSE; + } +} + + +static gboolean +method_signature_is_usable_when_marshalling_disabled (MonoMethodSignature *sig) +{ + return check_all_types_in_method_signature (sig, &type_is_usable_when_marshalling_disabled); +} + /** * mono_marshal_get_managed_wrapper: * Generates IL code to call managed methods from unmanaged code @@ -3777,6 +3955,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, GHashTable *cache; int i; EmitMarshalContext m; + gboolean marshalling_enabled; g_assert (method != NULL); error_init (error); @@ -3798,22 +3977,28 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, if (G_UNLIKELY (!delegate_klass)) { /* creating a wrapper for a function pointer with UnmanagedCallersOnlyAttribute */ - if (mono_method_has_marshal_info (method)) { - mono_error_set_invalid_program (error, "method %s with UnmanadedCallersOnlyAttribute has marshal specs", mono_method_full_name (method, TRUE)); - return NULL; - } + marshalling_enabled = runtime_marshalling_enabled(get_method_image(method)); invoke = NULL; invoke_sig = mono_method_signature_internal (method); if (invoke_sig->hasthis) { - mono_error_set_invalid_program (error, "method %s with UnamanagedCallersOnlyAttribute is an instance method", mono_method_full_name (method, TRUE)); + mono_error_set_invalid_program (error, "method %s with UnmanagedCallersOnlyAttribute is an instance method", mono_method_full_name (method, TRUE)); return NULL; } if (method->is_generic || method->is_inflated || mono_class_is_ginst (method->klass)) { - mono_error_set_invalid_program (error, "method %s with UnamangedCallersOnlyAttribute is generic", mono_method_full_name (method, TRUE)); + mono_error_set_invalid_program (error, "method %s with UnmanagedCallersOnlyAttribute is generic", mono_method_full_name (method, TRUE)); return NULL; } - if (!method_signature_is_blittable (invoke_sig)) { - mono_error_set_invalid_program (error, "method %s with UnmanagedCallersOnlyAttribute has non-blittable parameters or return type", mono_method_full_name (method, TRUE)); + if (marshalling_enabled) { + if (mono_method_has_marshal_info (method)) { + mono_error_set_invalid_program (error, "method %s with UnmanagedCallersOnlyAttribute has marshal specs", mono_method_full_name (method, TRUE)); + return NULL; + } + if (!method_signature_is_blittable (invoke_sig)) { + mono_error_set_invalid_program (error, "method %s with UnmanagedCallersOnlyAttribute has non-blittable parameters or return type", mono_method_full_name (method, TRUE)); + return NULL; + } + } else if (!method_signature_is_usable_when_marshalling_disabled(invoke_sig)) { + mono_error_set_invalid_program (error, "method %s with UnmanagedCallersOnlyAttribute has types not usable when marshalling is disabled", mono_method_full_name (method, TRUE)); return NULL; } mspecs = g_new0 (MonoMarshalSpec*, invoke_sig->param_count + 1); @@ -3822,6 +4007,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, invoke_sig = mono_method_signature_internal (invoke); mspecs = g_new0 (MonoMarshalSpec*, invoke_sig->param_count + 1); mono_method_get_marshal_info (invoke, mspecs); + marshalling_enabled = runtime_marshalling_enabled(m_class_get_image (delegate_klass)); } sig = mono_method_signature_internal (method); @@ -3840,6 +4026,9 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, csig->hasthis = 0; csig->pinvoke = 1; + if (!marshalling_enabled) + csig->marshalling_disabled = 1; + memset (&m, 0, sizeof (m)); m.mb = mb; m.sig = sig; @@ -3847,6 +4036,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, m.retobj_var = 0; m.csig = csig; m.image = get_method_image (method); + m.runtime_marshalling_enabled = marshalling_enabled; if (invoke) mono_marshal_set_callconv_from_modopt (invoke, csig, TRUE); @@ -3971,6 +4161,7 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type) MonoMethodSignature *csig; MonoMarshalSpec **mspecs; EmitMarshalContext m; + gboolean marshalling_enabled = runtime_marshalling_enabled(image); sig = mono_method_signature_internal (method); g_assert (!sig->hasthis); @@ -3982,6 +4173,8 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type) csig = mono_metadata_signature_dup_full (image, sig); csig->hasthis = 0; csig->pinvoke = 1; + if (!marshalling_enabled) + csig->marshalling_disabled = 1; memset (&m, 0, sizeof (m)); m.mb = mb; @@ -3990,6 +4183,7 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type) m.retobj_var = 0; m.csig = csig; m.image = image; + m.runtime_marshalling_enabled = marshalling_enabled; mono_marshal_set_callconv_from_modopt (method, csig, TRUE); diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index a941934c56446..1779131e45093 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -50,6 +50,7 @@ typedef struct { MonoClass *retobj_class; MonoMethodSignature *csig; /* Might need to be changed due to MarshalAs directives */ MonoImage *image; /* The image to use for looking up custom marshallers */ + gboolean runtime_marshalling_enabled; } EmitMarshalContext; typedef enum { @@ -295,12 +296,13 @@ typedef enum { EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS = 0x02, EMIT_NATIVE_WRAPPER_FUNC_PARAM = 0x04, EMIT_NATIVE_WRAPPER_FUNC_PARAM_UNBOXED = 0x08, - EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS=0x10, + EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS = 0x10, + EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED = 0x20, } MonoNativeWrapperFlags; G_ENUM_FUNCTIONS(MonoNativeWrapperFlags); -#define MONO_MARSHAL_CALLBACKS_VERSION 5 +#define MONO_MARSHAL_CALLBACKS_VERSION 6 typedef struct { int version; @@ -347,6 +349,7 @@ typedef struct { void (*mb_emit_exception) (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg); void (*mb_emit_exception_for_error) (MonoMethodBuilder *mb, const MonoError *emitted_error); void (*mb_emit_byte) (MonoMethodBuilder *mb, guint8 op); + void (*emit_marshal_directive_exception) (EmitMarshalContext *m, int argnum, const char* msg); } MonoMarshalCallbacks; /*type of the function pointer of methods returned by mono_marshal_get_runtime_invoke*/ diff --git a/src/mono/mono/metadata/metadata-internals.h b/src/mono/mono/metadata/metadata-internals.h index 4e5ddf40abe86..ba8f957aaf2d0 100644 --- a/src/mono/mono/metadata/metadata-internals.h +++ b/src/mono/mono/metadata/metadata-internals.h @@ -213,6 +213,8 @@ struct _MonoAssembly { guint8 wrap_non_exception_throws_inited; guint8 jit_optimizer_disabled; guint8 jit_optimizer_disabled_inited; + guint8 runtime_marshalling_enabled; + guint8 runtime_marshalling_enabled_inited; /* security manager flags (one bit is for lazy initialization) */ guint32 skipverification:2; /* Has SecurityPermissionFlag.SkipVerification permission */ }; @@ -657,6 +659,7 @@ struct _MonoMethodSignature { unsigned int is_inflated : 1; unsigned int has_type_parameters : 1; unsigned int suppress_gc_transition : 1; + unsigned int marshalling_disabled : 1; MonoType *params [MONO_ZERO_LEN_ARRAY]; }; diff --git a/src/mono/mono/mini/calls.c b/src/mono/mono/mini/calls.c index dc3007b36bfb7..e4877f6d98c03 100644 --- a/src/mono/mono/mini/calls.c +++ b/src/mono/mono/mini/calls.c @@ -193,7 +193,7 @@ mini_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL); MonoInst *loada; - temp->backend.is_pinvoke = sig->pinvoke; + temp->backend.is_pinvoke = sig->pinvoke && !sig->marshalling_disabled; /* * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 099c70695c138..d36e3388db713 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1534,11 +1534,11 @@ interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, // If index == -1, we finished executing an InterpFrame and the result is at retval. if (index == -1) - stackval_to_data (sig->ret, iframe->retval, data, TRUE); + stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke && !sig->marshalling_disabled); else if (sig->hasthis && index == 0) *(gpointer*)data = iframe->stack->data.p; else - stackval_to_data (sig->params [index - sig->hasthis], STACK_ADD_BYTES (iframe->stack, get_arg_offset (imethod, sig, index)), data, sig->pinvoke); + stackval_to_data (sig->params [index - sig->hasthis], STACK_ADD_BYTES (iframe->stack, get_arg_offset (imethod, sig, index)), data, sig->pinvoke && !sig->marshalling_disabled); } static void @@ -1549,11 +1549,11 @@ interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, // Get result from pinvoke call, put it directly on top of execution stack in the caller frame if (index == -1) - stackval_from_data (sig->ret, iframe->retval, data, TRUE); + stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke && !sig->marshalling_disabled); else if (sig->hasthis && index == 0) iframe->stack->data.p = *(gpointer*)data; else - stackval_from_data (sig->params [index - sig->hasthis], STACK_ADD_BYTES (iframe->stack, get_arg_offset (imethod, sig, index)), data, sig->pinvoke); + stackval_from_data (sig->params [index - sig->hasthis], STACK_ADD_BYTES (iframe->stack, get_arg_offset (imethod, sig, index)), data, sig->pinvoke && !sig->marshalling_disabled); } static gpointer @@ -1685,7 +1685,7 @@ ves_pinvoke_method ( #else // Only the vt address has been returned, we need to copy the entire content on interp stack if (!context->has_resume_state && MONO_TYPE_ISSTRUCT (sig->ret)) - stackval_from_data (sig->ret, frame.retval, (char*)frame.retval->data.p, sig->pinvoke); + stackval_from_data (sig->ret, frame.retval, (char*)frame.retval->data.p, sig->pinvoke && !sig->marshalling_disabled); g_free (margs->iargs); g_free (margs->fargs); @@ -2282,7 +2282,7 @@ do_icall (MonoMethodSignature *sig, int op, stackval *ret_sp, stackval *sp, gpoi /* convert the native representation to the stackval representation */ if (sig) - stackval_from_data (sig->ret, ret_sp, (char*) &ret_sp->data.p, sig->pinvoke); + stackval_from_data (sig->ret, ret_sp, (char*) &ret_sp->data.p, sig->pinvoke && !sig->marshalling_disabled); } /* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */ @@ -2879,7 +2879,7 @@ interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untype if (type->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (type)) { size = mono_class_value_size (mono_class_from_mono_type_internal (type), NULL); } else if (type->type == MONO_TYPE_VALUETYPE) { - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size (type->data.klass, NULL); else size = mono_class_value_size (type->data.klass, NULL); @@ -6486,7 +6486,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_BREAK; MINT_IN_CASE(MINT_MONO_RETOBJ) stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->stack, LOCAL_VAR (ip [1], gpointer), - mono_method_signature_internal (frame->imethod->method)->pinvoke); + mono_method_signature_internal (frame->imethod->method)->pinvoke && !mono_method_signature_internal (frame->imethod->method)->marshalling_disabled); frame_data_allocator_pop (&context->data_stack, frame); goto exit_frame; MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index a5d57007d885f..ba5075abd8166 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -980,7 +980,7 @@ load_arg(TransformData *td, int n) if (mt == MINT_TYPE_VT) { klass = mono_class_from_mono_type_internal (type); - if (mono_method_signature_internal (td->method)->pinvoke) + if (mono_method_signature_internal (td->method)->pinvoke && !mono_method_signature_internal (td->method)->marshalling_disabled) size = mono_class_native_size (klass, NULL); else size = mono_class_value_size (klass, NULL); @@ -1023,7 +1023,7 @@ store_arg(TransformData *td, int n) if (mt == MINT_TYPE_VT) { MonoClass *klass = mono_class_from_mono_type_internal (type); - if (mono_method_signature_internal (td->method)->pinvoke) + if (mono_method_signature_internal (td->method)->pinvoke && !mono_method_signature_internal (td->method)->marshalling_disabled) size = mono_class_native_size (klass, NULL); else size = mono_class_value_size (klass, NULL); @@ -3395,7 +3395,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target MonoClass *klass = mono_class_from_mono_type_internal (csignature->ret); if (mt == MINT_TYPE_VT) { - if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE) + if (csignature->pinvoke && !csignature->marshalling_disabled && method->wrapper_type != MONO_WRAPPER_NONE) res_size = mono_class_native_size (klass, NULL); else res_size = mono_class_value_size (klass, NULL); @@ -7014,7 +7014,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, int size; CHECK_STACK (td, 1); MonoClass *klass = td->sp [-1].klass; - if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) + if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && !signature->marshalling_disabled) size = mono_class_native_size (klass, NULL); else size = mono_class_value_size (klass, NULL); diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 7b5c36779f1b0..7e1f5a879ea6e 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -606,7 +606,7 @@ add_valuetype_win64 (MonoMethodSignature *signature, ArgInfo *arg_info, MonoType assert (signature != NULL && arg_info != NULL && type != NULL && current_int_reg != NULL && current_float_reg != NULL && stack_size != NULL); klass = mono_class_from_mono_type_internal (type); - get_valuetype_size_win64 (klass, signature->pinvoke, arg_info, type, &arg_class, &arg_size); + get_valuetype_size_win64 (klass, signature->pinvoke && !signature->marshalling_disabled, arg_info, type, &arg_class, &arg_size); /* Only drop value type if its not an empty struct as input that must be represented in call */ if ((arg_size == 0 && !arg_info->pass_empty_struct) || (arg_info->pass_empty_struct && is_return)) { @@ -640,7 +640,7 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, int struct_size; klass = mono_class_from_mono_type_internal (type); - size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke); + size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled); if (!sig->pinvoke && ((is_return && (size == 8)) || (!is_return && (size <= 16)))) { /* We pass and return vtypes of size 8 in a register */ @@ -650,7 +650,7 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, /* If this struct can't be split up naturally into 8-byte */ /* chunks (registers), pass it on the stack. */ - if (sig->pinvoke) { + if (sig->pinvoke && !sig->marshalling_disabled) { MonoMarshalType *info = mono_marshal_load_type_info (klass); g_assert (info); struct_size = info->native_size; @@ -662,7 +662,7 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, * handle nested structures. */ fields_array = g_array_new (FALSE, TRUE, sizeof (StructFieldInfo)); - collect_field_info_nested (klass, fields_array, 0, sig->pinvoke, m_class_is_unicode (klass)); + collect_field_info_nested (klass, fields_array, 0, sig->pinvoke && !sig->marshalling_disabled, m_class_is_unicode (klass)); fields = (StructFieldInfo*)fields_array->data; nfields = fields_array->len; @@ -2311,7 +2311,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) guint32 align; guint32 size; - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_type_native_stack_size (t, &align); else { /* @@ -2462,7 +2462,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) g_assert (ainfo->storage == ArgValuetypeAddrInIReg || (ainfo->storage == ArgValuetypeAddrOnStack && ainfo->pair_storage [0] == ArgNone)); vtaddr = mono_compile_create_var (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL); - vtaddr->backend.is_pinvoke = call->signature->pinvoke; + vtaddr->backend.is_pinvoke = call->signature->pinvoke && !call->signature->marshalling_disabled; MONO_INST_NEW (cfg, load, OP_LDADDR); cfg->has_indirection = TRUE; diff --git a/src/mono/mono/mini/mini-arm.c b/src/mono/mono/mini/mini-arm.c index 3f3b4a9bc88b3..c9a8c319786a5 100644 --- a/src/mono/mono/mini/mini-arm.c +++ b/src/mono/mono/mini/mini-arm.c @@ -605,7 +605,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit arg_info [0].size = frame_size; for (k = 0; k < param_count; k++) { - size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke); + size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke && !csig->marshalling_disabled); /* ignore alignment for now */ align = 1; @@ -1333,7 +1333,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) cinfo->ret.nregs = nfields; cinfo->ret.esize = esize; } else { - if (is_pinvoke) { + if (sig->pinvoke && !sig->marshalling_disabled) { int native_size = mono_class_native_size (mono_class_from_mono_type_internal (t), &align); int max_size; @@ -1496,7 +1496,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) align = sizeof (target_mgreg_t); } else { MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); - if (is_pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size (klass, &align); else size = mini_type_stack_size_full (t, &align, FALSE); @@ -2173,7 +2173,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) if (ins->opcode != OP_REGVAR) { ins->opcode = OP_REGOFFSET; ins->inst_basereg = cfg->frame_reg; - size = mini_type_stack_size_full (sig->params [i], &ualign, sig->pinvoke); + size = mini_type_stack_size_full (sig->params [i], &ualign, sig->pinvoke && !sig->marshalling_disabled); align = ualign; /* FIXME: if a structure is misaligned, our memcpy doesn't work, * since it loads/stores misaligned words, which don't do the right thing. @@ -6521,7 +6521,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) int soffset = 0; int cur_reg; int size = 0; - size = mini_type_stack_size_full (inst->inst_vtype, NULL, sig->pinvoke); + size = mini_type_stack_size_full (inst->inst_vtype, NULL, sig->pinvoke && !sig->marshalling_disabled); for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) { if (arm_is_imm12 (doffset)) { ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset); diff --git a/src/mono/mono/mini/mini-generic-sharing.c b/src/mono/mono/mini/mini-generic-sharing.c index f05a78aa8d804..91811f678deb6 100644 --- a/src/mono/mono/mini/mini-generic-sharing.c +++ b/src/mono/mono/mini/mini-generic-sharing.c @@ -1763,7 +1763,7 @@ mini_get_interp_in_wrapper (MonoMethodSignature *sig) * stack, pass this address to the interp_entry and when we return it we use * CEE_MONO_LDNATIVEOBJ */ - return_native_struct = sig->ret->type == MONO_TYPE_VALUETYPE && sig->pinvoke; + return_native_struct = sig->ret->type == MONO_TYPE_VALUETYPE && sig->pinvoke && !sig->marshalling_disabled; /* Create the signature for the wrapper */ csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*))); diff --git a/src/mono/mono/mini/mini-mips.c b/src/mono/mono/mini/mini-mips.c index 666c3cd51f936..3db3a9debab41 100644 --- a/src/mono/mono/mini/mini-mips.c +++ b/src/mono/mono/mini/mini-mips.c @@ -488,7 +488,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit arg_info [0].size = frame_size; for (k = 0; k < param_count; k++) { - size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke); + size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke && !csig->marshalling_disabled); /* ignore alignment for now */ align = 1; @@ -1156,7 +1156,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) alignment = sizeof (target_mgreg_t); } else { klass = mono_class_from_mono_type_internal (sig->params [i]); - if (is_pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size (klass, NULL); else size = mono_class_value_size (klass, NULL); @@ -1878,7 +1878,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) guint32 size; /* FIXME: alignment? */ - if (call->signature->pinvoke) { + if (call->signature->pinvoke && !call->signature->marshalling_disabled) { size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL); vtcopy->backend.is_pinvoke = 1; } else { diff --git a/src/mono/mono/mini/mini-ppc.c b/src/mono/mono/mini/mini-ppc.c index df2cd3b6f362b..48174a3130ac3 100644 --- a/src/mono/mono/mini/mini-ppc.c +++ b/src/mono/mono/mini/mini-ppc.c @@ -248,7 +248,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit for (k = 0; k < param_count; k++) { - if (csig->pinvoke) + if (csig->pinvoke && !csig->marshalling_disabled) size = mono_type_native_stack_size (csig->params [k], (guint32*)&align); else size = mini_type_stack_size (csig->params [k], &align); @@ -1109,7 +1109,7 @@ get_call_info (MonoMethodSignature *sig) MonoClass *klass = mono_class_from_mono_type_internal (sig->params [i]); if (simpletype->type == MONO_TYPE_TYPEDBYREF) size = MONO_ABI_SIZEOF (MonoTypedRef); - else if (is_pinvoke) + else if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size (klass, NULL); else size = mono_class_value_size (klass, NULL); @@ -1498,7 +1498,7 @@ mono_arch_allocate_vars (MonoCompile *m) if (inst->opcode != OP_REGVAR) { inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; - if (sig->pinvoke) { + if (sig->pinvoke && !sig->marshalling_disabled) { size = mono_type_native_stack_size (sig->params [i], (guint32*)&align); inst->backend.is_pinvoke = 1; } else { @@ -1739,7 +1739,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) * and 2 byte arguments */ g_assert (ins->klass); - if (call->signature->pinvoke) + if (call->signature->pinvoke && !call->signature->marshalling_disabled) size = mono_class_native_size (ins->klass, NULL); if (size == 2 || size == 1) { int tmpr = mono_alloc_ireg (cfg); @@ -1801,7 +1801,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) guint32 size; /* FIXME: alignment? */ - if (call->signature->pinvoke) { + if (call->signature->pinvoke && !call->signature->marshalling_disabled) { size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL); vtcopy->backend.is_pinvoke = 1; } else { @@ -5036,7 +5036,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) g_assert (ppc_is_imm16 (inst->inst_offset)); g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (target_mgreg_t))); /* FIXME: what if there is no class? */ - if (sig->pinvoke && mono_class_from_mono_type_internal (inst->inst_vtype)) + if (sig->pinvoke && !sig->marshalling_disabled && mono_class_from_mono_type_internal (inst->inst_vtype)) size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), NULL); for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) { if (ainfo->size == 4) { @@ -5055,7 +5055,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) g_assert (ppc_is_imm16 (inst->inst_offset)); g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (target_mgreg_t))); /* FIXME: what if there is no class? */ - if (sig->pinvoke && mono_class_from_mono_type_internal (inst->inst_vtype)) + if (sig->pinvoke && !sig->marshalling_disabled && mono_class_from_mono_type_internal (inst->inst_vtype)) size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), NULL); for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) { #if __APPLE__ diff --git a/src/mono/mono/mini/mini-s390x.c b/src/mono/mono/mini/mini-s390x.c index b3fb3de3ab061..5e4aca54eadb6 100644 --- a/src/mono/mono/mini/mini-s390x.c +++ b/src/mono/mono/mini/mini-s390x.c @@ -510,7 +510,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, for (k = 0; k < param_count; k++) { - if (csig->pinvoke) + if (csig->pinvoke && !csig->marshalling_disabled) size = mono_type_native_stack_size (csig->params [k], (guint32 *) &align); else size = mini_type_stack_size (csig->params [k], &align); @@ -556,7 +556,7 @@ emit_new_move(MonoCompile *cfg, int dr, MonoInst *ins, MonoInst *src) MonoInst *move; int size; - if (call->signature->pinvoke) { + if (call->signature->pinvoke && !call->signature->marshalling_disabled) { size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL); vtcopy->backend.is_pinvoke = 1; } else { @@ -1130,7 +1130,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) simpleType = mono_class_enum_basetype_internal (klass)->type; goto enum_retvalue; } - size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke); + size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled); cinfo->struct_ret = 1; cinfo->ret.size = size; @@ -1139,7 +1139,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } case MONO_TYPE_TYPEDBYREF: { MonoClass *klass = mono_class_from_mono_type_internal (sig->ret); - size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke); + size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled); cinfo->struct_ret = 1; cinfo->ret.size = size; @@ -1288,7 +1288,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) MonoMarshalType *info; MonoClass *klass = mono_class_from_mono_type_internal (ptype); - if (sig->pinvoke) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size(klass, NULL); else size = mono_class_value_size(klass, NULL); @@ -1950,7 +1950,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) guint32 size; /* FIXME: alignment? */ - if (call->signature->pinvoke) { + if (call->signature->pinvoke && !call->signature->marshalling_disabled) { size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL); vtcopy->backend.is_pinvoke = 1; } else { @@ -5814,7 +5814,7 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth } else if (ainfo->regtype == RegTypeStructByVal) { int doffset = inst->inst_offset; - size = (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE + size = (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && sig->pinvoke && !sig->marshalling_disabled ? mono_class_native_size(mono_class_from_mono_type_internal (inst->inst_vtype), NULL) : ainfo->size); diff --git a/src/mono/mono/mini/mini-sparc.c b/src/mono/mono/mini/mini-sparc.c index 184477cfc5175..2efe4ba06e74e 100644 --- a/src/mono/mono/mini/mini-sparc.c +++ b/src/mono/mono/mini/mini-sparc.c @@ -1297,7 +1297,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) arg_type = mini_get_underlying_type (arg_type); if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) - emit_pass_vtype (cfg, call, cinfo, ainfo, arg_type, in, sig->pinvoke); + emit_pass_vtype (cfg, call, cinfo, ainfo, arg_type, in, sig->pinvoke && !sig->marshalling_disabled); else if (!m_type_is_byref (arg_type) && ((arg_type->type == MONO_TYPE_I8) || (arg_type->type == MONO_TYPE_U8))) emit_pass_long (cfg, call, ainfo, in); else if (!m_type_is_byref (arg_type) && (arg_type->type == MONO_TYPE_R8)) @@ -2016,7 +2016,7 @@ emit_vret_token (MonoInst *ins, guint32 *code) * The sparc ABI requires that calls to functions which return a structure * contain an additional unimpl instruction which is checked by the callee. */ - if (call->signature->pinvoke && MONO_TYPE_ISSTRUCT(call->signature->ret)) { + if (call->signature->pinvoke && !call->signature->marshalling_disabled && MONO_TYPE_ISSTRUCT(call->signature->ret)) { if (call->signature->ret->type == MONO_TYPE_TYPEDBYREF) size = mini_type_stack_size (call->signature->ret, NULL); else diff --git a/src/mono/mono/mini/mini-x86.c b/src/mono/mono/mini/mini-x86.c index 52972a5e98ece..53a83263399bc 100644 --- a/src/mono/mono/mini/mini-x86.c +++ b/src/mono/mono/mini/mini-x86.c @@ -226,7 +226,7 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, MonoClass *klass; klass = mono_class_from_mono_type_internal (type); - size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke); + size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled); #if defined(TARGET_WIN32) /* @@ -728,7 +728,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit prev_stackarg = 0; for (k = 0; k < param_count; k++) { - size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke); + size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke && !csig->marshalling_disabled); if (storage_in_ireg (cinfo->args [csig->hasthis + k].storage)) { /* not in stack, we'll give it an offset at the end */ @@ -1592,7 +1592,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) align = sizeof (target_mgreg_t); } else { - size = mini_type_stack_size_full (m_class_get_byval_arg (in->klass), &align, sig->pinvoke); + size = mini_type_stack_size_full (m_class_get_byval_arg (in->klass), &align, sig->pinvoke && !sig->marshalling_disabled); } if (size > 0 || ainfo->pass_empty_struct) { diff --git a/src/tests/Common/XUnitWrapperGenerator/OptionsHelper.cs b/src/tests/Common/XUnitWrapperGenerator/OptionsHelper.cs index 9d27d24c46080..fa92071c917e8 100644 --- a/src/tests/Common/XUnitWrapperGenerator/OptionsHelper.cs +++ b/src/tests/Common/XUnitWrapperGenerator/OptionsHelper.cs @@ -10,7 +10,7 @@ public static class OptionsHelper private const string PriorityOption = "build_property.Priority"; private const string RuntimeFlavorOption = "build_property.RuntimeFlavor"; private const string IsOutOfProcessTestAssemblyOption = "build_metadata.AdditionalFiles.IsOutOfProcessTestAssembly"; - private const string TestFilterOption = "build_metadata.AdditionalFiles.TestFilter"; + private const string TestFilterOption = "build_property.TestFilter"; private const string TestAssemblyRelativePathOption = "build_metadata.AdditionalFiles.TestAssemblyRelativePath"; private const string TestDisplayNameOption = "build_metadata.AdditionalFiles.TestDisplayName"; private const string SingleTestDisplayNameOption = "build_metadata.AdditionalFiles.SingleTestDisplayName"; diff --git a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs index eb4295c06cc33..7b12b995f6801 100644 --- a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs +++ b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs @@ -402,7 +402,7 @@ private static IEnumerable GetTestMethodInfosForMethod(IMethodSymbol } break; case "Xunit.SkipOnMonoAttribute": - if (options.GlobalOptions.RuntimeFlavor() != "Mono") + if (options.GlobalOptions.RuntimeFlavor().ToLowerInvariant() != "mono") { // If we're building tests not for Mono, we can skip handling the specifics of the SkipOnMonoAttribute. continue; @@ -419,7 +419,7 @@ private static IEnumerable GetTestMethodInfosForMethod(IMethodSymbol testInfos = FilterForSkippedTargetFrameworkMonikers(testInfos, (int)filterAttribute.ConstructorArguments[0].Value!); break; case "Xunit.SkipOnCoreClrAttribute": - if (options.GlobalOptions.RuntimeFlavor() != "CoreCLR") + if (options.GlobalOptions.RuntimeFlavor().ToLowerInvariant() != "coreclr") { // If we're building tests not for CoreCLR, we can skip handling the specifics of the SkipOnCoreClrAttribute. continue; @@ -599,12 +599,12 @@ private static ImmutableArray CreateTestCases(IMethodSymbol method, L private static ImmutableArray FilterForSkippedRuntime(ImmutableArray testInfos, int skippedRuntimeValue, AnalyzerConfigOptionsProvider options) { Xunit.TestRuntimes skippedRuntimes = (Xunit.TestRuntimes)skippedRuntimeValue; - string runtimeFlavor = options.GlobalOptions.RuntimeFlavor(); - if (runtimeFlavor == "Mono" && skippedRuntimes.HasFlag(Xunit.TestRuntimes.Mono)) + string runtimeFlavor = options.GlobalOptions.RuntimeFlavor().ToLowerInvariant(); + if (runtimeFlavor == "mono" && skippedRuntimes.HasFlag(Xunit.TestRuntimes.Mono)) { return ImmutableArray.Empty; } - else if (runtimeFlavor == "CoreCLR" && skippedRuntimes.HasFlag(Xunit.TestRuntimes.CoreCLR)) + else if (runtimeFlavor == "coreclr" && skippedRuntimes.HasFlag(Xunit.TestRuntimes.CoreCLR)) { return ImmutableArray.Empty; } diff --git a/src/tests/Common/tests.targets b/src/tests/Common/tests.targets index ff6ba352e24cc..a99db7918fd22 100644 --- a/src/tests/Common/tests.targets +++ b/src/tests/Common/tests.targets @@ -66,17 +66,6 @@ $(XunitArgs) -nocolor - - $(CORE_ROOT)\corerun - $(CORE_ROOT)\corerun.exe - - - dotnet --roll-forward LatestMajor - $(DotnetRoot)/dotnet - true - $(DotnetExecutable) - $(CorerunExecutable) $(XunitConsoleRunner) @(TestAssemblies->'%(Identity)', ' ') $(XunitArgs) + $(DotNetCli) --roll-forward latestmajor $(XunitConsoleRunner) @(TestAssemblies->'%(Identity)', ' ') $(XunitArgs) (() => DisabledRuntimeMarshallingNative.CallWithAutoLayoutStruct(new AutoLayoutStruct())); + } + + [Fact] + public static void StructWithAutoLayoutField() + { + short s = 42; + bool b = true; + AssertThrowsMarshalDirectiveOrTypeLoad(() => DisabledRuntimeMarshallingNative.CallWithAutoLayoutStruct(new SequentialWithAutoLayoutField())); + } + + [Fact] + public static void StructWithNestedAutoLayoutField() + { + short s = 42; + bool b = true; + AssertThrowsMarshalDirectiveOrTypeLoad(() => DisabledRuntimeMarshallingNative.CallWithAutoLayoutStruct(new SequentialWithAutoLayoutNestedField())); + } + + private static void AssertThrowsMarshalDirectiveOrTypeLoad(Action testCode) + { + try + { + testCode(); + return; + } + catch (Exception ex) when(ex is MarshalDirectiveException or TypeLoadException) + { + return; + } + catch (Exception ex) + { + Assert.False(true, $"Expected either a MarshalDirectiveException or a TypeLoadException, but received a '{ex.GetType().FullName}' exception: '{ex.ToString()}'"); + } + Assert.False(true, $"Expected either a MarshalDirectiveException or a TypeLoadException, but received no exception."); + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/CMakeLists.txt b/src/tests/Interop/DisabledRuntimeMarshalling/CMakeLists.txt new file mode 100644 index 0000000000000..018819bf33073 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/CMakeLists.txt @@ -0,0 +1,10 @@ +project (DisabledRuntimeMarshallingNative) +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES DisabledRuntimeMarshallingNative.cpp ) + +# add the executable +add_library (DisabledRuntimeMarshallingNative SHARED ${SOURCES}) +target_link_libraries(DisabledRuntimeMarshallingNative ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS DisabledRuntimeMarshallingNative DESTINATION bin) diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshallingNative.cpp b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshallingNative.cpp new file mode 100644 index 0000000000000..e0a0a9e7f32a1 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshallingNative.cpp @@ -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. + +#include + +struct StructWithShortAndBool +{ + bool b; + short s; + // Make sure we don't have any cases where the native code could return a value of this type one way, + // but an invalid managed declaration would expect it differently. This ensures that test failures won't be + // due to crashes from a mismatched return scheme in the calling convention. + int padding; +}; + +struct StructWithWCharAndShort +{ + short s; + WCHAR c; +}; + +extern "C" DLL_EXPORT bool STDMETHODCALLTYPE CheckStructWithShortAndBool(StructWithShortAndBool str, short s, bool b) +{ + return str.s == s && str.b == b; +} + +extern "C" DLL_EXPORT bool STDMETHODCALLTYPE CheckStructWithWCharAndShort(StructWithWCharAndShort str, short s, WCHAR c) +{ + return str.s == s && str.c == c; +} + +using CheckStructWithShortAndBoolCallback = bool (STDMETHODCALLTYPE*)(StructWithShortAndBool, short, bool); + +extern "C" DLL_EXPORT CheckStructWithShortAndBoolCallback STDMETHODCALLTYPE GetStructWithShortAndBoolCallback() +{ + return &CheckStructWithShortAndBool; +} + +extern "C" DLL_EXPORT bool STDMETHODCALLTYPE CallCheckStructWithShortAndBoolCallback(CheckStructWithShortAndBoolCallback cb, StructWithShortAndBool str, short s, bool b) +{ + return cb(str, s, b); +} + +extern "C" DLL_EXPORT BYTE PassThrough(BYTE b) +{ + return b; +} + +extern "C" DLL_EXPORT void Invalid(...) {} + + +extern "C" DLL_EXPORT bool STDMETHODCALLTYPE CheckStructWithShortAndBoolWithVariantBool(StructWithShortAndBool str, short s, VARIANT_BOOL b) +{ + // Specifically use VARIANT_TRUE here as invalid marshalling (in the "disabled runtime marshalling" case) will incorrectly marshal VARAINT_TRUE + // but could accidentally marshal VARIANT_FALSE correctly since it is 0, which is the same representation as a zero or sign extension of the C# false value. + return str.s == s && str.b == (b == VARIANT_TRUE); +} + +using CheckStructWithShortAndBoolWithVariantBoolCallback = bool (STDMETHODCALLTYPE*)(StructWithShortAndBool, short, VARIANT_BOOL); + +extern "C" DLL_EXPORT CheckStructWithShortAndBoolWithVariantBoolCallback STDMETHODCALLTYPE GetStructWithShortAndBoolWithVariantBoolCallback() +{ + return &CheckStructWithShortAndBoolWithVariantBool; +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyDisabled.csproj b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyDisabled.csproj new file mode 100644 index 0000000000000..2de6caeb97d02 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyDisabled.csproj @@ -0,0 +1,13 @@ + + + true + + + + + + + + + + diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyEnabled.csproj b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyEnabled.csproj new file mode 100644 index 0000000000000..88ce904b51e4b --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyEnabled.csproj @@ -0,0 +1,13 @@ + + + true + + + + + + + + + + diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly.csproj b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly.csproj new file mode 100644 index 0000000000000..702588382eb33 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly.csproj @@ -0,0 +1,11 @@ + + + true + + + + + + + + diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly_ro.csproj b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly_ro.csproj new file mode 100644 index 0000000000000..b947e14f0b891 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly_ro.csproj @@ -0,0 +1,14 @@ + + + true + + None + true + + + + + + + + diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_NativeAssemblyDisabled.csproj b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_NativeAssemblyDisabled.csproj new file mode 100644 index 0000000000000..61ddd72ac618b --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_NativeAssemblyDisabled.csproj @@ -0,0 +1,14 @@ + + + true + + + + + + + + + + + diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/FunctionPointers.cs b/src/tests/Interop/DisabledRuntimeMarshalling/FunctionPointers.cs new file mode 100644 index 0000000000000..927c175623629 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/FunctionPointers.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. + +using System; +using System.Runtime.InteropServices; +using Xunit; +using static DisabledRuntimeMarshallingNative; + +namespace DisabledRuntimeMarshalling; + +public unsafe class FunctionPointers +{ + [Fact] + public static void StructWithDefaultNonBlittableFields_DoesNotMarshal() + { + short s = 42; + bool b = true; + Assert.True(DisabledRuntimeMarshallingNative.GetStructWithShortAndBoolCallback()(new StructWithShortAndBool(s, b), s, b)); + } + + [Fact] + public static void StructWithDefaultNonBlittableFields_IgnoresMarshalAsInfo() + { + short s = 41; + bool b = true; + + Assert.False(DisabledRuntimeMarshallingNative.GetStructWithShortAndBoolWithVariantBoolCallback()(new StructWithShortAndBool(s, b), s, b)); + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/Native_Default/DisabledRuntimeMarshallingNative.cs b/src/tests/Interop/DisabledRuntimeMarshalling/Native_Default/DisabledRuntimeMarshallingNative.cs new file mode 100644 index 0000000000000..5be5549f7b157 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/Native_Default/DisabledRuntimeMarshallingNative.cs @@ -0,0 +1,153 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using Xunit; + +public unsafe class DisabledRuntimeMarshallingNative +{ + public struct StructWithShortAndBool + { + public bool b; + public short s; + int padding; + + public StructWithShortAndBool(short s, bool b) + { + this.s = s; + this.b = b; + this.padding = 0xdeadbee; + } + } + + public struct StructWithShortAndBoolWithMarshalAs + { + [MarshalAs(UnmanagedType.U1)] + bool b; + short s; + int padding; + + public StructWithShortAndBoolWithMarshalAs(short s, bool b) + { + this.s = s; + this.b = b; + this.padding = 0xdeadbee; + } + } + + public struct StructWithWCharAndShort + { + short s; + [MarshalAs(UnmanagedType.U2)] + char c; + + public StructWithWCharAndShort(short s, char c) + { + this.s = s; + this.c = c; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructWithWCharAndShortWithMarshalAs + { + short s; + [MarshalAs(UnmanagedType.U2)] + char c; + + public StructWithWCharAndShortWithMarshalAs(short s, char c) + { + this.s = s; + this.c = c; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructWithShortAndGeneric + { + short s; + T t; + public StructWithShortAndGeneric(short s, T t) + { + this.s = s; + this.t = t; + } + } + + [StructLayout(LayoutKind.Auto)] + public struct AutoLayoutStruct + { + int i; + } + + public struct SequentialWithAutoLayoutField + { + AutoLayoutStruct auto; + } + + public struct SequentialWithAutoLayoutNestedField + { + SequentialWithAutoLayoutField field; + } + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + [return:MarshalAs(UnmanagedType.U1)] + public static extern bool CheckStructWithShortAndBool(StructWithShortAndBool str, short s, bool b); + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + [return:MarshalAs(UnmanagedType.U1)] + public static extern bool CheckStructWithShortAndBool(StructWithShortAndBoolWithMarshalAs str, short s, [MarshalAs(UnmanagedType.Bool)] bool b); + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + [return:MarshalAs(UnmanagedType.U1)] + public static extern bool CheckStructWithWCharAndShort(StructWithWCharAndShort str, short s, char c); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + [return:MarshalAs(UnmanagedType.U1)] + public static extern bool CheckStructWithWCharAndShort(StructWithShortAndGeneric str, short s, char c); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern bool CheckStructWithWCharAndShort(StructWithShortAndGeneric str, short s, short c); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + [return:MarshalAs(UnmanagedType.U1)] + public static extern bool CheckStructWithWCharAndShort(StructWithWCharAndShortWithMarshalAs str, short s, [MarshalAs(UnmanagedType.U1)] char c); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern delegate* unmanaged GetStructWithShortAndBoolCallback(); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern bool CallCheckStructWithShortAndBoolCallback(delegate* cb, StructWithShortAndBool str, short s, bool b); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern delegate* unmanaged GetStructWithShortAndBoolWithVariantBoolCallback(); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "PassThrough")] + [return:MarshalAs(UnmanagedType.U1)] + public static extern bool GetByteAsBool(byte b); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CallWithAutoLayoutStruct(AutoLayoutStruct s); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CallWithAutoLayoutStruct(SequentialWithAutoLayoutField s); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CallWithAutoLayoutStruct(SequentialWithAutoLayoutNestedField s); + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + [return:MarshalAs(UnmanagedType.U1)] + public static extern bool CheckStructWithShortAndBoolWithVariantBool(StructWithShortAndBoolWithMarshalAs str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b); + + // Apply the UnmanagedFunctionPointer attributes with the default calling conventions so that Mono's AOT compiler + // recognizes that these delegate types are used in interop and should have managed->native thunks generated for them. + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate bool CheckStructWithShortAndBoolCallback(StructWithShortAndBool str, short s, bool b); + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate bool CheckStructWithShortAndBoolWithMarshalAsAndVariantBoolCallback(StructWithShortAndBoolWithMarshalAs str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b); + + [UnmanagedCallersOnly] + public static bool CheckStructWithShortAndBoolManaged(StructWithShortAndBool str, short s, bool b) + { + return str.s == s && str.b == b; + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/Native_Default/DisabledRuntimeMarshallingNative_Default.csproj b/src/tests/Interop/DisabledRuntimeMarshalling/Native_Default/DisabledRuntimeMarshallingNative_Default.csproj new file mode 100644 index 0000000000000..e06e1e391659f --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/Native_Default/DisabledRuntimeMarshallingNative_Default.csproj @@ -0,0 +1,10 @@ + + + Library + SharedLibrary + true + + + + + diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/Native_DisabledMarshalling/DisabledRuntimeMarshallingNative.cs b/src/tests/Interop/DisabledRuntimeMarshalling/Native_DisabledMarshalling/DisabledRuntimeMarshallingNative.cs new file mode 100644 index 0000000000000..ed9b121bef6a2 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/Native_DisabledMarshalling/DisabledRuntimeMarshallingNative.cs @@ -0,0 +1,190 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using Xunit; + +public unsafe class DisabledRuntimeMarshallingNative +{ + public struct StructWithShortAndBool + { + public bool b; + public short s; + int padding; + + public StructWithShortAndBool(short s, bool b) + { + this.s = s; + this.b = b; + this.padding = 0xdeadbee; + } + } + + public struct StructWithShortAndBoolWithMarshalAs + { + [MarshalAs(UnmanagedType.VariantBool)] + bool b; + short s; + int padding; + + public StructWithShortAndBoolWithMarshalAs(short s, bool b) + { + this.s = s; + this.b = b; + this.padding = 0xdeadbee; + } + } + + public struct StructWithWCharAndShort + { + short s; + char c; + + public StructWithWCharAndShort(short s, char c) + { + this.s = s; + this.c = c; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructWithWCharAndShortWithMarshalAs + { + short s; + [MarshalAs(UnmanagedType.U1)] + char c; + + public StructWithWCharAndShortWithMarshalAs(short s, char c) + { + this.s = s; + this.c = c; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructWithShortAndGeneric + { + short s; + T t; + public StructWithShortAndGeneric(short s, T t) + { + this.s = s; + this.t = t; + } + } + + public struct StructWithString + { + string s; + + public StructWithString(string s) + { + this.s = s; + } + } + + [StructLayout(LayoutKind.Sequential)] + public class LayoutClass + {} + + [StructLayout(LayoutKind.Auto)] + public struct AutoLayoutStruct + { + int i; + } + + public struct SequentialWithAutoLayoutField + { + AutoLayoutStruct auto; + } + + public struct SequentialWithAutoLayoutNestedField + { + SequentialWithAutoLayoutField field; + } + + public enum ByteEnum : byte + { + Value = 42 + } + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern bool CheckStructWithShortAndBool(StructWithShortAndBool str, short s, bool b); + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern bool CheckStructWithShortAndBool(StructWithShortAndBoolWithMarshalAs str, short s, [MarshalAs(UnmanagedType.I4)] bool b); + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern bool CheckStructWithWCharAndShort(StructWithWCharAndShort str, short s, char c); + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern bool CheckStructWithWCharAndShort(StructWithWCharAndShortWithMarshalAs str, short s, char c); + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern bool CheckStructWithWCharAndShort(StructWithShortAndGeneric str, short s, char c); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern bool CheckStructWithWCharAndShort(StructWithShortAndGeneric str, short s, short c); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", CharSet = CharSet.Ansi)] + public static extern void CheckStringWithAnsiCharSet(string s); + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", CharSet = CharSet.Unicode)] + public static extern void CheckStringWithUnicodeCharSet(string s); + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", CharSet = CharSet.Unicode)] + public static extern string GetStringWithUnicodeCharSet(); + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CheckStructWithStructWithString(StructWithString s); + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CheckLayoutClass(LayoutClass c); + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", SetLastError = true)] + public static extern void CallWithSetLastError(); + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + [LCIDConversion(0)] + public static extern void CallWithLCID(); + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", PreserveSig = false)] + public static extern int CallWithHResultSwap(); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CallWithAutoLayoutStruct(AutoLayoutStruct s); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CallWithAutoLayoutStruct(SequentialWithAutoLayoutField s); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CallWithAutoLayoutStruct(SequentialWithAutoLayoutNestedField s); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CallWithByRef(ref int i); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")] + public static extern void CallWithVarargs(__arglist); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern delegate* unmanaged GetStructWithShortAndBoolCallback(); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern delegate* unmanaged GetStructWithShortAndBoolWithVariantBoolCallback(); + + [DllImport(nameof(DisabledRuntimeMarshallingNative))] + public static extern bool CallCheckStructWithShortAndBoolCallback(delegate* unmanaged cb, StructWithShortAndBool str, short s, bool b); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "PassThrough")] + public static extern bool GetByteAsBool(byte b); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "PassThrough")] + public static extern byte GetEnumUnderlyingValue(ByteEnum b); + + [DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "CheckStructWithShortAndBoolWithVariantBool")] + [return:MarshalAs(UnmanagedType.U1)] + public static extern bool CheckStructWithShortAndBoolWithVariantBool_FailureExpected(StructWithShortAndBool str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b); + + // Apply the UnmanagedFunctionPointer attributes with the default calling conventions so that Mono's AOT compiler + // recognizes that these delegate types are used in interop and should have managed->native thunks generated for them. + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate bool CheckStructWithShortAndBoolCallback(StructWithShortAndBool str, short s, bool b); + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate bool CheckStructWithShortAndBoolWithVariantBoolCallback(StructWithShortAndBool str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b); + + [UnmanagedCallersOnly] + public static bool CheckStructWithShortAndBoolManaged(StructWithShortAndBool str, short s, bool b) + { + return str.s == s && str.b == b; + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/Native_DisabledMarshalling/DisabledRuntimeMarshallingNative_DisabledMarshalling.csproj b/src/tests/Interop/DisabledRuntimeMarshalling/Native_DisabledMarshalling/DisabledRuntimeMarshallingNative_DisabledMarshalling.csproj new file mode 100644 index 0000000000000..c3572ce1ae3a5 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/Native_DisabledMarshalling/DisabledRuntimeMarshallingNative_DisabledMarshalling.csproj @@ -0,0 +1,11 @@ + + + Library + SharedLibrary + true + + + + + + diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/Delegates.cs b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/Delegates.cs new file mode 100644 index 0000000000000..a4eb0f33159d0 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/Delegates.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using Xunit; +using static DisabledRuntimeMarshallingNative; + +namespace DisabledRuntimeMarshalling.PInvokeAssemblyMarshallingDisabled; + +public unsafe class DelegatesFromExternalAssembly +{ + [Fact] + public static void StructWithDefaultNonBlittableFields_DoesNotMarshal() + { + short s = 42; + bool b = true; + + var callback = Marshal.GetDelegateForFunctionPointer((IntPtr)DisabledRuntimeMarshallingNative.GetStructWithShortAndBoolCallback()); + + Assert.True(callback(new StructWithShortAndBool(s, b), s, b)); + } + + [Fact] + public static void StructWithDefaultNonBlittableFields_IgnoresMarshalAsInfo() + { + short s = 41; + bool b = true; + + var callback = Marshal.GetDelegateForFunctionPointer((IntPtr)DisabledRuntimeMarshallingNative.GetStructWithShortAndBoolWithVariantBoolCallback()); + + Assert.False(callback(new StructWithShortAndBool(s, b), s, b)); + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/PInvokes.cs b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/PInvokes.cs new file mode 100644 index 0000000000000..4fa7315d43063 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/PInvokes.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; +using static DisabledRuntimeMarshallingNative; + +namespace DisabledRuntimeMarshalling.PInvokeAssemblyMarshallingDisabled; + +public class PInvokes +{ + + [Fact] + public static void StructWithDefaultNonBlittableFields_MarshalAsInfo() + { + short s = 41; + bool b = true; + + Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithShortAndBool(new StructWithShortAndBoolWithMarshalAs(s, b), s, b)); + + // We use a the "green check mark" character so that we use both bytes and + // have a value that can't be accidentally round-tripped. + char c = '✅'; + Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithWCharAndShortWithMarshalAs(s, c), s, c)); + } + + [Fact] + public static void Strings_NotSupported() + { + Assert.Throws(() => DisabledRuntimeMarshallingNative.CheckStringWithAnsiCharSet("")); + Assert.Throws(() => DisabledRuntimeMarshallingNative.CheckStringWithUnicodeCharSet("")); + Assert.Throws(() => DisabledRuntimeMarshallingNative.CheckStructWithStructWithString(new StructWithString(""))); + Assert.Throws(() => DisabledRuntimeMarshallingNative.GetStringWithUnicodeCharSet()); + } + + [Fact] + public static void LayoutClass_NotSupported() + { + Assert.Throws(() => DisabledRuntimeMarshallingNative.CheckLayoutClass(new LayoutClass())); + } + + [Fact] + public static void SetLastError_NotSupported() + { + Assert.Throws(() => DisabledRuntimeMarshallingNative.CallWithSetLastError()); + } + + [Fact] + [SkipOnMono("Mono does not support LCIDs at all and it is not worth the effort to add support just to make it throw an exception.")] + public static void LCID_NotSupported() + { + Assert.Throws(() => DisabledRuntimeMarshallingNative.CallWithLCID()); + } + + [Fact] + [SkipOnMono("Mono does not support PreserveSig=False in P/Invokes and it is not worth the effort to add support just to make it throw an exception.")] + public static void PreserveSig_False_NotSupported() + { + Assert.Throws(() => DisabledRuntimeMarshallingNative.CallWithHResultSwap()); + } + + [Fact] + public static void Varargs_NotSupported() + { + AssertThrowsCorrectException(() => DisabledRuntimeMarshallingNative.CallWithVarargs(__arglist(1, 2, 3))); + + static void AssertThrowsCorrectException(Action testCode) + { + try + { + testCode(); + return; + } +#pragma warning disable CS0618 // ExecutionEngineException has an ObsoleteAttribute + catch (Exception ex) when(ex is MarshalDirectiveException or InvalidProgramException or ExecutionEngineException) +#pragma warning restore CS0618 + { + // CoreCLR is expected to throw MarshalDirectiveException + // JIT-enabled Mono is expected to throw an InvalidProgramException + // AOT-only Mono throws an ExecutionEngineException when attempting to JIT the callback that would throw the InvalidProgramException. + return; + } + catch (Exception ex) + { + Assert.False(true, $"Expected either a MarshalDirectiveException, InvalidProgramException, or ExecutionEngineException, but received a '{ex.GetType().FullName}' exception: '{ex.ToString()}'"); + } + Assert.False(true, $"Expected either a MarshalDirectiveException, InvalidProgramException, or ExecutionEngineException, but received no exception."); + } + } + + [Fact] + public static void ByRef_Args_Not_Supported() + { + Assert.Throws(() => + { + int i = 0; + DisabledRuntimeMarshallingNative.CallWithByRef(ref i); + }); + } + + [Fact] + public static void NoBooleanNormalization() + { + byte byteVal = 42; + Assert.Equal(byteVal, Unsafe.As(ref Unsafe.AsRef(DisabledRuntimeMarshallingNative.GetByteAsBool(byteVal)))); + } + + [Fact] + public static void StructWithDefaultNonBlittableFields_DoesNotDoMarshalling() + { + short s = 42; + bool b = true; + + Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithShortAndBool(new StructWithShortAndBool(s, b), s, b)); + + // We use a the "green check mark" character so that we use both bytes and + // have a value that can't be accidentally round-tripped. + char c = '✅'; + Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithWCharAndShort(s, c), s, c)); + + Assert.False(DisabledRuntimeMarshallingNative.CheckStructWithShortAndBoolWithVariantBool_FailureExpected(new StructWithShortAndBool(s, b), s, b)); + } + + [Fact] + public static void StructWithNonBlittableGenericInstantiation() + { + short s = 42; + // We use a the "green check mark" character so that we use both bytes and + // have a value that can't be accidentally round-tripped. + char c = '✅'; + Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithShortAndGeneric(s, c), s, c)); + } + + [Fact] + public static void StructWithBlittableGenericInstantiation() + { + short s = 42; + // We use a the "green check mark" character so that we use both bytes and + // have a value that can't be accidentally round-tripped. + char c = '✅'; + Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithShortAndGeneric(s, (short)c), s, (short)c)); + } + + [Fact] + public static void CanUseEnumsWithDisabledMarshalling() + { + Assert.Equal((byte)ByteEnum.Value, DisabledRuntimeMarshallingNative.GetEnumUnderlyingValue(ByteEnum.Value)); + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/UnmanagedCallersOnly.cs b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/UnmanagedCallersOnly.cs new file mode 100644 index 0000000000000..f3f963f670d20 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/UnmanagedCallersOnly.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. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; +using static DisabledRuntimeMarshallingNative; + +namespace DisabledRuntimeMarshalling.PInvokeAssemblyMarshallingDisabled; + +public unsafe class UnmanagedCallersOnly +{ + + [Fact] + public static void UnmanagedCallersOnly_WithNonBlittableParameters_DoesNotMarshal() + { + short s = 41; + bool b = true; + + Assert.True(DisabledRuntimeMarshallingNative.CallCheckStructWithShortAndBoolCallback(&DisabledRuntimeMarshallingNative.CheckStructWithShortAndBoolManaged, new StructWithShortAndBool(s, b), s, b)); + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/Delegates.cs b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/Delegates.cs new file mode 100644 index 0000000000000..1e2f1118c88b5 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/Delegates.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. + +using System; +using System.Runtime.InteropServices; +using Xunit; +using static DisabledRuntimeMarshallingNative; + +namespace DisabledRuntimeMarshalling.PInvokeAssemblyMarshallingEnabled; + +public unsafe class DelegatesFromExternalAssembly +{ + [Fact] + public static void StructWithDefaultNonBlittableFields() + { + short s = 42; + bool b = true; + + var callback = Marshal.GetDelegateForFunctionPointer((IntPtr)DisabledRuntimeMarshallingNative.GetStructWithShortAndBoolCallback()); + + Assert.False(callback(new StructWithShortAndBool(s, b), s, b)); + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public static void StructWithDefaultNonBlittableFields_MarshalAsInfo() + { + short s = 41; + bool b = true; + + var callback = Marshal.GetDelegateForFunctionPointer((IntPtr)DisabledRuntimeMarshallingNative.GetStructWithShortAndBoolWithVariantBoolCallback()); + + Assert.True(callback(new StructWithShortAndBoolWithMarshalAs(s, b), s, b)); + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/PInvokes.cs b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/PInvokes.cs new file mode 100644 index 0000000000000..69f91b2391707 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/PInvokes.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using Xunit; +using static DisabledRuntimeMarshallingNative; + +namespace DisabledRuntimeMarshalling.PInvokeAssemblyMarshallingEnabled; + +public class PInvokes +{ + public static bool IsWindowsX86Process => OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.X86; + public static bool IsNotWindowsX86Process => !IsWindowsX86Process; + + [ConditionalFact(nameof(IsNotWindowsX86Process))] + public static void StructWithDefaultNonBlittableFields_Bool() + { + short s = 42; + bool b = true; + + // By default, bool is a 4-byte Windows BOOL, which will cause us to incorrectly marshal back the struct from native code. + Assert.False(DisabledRuntimeMarshallingNative.CheckStructWithShortAndBool(new StructWithShortAndBool(s, b), s, b)); + } + + [Fact] + [SkipOnMono("Mono doesn't support marshalling a .NET Char to a C char (only a char16_t).")] + public static void StructWithDefaultNonBlittableFields_Char() + { + short s = 42; + // We use a the "green check mark" character so that we use both bytes and + // have a value that can't be accidentally round-tripped. + char c = '✅'; + Assert.False(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithWCharAndShort(s, c), s, c)); + + } + + [ConditionalFact(nameof(IsNotWindowsX86Process))] + public static void StructWithDefaultNonBlittableFields_Bool_MarshalAsInfo() + { + short s = 41; + bool b = true; + + Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithShortAndBool(new StructWithShortAndBoolWithMarshalAs(s, b), s, b)); + } + + [Fact] + [SkipOnMono("Mono doesn't support marshalling a .NET Char to a C char (only a char16_t).")] + public static void StructWithDefaultNonBlittableFields_Char_MarshalAsInfo() + { + short s = 41; + // We use a the "green check mark" character so that we use both bytes and + // have a value that can't be accidentally round-tripped. + char c = '✅'; + Assert.False(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithWCharAndShortWithMarshalAs(s, c), s, c)); + } + + [ConditionalFact(nameof(IsWindowsX86Process))] + public static void EntryPoint_With_StructWithDefaultNonBlittableFields_NotFound() + { + short s = 42; + bool b = true; + + // By default, bool is a 4-byte Windows BOOL, which will make the calculation of stack space for the stdcall calling convention + // incorrect, causing the entry point to not be found. + Assert.Throws(() => DisabledRuntimeMarshallingNative.CheckStructWithShortAndBool(new StructWithShortAndBool(s, b), s, b)); + } + + [Fact] + [SkipOnMono("Mono supports non-blittable generic instantiations in P/Invokes")] + public static void StructWithNonBlittableGenericInstantiation_Fails() + { + short s = 41; + char c = '✅'; + Assert.Throws(() => DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithShortAndGeneric(s, c), s, c)); + } + + [Fact] + public static void StructWithBlittableGenericInstantiation() + { + short s = 42; + // We use a the "green check mark" character so that we use both bytes and + // have a value that can't be accidentally round-tripped. + char c = '✅'; + Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithShortAndGeneric(s, (short)c), s, (short)c)); + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public static void StructWithDefaultNonBlittableFields_MarshalAsInfo_WindowsOnly() + { + short s = 41; + bool b = true; + Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithShortAndBoolWithVariantBool(new StructWithShortAndBoolWithMarshalAs(s, b), s, b)); + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/UnmanagedCallersOnly.cs b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/UnmanagedCallersOnly.cs new file mode 100644 index 0000000000000..6f94ad67f6b97 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/UnmanagedCallersOnly.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. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; +using static DisabledRuntimeMarshallingNative; + +namespace DisabledRuntimeMarshalling.PInvokeAssemblyMarshallingDisabled; + +public unsafe class UnmanagedCallersOnly +{ + + [Fact] + public static void UnmanagedCallersOnly_Defined_InDisabledAssembly_WithNonBlittableParameters_Fails() + { + short s = 41; + bool b = true; + + Assert.Throws(() => + { + delegate* unmanaged cb = &DisabledRuntimeMarshallingNative.CheckStructWithShortAndBoolManaged; + cb(new StructWithShortAndBool(s, b), s, b); + }); + } +} diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/RuntimeMarshallingDisabledAttribute.cs b/src/tests/Interop/DisabledRuntimeMarshalling/RuntimeMarshallingDisabledAttribute.cs new file mode 100644 index 0000000000000..6383488049037 --- /dev/null +++ b/src/tests/Interop/DisabledRuntimeMarshalling/RuntimeMarshallingDisabledAttribute.cs @@ -0,0 +1,5 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + +[assembly:DisableRuntimeMarshalling] diff --git a/src/tests/Interop/common/xplatform.h b/src/tests/Interop/common/xplatform.h index cb86b1559fec5..00f9a08b12e63 100644 --- a/src/tests/Interop/common/xplatform.h +++ b/src/tests/Interop/common/xplatform.h @@ -155,6 +155,16 @@ typedef struct tagDEC { #define FALSE 0 #endif +typedef USHORT VARIANT_BOOL; + +#ifndef VARIANT_TRUE +#define VARIANT_TRUE -1 +#endif + +#ifndef VARIANT_FALSE +#define VARIANT_FALSE 0 +#endif + #ifndef __IUnknown_INTERFACE_DEFINED__ #define __IUnknown_INTERFACE_DEFINED__ @@ -175,12 +185,12 @@ IUnknown #endif // __IUnknown_INTERFACE_DEFINED__ -typedef /* [v1_enum] */ +typedef /* [v1_enum] */ enum TrustLevel { BaseTrust = 0, PartialTrust = ( BaseTrust + 1 ) , - FullTrust = ( PartialTrust + 1 ) + FullTrust = ( PartialTrust + 1 ) } TrustLevel; // AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90 diff --git a/src/tests/issues.targets b/src/tests/issues.targets index f6ffb0f93efa2..3269c33f9bd46 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2795,6 +2795,10 @@ https://github.com/dotnet/runtime/issues/57512 + + + This test includes an intentionally-invalid UnmanagedCallersOnly method. Invalid UnmanagedCallersOnly methods cause failures at AOT-time. + From 4a099dc0eea7acd5d9a8d4c62cb89f24da6bf7ff Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Fri, 21 Jan 2022 10:09:24 +0100 Subject: [PATCH 113/308] Make ILLink validation steps in libs incrementally buildable (#64041) * Make ILLink validation steps in libs incrementally buildable Both the illink-oob and the illink-sharedframework targets don't define Inputs and Outputs which makes them run during no-op incremental builds. This change defines Inputs and Outputs based on what's used during the target's execution so that if the input assemblies or the illink assembly itself haven't changed, the step will be skipped. Also renaming properties and items to make them more readable and consistent. As these target files are "extensions" of the src.proj file and aren't shared anywhere, they can be treated like logic inside a project file and hence prefixing properties and items with an underscore "_" isn't necessary. --- src/libraries/illink-oob.targets | 93 ++++++++++++-------- src/libraries/illink-sharedframework.targets | 58 +++++++----- 2 files changed, 89 insertions(+), 62 deletions(-) diff --git a/src/libraries/illink-oob.targets b/src/libraries/illink-oob.targets index 72cecaf3b8bee..4775c20bd9301 100644 --- a/src/libraries/illink-oob.targets +++ b/src/libraries/illink-oob.targets @@ -1,63 +1,78 @@ - - - - $([MSBuild]::NormalizePath('$(ILLinkTrimAssemblyArtifactsRootDir)', 'trimmed-oobs')) + $([MSBuild]::NormalizePath('$(ILLinkTrimAssemblyArtifactsRootDir)', 'trimmed-oobs')) - + + + - <_OOBsToIgnore Include="System.CodeDom" /> - <_OOBsToIgnore Include="System.ComponentModel.Composition" /> - <_OOBsToIgnore Include="System.ComponentModel.Composition.Registration" /> - <_OOBsToIgnore Include="System.Composition.AttributedModel" /> - <_OOBsToIgnore Include="System.Composition.Convention" /> - <_OOBsToIgnore Include="System.Composition.Hosting" /> - <_OOBsToIgnore Include="System.Composition.Runtime" /> - <_OOBsToIgnore Include="System.Composition.TypedParts" /> - <_OOBsToIgnore Include="System.Configuration.ConfigurationManager" /> - <_OOBsToIgnore Include="System.Speech" /> - - <_NetCoreAppRuntimeAssemblies Include="$(NetCoreAppCurrentRuntimePath)*.dll" Exclude="$(NetCoreAppCurrentRuntimePath)*.Generator.dll;$(NetCoreAppCurrentRuntimePath)*.Native.dll;$(NetCoreAppCurrentRuntimePath)*msquic.dll" /> - <_RuntimePackTrimmedAssemblies Include="$(MicrosoftNetCoreAppRuntimePackRidLibTfmDir)*.dll" /> - - - <_NetCoreAppRuntimeAssembliesToFileName Include="@(_NetCoreAppRuntimeAssemblies -> '%(FileName)')"> - %(Identity) - - <_RuntimePackAssembliesToFileName Include="@(_RuntimePackTrimmedAssemblies -> '%(FileName)')"> - %(Identity) - - - <_OOBsToTrimFileName Include="@(_NetCoreAppRuntimeAssembliesToFileName)" Exclude="@(_RuntimePackAssembliesToFileName);@(_OOBsToIgnore)" /> - <_OOBReferencesFileName Include="@(_NetCoreAppRuntimeAssembliesToFileName)" Exclude="@(_OOBsToTrimFileName)" /> - <_OOBsToTrim Include="@(_OOBsToTrimFileName -> '%(OriginalIdentity)')" /> - <_OOBReferences Include="@(_OOBReferencesFileName -> '%(OriginalIdentity)')" /> - <_OOBReferences Include="$(SystemPrivateCoreLibPath)" /> + + + + + + + + + + + + + + + + + + + + + + + + - - <_OOBSuppressionsXmls Include="$(ILLinkTrimAssemblyOOBSuppressionsXmlsDir)*.xml" /> + + + + + + + $(ILLinkArgs) - $(OOBILLinkArgs) --link-attributes "@(_OOBSuppressionsXmls->'%(FullPath)', '" --link-attributes "')" + $(OOBILLinkArgs) --link-attributes "@(OOBLibrarySuppressionsXml->'%(FullPath)', '" --link-attributes "')" + + diff --git a/src/libraries/illink-sharedframework.targets b/src/libraries/illink-sharedframework.targets index 77be745765c44..0cc83fb1c7467 100644 --- a/src/libraries/illink-sharedframework.targets +++ b/src/libraries/illink-sharedframework.targets @@ -1,48 +1,60 @@ - - - - $([MSBuild]::NormalizePath('$(ILLinkTrimAssemblyArtifactsRootDir)', 'trimmed-runtimepack')) + $([MSBuild]::NormalizePath('$(ILLinkTrimAssemblyArtifactsRootDir)', 'trimmed-runtimepack')) + + + + + + + + + + + + + + + + + + + + + - $(ILLinkArgs) + $(ILLinkArgs) - $(RuntimePackILLinkArgs) -b true + $(SharedFrameworkILLinkArgs) -b true - <_LibrariesToTrim Include="$(MicrosoftNetCoreAppRuntimePackRidLibTfmDir)*.dll" /> - <_LibrariesToTrim Include="$(SystemPrivateCoreLibPath)" /> - - + library - - - <_RuntimePackSuppressionsXmls Include="$(ILLinkTrimAssemblyRuntimePackSuppressionsXmlsDir)*.xml" /> - - - <_RuntimePackSuppressionsXmls Include="$(CoreLibSharedDir)ILLink\ILLink.Suppressions.LibraryBuild.xml" /> - <_RuntimePackSuppressionsXmls Condition="'$(RuntimeFlavor)' == 'CoreCLR'" Include="$(CoreClrProjectRoot)System.Private.CoreLib\$(ProjectILLinkSuppressionsFile).LibraryBuild.xml" /> - - - $(RuntimePackILLinkArgs) --link-attributes "@(_RuntimePackSuppressionsXmls->'%(FullPath)', '" --link-attributes "')" + $(SharedFrameworkILLinkArgs) --link-attributes "@(SharedFrameworkSuppressionsXml->'%(FullPath)', '" --link-attributes "')" + + From 8c188f38bd9b4cca0dda9e7fce63a59294964e60 Mon Sep 17 00:00:00 2001 From: Johan Lorensson Date: Fri, 21 Jan 2022 10:31:08 +0100 Subject: [PATCH 114/308] Fix broken callstacks in interpreter on MonoVM. (#60338) * Fix some broken callstacks in interpreter. * Fix build error. --- src/mono/mono/mini/interp/interp-internals.h | 5 - src/mono/mono/mini/interp/interp.c | 369 ++++++++++++------- 2 files changed, 230 insertions(+), 144 deletions(-) diff --git a/src/mono/mono/mini/interp/interp-internals.h b/src/mono/mono/mini/interp/interp-internals.h index a06a92420c884..c239cab5ab7fc 100644 --- a/src/mono/mono/mini/interp/interp-internals.h +++ b/src/mono/mono/mini/interp/interp-internals.h @@ -227,11 +227,6 @@ typedef struct { guchar *stack_pointer; /* Used for allocation of localloc regions */ FrameDataAllocator data_stack; - /* Used when a thread self-suspends at a safepoint in the interpreter, points to the - * currently executing frame. (If a thread self-suspends somewhere else in the runtime, this - * is NULL - the LMF will point to the InterpFrame before the thread exited the interpreter) - */ - InterpFrame *safepoint_frame; } ThreadContext; typedef struct { diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index d36e3388db713..fa00bca3b67d3 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -248,7 +248,7 @@ static gboolean interp_init_done = FALSE; static void interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args); -static MonoException* do_transform_method (InterpFrame *frame, ThreadContext *context); +static MonoException* do_transform_method (InterpMethod *imethod, InterpFrame *method, ThreadContext *context); static InterpMethod* lookup_method_pointer (gpointer addr); @@ -419,8 +419,6 @@ interp_free_context (gpointer ctx) set_context (NULL); } - context->safepoint_frame = NULL; - mono_vfree (context->stack_start, INTERP_STACK_SIZE, MONO_MEM_ACCOUNT_INTERP_STACK); /* Prevent interp_mark_stack from trying to scan the data_stack, before freeing it */ context->stack_start = NULL; @@ -429,19 +427,6 @@ interp_free_context (gpointer ctx) g_free (context); } -static void -context_set_safepoint_frame (ThreadContext *context, InterpFrame *frame) -{ - g_assert (!context->has_resume_state); - context->safepoint_frame = frame; -} - -static void -context_clear_safepoint_frame (ThreadContext *context) -{ - context->safepoint_frame = NULL; -} - void mono_interp_error_cleanup (MonoError* error) { @@ -1052,6 +1037,8 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con */ frame->state.ip = ip + 1; + interp_push_lmf (&ext, frame); + if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) { MonoException *mono_ex = ex; if (!rethrow) { @@ -1071,7 +1058,6 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con * Since ctx.ip is 0, this will start unwinding from the LMF frame * pushed above, which points to our frames. */ - interp_push_lmf (&ext, frame); mono_handle_exception (&ctx, (MonoObject*)ex); @@ -1086,6 +1072,62 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con g_assert (context->has_resume_state); } +static MONO_NEVER_INLINE MonoException * +interp_error_convert_to_exception (InterpFrame *frame, MonoError *error, const guint16 *ip) +{ + MonoLMFExt ext; + MonoException *ex; + + /* + * When calling runtime functions we pass the ip of the instruction triggering the runtime call. + * Offset the subtraction from interp_frame_get_ip, so we don't end up in prev instruction. + */ + frame->state.ip = ip + 1; + + interp_push_lmf (&ext, frame); + ex = mono_error_convert_to_exception (error); + interp_pop_lmf (&ext); + return ex; +} + +#define INTERP_BUILD_EXCEPTION_TYPE_FUNC_NAME(prefix_name, type_name) \ +prefix_name ## _ ## type_name + +#define INTERP_GET_EXCEPTION(exception_type) \ +static MONO_NEVER_INLINE MonoException * \ +INTERP_BUILD_EXCEPTION_TYPE_FUNC_NAME(interp_get_exception, exception_type) (InterpFrame *frame, const guint16 *ip)\ +{ \ + MonoLMFExt ext; \ + MonoException *ex; \ + frame->state.ip = ip + 1; \ + interp_push_lmf (&ext, frame); \ + ex = INTERP_BUILD_EXCEPTION_TYPE_FUNC_NAME(mono_get_exception,exception_type) (); \ + interp_pop_lmf (&ext); \ + return ex; \ +} + +#define INTERP_GET_EXCEPTION_CHAR_ARG(exception_type) \ +static MONO_NEVER_INLINE MonoException * \ +INTERP_BUILD_EXCEPTION_TYPE_FUNC_NAME(interp_get_exception, exception_type) (const char *arg, InterpFrame *frame, const guint16 *ip)\ +{ \ + MonoLMFExt ext; \ + MonoException *ex; \ + frame->state.ip = ip + 1; \ + interp_push_lmf (&ext, frame); \ + ex = INTERP_BUILD_EXCEPTION_TYPE_FUNC_NAME(mono_get_exception,exception_type) (arg); \ + interp_pop_lmf (&ext); \ + return ex; \ +} + +INTERP_GET_EXCEPTION(null_reference) +INTERP_GET_EXCEPTION(divide_by_zero) +INTERP_GET_EXCEPTION(overflow) +INTERP_GET_EXCEPTION(invalid_cast) +INTERP_GET_EXCEPTION(index_out_of_range) +INTERP_GET_EXCEPTION(array_type_mismatch) +INTERP_GET_EXCEPTION(arithmetic) +INTERP_GET_EXCEPTION_CHAR_ARG(argument_out_of_range) + // We conservatively pin exception object here to avoid tweaking the // numerous call sites of this macro, even though, in a few cases, // this is not needed. @@ -1102,7 +1144,7 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con #define NULL_CHECK(o) do { \ if (G_UNLIKELY (!(o))) \ - THROW_EX (mono_get_exception_null_reference (), ip); \ + THROW_EX (interp_get_exception_null_reference (frame, ip), ip); \ } while (0) #define EXCEPTION_CHECKPOINT \ @@ -1115,19 +1157,27 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con } while (0) // Reduce duplicate code in interp_exec_method -static void -do_safepoint (InterpFrame *frame, ThreadContext *context) +static MONO_NEVER_INLINE void +do_safepoint (InterpFrame *frame, ThreadContext *context, const guint16 *ip) { - context_set_safepoint_frame (context, frame); + MonoLMFExt ext; + + /* + * When calling runtime functions we pass the ip of the instruction triggering the runtime call. + * Offset the subtraction from interp_frame_get_ip, so we don't end up in prev instruction. + */ + frame->state.ip = ip + 1; + + interp_push_lmf (&ext, frame); /* Poll safepoint */ mono_threads_safepoint (); - context_clear_safepoint_frame (context); + interp_pop_lmf (&ext); } #define SAFEPOINT \ do { \ if (G_UNLIKELY (mono_polling_required)) \ - do_safepoint (frame, context); \ + do_safepoint (frame, context, ip); \ } while (0) static MonoObject* @@ -2163,8 +2213,6 @@ interp_entry (InterpEntryData *data) context->stack_pointer = (guchar*)sp; - g_assert (!context->safepoint_frame); - if (rmethod->needs_thread_attach) mono_threads_detach_coop (orig_domain, &attach_cookie); @@ -2634,29 +2682,34 @@ do_debugger_tramp (void (*tramp) (void), InterpFrame *frame) } static MONO_NEVER_INLINE MonoException* -do_transform_method (InterpFrame *frame, ThreadContext *context) +do_transform_method (InterpMethod *imethod, InterpFrame *frame, ThreadContext *context) { MonoLMFExt ext; /* Don't push lmf if we have no interp data */ gboolean push_lmf = frame->parent != NULL; + MonoException *ex = NULL; ERROR_DECL (error); -#if DEBUG_INTERP - char *mn = mono_method_full_name (frame->imethod->method, TRUE); - g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn); - g_free (mn); -#endif - /* Use the parent frame as the current frame is not complete yet */ if (push_lmf) interp_push_lmf (&ext, frame->parent); - mono_interp_transform_method (frame->imethod, context, error); +#if DEBUG_INTERP + if (imethod->method) { + char* mn = mono_method_full_name (imethod->method, TRUE); + g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn); + g_free (mn); + } +#endif + + mono_interp_transform_method (imethod, context, error); + if (!is_ok (error)) + ex = mono_error_convert_to_exception (error); if (push_lmf) interp_pop_lmf (&ext); - return mono_error_convert_to_exception (error); + return ex; } static void @@ -3249,11 +3302,31 @@ static long opcode_counts[MINT_LASTOP]; #define DUMP_INSTR() #endif +static MONO_NEVER_INLINE MonoException* +do_init_vtable (MonoVTable *vtable, MonoError *error, InterpFrame *frame, const guint16 *ip) +{ + MonoLMFExt ext; + MonoException *ex = NULL; + + /* + * When calling runtime functions we pass the ip of the instruction triggering the runtime call. + * Offset the subtraction from interp_frame_get_ip, so we don't end up in prev instruction. + */ + frame->state.ip = ip + 1; + + interp_push_lmf (&ext, frame); + mono_runtime_class_init_full (vtable, error); + if (!is_ok (error)) + ex = mono_error_convert_to_exception (error); + interp_pop_lmf (&ext); + return ex; +} + #define INIT_VTABLE(vtable) do { \ if (G_UNLIKELY (!(vtable)->initialized)) { \ - mono_runtime_class_init_full ((vtable), error); \ - if (!is_ok (error)) \ - THROW_EX (mono_error_convert_to_exception (error), ip); \ + MonoException *__init_vtable_ex = do_init_vtable ((vtable), error, frame, ip); \ + if (G_UNLIKELY (__init_vtable_ex)) \ + THROW_EX (__init_vtable_ex, ip); \ } \ } while (0); @@ -3363,7 +3436,7 @@ method_entry (ThreadContext *context, InterpFrame *frame, *out_ex = NULL; if (!G_UNLIKELY (frame->imethod->transformed)) { slow = TRUE; - MonoException *ex = do_transform_method (frame, context); + MonoException *ex = do_transform_method (frame->imethod, frame, context); if (ex) { *out_ex = ex; /* @@ -3620,10 +3693,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method)); if (!new_method->transformed) { - error_init_reuse (error); - - mono_interp_transform_method (new_method, context, error); - MonoException *ex = mono_error_convert_to_exception (error); + MonoException *ex = do_transform_method (new_method, frame, context); if (ex) THROW_EX (ex, ip); EXCEPTION_CHECKPOINT; @@ -3648,6 +3718,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs InterpMethod *del_imethod = (InterpMethod*)del->interp_invoke_impl; if (!del_imethod) { + // FIXME push/pop LMF if (is_multicast) { error_init_reuse (error); MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass); @@ -3712,6 +3783,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs cmethod = ftnptr_to_imethod (LOCAL_VAR (ip [2], gpointer), &need_unbox); if (cmethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { + // FIXME push/pop LMF cmethod = mono_interp_get_imethod (mono_marshal_get_native_wrapper (cmethod->method, FALSE, FALSE), error); mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */ } @@ -3751,6 +3823,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs guchar* code = LOCAL_VAR (ip [2], guchar*); call_args_offset = ip [3]; + // FIXME push/pop LMF cmethod = mono_interp_get_native_func_wrapper (frame->imethod, csignature, code); ip += 5; @@ -3786,6 +3859,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs slot = (gint16)ip [4]; ip += 5; + // FIXME push/pop LMF cmethod = get_virtual_method_fast (cmethod, this_arg->vtable, slot); if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { /* unbox */ @@ -3800,6 +3874,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs code_type == IMETHOD_CODE_COMPILED); if (G_UNLIKELY (code_type == IMETHOD_CODE_UNKNOWN)) { + // FIXME push/pop LMF MonoMethodSignature *sig = mono_method_signature_internal (cmethod->method); if (mono_interp_jit_call_supported (cmethod->method, sig)) code_type = IMETHOD_CODE_COMPILED; @@ -3817,7 +3892,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs error_init_reuse (error); do_jit_call (context, (stackval*)(locals + return_offset), (stackval*)(locals + call_args_offset), frame, cmethod, error); if (!is_ok (error)) { - MonoException *ex = mono_error_convert_to_exception (error); + MonoException *ex = interp_error_convert_to_exception (frame, error, ip); THROW_EX (ex, ip); } @@ -3844,6 +3919,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MonoObject *this_arg = LOCAL_VAR (call_args_offset, MonoObject*); + // FIXME push/pop LMF cmethod = get_virtual_method (cmethod, this_arg->vtable); if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { /* unbox */ @@ -3912,7 +3988,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs frame->state.ip = ip + 4; do_jit_call (context, (stackval*)(locals + ip [1]), (stackval*)(locals + ip [2]), frame, rmethod, error); if (!is_ok (error)) { - MonoException *ex = mono_error_convert_to_exception (error); + MonoException *ex = interp_error_convert_to_exception (frame, error, ip); THROW_EX (ex, ip); } @@ -3930,7 +4006,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs frame->state.ip = ip + 6; do_jit_call (context, (stackval*)(locals + ip [1]), frame, rmethod, error); if (!is_ok (error)) { - MonoException *ex = mono_error_convert_to_exception (error); + MonoException *ex = interp_error_convert_to_exception (frame, error); THROW_EX (ex, ip); } @@ -4828,9 +4904,9 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint32 i1 = LOCAL_VAR (ip [2], gint32); gint32 i2 = LOCAL_VAR (ip [3], gint32); if (i2 == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); + THROW_EX (interp_get_exception_divide_by_zero (frame, ip), ip); if (i2 == (-1) && i1 == G_MININT32) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = i1 / i2; ip += 4; MINT_IN_BREAK; @@ -4839,9 +4915,9 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint64 l1 = LOCAL_VAR (ip [2], gint64); gint64 l2 = LOCAL_VAR (ip [3], gint64); if (l2 == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); + THROW_EX (interp_get_exception_divide_by_zero (frame, ip), ip); if (l2 == (-1) && l1 == G_MININT64) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint64) = l1 / l2; ip += 4; MINT_IN_BREAK; @@ -4855,7 +4931,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_DIV_UN_I4) { guint32 i2 = LOCAL_VAR (ip [3], guint32); if (i2 == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); + THROW_EX (interp_get_exception_divide_by_zero (frame, ip), ip); LOCAL_VAR (ip [1], guint32) = LOCAL_VAR (ip [2], guint32) / i2; ip += 4; MINT_IN_BREAK; @@ -4863,7 +4939,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_DIV_UN_I8) { guint64 l2 = LOCAL_VAR (ip [3], guint64); if (l2 == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); + THROW_EX (interp_get_exception_divide_by_zero (frame, ip), ip); LOCAL_VAR (ip [1], guint64) = LOCAL_VAR (ip [2], guint64) / l2; ip += 4; MINT_IN_BREAK; @@ -4872,9 +4948,9 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint32 i1 = LOCAL_VAR (ip [2], gint32); gint32 i2 = LOCAL_VAR (ip [3], gint32); if (i2 == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); + THROW_EX (interp_get_exception_divide_by_zero (frame, ip), ip); if (i2 == (-1) && i1 == G_MININT32) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = i1 % i2; ip += 4; MINT_IN_BREAK; @@ -4883,9 +4959,9 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint64 l1 = LOCAL_VAR (ip [2], gint64); gint64 l2 = LOCAL_VAR (ip [3], gint64); if (l2 == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); + THROW_EX (interp_get_exception_divide_by_zero (frame, ip), ip); if (l2 == (-1) && l1 == G_MININT64) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint64) = l1 % l2; ip += 4; MINT_IN_BREAK; @@ -4901,7 +4977,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_REM_UN_I4) { guint32 i2 = LOCAL_VAR (ip [3], guint32); if (i2 == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); + THROW_EX (interp_get_exception_divide_by_zero (frame, ip), ip); LOCAL_VAR (ip [1], guint32) = LOCAL_VAR (ip [2], guint32) % i2; ip += 4; MINT_IN_BREAK; @@ -4909,7 +4985,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_REM_UN_I8) { guint64 l2 = LOCAL_VAR (ip [3], guint64); if (l2 == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); + THROW_EX (interp_get_exception_divide_by_zero (frame, ip), ip); LOCAL_VAR (ip [1], guint64) = LOCAL_VAR (ip [2], guint64) % l2; ip += 4; MINT_IN_BREAK; @@ -5188,6 +5264,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) { s = (MonoString*)mono_method_get_wrapper_data (method, strtoken); } else if (method->wrapper_type != MONO_WRAPPER_NONE) { + // FIXME push/pop LMF s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken)); } else { g_assert_not_reached (); @@ -5203,9 +5280,10 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; newobj_class = (MonoClass*) frame->imethod->data_items [token]; + // FIXME push/pop LMF LOCAL_VAR (ip [1], MonoObject*) = ves_array_create (newobj_class, param_count, (stackval*)(locals + ip [2]), error); if (!is_ok (error)) - THROW_EX (mono_error_convert_to_exception (error), ip); + THROW_EX (interp_error_convert_to_exception (frame, error, ip), ip); ip += 5; MINT_IN_BREAK; } @@ -5227,10 +5305,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; return_offset = ip [1]; call_args_offset = ip [2]; + // FIXME push/pop LMF MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass)); if (G_UNLIKELY (!o)) { mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass)); - THROW_EX (mono_error_convert_to_exception (error), ip); + THROW_EX (interp_error_convert_to_exception (frame, error, ip), ip); } // This is return value @@ -5247,10 +5326,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [2]]; INIT_VTABLE (vtable); + // FIXME push/pop LMF MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass)); if (G_UNLIKELY (!o)) { mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass)); - THROW_EX (mono_error_convert_to_exception (error), ip); + THROW_EX (interp_error_convert_to_exception (frame, error, ip), ip); } // This is return value @@ -5301,9 +5381,10 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; g_assert (!m_class_is_valuetype (newobj_class)); + // FIXME push/pop LMF MonoVTable *vtable = mono_class_vtable_checked (newobj_class, error); if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) { - MonoException *exc = mono_error_convert_to_exception (error); + MonoException *exc = interp_error_convert_to_exception (frame, error, ip); g_assert (exc); THROW_EX (exc, ip); } @@ -5321,7 +5402,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gpointer ptr = LOCAL_VAR (ip [2], gpointer); int len = LOCAL_VAR (ip [3], gint32); if (len < 0) - THROW_EX (mono_get_exception_argument_out_of_range ("length"), ip); + THROW_EX (interp_get_exception_argument_out_of_range ("length", frame, ip), ip); gpointer span = locals + ip [1]; *(gpointer*)span = ptr; *(gint32*)((gpointer*)span + 1) = len; @@ -5395,6 +5476,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; isinst = TRUE; } else if (m_class_is_array_special_interface (c)) { /* slow path */ + // FIXME push/pop LMF isinst = mono_interp_isinst (o, c); // FIXME: do not swallow the error } else { isinst = FALSE; @@ -5405,7 +5487,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (isinst_instr) LOCAL_VAR (ip [1], MonoObject*) = NULL; else - THROW_EX (mono_get_exception_invalid_cast (), ip); + THROW_EX (interp_get_exception_invalid_cast (frame, ip), ip); } else { LOCAL_VAR (ip [1], MonoObject*) = o; } @@ -5427,7 +5509,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (isinst_instr) LOCAL_VAR (ip [1], MonoObject*) = NULL; else - THROW_EX (mono_get_exception_invalid_cast (), ip); + THROW_EX (interp_get_exception_invalid_cast (frame, ip), ip); } else { LOCAL_VAR (ip [1], MonoObject*) = o; } @@ -5442,12 +5524,13 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); if (o) { MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [3]]; + // FIXME push/pop LMF if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error gboolean const isinst_instr = *ip == MINT_ISINST; if (isinst_instr) LOCAL_VAR (ip [1], MonoObject*) = NULL; else - THROW_EX (mono_get_exception_invalid_cast (), ip); + THROW_EX (interp_get_exception_invalid_cast (frame, ip), ip); } else { LOCAL_VAR (ip [1], MonoObject*) = o; } @@ -5471,7 +5554,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c))) - THROW_EX (mono_get_exception_invalid_cast (), ip); + THROW_EX (interp_get_exception_invalid_cast (frame, ip), ip); LOCAL_VAR (ip [1], gpointer) = mono_object_unbox_internal (o); ip += 4; @@ -5480,7 +5563,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_THROW) { MonoException *ex = LOCAL_VAR (ip [1], MonoException*); if (!ex) - ex = mono_get_exception_null_reference (); + ex = interp_get_exception_null_reference (frame, ip); THROW_EX (ex, ip); MINT_IN_BREAK; @@ -5689,7 +5772,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U8_I4) { gint32 val = LOCAL_VAR (ip [2], gint32); if (val < 0) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], guint64) = val; ip += 3; MINT_IN_BREAK; @@ -5697,7 +5780,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U8_I8) { gint64 val = LOCAL_VAR (ip [2], gint64); if (val < 0) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], guint64) = val; ip += 3; MINT_IN_BREAK; @@ -5705,7 +5788,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I8_U8) { guint64 val = LOCAL_VAR (ip [2], guint64); if (val > G_MAXINT64) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint64) = val; ip += 3; MINT_IN_BREAK; @@ -5713,34 +5796,35 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U8_R4) { float val = LOCAL_VAR (ip [2], float); if (!mono_try_trunc_u64 (val, (guint64*)(locals + ip [1]))) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U8_R8) { double val = LOCAL_VAR (ip [2], double); if (!mono_try_trunc_u64 (val, (guint64*)(locals + ip [1]))) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I8_R4) { float val = LOCAL_VAR (ip [2], float); if (!mono_try_trunc_i64 (val, (gint64*)(locals + ip [1]))) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I8_R8) { double val = LOCAL_VAR (ip [2], double); if (!mono_try_trunc_i64 (val, (gint64*)(locals + ip [1]))) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_BOX) { MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [3]]; + // FIXME push/pop LMF MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass)); MONO_HANDLE_ASSIGN_RAW (tmp_handle, o); stackval_to_data (m_class_get_byval_arg (vtable->klass), (stackval*)(locals + ip [2]), mono_object_get_data (o), FALSE); @@ -5754,6 +5838,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [3]]; MonoClass *c = vtable->klass; + // FIXME push/pop LMF MonoObject* o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (c)); MONO_HANDLE_ASSIGN_RAW (tmp_handle, o); mono_value_copy_internal (mono_object_get_data (o), locals + ip [2], c); @@ -5767,6 +5852,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [3]]; MonoClass *c = vtable->klass; + // FIXME push/pop LMF MonoObject* o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (c)); MONO_HANDLE_ASSIGN_RAW (tmp_handle, o); mono_value_copy_internal (mono_object_get_data (o), LOCAL_VAR (ip [2], gpointer), c); @@ -5779,16 +5865,18 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BOX_NULLABLE_PTR) { MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; + // FIXME push/pop LMF LOCAL_VAR (ip [1], MonoObject*) = mono_nullable_box (LOCAL_VAR (ip [2], gpointer), c, error); mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */ ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_NEWARR) { + // FIXME push/pop LMF MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [3]]; LOCAL_VAR (ip [1], MonoObject*) = (MonoObject*) mono_array_new_specific_checked (vtable, LOCAL_VAR (ip [2], gint32), error); if (!is_ok (error)) { - THROW_EX (mono_error_convert_to_exception (error), ip); + THROW_EX (interp_error_convert_to_exception (frame, error, ip), ip); } ip += 4; /*if (profiling_classes) { @@ -5820,7 +5908,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; NULL_CHECK (s); int i32 = LOCAL_VAR (ip [3], int); if (i32 < 0 || i32 >= mono_string_length_internal (s)) - THROW_EX (mono_get_exception_index_out_of_range (), ip); + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = mono_string_chars_internal (s)[i32]; ip += 4; MINT_IN_BREAK; @@ -5834,7 +5922,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; const gint32 length = *(gint32 *) (span + offset_length); if (index < 0 || index >= length) - THROW_EX (mono_get_exception_index_out_of_range (), ip); + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); gsize element_size = (gsize)(gint16)ip [4]; gsize offset_pointer = (gsize)(gint16)ip [6]; @@ -5860,6 +5948,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_BREAK; } MINT_IN_CASE(MINT_ARRAY_ELEMENT_SIZE) { + // FIXME push/pop LMF MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); LOCAL_VAR (ip [1], gint32) = mono_array_element_size (mono_object_class (o)); @@ -5879,7 +5968,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; NULL_CHECK (ao); gint32 index = LOCAL_VAR (ip [3], gint32); if (index >= ao->max_length) - THROW_EX (mono_get_exception_index_out_of_range (), ip); + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); guint16 size = ip [4]; LOCAL_VAR (ip [1], gpointer) = mono_array_addr_with_size_fast (ao, size, index); ip += 5; @@ -5900,7 +5989,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint32 lower = ao->bounds [i].lower_bound; guint32 len = ao->bounds [i].length; if (idx < lower || (guint32)(idx - lower) >= len) - THROW_EX (mono_get_exception_index_out_of_range (), ip); + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); pos = (pos * len) + (guint32)(idx - lower); } @@ -5909,6 +5998,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDELEMA_TC) { + // FIXME push/pop LMF stackval *sp = (stackval*)(locals + ip [2]); MonoObject *o = (MonoObject*) sp [0].data.o; @@ -5927,7 +6017,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; NULL_CHECK (o); \ gint32 aindex = LOCAL_VAR (ip [3], gint32); \ if (aindex >= mono_array_length_internal (o)) \ - THROW_EX (mono_get_exception_index_out_of_range (), ip); \ + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); \ LOCAL_VAR (ip [1], datatype) = mono_array_get_fast (o, elemtype, aindex); \ ip += 4; \ } while (0) @@ -5947,7 +6037,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; NULL_CHECK (o); mono_u aindex = LOCAL_VAR (ip [3], gint32); if (aindex >= mono_array_length_internal (o)) - THROW_EX (mono_get_exception_index_out_of_range (), ip); + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); guint16 size = ip [4]; char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, size, aindex); @@ -5961,7 +6051,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; NULL_CHECK (o); \ aindex = LOCAL_VAR (ip [2], gint32); \ if (aindex >= mono_array_length_internal (o)) \ - THROW_EX (mono_get_exception_index_out_of_range (), ip); \ + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); \ } while (0) #define STELEM(datatype, elemtype) do { \ @@ -5987,9 +6077,10 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoObject *ref = LOCAL_VAR (ip [3], MonoObject*); if (ref) { + // FIXME push/pop LMF gboolean isinst = mono_interp_isinst (ref, m_class_get_element_class (mono_object_class (o))); if (!isinst) - THROW_EX (mono_get_exception_array_type_mismatch (), ip); + THROW_EX (interp_get_exception_array_type_mismatch (frame, ip), ip); } mono_array_setref_fast ((MonoArray *) o, aindex, ref); ip += 4; @@ -6001,7 +6092,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; NULL_CHECK (o); gint32 aindex = LOCAL_VAR (ip [2], gint32); if (aindex >= mono_array_length_internal (o)) - THROW_EX (mono_get_exception_index_out_of_range (), ip); + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); guint16 size = ip [5]; char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, size, aindex); @@ -6013,7 +6104,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I4_U4) { gint32 val = LOCAL_VAR (ip [2], gint32); if (val < 0) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = val; ip += 3; MINT_IN_BREAK; @@ -6021,7 +6112,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I4_I8) { gint64 val = LOCAL_VAR (ip [2], gint64); if (val < G_MININT32 || val > G_MAXINT32) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (gint32) val; ip += 3; MINT_IN_BREAK; @@ -6029,7 +6120,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I4_U8) { guint64 val = LOCAL_VAR (ip [2], guint64); if (val > G_MAXINT32) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (gint32) val; ip += 3; MINT_IN_BREAK; @@ -6040,7 +6131,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val_r8 > ((double)G_MININT32 - 1) && val_r8 < ((double)G_MAXINT32 + 1)) LOCAL_VAR (ip [1], gint32) = (gint32) val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } @@ -6049,14 +6140,14 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > ((double)G_MININT32 - 1) && val < ((double)G_MAXINT32 + 1)) LOCAL_VAR (ip [1], gint32) = (gint32) val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U4_I4) { gint32 val = LOCAL_VAR (ip [2], gint32); if (val < 0) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = val; ip += 3; MINT_IN_BREAK; @@ -6064,7 +6155,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U4_I8) { gint64 val = LOCAL_VAR (ip [2], gint64); if (val < 0 || val > G_MAXUINT32) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (guint32) val; ip += 3; MINT_IN_BREAK; @@ -6075,7 +6166,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val_r8 > -1.0 && val_r8 < ((double)G_MAXUINT32 + 1)) LOCAL_VAR (ip [1], gint32) = (guint32)val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } @@ -6084,14 +6175,14 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > -1.0 && val < ((double)G_MAXUINT32 + 1)) LOCAL_VAR (ip [1], gint32) = (guint32)val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I2_I4) { gint32 val = LOCAL_VAR (ip [2], gint32); if (val < G_MININT16 || val > G_MAXINT16) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (gint16)val; ip += 3; MINT_IN_BREAK; @@ -6099,7 +6190,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_U4) { gint32 val = LOCAL_VAR (ip [2], gint32); if (val < 0 || val > G_MAXINT16) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (gint16)val; ip += 3; MINT_IN_BREAK; @@ -6107,7 +6198,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_I8) { gint64 val = LOCAL_VAR (ip [2], gint64); if (val < G_MININT16 || val > G_MAXINT16) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (gint16) val; ip += 3; MINT_IN_BREAK; @@ -6115,7 +6206,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I2_U8) { gint64 val = LOCAL_VAR (ip [2], gint64); if (val < 0 || val > G_MAXINT16) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (gint16) val; ip += 3; MINT_IN_BREAK; @@ -6125,7 +6216,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > (G_MININT16 - 1) && val < (G_MAXINT16 + 1)) LOCAL_VAR (ip [1], gint32) = (gint16) val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } @@ -6134,14 +6225,14 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > (G_MININT16 - 1) && val < (G_MAXINT16 + 1)) LOCAL_VAR (ip [1], gint32) = (gint16) val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U2_I4) { gint32 val = LOCAL_VAR (ip [2], gint32); if (val < 0 || val > G_MAXUINT16) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = val; ip += 3; MINT_IN_BREAK; @@ -6149,7 +6240,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U2_I8) { gint64 val = LOCAL_VAR (ip [2], gint64); if (val < 0 || val > G_MAXUINT16) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (guint16) val; ip += 3; MINT_IN_BREAK; @@ -6159,7 +6250,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > -1.0f && val < (G_MAXUINT16 + 1)) LOCAL_VAR (ip [1], gint32) = (guint16) val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } @@ -6168,14 +6259,14 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > -1.0 && val < (G_MAXUINT16 + 1)) LOCAL_VAR (ip [1], gint32) = (guint16) val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I1_I4) { gint32 val = LOCAL_VAR (ip [2], gint32); if (val < G_MININT8 || val > G_MAXINT8) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = val; ip += 3; MINT_IN_BREAK; @@ -6183,7 +6274,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_U4) { gint32 val = LOCAL_VAR (ip [2], gint32); if (val < 0 || val > G_MAXINT8) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = val; ip += 3; MINT_IN_BREAK; @@ -6191,7 +6282,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_I8) { gint64 val = LOCAL_VAR (ip [2], gint64); if (val < G_MININT8 || val > G_MAXINT8) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (gint8) val; ip += 3; MINT_IN_BREAK; @@ -6199,7 +6290,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_I1_U8) { gint64 val = LOCAL_VAR (ip [2], gint64); if (val < 0 || val > G_MAXINT8) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (gint8) val; ip += 3; MINT_IN_BREAK; @@ -6209,7 +6300,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > (G_MININT8 - 1) && val < (G_MAXINT8 + 1)) LOCAL_VAR (ip [1], gint32) = (gint8) val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } @@ -6218,14 +6309,14 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > (G_MININT8 - 1) && val < (G_MAXINT8 + 1)) LOCAL_VAR (ip [1], gint32) = (gint8) val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U1_I4) { gint32 val = LOCAL_VAR (ip [2], gint32); if (val < 0 || val > G_MAXUINT8) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = val; ip += 3; MINT_IN_BREAK; @@ -6233,7 +6324,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_OVF_U1_I8) { gint64 val = LOCAL_VAR (ip [2], gint64); if (val < 0 || val > G_MAXUINT8) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = (guint8) val; ip += 3; MINT_IN_BREAK; @@ -6243,7 +6334,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > -1.0f && val < (G_MAXUINT8 + 1)) LOCAL_VAR (ip [1], gint32) = (guint8)val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } @@ -6252,14 +6343,14 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; if (val > -1.0 && val < (G_MAXUINT8 + 1)) LOCAL_VAR (ip [1], gint32) = (guint8)val; else - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CKFINITE) { double val = LOCAL_VAR (ip [2], double); if (!mono_isfinite (val)) - THROW_EX (mono_get_exception_arithmetic (), ip); + THROW_EX (interp_get_exception_arithmetic (frame, ip), ip); LOCAL_VAR (ip [1], double) = val; ip += 3; MINT_IN_BREAK; @@ -6289,7 +6380,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; if (c != tref->klass) - THROW_EX (mono_get_exception_invalid_cast (), ip); + THROW_EX (interp_get_exception_invalid_cast (frame, ip), ip); LOCAL_VAR (ip [1], gpointer) = tref->value; ip += 4; @@ -6304,7 +6395,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint32 i1 = LOCAL_VAR (ip [2], gint32); gint32 i2 = LOCAL_VAR (ip [3], gint32); if (CHECK_ADD_OVERFLOW (i1, i2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = i1 + i2; ip += 4; MINT_IN_BREAK; @@ -6313,7 +6404,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint64 l1 = LOCAL_VAR (ip [2], gint64); gint64 l2 = LOCAL_VAR (ip [3], gint64); if (CHECK_ADD_OVERFLOW64 (l1, l2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint64) = l1 + l2; ip += 4; MINT_IN_BREAK; @@ -6322,7 +6413,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; guint32 i1 = LOCAL_VAR (ip [2], guint32); guint32 i2 = LOCAL_VAR (ip [3], guint32); if (CHECK_ADD_OVERFLOW_UN (i1, i2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], guint32) = i1 + i2; ip += 4; MINT_IN_BREAK; @@ -6331,7 +6422,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; guint64 l1 = LOCAL_VAR (ip [2], guint64); guint64 l2 = LOCAL_VAR (ip [3], guint64); if (CHECK_ADD_OVERFLOW64_UN (l1, l2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], guint64) = l1 + l2; ip += 4; MINT_IN_BREAK; @@ -6340,7 +6431,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint32 i1 = LOCAL_VAR (ip [2], gint32); gint32 i2 = LOCAL_VAR (ip [3], gint32); if (CHECK_MUL_OVERFLOW (i1, i2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = i1 * i2; ip += 4; MINT_IN_BREAK; @@ -6349,7 +6440,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint64 l1 = LOCAL_VAR (ip [2], gint64); gint64 l2 = LOCAL_VAR (ip [3], gint64); if (CHECK_MUL_OVERFLOW64 (l1, l2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint64) = l1 * l2; ip += 4; MINT_IN_BREAK; @@ -6358,7 +6449,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; guint32 i1 = LOCAL_VAR (ip [2], guint32); guint32 i2 = LOCAL_VAR (ip [3], guint32); if (CHECK_MUL_OVERFLOW_UN (i1, i2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], guint32) = i1 * i2; ip += 4; MINT_IN_BREAK; @@ -6367,7 +6458,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; guint64 l1 = LOCAL_VAR (ip [2], guint64); guint64 l2 = LOCAL_VAR (ip [3], guint64); if (CHECK_MUL_OVERFLOW64_UN (l1, l2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], guint64) = l1 * l2; ip += 4; MINT_IN_BREAK; @@ -6376,7 +6467,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint32 i1 = LOCAL_VAR (ip [2], gint32); gint32 i2 = LOCAL_VAR (ip [3], gint32); if (CHECK_SUB_OVERFLOW (i1, i2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint32) = i1 - i2; ip += 4; MINT_IN_BREAK; @@ -6385,7 +6476,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gint64 l1 = LOCAL_VAR (ip [2], gint64); gint64 l2 = LOCAL_VAR (ip [3], gint64); if (CHECK_SUB_OVERFLOW64 (l1, l2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint64) = l1 - l2; ip += 4; MINT_IN_BREAK; @@ -6394,7 +6485,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; guint32 i1 = LOCAL_VAR (ip [2], guint32); guint32 i2 = LOCAL_VAR (ip [3], guint32); if (CHECK_SUB_OVERFLOW_UN (i1, i2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], guint32) = i1 - i2; ip += 4; MINT_IN_BREAK; @@ -6403,7 +6494,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; guint64 l1 = LOCAL_VAR (ip [2], guint64); guint64 l2 = LOCAL_VAR (ip [3], guint64); if (CHECK_SUB_OVERFLOW64_UN (l1, l2)) - THROW_EX (mono_get_exception_overflow (), ip); + THROW_EX (interp_get_exception_overflow (frame, ip), ip); LOCAL_VAR (ip [1], gint64) = l1 - l2; ip += 4; MINT_IN_BREAK; @@ -6481,10 +6572,12 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_MONO_NEWOBJ) + // FIXME push/pop LMF LOCAL_VAR (ip [1], MonoObject*) = mono_interp_new ((MonoClass*)frame->imethod->data_items [ip [2]]); // FIXME: do not swallow the error ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_MONO_RETOBJ) + // FIXME push/pop LMF stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->stack, LOCAL_VAR (ip [1], gpointer), mono_method_signature_internal (frame->imethod->method)->pinvoke && !mono_method_signature_internal (frame->imethod->method)->marshalling_disabled); frame_data_allocator_pop (&context->data_stack, frame); @@ -6532,6 +6625,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; static T ss_tramp; if (!ss_tramp) { + // FIXME push/pop LMF void *tramp = mini_get_single_step_trampoline (); mono_memory_barrier (); ss_tramp = (T)tramp; @@ -6563,6 +6657,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; typedef void (*T) (void); static T bp_tramp; if (!bp_tramp) { + // FIXME push/pop LMF void *tramp = mini_get_breakpoint_trampoline (); mono_memory_barrier (); bp_tramp = (T)tramp; @@ -6724,6 +6819,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFTN) { InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [2]]; + // FIXME push/pop LMF LOCAL_VAR (ip [1], gpointer) = imethod_to_ftnptr (m, FALSE); ip += 3; MINT_IN_BREAK; @@ -6733,6 +6829,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); + // FIXME push/pop LMF InterpMethod *res_method = get_virtual_method (virtual_method, o->vtable); gboolean need_unbox = m_class_is_valuetype (res_method->method->klass) && !m_class_is_valuetype (virtual_method->method->klass); LOCAL_VAR (ip [1], gpointer) = imethod_to_ftnptr (res_method, need_unbox); @@ -6744,6 +6841,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoMethod *cmethod = LOCAL_VAR (ip [2], MonoMethod*); + // FIXME push/pop LMF if (G_UNLIKELY (mono_method_has_unmanaged_callers_only_attribute (cmethod))) { cmethod = mono_marshal_get_managed_wrapper (cmethod, NULL, (MonoGCHandle)0, error); mono_error_assert_ok (error); @@ -6766,6 +6864,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoProfilerCallContext *prof_ctx = g_new0 (MonoProfilerCallContext, 1); prof_ctx->interp_frame = frame; prof_ctx->method = frame->imethod->method; + // FIXME push/pop LMF if (flag & TRACING_FLAG) mono_trace_enter_method (frame->imethod->method, frame->imethod->jinfo, prof_ctx); if (flag & PROFILING_FLAG) @@ -6797,6 +6896,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; prof_ctx->method = frame->imethod->method; if (!is_void) prof_ctx->return_value = frame->retval; + // FIXME push/pop LMF if (flag & TRACING_FLAG) mono_trace_leave_method (frame->imethod->method, frame->imethod->jinfo, prof_ctx); if (flag & PROFILING_FLAG) @@ -6891,7 +6991,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; gpointer src = LOCAL_VAR (ip [2], gpointer); guint32 size = LOCAL_VAR (ip [3], guint32); if (size && (!dest || !src)) - THROW_EX (mono_get_exception_null_reference(), ip); + THROW_EX (interp_get_exception_null_reference(frame, ip), ip); else memcpy (dest, src, size); ip += 4; @@ -6922,12 +7022,13 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MonoException *exc = LOCAL_VAR (ip [1], MonoException*); if (!exc) - exc = mono_get_exception_null_reference (); + exc = interp_get_exception_null_reference (frame, ip); THROW_EX_GENERAL (exc, ip, TRUE); MINT_IN_BREAK; } MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) { + // FIXME push/pop LMF MonoDelegate *del = LOCAL_VAR (ip [2], MonoDelegate*); if (!del->interp_method) { /* Not created from interpreted code */ @@ -7710,16 +7811,6 @@ metadata_update_prepare_to_invalidate (void) if (!info || !info->jit_data) continue; - ThreadContext *context = (ThreadContext*)info->jit_data->interp_context; - - /* If the thread was in the interpreter and hit a safepoint - * opcode and suspended, backup the frames since the last lmf. - */ - if (context && context->safepoint_frame) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "threadinfo=%p, has safepoint frame %p", info, context->safepoint_frame); - metadata_update_backup_frames (info, context->safepoint_frame); - } - MonoLMF *lmf = info->jit_data->lmf; while (lmf) { if (((gsize) lmf->previous_lmf) & 2) { From b85a43593ec6841050f67fc232d87e8b0e44cfb1 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Fri, 21 Jan 2022 09:41:24 +0000 Subject: [PATCH 115/308] Initial WASI support prototype (#63890) --- src/mono/CMakeLists.txt | 18 +- src/mono/cmake/configure.cmake | 28 +- src/mono/mono/eglib/gfile-posix.c | 5 + src/mono/mono/eglib/gfile-unix.c | 3 + src/mono/mono/metadata/gc.c | 4 +- src/mono/mono/metadata/threads.c | 3 + src/mono/mono/mini/CMakeLists.txt | 2 +- src/mono/mono/mini/mini-exceptions.c | 2 + src/mono/mono/mini/mini-wasm.c | 26 +- src/mono/mono/profiler/CMakeLists.txt | 8 +- src/mono/mono/utils/mono-dl-wasm.c | 7 + src/mono/mono/utils/mono-log-posix.c | 2 +- src/mono/mono/utils/mono-mmap-wasm.c | 9 +- src/mono/mono/utils/mono-stdlib.h | 4 + src/mono/mono/utils/mono-threads-wasm.c | 19 +- src/mono/mono/utils/mono-threads.c | 5 + src/mono/mono/utils/networking-posix.c | 9 + src/mono/wasi/Makefile | 29 + src/mono/wasi/Makefile.variable | 8 + src/mono/wasi/README.md | 52 ++ src/mono/wasi/include/pthread.h | 230 +++++++ src/mono/wasi/include/setjmp.h | 2 + src/mono/wasi/mono-wasi-driver/driver.c | 624 ++++++++++++++++++ src/mono/wasi/mono-wasi-driver/driver.h | 25 + src/mono/wasi/mono-wasi-driver/stubs.c | 22 + .../wasi/mono-wasi-driver/synthetic-pthread.c | 62 ++ src/mono/wasi/sample/.gitignore | 1 + src/mono/wasi/sample/Directory.Build.props | 8 + src/mono/wasi/sample/SampleMakefile.variable | 18 + src/mono/wasi/sample/console/Makefile | 20 + .../sample/console/WasiConsoleApp/Program.cs | 16 + .../WasiConsoleApp/WasiConsoleApp.csproj | 9 + src/mono/wasi/sample/console/main.c | 21 + 33 files changed, 1276 insertions(+), 25 deletions(-) create mode 100644 src/mono/wasi/Makefile create mode 100644 src/mono/wasi/Makefile.variable create mode 100644 src/mono/wasi/README.md create mode 100644 src/mono/wasi/include/pthread.h create mode 100644 src/mono/wasi/include/setjmp.h create mode 100644 src/mono/wasi/mono-wasi-driver/driver.c create mode 100644 src/mono/wasi/mono-wasi-driver/driver.h create mode 100644 src/mono/wasi/mono-wasi-driver/stubs.c create mode 100644 src/mono/wasi/mono-wasi-driver/synthetic-pthread.c create mode 100644 src/mono/wasi/sample/.gitignore create mode 100644 src/mono/wasi/sample/Directory.Build.props create mode 100644 src/mono/wasi/sample/SampleMakefile.variable create mode 100644 src/mono/wasi/sample/console/Makefile create mode 100644 src/mono/wasi/sample/console/WasiConsoleApp/Program.cs create mode 100644 src/mono/wasi/sample/console/WasiConsoleApp/WasiConsoleApp.csproj create mode 100644 src/mono/wasi/sample/console/main.c diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt index 6b97bae13a95a..79d238e6eeb28 100644 --- a/src/mono/CMakeLists.txt +++ b/src/mono/CMakeLists.txt @@ -246,6 +246,15 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "WASI") set(INTERNAL_ZLIB 1) set(DISABLE_EXECUTABLES 1) set(DISABLE_COMPONENTS 1) + + set(WASI_DRIVER_SOURCES + wasi/mono-wasi-driver/driver.c + wasi/mono-wasi-driver/stubs.c + wasi/mono-wasi-driver/synthetic-pthread.c + ) + add_library(mono-wasi-driver STATIC ${WASI_DRIVER_SOURCES}) + target_compile_options(mono-wasi-driver PRIVATE -Wno-missing-prototypes -Wno-strict-prototypes) + install(TARGETS mono-wasi-driver LIBRARY) elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") set(HOST_WIN32 1) set(EXE_SUFFIX ".exe") @@ -463,8 +472,13 @@ include(configure) ###################################### if(GCC) - # We require C99 with some GNU extensions, e.g. `linux` macro - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") + if(HOST_WASI) + # WASI SDK only includes some required definitions if the C version is at least this new + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11") + else() + # We require C99 with some GNU extensions, e.g. `linux` macro + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") + endif() # The runtime code does not respect ANSI C strict aliasing rules append("-fno-strict-aliasing" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) # We rely on signed overflow to behave diff --git a/src/mono/cmake/configure.cmake b/src/mono/cmake/configure.cmake index 1db1ce3119a3f..ee6224390fa61 100644 --- a/src/mono/cmake/configure.cmake +++ b/src/mono/cmake/configure.cmake @@ -213,7 +213,33 @@ elseif(HOST_WASI) # Some headers exist, but don't compile (wasi sdk 12.0) set(HAVE_SYS_SOCKET_H 0) set(HAVE_SYS_UN_H 0) - set(HAVE_NETINET_IN_H 0) set(HAVE_NETINET_TCP_H 0) set(HAVE_ARPA_INET_H 0) + set(HAVE_GETPWUID_R 0) + set(HAVE_MKDTEMP 0) + set(HAVE_EXECVE 0) + set(HAVE_FORK 0) + set(HAVE_GETRLIMIT 0) + set(HAVE_GETDTABLESIZE 0) + set(HAVE_MKSTEMP 0) + set(HAVE_BACKTRACE_SYMBOLS 0) + set(HAVE_GETPID 0) + set(HAVE_MACH_ABSOLUTE_TIME 0) + set(HAVE_GETHRTIME 0) + set(HAVE_READ_REAL_TIME 0) + set(HAVE_SCHED_GETAFFINITY 0) + set(HAVE_SCHED_SETAFFINITY 0) + set(HAVE_GETIFADDRS 0) + set(HAVE_QP2GETIFADDRS 0) + set(HAVE_GETADDRINFO 0) + set(HAVE_GETHOSTBYNAME 0) + set(HAVE_GETHOSTBYNAME2 0) + set(HAVE_GETPROTOBYNAME 0) + set(HAVE_GETNAMEINFO 0) + set(HAVE_INET_NTOP 0) + set(HAVE_SYS_ICU 0) + set(HAVE_EXECVP 0) + set(HAVE_MMAP 1) + set(DISABLE_PROFILER 1) + set(ENABLE_INTERP_LIB 1) endif() diff --git a/src/mono/mono/eglib/gfile-posix.c b/src/mono/mono/eglib/gfile-posix.c index f46f8098f6bcf..53414c659d780 100644 --- a/src/mono/mono/eglib/gfile-posix.c +++ b/src/mono/mono/eglib/gfile-posix.c @@ -143,7 +143,12 @@ g_file_open_tmp (const gchar *tmpl, gchar **name_used, GError **gerror) t = g_build_filename (g_get_tmp_dir (), tmpl, (const char*)NULL); + #ifdef HOST_WASI + g_critical ("g_file_open_tmp is not implemented for WASI"); + return 0; + #else fd = mkstemp (t); + #endif if (fd == -1) { if (gerror) { diff --git a/src/mono/mono/eglib/gfile-unix.c b/src/mono/mono/eglib/gfile-unix.c index eab90669a25ae..78815dc9c82bd 100644 --- a/src/mono/mono/eglib/gfile-unix.c +++ b/src/mono/mono/eglib/gfile-unix.c @@ -111,6 +111,9 @@ g_mkdtemp (char *temp) */ #if defined(HAVE_MKDTEMP) && !defined(_AIX) return mkdtemp (g_strdup (temp)); +#elif defined(HOST_WASI) + g_critical ("g_mkdtemp is not implemented for WASI\n"); + return NULL; #else temp = mktemp (g_strdup (temp)); /* 0700 is the mode specified in specs */ diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c index 8c0745705e861..ad8f0c2b9e337 100644 --- a/src/mono/mono/metadata/gc.c +++ b/src/mono/mono/metadata/gc.c @@ -702,7 +702,9 @@ mono_gc_finalize_notify (void) if (mono_gc_is_null ()) return; -#ifdef HOST_WASM +#if defined(HOST_WASI) + // TODO: Schedule the background job on WASI. Threads aren't yet supported in this build. +#elif defined(HOST_WASM) mono_threads_schedule_background_job (mono_runtime_do_background_work); #else mono_coop_sem_post (&finalizer_sem); diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index 862a3437f82ce..4f9d15fcd8a5e 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -680,6 +680,9 @@ mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPrior // When this API becomes available on an arbitrary thread, we can use it, // not available on current Zircon // +#elif HOST_WASI + // Thread scheduling isn't yet implemented in the WASI build + return; #else /* !HOST_WIN32 and not HOST_FUCHSIA */ pthread_t tid; int policy; diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt index 175aa7759aad4..6ed23b463151d 100644 --- a/src/mono/mono/mini/CMakeLists.txt +++ b/src/mono/mono/mini/CMakeLists.txt @@ -46,7 +46,7 @@ if(HOST_WIN32) endif() # ICU -if(HAVE_SYS_ICU) +if(HAVE_SYS_ICU AND NOT HOST_WASI) if(STATIC_ICU) set(pal_icushim_sources_base pal_icushim_static.c) diff --git a/src/mono/mono/mini/mini-exceptions.c b/src/mono/mono/mini/mini-exceptions.c index c350d4307bd62..266c451c1715c 100644 --- a/src/mono/mono/mini/mini-exceptions.c +++ b/src/mono/mono/mini/mini-exceptions.c @@ -3256,6 +3256,8 @@ mono_thread_state_init (MonoThreadUnwindState *ctx) #if defined(MONO_CROSS_COMPILE) ctx->valid = FALSE; //A cross compiler doesn't need to suspend. +#elif defined(HOST_WASI) + // TODO: For WASI, we need to review how thread state is initialized #elif MONO_ARCH_HAS_MONO_CONTEXT MONO_CONTEXT_GET_CURRENT (ctx->ctx); #else diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index 67bbdbc94af69..82c8b1fcd6572 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -508,6 +508,21 @@ mono_arch_context_get_int_reg_address (MonoContext *ctx, int reg) return 0; } +#if defined(HOST_BROWSER) || defined(HOST_WASI) + +void +mono_runtime_install_handlers (void) +{ +} + +void +mono_init_native_crash_info (void) +{ + return; +} + +#endif + #ifdef HOST_BROWSER void @@ -524,17 +539,6 @@ MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) return FALSE; } -void -mono_runtime_install_handlers (void) -{ -} - -void -mono_init_native_crash_info (void) -{ - return; -} - gboolean mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info, void *sigctx) { diff --git a/src/mono/mono/profiler/CMakeLists.txt b/src/mono/mono/profiler/CMakeLists.txt index 74ebd6ba30706..b8092fe882578 100644 --- a/src/mono/mono/profiler/CMakeLists.txt +++ b/src/mono/mono/profiler/CMakeLists.txt @@ -28,7 +28,9 @@ if(NOT DISABLE_LIBS) endif() endif() - add_library(mono-profiler-aot-static STATIC aot.c helper.c) - set_target_properties(mono-profiler-aot-static PROPERTIES OUTPUT_NAME mono-profiler-aot) - install(TARGETS mono-profiler-aot-static LIBRARY) + if(NOT HOST_WASI) + add_library(mono-profiler-aot-static STATIC aot.c helper.c) + set_target_properties(mono-profiler-aot-static PROPERTIES OUTPUT_NAME mono-profiler-aot) + install(TARGETS mono-profiler-aot-static LIBRARY) + endif() endif() diff --git a/src/mono/mono/utils/mono-dl-wasm.c b/src/mono/mono/utils/mono-dl-wasm.c index 3827dcea49584..4d5529926d814 100644 --- a/src/mono/mono/utils/mono-dl-wasm.c +++ b/src/mono/mono/utils/mono-dl-wasm.c @@ -12,7 +12,10 @@ #include #include #include + +#ifndef HOST_WASI #include +#endif const char * mono_dl_get_so_prefix (void) @@ -55,6 +58,8 @@ mono_dl_convert_flags (int mono_flags, int native_flags) { int lflags = native_flags; +#ifndef HOST_WASI // On WASI, these flags are undefined and not required + // Specifying both will default to LOCAL if (mono_flags & MONO_DL_GLOBAL && !(mono_flags & MONO_DL_LOCAL)) lflags |= RTLD_GLOBAL; @@ -66,6 +71,8 @@ mono_dl_convert_flags (int mono_flags, int native_flags) else lflags |= RTLD_NOW; +#endif + return lflags; } diff --git a/src/mono/mono/utils/mono-log-posix.c b/src/mono/mono/utils/mono-log-posix.c index 6a1568d8bbb32..454bf021356e1 100644 --- a/src/mono/mono/utils/mono-log-posix.c +++ b/src/mono/mono/utils/mono-log-posix.c @@ -14,7 +14,7 @@ #include #endif -#if defined(_POSIX_VERSION) +#if defined(_POSIX_VERSION) && !defined(HOST_WASI) #include #include diff --git a/src/mono/mono/utils/mono-mmap-wasm.c b/src/mono/mono/utils/mono-mmap-wasm.c index b04d69ab1b5e2..82f117b728c79 100644 --- a/src/mono/mono/utils/mono-mmap-wasm.c +++ b/src/mono/mono/utils/mono-mmap-wasm.c @@ -63,7 +63,13 @@ mono_valloc_granule (void) static int prot_from_flags (int flags) -{ +{ +#if HOST_WASI + // The mmap in wasi-sdk rejects PROT_NONE, but otherwise disregards the flags + // We just need to pass an acceptable value + return PROT_READ; +#endif + int prot = PROT_NONE; /* translate the protection bits */ if (flags & MONO_MMAP_READ) @@ -72,6 +78,7 @@ prot_from_flags (int flags) prot |= PROT_WRITE; if (flags & MONO_MMAP_EXEC) prot |= PROT_EXEC; + return prot; } diff --git a/src/mono/mono/utils/mono-stdlib.h b/src/mono/mono/utils/mono-stdlib.h index eb8531bc86a43..64793b223b846 100644 --- a/src/mono/mono/utils/mono-stdlib.h +++ b/src/mono/mono/utils/mono-stdlib.h @@ -12,5 +12,9 @@ int mono_mkstemp (char *templ); #endif +#if HOST_WASI +char *mktemp (char *); +#endif + #endif /* __MONO_FILE_H */ diff --git a/src/mono/mono/utils/mono-threads-wasm.c b/src/mono/mono/utils/mono-threads-wasm.c index fae0193050b9c..e7415532cbf09 100644 --- a/src/mono/mono/utils/mono-threads-wasm.c +++ b/src/mono/mono/utils/mono-threads-wasm.c @@ -37,15 +37,19 @@ wasm_get_stack_size (void) static int wasm_get_stack_base (void) { - g_assert_not_reached (); - return 0; + // TODO: For WASI, we need to ensure the stack location makes sense and won't interfere with the heap. + // Currently these hardcoded values are sufficient for a working prototype. It's an arbitrary nonzero + // value that aligns to 32 bits. + return 4; } static int wasm_get_stack_size (void) { - g_assert_not_reached (); - return 0; + // TODO: For WASI, we need to ensure the stack location makes sense and won't interfere with the heap. + // Currently these hardcoded values are sufficient for a working prototype. It's an arbitrary nonzero + // value that aligns to 32 bits. + return 4; } #endif @@ -201,8 +205,13 @@ mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize) *stsize = wasm_get_stack_size (); #endif +#ifdef HOST_WASI + // TODO: For WASI, we need to ensure the stack is positioned correctly and reintroduce these assertions. + // Currently it works anyway in prototypes (except these checks would fail) +#else g_assert ((guint8*)&tmp > *staddr); g_assert ((guint8*)&tmp < (guint8*)*staddr + *stsize); +#endif } gboolean @@ -272,6 +281,8 @@ mono_thread_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_d if (res != 0) g_error ("%s: pthread_attr_destroy failed, error: \"%s\" (%d)", __func__, g_strerror (res), res); + return TRUE; +#elif defined(HOST_WASI) return TRUE; #else g_assert_not_reached (); diff --git a/src/mono/mono/utils/mono-threads.c b/src/mono/mono/utils/mono-threads.c index 233e89e48727f..e3a936a1abc3c 100644 --- a/src/mono/mono/utils/mono-threads.c +++ b/src/mono/mono/utils/mono-threads.c @@ -1616,8 +1616,13 @@ mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize) if (!*staddr) return; +#ifdef HOST_WASI + // TODO: Fix the stack positioning on WASI and re-enable the following check. + // Currently it works as a prototype anyway. +#else /* Sanity check the result */ g_assert ((current > *staddr) && (current < *staddr + *stsize)); +#endif #ifndef TARGET_WASM /* When running under emacs, sometimes staddr is not aligned to a page size */ diff --git a/src/mono/mono/utils/networking-posix.c b/src/mono/mono/utils/networking-posix.c index e307a728fa36d..8d79cc637f7bc 100644 --- a/src/mono/mono/utils/networking-posix.c +++ b/src/mono/mono/utils/networking-posix.c @@ -174,6 +174,15 @@ fetch_protocol (const char *proto_name, int *cache, int *proto, int default_val) return *proto; } +#elif defined(HOST_WASI) + +static int +fetch_protocol (const char *proto_name, int *cache, int *proto, int default_val) +{ + g_critical("fetch_protocol is not implemented on WASI\n"); + return 0; +} + #endif int diff --git a/src/mono/wasi/Makefile b/src/mono/wasi/Makefile new file mode 100644 index 0000000000000..d537988471eb8 --- /dev/null +++ b/src/mono/wasi/Makefile @@ -0,0 +1,29 @@ +include Makefile.variable + +all: build-all + +build-all: $(WASI_SDK_CLANG) + mkdir -p $(WASI_OBJ_DIR) + cd $(WASI_OBJ_DIR) && \ + cmake -G Ninja \ + -DWASI_SDK_PREFIX=$(WASI_SDK_ROOT) \ + -DCMAKE_SYSROOT=$(WASI_SDK_ROOT)/share/wasi-sysroot \ + -DCMAKE_TOOLCHAIN_FILE=$(WASI_SDK_ROOT)/share/cmake/wasi-sdk.cmake \ + -DCMAKE_C_FLAGS="--sysroot=$(WASI_SDK_ROOT)/share/wasi-sysroot -I$(CURDIR)/include -I$(TOP)/src/mono" \ + -DCMAKE_CXX_FLAGS="--sysroot=$(WASI_SDK_ROOT)/share/wasi-sysroot" \ + -DENABLE_MINIMAL=jit,sgen_major_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,sgen_toggleref,sgen_debug_helpers,sgen_binary_protocol,logging,shared_perfcounters,interpreter,threads,qcalls,debugger_agent,sockets,eventpipe \ + -DDISABLE_SHARED_LIBS=1 \ + -Wl,--allow-undefined \ + $(TOP)/src/mono + cd $(WASI_OBJ_DIR) && ninja + + mkdir -p $(WASI_BIN_DIR) + cp $(WASI_OBJ_DIR)/mono/mini/*.a $(WASI_OBJ_DIR)/libmono-wasi-driver.a $(WASI_BIN_DIR) + mkdir -p $(WASI_BIN_DIR)/include/mono-wasi + cp mono-wasi-driver/*.h $(WASI_BIN_DIR)/include/mono-wasi + +$(WASI_SDK_CLANG): + mkdir -p $(WASI_OBJ_DIR) + cd $(WASI_OBJ_DIR) && \ + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WASI_SDK_VERSION)/wasi-sdk-$(WASI_SDK_VERSION).0-linux.tar.gz && \ + tar xf wasi-sdk-*.tar.gz diff --git a/src/mono/wasi/Makefile.variable b/src/mono/wasi/Makefile.variable new file mode 100644 index 0000000000000..fb1d6d5a6e5de --- /dev/null +++ b/src/mono/wasi/Makefile.variable @@ -0,0 +1,8 @@ +TOP=$(realpath $(CURDIR)/../../..) +CONFIG?=Release +WASI_SDK_VERSION=12 + +WASI_OBJ_DIR=$(TOP)/artifacts/obj/mono/Wasi.$(CONFIG) +WASI_BIN_DIR=$(TOP)/artifacts/bin/mono/Wasi.$(CONFIG) +WASI_SDK_ROOT=$(WASI_OBJ_DIR)/wasi-sdk-$(WASI_SDK_VERSION).0 +WASI_SDK_CLANG=$(WASI_SDK_ROOT)/bin/clang diff --git a/src/mono/wasi/README.md b/src/mono/wasi/README.md new file mode 100644 index 0000000000000..b4037f7701593 --- /dev/null +++ b/src/mono/wasi/README.md @@ -0,0 +1,52 @@ +# Prototype WASI support + +This directory contains a build configuration for WASI support, plus a basic sample. This is not intended for production use, nor is it currently supported. This is a step towards possible future support. + +## How it works + +The mechanism for executing .NET code in a WASI runtime environment is equivalent to how `dotnet.wasm` executes .NET code in a browser environment. That is, it runs the Mono interpreter to execute .NET bytecode that has been built in the normal way. It should also work with AOT but this is not yet attempted. + +## How to build the runtime + +Currently this can only be built in Linux or WSL (tested on Windows 11). Simply run `make` in this directory. It will automatically download and use [WASI SDK](https://github.com/WebAssembly/wasi-sdk). + +The resulting libraries are placed in `(repo_root)/artifacts/bin/mono/Wasi.Release`. + +## How to build and run the sample + +### 1. Obtain a WASI runtime + +To run an application in a WASI environment, you need to have a WASI runtime available. For example, download [wasmtime](https://github.com/bytecodealliance/wasmtime/releases) and make sure it's available on `PATH`: + +``` +export PATH=~/wasmtime-v0.31.0-x86_64-linux +wasmtime --version +``` + +Other WASI runtimes also work. Tested: [wamr](https://github.com/bytecodealliance/wasm-micro-runtime), [wasmer](https://wasmer.io/). + +### 2. Obtain a suitable .NET build toolchain + +You also need to have a working installation of .NET 7 including the `browser-wasm` runtime pack. For example, obtain the [.NET SDK daily build](https://github.com/dotnet/installer/blob/main/README.md#installers-and-binaries) (`main` branch), and ensure the `browser-wasm` pack is installed: + +``` +dotnet workload install wasm-tools -s https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json +``` + +To make this available to the build scripts, supply environment variables. Example: + +``` +export DOTNET_ROOT=~/dotnet7 +export BROWSER_WASM_RUNTIME_PATH=$(DOTNET_ROOT)/packs/Microsoft.NETCore.App.Runtime.Mono.browser-wasm/7.0.0-alpha.1.22061.11/runtimes/browser-wasm +``` + +You'll need to update these paths to match the location where you extracted the .NET daily SDK build and the exact version of the `browser-wasm` pack you received. + +### 3. Run it + +Finally, you can build and run the sample: + +``` +cd samples/console +make run +``` diff --git a/src/mono/wasi/include/pthread.h b/src/mono/wasi/include/pthread.h new file mode 100644 index 0000000000000..a5ea63882e7b9 --- /dev/null +++ b/src/mono/wasi/include/pthread.h @@ -0,0 +1,230 @@ +// This file is multi-licensed: +// Apache-2.0: https://github.com/WebAssembly/wasi-libc/blob/main/LICENSE-APACHE +// MIT: https://github.com/WebAssembly/wasi-libc/blob/main/LICENSE-MIT + +// This file is duplicated from https://github.com/WebAssembly/wasi-libc/blob/ad5133410f66b93a2381db5b542aad5e0964db96/libc-top-half/musl/include/pthread.h +// with small edits for compatibility. We may be able to remove it once https://github.com/WebAssembly/wasi-libc/issues/209 is resolved + +// The WASI SDK doesn't include pthread.h, but the definitions are required by various parts of the Mono sources +// On certain runtimes such as WAMR there is actually an implementation provided for the pthread APIs so threading +// does work. However that's not yet in the WASI standard, so we're not yet relying on being able to call the ones +// that really start up new threads. + +#ifndef _PTHREAD_H +#define _PTHREAD_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_time_t +#define __NEED_clockid_t +#define __NEED_struct_timespec +#define __NEED_sigset_t +#define __NEED_pthread_t +#define __NEED_pthread_attr_t +#define __NEED_pthread_mutexattr_t +#define __NEED_pthread_condattr_t +#define __NEED_pthread_rwlockattr_t +#define __NEED_pthread_barrierattr_t +#define __NEED_pthread_mutex_t +#define __NEED_pthread_cond_t +#define __NEED_pthread_rwlock_t +#define __NEED_pthread_barrier_t +#define __NEED_pthread_spinlock_t +#define __NEED_pthread_key_t +#define __NEED_pthread_once_t +#define __NEED_size_t + +#include + +#include +#include + +#define PTHREAD_CREATE_JOINABLE 0 +#define PTHREAD_CREATE_DETACHED 1 + +#define PTHREAD_MUTEX_NORMAL 0 +#define PTHREAD_MUTEX_DEFAULT 0 +#define PTHREAD_MUTEX_RECURSIVE 1 +#define PTHREAD_MUTEX_ERRORCHECK 2 + +#define PTHREAD_MUTEX_STALLED 0 +#define PTHREAD_MUTEX_ROBUST 1 + +#define PTHREAD_PRIO_NONE 0 +#define PTHREAD_PRIO_INHERIT 1 +#define PTHREAD_PRIO_PROTECT 2 + +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +#define PTHREAD_SCOPE_SYSTEM 0 +#define PTHREAD_SCOPE_PROCESS 1 + +#define PTHREAD_PROCESS_PRIVATE 0 +#define PTHREAD_PROCESS_SHARED 1 + + +#define PTHREAD_MUTEX_INITIALIZER {{{0}}} +#define PTHREAD_RWLOCK_INITIALIZER {{{0}}} +#define PTHREAD_COND_INITIALIZER {{{0}}} +#define PTHREAD_ONCE_INIT 0 + + +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_MASKED 2 + +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 + +#define PTHREAD_CANCELED ((void *)-1) + + +#define PTHREAD_BARRIER_SERIAL_THREAD (-1) + +struct sched_param; +#define PTHREAD_NULL ((pthread_t)0) + +int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict); +int pthread_detach(pthread_t); +_Noreturn void pthread_exit(void *); +int pthread_join(pthread_t, void **); + +pthread_t pthread_self(void); + +int pthread_equal(pthread_t, pthread_t); +#ifndef __cplusplus +#define pthread_equal(x,y) ((x)==(y)) +#endif + +int pthread_setcancelstate(int, int *); +int pthread_setcanceltype(int, int *); +void pthread_testcancel(void); +int pthread_cancel(pthread_t); + +int pthread_getschedparam(pthread_t, int *__restrict, struct sched_param *__restrict); +int pthread_setschedparam(pthread_t, int, const struct sched_param *); +int pthread_setschedprio(pthread_t, int); + +int pthread_once(pthread_once_t *, void (*)(void)); + +int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *__restrict); +int pthread_mutex_lock(pthread_mutex_t *); +int pthread_mutex_unlock(pthread_mutex_t *); +int pthread_mutex_trylock(pthread_mutex_t *); +int pthread_mutex_timedlock(pthread_mutex_t *__restrict, const struct timespec *__restrict); +int pthread_mutex_destroy(pthread_mutex_t *); +int pthread_mutex_consistent(pthread_mutex_t *); + +int pthread_mutex_getprioceiling(const pthread_mutex_t *__restrict, int *__restrict); +int pthread_mutex_setprioceiling(pthread_mutex_t *__restrict, int, int *__restrict); + +int pthread_cond_init(pthread_cond_t *__restrict, const pthread_condattr_t *__restrict); +int pthread_cond_destroy(pthread_cond_t *); +int pthread_cond_wait(pthread_cond_t *__restrict, pthread_mutex_t *__restrict); +int pthread_cond_timedwait(pthread_cond_t *__restrict, pthread_mutex_t *__restrict, const struct timespec *__restrict); +int pthread_cond_broadcast(pthread_cond_t *); +int pthread_cond_signal(pthread_cond_t *); + +int pthread_rwlock_init(pthread_rwlock_t *__restrict, const pthread_rwlockattr_t *__restrict); +int pthread_rwlock_destroy(pthread_rwlock_t *); +int pthread_rwlock_rdlock(pthread_rwlock_t *); +int pthread_rwlock_tryrdlock(pthread_rwlock_t *); +int pthread_rwlock_timedrdlock(pthread_rwlock_t *__restrict, const struct timespec *__restrict); +int pthread_rwlock_wrlock(pthread_rwlock_t *); +int pthread_rwlock_trywrlock(pthread_rwlock_t *); +int pthread_rwlock_timedwrlock(pthread_rwlock_t *__restrict, const struct timespec *__restrict); +int pthread_rwlock_unlock(pthread_rwlock_t *); + +int pthread_spin_init(pthread_spinlock_t *, int); +int pthread_spin_destroy(pthread_spinlock_t *); +int pthread_spin_lock(pthread_spinlock_t *); +int pthread_spin_trylock(pthread_spinlock_t *); +int pthread_spin_unlock(pthread_spinlock_t *); + +int pthread_barrier_init(pthread_barrier_t *__restrict, const pthread_barrierattr_t *__restrict, unsigned); +int pthread_barrier_destroy(pthread_barrier_t *); +int pthread_barrier_wait(pthread_barrier_t *); + +int pthread_key_create(pthread_key_t *, void (*)(void *)); +int pthread_key_delete(pthread_key_t); +void *pthread_getspecific(pthread_key_t); +int pthread_setspecific(pthread_key_t, const void *); + +int pthread_attr_init(pthread_attr_t *); +int pthread_attr_destroy(pthread_attr_t *); + +int pthread_attr_getguardsize(const pthread_attr_t *__restrict, size_t *__restrict); +int pthread_attr_setguardsize(pthread_attr_t *, size_t); +int pthread_attr_getstacksize(const pthread_attr_t *__restrict, size_t *__restrict); +int pthread_attr_setstacksize(pthread_attr_t *, size_t); +int pthread_attr_getdetachstate(const pthread_attr_t *, int *); +int pthread_attr_setdetachstate(pthread_attr_t *, int); +int pthread_attr_getstack(const pthread_attr_t *__restrict, void **__restrict, size_t *__restrict); +int pthread_attr_setstack(pthread_attr_t *, void *, size_t); +int pthread_attr_getscope(const pthread_attr_t *__restrict, int *__restrict); +int pthread_attr_setscope(pthread_attr_t *, int); +int pthread_attr_getschedpolicy(const pthread_attr_t *__restrict, int *__restrict); +int pthread_attr_setschedpolicy(pthread_attr_t *, int); +int pthread_attr_getschedparam(const pthread_attr_t *__restrict, struct sched_param *__restrict); +int pthread_attr_setschedparam(pthread_attr_t *__restrict, const struct sched_param *__restrict); +int pthread_attr_getinheritsched(const pthread_attr_t *__restrict, int *__restrict); +int pthread_attr_setinheritsched(pthread_attr_t *, int); + +int pthread_mutexattr_destroy(pthread_mutexattr_t *); +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_init(pthread_mutexattr_t *); +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int); +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int); +int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int); +int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int); +int pthread_mutexattr_settype(pthread_mutexattr_t *, int); + +int pthread_condattr_init(pthread_condattr_t *); +int pthread_condattr_destroy(pthread_condattr_t *); +int pthread_condattr_setclock(pthread_condattr_t *, clockid_t); +int pthread_condattr_setpshared(pthread_condattr_t *, int); +int pthread_condattr_getclock(const pthread_condattr_t *__restrict, clockid_t *__restrict); +int pthread_condattr_getpshared(const pthread_condattr_t *__restrict, int *__restrict); + +int pthread_rwlockattr_init(pthread_rwlockattr_t *); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *); +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int); +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *__restrict, int *__restrict); + +int pthread_barrierattr_destroy(pthread_barrierattr_t *); +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict, int *__restrict); +int pthread_barrierattr_init(pthread_barrierattr_t *); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); + +int pthread_atfork(void (*)(void), void (*)(void), void (*)(void)); + +int pthread_getconcurrency(void); +int pthread_setconcurrency(int); + +int pthread_getcpuclockid(pthread_t, clockid_t *); + +struct __ptcb { + void (*__f)(void *); + void *__x; + struct __ptcb *__next; +}; + +void _pthread_cleanup_push(struct __ptcb *, void (*)(void *), void *); +void _pthread_cleanup_pop(struct __ptcb *, int); + +#define pthread_cleanup_push(f, x) do { struct __ptcb __cb; _pthread_cleanup_push(&__cb, f, x); +#define pthread_cleanup_pop(r) _pthread_cleanup_pop(&__cb, (r)); } while(0) + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/mono/wasi/include/setjmp.h b/src/mono/wasi/include/setjmp.h new file mode 100644 index 0000000000000..5fd8fd2380818 --- /dev/null +++ b/src/mono/wasi/include/setjmp.h @@ -0,0 +1,2 @@ +// setjmp.h isn't provided by WASI SDK, but many Mono source files want to import it, so we need this here +// We don't call any of its symbols at runtime so it can be left empty diff --git a/src/mono/wasi/mono-wasi-driver/driver.c b/src/mono/wasi/mono-wasi-driver/driver.c new file mode 100644 index 0000000000000..cadbcbd4aebc4 --- /dev/null +++ b/src/mono/wasi/mono-wasi-driver/driver.c @@ -0,0 +1,624 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include +#include +#include +#include +#include +#include + +#define INVARIANT_GLOBALIZATION 1 + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "wasm/runtime/pinvoke.h" + +void mono_wasm_enable_debugging (int); + +int mono_wasm_register_root (char *start, size_t size, const char *name); +void mono_wasm_deregister_root (char *addr); + +void mono_ee_interp_init (const char *opts); +void mono_marshal_ilgen_init (void); +void mono_method_builder_ilgen_init (void); +void mono_sgen_mono_ilgen_init (void); +void mono_icall_table_init (void); +void mono_aot_register_module (void **aot_info); +char *monoeg_g_getenv(const char *variable); +int monoeg_g_setenv(const char *variable, const char *value, int overwrite); +int32_t monoeg_g_hasenv(const char *variable); +void mono_free (void*); +int32_t mini_parse_debug_option (const char *option); +char *mono_method_get_full_name (MonoMethod *method); + +int mono_wasm_enable_gc = 1; + +int +mono_string_instance_is_interned (MonoString *str_raw); + +void mono_trace_init (void); + +#define g_new(type, size) ((type *) malloc (sizeof (type) * (size))) +#define g_new0(type, size) ((type *) calloc (sizeof (type), (size))) + +static MonoDomain *root_domain; + +#define RUNTIMECONFIG_BIN_FILE "runtimeconfig.bin" + +static void +wasm_trace_logger (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) +{ + printf("[wasm_trace_logger] %s\n", message); + if (fatal) + exit (1); +} + +typedef uint32_t target_mword; +typedef target_mword SgenDescriptor; +typedef SgenDescriptor MonoGCDescriptor; + +typedef struct WasmAssembly_ WasmAssembly; + +struct WasmAssembly_ { + MonoBundledAssembly assembly; + WasmAssembly *next; +}; + +static WasmAssembly *assemblies; +static int assembly_count; + +int +mono_wasm_add_assembly (const char *name, const unsigned char *data, unsigned int size) +{ + int len = strlen (name); + if (!strcasecmp (".pdb", &name [len - 4])) { + char *new_name = strdup (name); + //FIXME handle debugging assemblies with .exe extension + strcpy (&new_name [len - 3], "dll"); + mono_register_symfile_for_assembly (new_name, data, size); + return 1; + } + WasmAssembly *entry = g_new0 (WasmAssembly, 1); + entry->assembly.name = strdup (name); + entry->assembly.data = data; + entry->assembly.size = size; + entry->next = assemblies; + assemblies = entry; + ++assembly_count; + return mono_has_pdb_checksum ((char*)data, size); +} + +typedef struct WasmSatelliteAssembly_ WasmSatelliteAssembly; + +struct WasmSatelliteAssembly_ { + MonoBundledSatelliteAssembly *assembly; + WasmSatelliteAssembly *next; +}; + +static WasmSatelliteAssembly *satellite_assemblies; +static int satellite_assembly_count; + +void +mono_wasm_add_satellite_assembly (const char *name, const char *culture, const unsigned char *data, unsigned int size) +{ + WasmSatelliteAssembly *entry = g_new0 (WasmSatelliteAssembly, 1); + entry->assembly = mono_create_new_bundled_satellite_assembly (name, culture, data, size); + entry->next = satellite_assemblies; + satellite_assemblies = entry; + ++satellite_assembly_count; +} + +void +mono_wasm_setenv (const char *name, const char *value) +{ + monoeg_g_setenv (strdup (name), strdup (value), 1); +} + +static void *sysglobal_native_handle; +int32_t SystemNative_LChflagsCanSetHiddenFlag(void); +char* SystemNative_GetEnv(char* name); +intptr_t SystemNative_Dup(intptr_t oldfd); +int32_t SystemNative_Write(intptr_t fd, const void* buffer, int32_t bufferSize); +int64_t SystemNative_GetSystemTimeAsTicks(); +int32_t SystemNative_LStat(const char* path, int output); +int32_t SystemNative_ConvertErrorPlatformToPal(int32_t platformErrno); +void* SystemNative_LowLevelMonitor_Create(); +void SystemNative_LowLevelMonitor_Acquire(void* monitor); +void SystemNative_LowLevelMonitor_Release(void* monitor); +int32_t SystemNative_LowLevelMonitor_TimedWait(void *monitor, int32_t timeoutMilliseconds); +void SystemNative_LowLevelMonitor_Wait(void* monitor); +int SystemNative_GetErrNo(); +void SystemNative_SetErrNo(int value); + +int32_t SystemNative_Write2(intptr_t fd, const void* buffer, int32_t bufferSize) { + // Not sure why, but am getting fd=-1 when trying to write to stdout (which fails), so here's a workaround + return SystemNative_Write((int)fd == -1 ? 1: fd, buffer, bufferSize); +} + +static PinvokeImport SystemNativeImports [] = { + {"SystemNative_GetEnv", SystemNative_GetEnv }, + {"SystemNative_LChflagsCanSetHiddenFlag", SystemNative_LChflagsCanSetHiddenFlag }, + {"SystemNative_Dup", SystemNative_Dup}, + {"SystemNative_Write", SystemNative_Write2}, + {"SystemNative_GetSystemTimeAsTicks", SystemNative_GetSystemTimeAsTicks}, + {"SystemNative_LStat", SystemNative_LStat}, + {"SystemNative_ConvertErrorPlatformToPal", SystemNative_ConvertErrorPlatformToPal}, + {"SystemNative_LowLevelMonitor_Create", SystemNative_LowLevelMonitor_Create}, + {"SystemNative_LowLevelMonitor_Acquire", SystemNative_LowLevelMonitor_Acquire}, + {"SystemNative_LowLevelMonitor_Release", SystemNative_LowLevelMonitor_Release}, + {"SystemNative_LowLevelMonitor_TimedWait", SystemNative_LowLevelMonitor_TimedWait}, + {"SystemNative_LowLevelMonitor_Wait", SystemNative_LowLevelMonitor_Wait}, + {"SystemNative_GetErrNo", SystemNative_GetErrNo}, + {"SystemNative_SetErrNo", SystemNative_SetErrNo}, + {NULL, NULL} +}; + +void GlobalizationNative_LoadICU() { + assert(0); +} + +static PinvokeImport SystemGlobalizationNativeImports [] = { + {"GlobalizationNative_LoadICU", GlobalizationNative_LoadICU }, + {NULL, NULL} +}; + +static void* +wasm_dl_load (const char *name, int flags, char **err, void *user_data) +{ + if (!strcmp (name, "libSystem.Native")) + return SystemNativeImports; + if (!strcmp (name, "libSystem.Globalization.Native")) + return SystemGlobalizationNativeImports; + //printf("In wasm_dl_load for name %s but treating as NOT FOUND\n", name); + return 0; +} + +static void* +wasm_dl_symbol (void *handle, const char *name, char **err, void *user_data) +{ + if (handle == sysglobal_native_handle) + assert (0); + + PinvokeImport *table = (PinvokeImport*)handle; + for (int i = 0; table [i].name; ++i) { + if (!strcmp (table [i].name, name)) + return table [i].func; + } + return NULL; +} + +#define NEED_INTERP 1 + +/* + * get_native_to_interp: + * + * Return a pointer to a wasm function which can be used to enter the interpreter to + * execute METHOD from native code. + * EXTRA_ARG is the argument passed to the interp entry functions in the runtime. + */ +void* +get_native_to_interp (MonoMethod *method, void *extra_arg) +{ + MonoClass *klass = mono_method_get_class (method); + MonoImage *image = mono_class_get_image (klass); + MonoAssembly *assembly = mono_image_get_assembly (image); + MonoAssemblyName *aname = mono_assembly_get_name (assembly); + const char *name = mono_assembly_name_get_name (aname); + const char *class_name = mono_class_get_name (klass); + const char *method_name = mono_method_get_name (method); + char key [128]; + int len; + + assert (strlen (name) < 100); + snprintf (key, sizeof(key), "%s_%s_%s", name, class_name, method_name); + len = strlen (key); + for (int i = 0; i < len; ++i) { + if (key [i] == '.') + key [i] = '_'; + } + + assert(0); return 0; + //void *addr = wasm_dl_get_native_to_interp (key, extra_arg); + //return addr; +} + +void +mono_wasm_register_bundled_satellite_assemblies () +{ + /* In legacy satellite_assembly_count is always false */ + if (satellite_assembly_count) { + MonoBundledSatelliteAssembly **satellite_bundle_array = g_new0 (MonoBundledSatelliteAssembly *, satellite_assembly_count + 1); + WasmSatelliteAssembly *cur = satellite_assemblies; + int i = 0; + while (cur) { + satellite_bundle_array [i] = cur->assembly; + cur = cur->next; + ++i; + } + mono_register_bundled_satellite_assemblies ((const MonoBundledSatelliteAssembly **)satellite_bundle_array); + } +} + +void +cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data) +{ + free (args); + free (user_data); +} + +void +mono_wasm_load_runtime (const char *unused, int debug_level) +{ + const char *interp_opts = ""; + +#ifndef INVARIANT_GLOBALIZATION + mono_wasm_link_icu_shim (); +#else + monoeg_g_setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "true", 1); +#endif + +#ifdef DEBUG + monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 0); + monoeg_g_setenv ("MONO_LOG_MASK", "gc", 0); + // Setting this env var allows Diagnostic.Debug to write to stderr. In a browser environment this + // output will be sent to the console. Right now this is the only way to emit debug logging from + // corlib assemblies. + monoeg_g_setenv ("COMPlus_DebugWriteToStdErr", "1", 0); +#endif + // When the list of app context properties changes, please update RuntimeConfigReservedProperties for + // target _WasmGenerateRuntimeConfig in WasmApp.targets file + const char *appctx_keys[2]; + appctx_keys [0] = "APP_CONTEXT_BASE_DIRECTORY"; + appctx_keys [1] = "RUNTIME_IDENTIFIER"; + + const char *appctx_values[2]; + appctx_values [0] = "/"; + appctx_values [1] = "browser-wasm"; + + char *file_name = RUNTIMECONFIG_BIN_FILE; + int str_len = strlen (file_name) + 1; // +1 is for the "/" + char *file_path = (char *)malloc (sizeof (char) * (str_len +1)); // +1 is for the terminating null character + int num_char = snprintf (file_path, (str_len + 1), "/%s", file_name); + struct stat buffer; + + assert (num_char > 0 && num_char == str_len); + + if (stat (file_path, &buffer) == 0) { + MonovmRuntimeConfigArguments *arg = (MonovmRuntimeConfigArguments *)malloc (sizeof (MonovmRuntimeConfigArguments)); + arg->kind = 0; + arg->runtimeconfig.name.path = file_path; + monovm_runtimeconfig_initialize (arg, cleanup_runtime_config, file_path); + } else { + free (file_path); + } + + monovm_initialize (2, appctx_keys, appctx_values); + + mini_parse_debug_option ("top-runtime-invoke-unhandled"); + + mono_dl_fallback_register (wasm_dl_load, wasm_dl_symbol, NULL, NULL); + mono_wasm_install_get_native_to_interp_tramp (get_native_to_interp); + + mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_ONLY); + + /* + * debug_level > 0 enables debugging and sets the debug log level to debug_level + * debug_level == 0 disables debugging and enables interpreter optimizations + * debug_level < 0 enabled debugging and disables debug logging. + * + * Note: when debugging is enabled interpreter optimizations are disabled. + */ + if (debug_level) { + // Disable optimizations which interfere with debugging + interp_opts = "-all"; + mono_wasm_enable_debugging (debug_level); + } + + mono_ee_interp_init (interp_opts); + mono_marshal_ilgen_init (); + mono_method_builder_ilgen_init (); + mono_sgen_mono_ilgen_init (); + + if (assembly_count) { + MonoBundledAssembly **bundle_array = g_new0 (MonoBundledAssembly*, assembly_count + 1); + WasmAssembly *cur = assemblies; + int i = 0; + while (cur) { + bundle_array [i] = &cur->assembly; + cur = cur->next; + ++i; + } + mono_register_bundled_assemblies ((const MonoBundledAssembly **)bundle_array); + } + + mono_wasm_register_bundled_satellite_assemblies (); + mono_trace_init (); + mono_trace_set_log_handler (wasm_trace_logger, NULL); + + root_domain = mono_jit_init_version ("mono", "v4.0.30319"); + mono_thread_set_main (mono_thread_current ()); +} + +MonoAssembly* +mono_wasm_assembly_load (const char *name) +{ + MonoImageOpenStatus status; + MonoAssemblyName* aname = mono_assembly_name_new (name); + if (!name) + return NULL; + + MonoAssembly *res = mono_assembly_load (aname, NULL, &status); + mono_assembly_name_free (aname); + + return res; +} + +MonoClass* +mono_wasm_find_corlib_class (const char *namespace, const char *name) +{ + return mono_class_from_name (mono_get_corlib (), namespace, name); +} + +MonoClass* +mono_wasm_assembly_find_class (MonoAssembly *assembly, const char *namespace, const char *name) +{ + return mono_class_from_name (mono_assembly_get_image (assembly), namespace, name); +} + +MonoMethod* +mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int arguments) +{ + return mono_class_get_method_from_name (klass, name, arguments); +} + +MonoMethod* +mono_wasm_get_delegate_invoke (MonoObject *delegate) +{ + return mono_get_delegate_invoke(mono_object_get_class (delegate)); +} + +MonoObject* +mono_wasm_box_primitive (MonoClass *klass, void *value, int value_size) +{ + if (!klass) + return NULL; + + MonoType *type = mono_class_get_type (klass); + int alignment; + if (mono_type_size (type, &alignment) > value_size) + return NULL; + + // TODO: use mono_value_box_checked and propagate error out + return mono_value_box (root_domain, klass, value); +} + +MonoObject* +mono_wasm_invoke_method (MonoMethod *method, MonoObject *this_arg, void *params[], MonoObject **out_exc) +{ + MonoObject *exc = NULL; + MonoObject *res; + + if (out_exc) + *out_exc = NULL; + res = mono_runtime_invoke (method, this_arg, params, &exc); + if (exc) { + if (out_exc) + *out_exc = exc; + + MonoObject *exc2 = NULL; + res = (MonoObject*)mono_object_to_string (exc, &exc2); + if (exc2) + res = (MonoObject*) mono_string_new (root_domain, "Exception Double Fault"); + return res; + } + + MonoMethodSignature *sig = mono_method_signature (method); + MonoType *type = mono_signature_get_return_type (sig); + // If the method return type is void return null + // This gets around a memory access crash when the result return a value when + // a void method is invoked. + if (mono_type_get_type (type) == MONO_TYPE_VOID) + return NULL; + + return res; +} + +MonoMethod* +mono_wasm_assembly_get_entry_point (MonoAssembly *assembly) +{ + MonoImage *image; + MonoMethod *method; + + image = mono_assembly_get_image (assembly); + uint32_t entry = mono_image_get_entry_point (image); + if (!entry) + return NULL; + + mono_domain_ensure_entry_assembly (root_domain, assembly); + method = mono_get_method (image, entry, NULL); + + /* + * If the entry point looks like a compiler generated wrapper around + * an async method in the form "" then try to look up the async methods + * "$" and "Name" it could be wrapping. We do this because the generated + * sync wrapper will call task.GetAwaiter().GetResult() when we actually want + * to yield to the host runtime. + */ + if (mono_method_get_flags (method, NULL) & 0x0800 /* METHOD_ATTRIBUTE_SPECIAL_NAME */) { + const char *name = mono_method_get_name (method); + int name_length = strlen (name); + + if ((*name != '<') || (name [name_length - 1] != '>')) + return method; + + MonoClass *klass = mono_method_get_class (method); + char *async_name = malloc (name_length + 2); + snprintf (async_name, name_length + 2, "%s$", name); + + // look for "$" + MonoMethodSignature *sig = mono_method_get_signature (method, image, mono_method_get_token (method)); + MonoMethod *async_method = mono_class_get_method_from_name (klass, async_name, mono_signature_get_param_count (sig)); + if (async_method != NULL) { + free (async_name); + return async_method; + } + + // look for "Name" by trimming the first and last character of "" + async_name [name_length - 1] = '\0'; + async_method = mono_class_get_method_from_name (klass, async_name + 1, mono_signature_get_param_count (sig)); + + free (async_name); + if (async_method != NULL) + return async_method; + } + return method; +} + +char * +mono_wasm_string_get_utf8 (MonoString *str) +{ + return mono_string_to_utf8 (str); //XXX JS is responsible for freeing this +} + +mono_wasm_string_from_js (const char *str) +{ + if (str) + return mono_string_new (root_domain, str); + else + return NULL; +} + +int +mono_unbox_int (MonoObject *obj) +{ + if (!obj) + return 0; + MonoType *type = mono_class_get_type (mono_object_get_class(obj)); + + void *ptr = mono_object_unbox (obj); + switch (mono_type_get_type (type)) { + case MONO_TYPE_I1: + case MONO_TYPE_BOOLEAN: + return *(signed char*)ptr; + case MONO_TYPE_U1: + return *(unsigned char*)ptr; + case MONO_TYPE_I2: + return *(short*)ptr; + case MONO_TYPE_U2: + return *(unsigned short*)ptr; + case MONO_TYPE_I4: + case MONO_TYPE_I: + return *(int*)ptr; + case MONO_TYPE_U4: + return *(unsigned int*)ptr; + case MONO_TYPE_CHAR: + return *(short*)ptr; + // WASM doesn't support returning longs to JS + // case MONO_TYPE_I8: + // case MONO_TYPE_U8: + default: + printf ("Invalid type %d to mono_unbox_int\n", mono_type_get_type (type)); + return 0; + } +} + +int +mono_wasm_array_length (MonoArray *array) +{ + return mono_array_length (array); +} + +MonoObject* +mono_wasm_array_get (MonoArray *array, int idx) +{ + return mono_array_get (array, MonoObject*, idx); +} + +MonoArray* +mono_wasm_obj_array_new (int size) +{ + return mono_array_new (root_domain, mono_get_object_class (), size); +} + +void +mono_wasm_obj_array_set (MonoArray *array, int idx, MonoObject *obj) +{ + mono_array_setref (array, idx, obj); +} + +MonoArray* +mono_wasm_string_array_new (int size) +{ + return mono_array_new (root_domain, mono_get_string_class (), size); +} + +void +mono_wasm_string_get_data ( + MonoString *string, mono_unichar2 **outChars, int *outLengthBytes, int *outIsInterned +) { + if (!string) { + if (outChars) + *outChars = 0; + if (outLengthBytes) + *outLengthBytes = 0; + if (outIsInterned) + *outIsInterned = 1; + return; + } + + if (outChars) + *outChars = mono_string_chars (string); + if (outLengthBytes) + *outLengthBytes = mono_string_length (string) * 2; + if (outIsInterned) + *outIsInterned = mono_string_instance_is_interned (string); + return; +} + +void add_assembly(const char* base_dir, const char *name) { + FILE *fileptr; + unsigned char *buffer; + long filelen; + char filename[256]; + sprintf(filename, "%s/%s", base_dir, name); + // printf("Loading %s...\n", filename); + + fileptr = fopen(filename, "rb"); + if (fileptr == 0) { + printf("Failed to load %s\n", filename); + fflush(stdout); + } + + fseek(fileptr, 0, SEEK_END); + filelen = ftell(fileptr); + rewind(fileptr); + + buffer = (unsigned char *)malloc(filelen * sizeof(char)); + fread(buffer, filelen, 1, fileptr); + fclose(fileptr); + + assert(mono_wasm_add_assembly(name, buffer, filelen)); +} + +MonoMethod* lookup_dotnet_method(const char* assembly_name, const char* namespace, const char* type_name, const char* method_name, int num_params) { + MonoAssembly* assembly = mono_wasm_assembly_load (assembly_name); + assert (assembly); + MonoClass* class = mono_wasm_assembly_find_class (assembly, namespace, type_name); + assert (class); + MonoMethod* method = mono_wasm_assembly_find_method (class, method_name, num_params); + assert (method); + return method; +} diff --git a/src/mono/wasi/mono-wasi-driver/driver.h b/src/mono/wasi/mono-wasi-driver/driver.h new file mode 100644 index 0000000000000..af5043e0a27a6 --- /dev/null +++ b/src/mono/wasi/mono-wasi-driver/driver.h @@ -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. + +#include +#include + +void mono_wasm_load_runtime (const char *unused, int debug_level); +int mono_wasm_add_assembly (const char *name, const unsigned char *data, unsigned int size); +MonoAssembly* mono_wasm_assembly_load(const char *name); +MonoMethod* mono_wasm_assembly_get_entry_point (MonoAssembly *assembly); +MonoClass* mono_wasm_assembly_find_class (MonoAssembly *assembly, const char *namespace, const char *name); +MonoMethod* mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int arguments); +MonoObject* mono_wasm_invoke_method (MonoMethod *method, MonoObject *this_arg, void *params[], MonoObject **out_exc); +int mono_unbox_int (MonoObject *obj); +void mono_wasm_setenv (const char *name, const char *value); +void add_assembly(const char* base_dir, const char *name); + +MonoArray* mono_wasm_obj_array_new (int size); +void mono_wasm_obj_array_set (MonoArray *array, int idx, MonoObject *obj); +MonoArray* mono_wasm_string_array_new (int size); +MonoString *mono_wasm_string_from_js (const char *str); +int mono_wasm_array_length(MonoArray* array); +char *mono_wasm_string_get_utf8 (MonoString *str); + +MonoMethod* lookup_dotnet_method(const char* assembly_name, const char* namespace, const char* type_name, const char* method_name, int num_params); diff --git a/src/mono/wasi/mono-wasi-driver/stubs.c b/src/mono/wasi/mono-wasi-driver/stubs.c new file mode 100644 index 0000000000000..90ae87c5b62ae --- /dev/null +++ b/src/mono/wasi/mono-wasi-driver/stubs.c @@ -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. + +#include + +// These are symbols that are never used at runtime, or at least don't need to do anything for prototype apps + +int sem_init(int a, int b, int c) { return 0; } +int sem_destroy(int x) { return 0; } +int sem_post(int x) { return 0; } +int sem_wait(int x) { return 0; } +int sem_trywait(int x) { return 0; } +int sem_timedwait (int *sem, const struct timespec *abs_timeout) { assert(0); return 0; } + +int __errno_location() { return 0; } + +void mono_log_close_syslog () { assert(0); } +void mono_log_open_syslog (const char *a, void *b) { assert(0); } +void mono_log_write_syslog (const char *a, int b, int c, const char *d) { assert(0); } + +void mono_runtime_setup_stat_profiler () { assert(0); } +int mono_thread_state_init_from_handle (int *tctx, int *info, void *sigctx) { assert(0); return 0; } diff --git a/src/mono/wasi/mono-wasi-driver/synthetic-pthread.c b/src/mono/wasi/mono-wasi-driver/synthetic-pthread.c new file mode 100644 index 0000000000000..aa15f21f71107 --- /dev/null +++ b/src/mono/wasi/mono-wasi-driver/synthetic-pthread.c @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include + +#define SYNTHETIC_PTHREAD_KEYS_MAX 32 + +typedef struct { + int is_created; + const void* current_value; + void* destructor_func; +} synthetic_pthread_key; + +// Since we're not really supporting multiple threads, there's just a single global list of pthread keys +// (If we did have real threads, there would be a separate set for each thread) +synthetic_pthread_key synthetic_key_list[SYNTHETIC_PTHREAD_KEYS_MAX]; + +int pthread_key_create(int *key_index, void* destructor) { + int i; + for (i = 0; i < SYNTHETIC_PTHREAD_KEYS_MAX; i++) { + if (!synthetic_key_list[i].is_created) { + break; + } + } + + if (i == SYNTHETIC_PTHREAD_KEYS_MAX) { + return -1; + } + + synthetic_key_list[i].is_created = 1; + synthetic_key_list[i].destructor_func = destructor; // Not really used since we never destroy keys + *key_index = i; + return 0; +} + +int pthread_setspecific(int key_index, const void* value) { + if (!synthetic_key_list[key_index].is_created) + return -1; + + synthetic_key_list[key_index].current_value = value; + return 0; +} + +const void* pthread_getspecific(int key_index) { + assert (synthetic_key_list[key_index].is_created); + return synthetic_key_list[key_index].current_value; +} + +// Since we're not really supporting threads, mutex operations are no-ops +// It would be more robust if we actually just aborted if you tried to lock an already-locked mutex +int pthread_mutex_lock(void *mutex) { /*printf("pthread_mutex_lock with mutex=%i\n", mutex);*/ return 0; } +int pthread_mutex_unlock(int *mutex) { /*printf("pthread_mutex_unlock with mutex=%i\n", mutex);*/ return 0; } + +// Unused pthread APIs +int pthread_self() { assert(0); return 0; } +int pthread_cond_signal(int a) { assert(0); return 0; } +int pthread_cond_init(int a, int b) { return 0; } +int pthread_cond_wait(int a, int b) { return 0; } +int pthread_cond_destroy(int a) { return 0; } +int pthread_mutex_init(int a, int b) { return 0; } +int pthread_mutex_destroy(int a) { return 0; } +int pthread_cond_timedwait(int a, int b, int c) { return 0; } diff --git a/src/mono/wasi/sample/.gitignore b/src/mono/wasi/sample/.gitignore new file mode 100644 index 0000000000000..19e1bced9ad8a --- /dev/null +++ b/src/mono/wasi/sample/.gitignore @@ -0,0 +1 @@ +*.wasm diff --git a/src/mono/wasi/sample/Directory.Build.props b/src/mono/wasi/sample/Directory.Build.props new file mode 100644 index 0000000000000..69b70ee868b5a --- /dev/null +++ b/src/mono/wasi/sample/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + + bin/$(Configuration)/net7.0 + + diff --git a/src/mono/wasi/sample/SampleMakefile.variable b/src/mono/wasi/sample/SampleMakefile.variable new file mode 100644 index 0000000000000..ba14317ec54cb --- /dev/null +++ b/src/mono/wasi/sample/SampleMakefile.variable @@ -0,0 +1,18 @@ +TOP=$(realpath $(CURDIR)/../../../../..) + +COMPILE_FLAGS=\ + $(WASI_BIN_DIR)/*.a \ + $(BROWSER_WASM_RUNTIME_PATH)/native/libSystem.Native.a \ + --sysroot=$(WASI_SDK_ROOT)/share/wasi-sysroot \ + -I$(TOP)/src/mono + +LINK_FLAGS=\ + -Wl,--export=malloc,--export=free,--export=__heap_base,--export=__data_end \ + -Wl,-z,stack-size=1048576,--initial-memory=5242880,--max-memory=52428800,-lwasi-emulated-mman + +ifndef DOTNET_ROOT +$(error DOTNET_ROOT is undefined. Example: export DOTNET_ROOT=~/dotnet7) +endif +ifndef BROWSER_WASM_RUNTIME_PATH +$(error BROWSER_WASM_RUNTIME_PATH is undefined. Example: export BROWSER_WASM_RUNTIME_PATH=$(DOTNET_ROOT)/packs/Microsoft.NETCore.App.Runtime.Mono.browser-wasm/7.0.0-alpha.1.22061.11/runtimes/browser-wasm) +endif diff --git a/src/mono/wasi/sample/console/Makefile b/src/mono/wasi/sample/console/Makefile new file mode 100644 index 0000000000000..bc9fd14dcb751 --- /dev/null +++ b/src/mono/wasi/sample/console/Makefile @@ -0,0 +1,20 @@ +include ../../Makefile.variable +include ../SampleMakefile.variable + +BIN_DIR=WasiConsoleApp/bin/$(CONFIG)/net7.0 + +all: console.wasm $(BIN_DIR)/WasiConsoleApp.dll + +run: all + wasmtime --dir=. console.wasm + +run-wasmer: all + wasmer --dir=. console.wasm + +console.wasm: main.c + $(WASI_SDK_CLANG) main.c -o console.wasm $(COMPILE_FLAGS) $(LINK_FLAGS) + +$(BIN_DIR)/WasiConsoleApp.dll: WasiConsoleApp/*.csproj WasiConsoleApp/*.cs + cd WasiConsoleApp && $(DOTNET_ROOT)/dotnet build -c $(CONFIG) + touch $(BIN_DIR)/*.dll + cp -R $(BROWSER_WASM_RUNTIME_PATH) $(BIN_DIR)/runtime diff --git a/src/mono/wasi/sample/console/WasiConsoleApp/Program.cs b/src/mono/wasi/sample/console/WasiConsoleApp/Program.cs new file mode 100644 index 0000000000000..83a7facbcf64d --- /dev/null +++ b/src/mono/wasi/sample/console/WasiConsoleApp/Program.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. + +using System; + +namespace WasiConsoleApp +{ + public class Program + { + public static int Main() + { + Console.WriteLine($"Hello from .NET at {DateTime.Now.ToLongTimeString()}"); + return 0; + } + } +} diff --git a/src/mono/wasi/sample/console/WasiConsoleApp/WasiConsoleApp.csproj b/src/mono/wasi/sample/console/WasiConsoleApp/WasiConsoleApp.csproj new file mode 100644 index 0000000000000..49755d024c8a1 --- /dev/null +++ b/src/mono/wasi/sample/console/WasiConsoleApp/WasiConsoleApp.csproj @@ -0,0 +1,9 @@ + + + + Exe + net7.0 + true + + + diff --git a/src/mono/wasi/sample/console/main.c b/src/mono/wasi/sample/console/main.c new file mode 100644 index 0000000000000..4ee373135cd72 --- /dev/null +++ b/src/mono/wasi/sample/console/main.c @@ -0,0 +1,21 @@ +#include +#include "../../mono-wasi-driver/driver.h" + +int main() { + // Assume the runtime pack has been copied into the output directory as 'runtime' + // Otherwise we have to mount an unrelated part of the filesystem within the WASM environment + const char* app_base_dir = "./WasiConsoleApp/bin/Release/net7.0"; + char* assemblies_path; + asprintf(&assemblies_path, "%s:%s/runtime/native:%s/runtime/lib/net7.0", app_base_dir, app_base_dir, app_base_dir); + + add_assembly(app_base_dir, "WasiConsoleApp.dll"); + mono_set_assemblies_path(assemblies_path); + + mono_wasm_load_runtime("", 0); + + MonoAssembly* assembly = mono_wasm_assembly_load ("WasiConsoleApp.dll"); + MonoMethod* entry_method = mono_wasm_assembly_get_entry_point (assembly); + MonoObject* out_exc; + MonoObject *exit_code = mono_wasm_invoke_method (entry_method, NULL, NULL, &out_exc); + return mono_unbox_int (exit_code); +} From 5e6120b5bf0502bd10e3b050c9c9250abf4dba56 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 21 Jan 2022 07:44:36 -0500 Subject: [PATCH 116/308] Add StringSyntaxAttribute.Json (#64081) --- .../CodeAnalysis/StringSyntaxAttribute.cs | 3 +++ .../System.Runtime/ref/System.Runtime.cs | 1 + .../StringSyntaxAttributeTests.cs | 1 + .../System.Text.Json/ref/System.Text.Json.cs | 26 +++++++++---------- .../ref/System.Text.Json.csproj | 4 +++ .../src/System.Text.Json.csproj | 3 +++ .../Text/Json/Document/JsonDocument.Parse.cs | 4 +-- .../System/Text/Json/Nodes/JsonNode.Parse.cs | 3 ++- .../JsonSerializer.Read.String.cs | 16 ++++++------ .../Writer/Utf8JsonWriter.WriteValues.Raw.cs | 5 ++-- 10 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs index 5b9dbda76e5f1..5341f9d295d1a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs @@ -40,6 +40,9 @@ public StringSyntaxAttribute(string syntax, params object?[] arguments) /// The syntax identifier for strings containing date and time format specifiers. public const string DateTimeFormat = nameof(DateTimeFormat); + /// The syntax identifier for strings containing JavaScript Object Notation (JSON). + public const string Json = nameof(Json); + /// The syntax identifier for strings containing regular expressions. public const string Regex = nameof(Regex); } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 256f032352baa..c57c5b13cc119 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -9187,6 +9187,7 @@ public StringSyntaxAttribute(string syntax, params object?[] arguments) { } public string Syntax { get { throw null; } } public object?[] Arguments { get { throw null; } } public const string DateTimeFormat = "DateTimeFormat"; + public const string Json = "Json"; public const string Regex = "Regex"; } [System.AttributeUsageAttribute(System.AttributeTargets.All, Inherited=false, AllowMultiple=true)] diff --git a/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs index 2dde50c727a3f..ba53ab2c0f3bb 100644 --- a/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs +++ b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/StringSyntaxAttributeTests.cs @@ -9,6 +9,7 @@ public sealed class StringSyntaxAttributeTests { [Theory] [InlineData(StringSyntaxAttribute.DateTimeFormat)] + [InlineData(StringSyntaxAttribute.Json)] [InlineData(StringSyntaxAttribute.Regex)] public void Ctor_Roundtrips(string syntax) { 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 f6b25cdcb23d4..2bae8025f0ca0 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -20,8 +20,8 @@ public void Dispose() { } public static System.Text.Json.JsonDocument Parse(System.Buffers.ReadOnlySequence utf8Json, System.Text.Json.JsonDocumentOptions options = default(System.Text.Json.JsonDocumentOptions)) { throw null; } public static System.Text.Json.JsonDocument Parse(System.IO.Stream utf8Json, System.Text.Json.JsonDocumentOptions options = default(System.Text.Json.JsonDocumentOptions)) { throw null; } public static System.Text.Json.JsonDocument Parse(System.ReadOnlyMemory utf8Json, System.Text.Json.JsonDocumentOptions options = default(System.Text.Json.JsonDocumentOptions)) { throw null; } - public static System.Text.Json.JsonDocument Parse(System.ReadOnlyMemory json, System.Text.Json.JsonDocumentOptions options = default(System.Text.Json.JsonDocumentOptions)) { throw null; } - public static System.Text.Json.JsonDocument Parse(string json, System.Text.Json.JsonDocumentOptions options = default(System.Text.Json.JsonDocumentOptions)) { throw null; } + public static System.Text.Json.JsonDocument Parse([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] System.ReadOnlyMemory json, System.Text.Json.JsonDocumentOptions options = default(System.Text.Json.JsonDocumentOptions)) { throw null; } + public static System.Text.Json.JsonDocument Parse([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] string json, System.Text.Json.JsonDocumentOptions options = default(System.Text.Json.JsonDocumentOptions)) { throw null; } public static System.Threading.Tasks.Task ParseAsync(System.IO.Stream utf8Json, System.Text.Json.JsonDocumentOptions options = default(System.Text.Json.JsonDocumentOptions), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Text.Json.JsonDocument ParseValue(ref System.Text.Json.Utf8JsonReader reader) { throw null; } public static bool TryParseValue(ref System.Text.Json.Utf8JsonReader reader, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Text.Json.JsonDocument? document) { throw null; } @@ -193,11 +193,11 @@ public static partial class JsonSerializer public static object? Deserialize(System.ReadOnlySpan utf8Json, System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } public static object? Deserialize(System.ReadOnlySpan utf8Json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] - public static object? Deserialize(System.ReadOnlySpan json, System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } - public static object? Deserialize(System.ReadOnlySpan json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } + public static object? Deserialize([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] System.ReadOnlySpan json, System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static object? Deserialize([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] System.ReadOnlySpan json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] - public static object? Deserialize(string json, System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } - public static object? Deserialize(string json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } + public static object? Deserialize([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] string json, System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static object? Deserialize([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] string json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] public static object? Deserialize(this System.Text.Json.JsonDocument document, System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } public static object? Deserialize(this System.Text.Json.JsonDocument document, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } @@ -225,11 +225,11 @@ public static partial class JsonSerializer public static TValue? Deserialize(System.ReadOnlySpan utf8Json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } public static TValue? Deserialize(System.ReadOnlySpan utf8Json, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] - public static TValue? Deserialize(System.ReadOnlySpan json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } - public static TValue? Deserialize(System.ReadOnlySpan json, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } + public static TValue? Deserialize([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] System.ReadOnlySpan json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static TValue? Deserialize([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] System.ReadOnlySpan json, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] - public static TValue? Deserialize(string json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } - public static TValue? Deserialize(string json, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } + public static TValue? Deserialize([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] string json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static TValue? Deserialize([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] string json, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] public static TValue? Deserialize(this System.Text.Json.JsonDocument document, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } public static TValue? Deserialize(this System.Text.Json.JsonDocument document, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } @@ -511,9 +511,9 @@ public void WritePropertyName(System.ReadOnlySpan utf8PropertyName) { } public void WritePropertyName(System.ReadOnlySpan propertyName) { } public void WritePropertyName(string propertyName) { } public void WritePropertyName(System.Text.Json.JsonEncodedText propertyName) { } - public void WriteRawValue(string json, bool skipInputValidation = false) { } + public void WriteRawValue([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] string json, bool skipInputValidation = false) { } public void WriteRawValue(System.ReadOnlySpan utf8Json, bool skipInputValidation = false) { } - public void WriteRawValue(System.ReadOnlySpan json, bool skipInputValidation = false) { } + public void WriteRawValue([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] System.ReadOnlySpan json, bool skipInputValidation = false) { } public void WriteStartArray() { } public void WriteStartArray(System.ReadOnlySpan utf8PropertyName) { } public void WriteStartArray(System.ReadOnlySpan propertyName) { } @@ -682,7 +682,7 @@ internal JsonNode() { } public static implicit operator System.Text.Json.Nodes.JsonNode (ulong value) { throw null; } public static System.Text.Json.Nodes.JsonNode? Parse(System.IO.Stream utf8Json, System.Text.Json.Nodes.JsonNodeOptions? nodeOptions = default(System.Text.Json.Nodes.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; } public static System.Text.Json.Nodes.JsonNode? Parse(System.ReadOnlySpan utf8Json, System.Text.Json.Nodes.JsonNodeOptions? nodeOptions = default(System.Text.Json.Nodes.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; } - public static System.Text.Json.Nodes.JsonNode? Parse(string json, System.Text.Json.Nodes.JsonNodeOptions? nodeOptions = default(System.Text.Json.Nodes.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; } + public static System.Text.Json.Nodes.JsonNode? Parse([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Json)] string json, System.Text.Json.Nodes.JsonNodeOptions? nodeOptions = default(System.Text.Json.Nodes.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; } public static System.Text.Json.Nodes.JsonNode? Parse(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.Nodes.JsonNodeOptions? nodeOptions = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } public string ToJsonString(System.Text.Json.JsonSerializerOptions? options = null) { throw null; } public override string ToString() { throw null; } diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.csproj b/src/libraries/System.Text.Json/ref/System.Text.Json.csproj index 13c5c50fbc0e5..a468f99d4e1bc 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.csproj @@ -20,6 +20,10 @@ + + + + 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 3c9c90848ff36..d24617f74a3d3 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -322,6 +322,9 @@ System.Text.Json.Nodes.JsonValue + + + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs index 0e7446601716c..6ceaa0af7dd95 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs @@ -247,7 +247,7 @@ private static async Task ParseAsyncCore( /// /// contains unsupported options. /// - public static JsonDocument Parse(ReadOnlyMemory json, JsonDocumentOptions options = default) + public static JsonDocument Parse([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlyMemory json, JsonDocumentOptions options = default) { ReadOnlySpan jsonChars = json.Span; int expectedByteCount = JsonReaderHelper.GetUtf8ByteCount(jsonChars); @@ -311,7 +311,7 @@ internal static JsonDocument ParseValue(ReadOnlyMemory json, JsonDocumentO /// /// contains unsupported options. /// - public static JsonDocument Parse(string json, JsonDocumentOptions options = default) + public static JsonDocument Parse([StringSyntax(StringSyntaxAttribute.Json)] string json, JsonDocumentOptions options = default) { if (json == null) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Parse.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Parse.cs index e59eedb567b06..0d6f3a75263eb 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Parse.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Parse.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text.Json.Serialization.Converters; @@ -65,7 +66,7 @@ public abstract partial class JsonNode /// does not represent a valid single JSON value. /// public static JsonNode? Parse( - string json, + [StringSyntax(StringSyntaxAttribute.Json)] string json, JsonNodeOptions? nodeOptions = null, JsonDocumentOptions documentOptions = default(JsonDocumentOptions)) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs index 8606c9b1efc49..9056413479aca 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs @@ -42,7 +42,7 @@ public static partial class JsonSerializer /// UTF-8 methods since the implementation natively uses UTF-8. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static TValue? Deserialize(string json, JsonSerializerOptions? options = null) + public static TValue? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] string json, JsonSerializerOptions? options = null) { if (json == null) { @@ -78,7 +78,7 @@ public static partial class JsonSerializer /// UTF-8 methods since the implementation natively uses UTF-8. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static TValue? Deserialize(ReadOnlySpan json, JsonSerializerOptions? options = null) + public static TValue? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan json, JsonSerializerOptions? options = null) { // default/null span is treated as empty @@ -114,7 +114,7 @@ public static partial class JsonSerializer /// UTF-8 methods since the implementation natively uses UTF-8. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static object? Deserialize(string json, Type returnType, JsonSerializerOptions? options = null) + public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] string json, Type returnType, JsonSerializerOptions? options = null) { if (json == null) { @@ -158,7 +158,7 @@ public static partial class JsonSerializer /// UTF-8 methods since the implementation natively uses UTF-8. /// [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - public static object? Deserialize(ReadOnlySpan json, Type returnType, JsonSerializerOptions? options = null) + public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan json, Type returnType, JsonSerializerOptions? options = null) { // default/null span is treated as empty @@ -202,7 +202,7 @@ public static partial class JsonSerializer /// Using a is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// - public static TValue? Deserialize(string json, JsonTypeInfo jsonTypeInfo) + public static TValue? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] string json, JsonTypeInfo jsonTypeInfo) { // default/null span is treated as empty @@ -250,7 +250,7 @@ public static partial class JsonSerializer /// Using a is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// - public static TValue? Deserialize(ReadOnlySpan json, JsonTypeInfo jsonTypeInfo) + public static TValue? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan json, JsonTypeInfo jsonTypeInfo) { // default/null span is treated as empty @@ -297,7 +297,7 @@ public static partial class JsonSerializer /// Using a is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// - public static object? Deserialize(string json, Type returnType, JsonSerializerContext context) + public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] string json, Type returnType, JsonSerializerContext context) { if (json == null) { @@ -353,7 +353,7 @@ public static partial class JsonSerializer /// Using a is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// - public static object? Deserialize(ReadOnlySpan json, Type returnType, JsonSerializerContext context) + public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan json, Type returnType, JsonSerializerContext context) { if (returnType == null) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Raw.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Raw.cs index 5ac9c8cebe315..d1a5c504993f8 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Raw.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Raw.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Text.Json { @@ -30,7 +31,7 @@ public sealed partial class Utf8JsonWriter /// /// The and values for the writer instance are not applied when using this method. /// - public void WriteRawValue(string json, bool skipInputValidation = false) + public void WriteRawValue([StringSyntax(StringSyntaxAttribute.Json)] string json, bool skipInputValidation = false) { if (!_options.SkipValidation) { @@ -66,7 +67,7 @@ public void WriteRawValue(string json, bool skipInputValidation = false) /// /// The and values for the writer instance are not applied when using this method. /// - public void WriteRawValue(ReadOnlySpan json, bool skipInputValidation = false) + public void WriteRawValue([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan json, bool skipInputValidation = false) { if (!_options.SkipValidation) { From 090430c7d04604f7cecbecf9d2de3f407a4fa308 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 21 Jan 2022 14:44:23 +0100 Subject: [PATCH 117/308] [main] Update dependencies from 5 repositories (#64002) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dotnet-maestro[bot] Co-authored-by: Přemek Vysoký --- eng/Version.Details.xml | 40 ++++++++++++++++++++-------------------- eng/Versions.props | 20 ++++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a8d298b5be9c8..af284815b19ec 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -16,37 +16,37 @@ https://github.com/dotnet/wcf 7f504aabb1988e9a093c1e74d8040bd52feb2f01 - + https://github.com/dotnet/llvm-project - e7e0ebc663c70ccb19c331af50d418a06dc92df8 + fe77708023f3d8a51c1548b86487a692897227ec - + https://github.com/dotnet/llvm-project - e7e0ebc663c70ccb19c331af50d418a06dc92df8 + fe77708023f3d8a51c1548b86487a692897227ec - + https://github.com/dotnet/llvm-project - e7e0ebc663c70ccb19c331af50d418a06dc92df8 + fe77708023f3d8a51c1548b86487a692897227ec - + https://github.com/dotnet/llvm-project - e7e0ebc663c70ccb19c331af50d418a06dc92df8 + fe77708023f3d8a51c1548b86487a692897227ec - + https://github.com/dotnet/llvm-project - e7e0ebc663c70ccb19c331af50d418a06dc92df8 + fe77708023f3d8a51c1548b86487a692897227ec - + https://github.com/dotnet/llvm-project - e7e0ebc663c70ccb19c331af50d418a06dc92df8 + fe77708023f3d8a51c1548b86487a692897227ec - + https://github.com/dotnet/llvm-project - e7e0ebc663c70ccb19c331af50d418a06dc92df8 + fe77708023f3d8a51c1548b86487a692897227ec - + https://github.com/dotnet/llvm-project - e7e0ebc663c70ccb19c331af50d418a06dc92df8 + fe77708023f3d8a51c1548b86487a692897227ec @@ -270,17 +270,17 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 91d6b3c1f51888d166701510189505f35714665c - + https://github.com/dotnet/hotreload-utils - 5bc948c6242bc9423c3269d122dcdf0ad6c06a83 + b6504c8dca937ff1a59d3283374241eacf26684a https://github.com/dotnet/runtime-assets a597df23119faf540d95cebab14b82f084c47384 - + https://github.com/dotnet/roslyn-analyzers - 6c43d213c426cf64c78eb1e9e38e4b9ec6454181 + f471d3381584f10f9908432e0b2b2b8ef07a0aa6 https://github.com/dotnet/sdk diff --git a/eng/Versions.props b/eng/Versions.props index f368a31dc3c93..04f7adea4cff9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -50,7 +50,7 @@ 3.3.2 4.0.1 4.0.1 - 7.0.0-preview1.22067.1 + 7.0.0-preview1.22068.2 2.0.0-alpha.1.21525.11 @@ -78,14 +78,14 @@ 3.1.0 7.0.0-alpha.1.22066.4 - 1.0.0-alpha.1.22060.1 - 1.0.0-alpha.1.22060.1 - 1.0.0-alpha.1.22060.1 - 1.0.0-alpha.1.22060.1 - 1.0.0-alpha.1.22060.1 - 1.0.0-alpha.1.22060.1 - 1.0.0-alpha.1.22060.1 - 1.0.0-alpha.1.22060.1 + 1.0.0-alpha.1.22070.1 + 1.0.0-alpha.1.22070.1 + 1.0.0-alpha.1.22070.1 + 1.0.0-alpha.1.22070.1 + 1.0.0-alpha.1.22070.1 + 1.0.0-alpha.1.22070.1 + 1.0.0-alpha.1.22070.1 + 1.0.0-alpha.1.22070.1 5.0.0 4.3.0 @@ -163,7 +163,7 @@ 1.0.0-prerelease.22067.1 1.0.0-prerelease.22067.1 1.0.0-prerelease.22067.1 - 1.0.2-alpha.0.22060.2 + 1.0.2-alpha.0.22069.1 2.4.2-pre.22 0.12.0-pre.20 2.4.2 From 024082891c683163c6fa2107fc019e39e9ccf04e Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Fri, 21 Jan 2022 06:09:07 -0800 Subject: [PATCH 118/308] Fix crash when VS4Mac is debugging VS4Mac arm64 (#64085) Fix crash when VS4Mac is debugging VS4Mac arm64 Issue: https://github.com/dotnet/runtime/issues/64011 --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index ebb5d12c0ce3a..4efcd8a8323b4 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -5428,6 +5428,16 @@ GENERICS_TYPE_TOKEN DacDbiInterfaceImpl::ResolveExactGenericArgsToken(DWORD if (dwExactGenericArgsTokenIndex == 0) { + // In a rare case of VS4Mac debugging VS4Mac ARM64 optimized code we get a null generics argument token. We aren't sure + // why the token is null, it may be a bug or it may be by design in the runtime. In the interest of time we are working + // around the issue rather than investigating the root cause. This workaround should only cause us to degrade generic + // types from exact type parameters to approximate or canonical type parameters. In the future if we discover this issue + // is happening more frequently than we expect or the workaround is more impactful than we expect we may need to remove + // this workaround and resolve the underlying issue. + if (rawToken == 0) + { + return rawToken; + } // In this case the real generics type token is the MethodTable of the "this" object. // Note that we want the target address here. From 9c8b804099ce79f44733c23d4fc59801ab03f86d Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 21 Jan 2022 08:22:51 -0800 Subject: [PATCH 119/308] ILVerify: Handle readonly references in ldfld (#64077) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ILVerify: Handle readonly references in ldfld Fixes #63953 * Fix test name Co-authored-by: Michal Strehovský --- .../tools/ILVerification/ILImporter.Verify.cs | 2 +- src/tests/ilverify/ILTests/ValueTypeTests.il | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/ILVerification/ILImporter.Verify.cs b/src/coreclr/tools/ILVerification/ILImporter.Verify.cs index d1b3d10ed5a3f..258a005ffdd09 100644 --- a/src/coreclr/tools/ILVerification/ILImporter.Verify.cs +++ b/src/coreclr/tools/ILVerification/ILImporter.Verify.cs @@ -2060,7 +2060,7 @@ void ImportLoadField(int token, bool isStatic) actualThis = StackValue.CreateByRef(actualThis.Type); var declaredThis = owningType.IsValueType ? - StackValue.CreateByRef(owningType) : StackValue.CreateObjRef(owningType); + StackValue.CreateByRef(owningType, readOnly : true) : StackValue.CreateObjRef(owningType); CheckIsAssignable(actualThis, declaredThis); diff --git a/src/tests/ilverify/ILTests/ValueTypeTests.il b/src/tests/ilverify/ILTests/ValueTypeTests.il index a52cb76522464..8eb3aac002de8 100644 --- a/src/tests/ilverify/ILTests/ValueTypeTests.il +++ b/src/tests/ilverify/ILTests/ValueTypeTests.il @@ -26,3 +26,16 @@ } } +.class public sequential ansi sealed beforefieldinit ValueTypeFieldTests + extends [System.Runtime]System.ValueType +{ + .field public int32 InstanceField + + .method public static int32 ValueType.UnboxLdfld_Valid(object o) cil managed + { + ldarg.0 + unbox ValueTypeFieldTests + ldfld int32 ValueTypeFieldTests::InstanceField + ret + } +} From 1bb3276544b0bfbe3e30be52b7f19ce2a45dccb6 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Fri, 21 Jan 2022 18:25:32 +0100 Subject: [PATCH 120/308] Avoid additional local created for delegate invocations (#63796) Very often 'this' is already a local and we can avoid creating another local. --- src/coreclr/jit/lower.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 51b7a51eb1005..f29baa320940d 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3792,32 +3792,29 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call) assert(thisArgNode != nullptr); assert(thisArgNode->gtOper == GT_PUTARG_REG); - GenTree* originalThisExpr = thisArgNode->AsOp()->gtOp1; - GenTree* thisExpr = originalThisExpr; + GenTree* thisExpr = thisArgNode->AsOp()->gtOp1; // We're going to use the 'this' expression multiple times, so make a local to copy it. - unsigned lclNum; - - if (call->IsTailCallViaJitHelper() && originalThisExpr->IsLocal()) + GenTree* base; + if (thisExpr->OperIs(GT_LCL_VAR)) { - // For ordering purposes for the special tailcall arguments on x86, we forced the - // 'this' pointer in this case to a local in Compiler::fgMorphTailCall(). - // We could possibly use this case to remove copies for all architectures and non-tailcall - // calls by creating a new lcl var or lcl field reference, as is done in the - // LowerVirtualVtableCall() code. - assert(originalThisExpr->OperGet() == GT_LCL_VAR); - lclNum = originalThisExpr->AsLclVarCommon()->GetLclNum(); + base = comp->gtNewLclvNode(thisExpr->AsLclVar()->GetLclNum(), thisExpr->TypeGet()); + } + else if (thisExpr->OperIs(GT_LCL_FLD)) + { + base = comp->gtNewLclFldNode(thisExpr->AsLclFld()->GetLclNum(), thisExpr->TypeGet(), + thisExpr->AsLclFld()->GetLclOffs()); } else { unsigned delegateInvokeTmp = comp->lvaGrabTemp(true DEBUGARG("delegate invoke call")); + base = comp->gtNewLclvNode(delegateInvokeTmp, thisExpr->TypeGet()); LIR::Use thisExprUse(BlockRange(), &thisArgNode->AsOp()->gtOp1, thisArgNode); ReplaceWithLclVar(thisExprUse, delegateInvokeTmp); thisExpr = thisExprUse.Def(); // it's changed; reload it. - lclNum = delegateInvokeTmp; } // replace original expression feeding into thisPtr with @@ -3836,8 +3833,6 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call) // the control target is // [originalThis + firstTgtOffs] - GenTree* base = new (comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR, originalThisExpr->TypeGet(), lclNum); - unsigned targetOffs = comp->eeGetEEInfo()->offsetOfDelegateFirstTarget; GenTree* result = new (comp, GT_LEA) GenTreeAddrMode(TYP_REF, base, nullptr, 0, targetOffs); GenTree* callTarget = Ind(result); @@ -4606,7 +4601,7 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call) // If what we are passing as the thisptr is not already a local, make a new local to place it in // because we will be creating expressions based on it. unsigned lclNum; - if (thisPtr->IsLocal()) + if (thisPtr->OperIsLocal()) { lclNum = thisPtr->AsLclVarCommon()->GetLclNum(); } From 744d96ac559de6fe61be028f8527339d0eed89a2 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Fri, 21 Jan 2022 15:10:04 -0300 Subject: [PATCH 121/308] [wasm][debugger] Apply changes on wasm using sdb protocol. (#63705) * Apply changes on wasm using sdb protocol. * conflict * Merge conflict. * Fix merge * Fix compilation error. --- src/mono/mono/component/debugger-agent.c | 23 +++ src/mono/mono/component/debugger-protocol.h | 5 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 21 ++ .../BrowserDebugProxy/MonoSDBHelper.cs | 56 +++++- .../DebuggerTestSuite/BreakpointTests.cs | 183 ++++++++++++++++++ .../DebuggerTestSuite/DebuggerTestBase.cs | 65 ++++++- .../tests/debugger-test/debugger-test.cs | 26 +++ 7 files changed, 373 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c index f9712c5b77e38..d558691594751 100644 --- a/src/mono/mono/component/debugger-agent.c +++ b/src/mono/mono/component/debugger-agent.c @@ -7012,6 +7012,29 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) buffer_add_assemblyid (buf, mono_get_root_domain (), assembly); break; } + case MDBGPROT_CMD_GET_MODULE_BY_GUID: { + int len = 0; + uint8_t* guid = m_dbgprot_decode_byte_array (p, &p, end, &len); + MonoAssembly *assembly = NULL; + GPtrArray *assemblies = mono_alc_get_all_loaded_assemblies (); + for (int i = 0; i < assemblies->len; ++i) { + MonoAssembly *assemblyOnALC = (MonoAssembly*)g_ptr_array_index (assemblies, i); + if (!memcmp(assemblyOnALC->image->heap_guid.data, guid, len)) { + assembly = assemblyOnALC; + break; + } + } + g_ptr_array_free (assemblies, TRUE); + if (!assembly) { + PRINT_DEBUG_MSG (1, "Could not resolve guid\n"); + g_free (guid); + buffer_add_int (buf, -1); + break; + } + g_free (guid); + buffer_add_moduleid (buf, mono_get_root_domain (), assembly->image); + break; + } default: return ERR_NOT_IMPLEMENTED; } diff --git a/src/mono/mono/component/debugger-protocol.h b/src/mono/mono/component/debugger-protocol.h index 6bce7c5ff2ec1..2aa52c2a857ff 100644 --- a/src/mono/mono/component/debugger-protocol.h +++ b/src/mono/mono/component/debugger-protocol.h @@ -35,7 +35,8 @@ typedef enum { MDBGPROT_CMD_VM_STOP_BUFFERING = 15, MDBGPROT_CMD_VM_READ_MEMORY = 16, MDBGPROT_CMD_VM_WRITE_MEMORY = 17, - MDBGPROT_CMD_GET_ASSEMBLY_BY_NAME = 18 + MDBGPROT_CMD_GET_ASSEMBLY_BY_NAME = 18, + MDBGPROT_CMD_GET_MODULE_BY_GUID = 19 } MdbgProtCmdVM; typedef enum { @@ -150,7 +151,7 @@ typedef enum { typedef enum { MDBGPROT_CMD_MODULE_GET_INFO = 1, - MDBGPROT_CMD_MODULE_APPLY_CHANGES = 2, + MDBGPROT_CMD_MODULE_APPLY_CHANGES = 2 } MdbgProtCmdModule; typedef enum { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index 36d6289bf241c..5fc72c491c3b5 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -499,6 +499,14 @@ protected override async Task AcceptCommand(MessageId id, string method, J } // Protocol extensions + case "DotnetDebugger.applyUpdates": + { + if (await ApplyUpdates(id, args, token)) + SendResponse(id, Result.OkFromObject(new { }), token); + else + SendResponse(id, Result.Err("ApplyUpdate failed."), token); + return true; + } case "DotnetDebugger.addSymbolServerUrl": { string url = args["url"]?.Value(); @@ -593,6 +601,19 @@ protected override async Task AcceptCommand(MessageId id, string method, J return false; } + + private async Task ApplyUpdates(MessageId id, JObject args, CancellationToken token) + { + var context = GetContext(id); + string moduleGUID = args["moduleGUID"]?.Value(); + string dmeta = args["dmeta"]?.Value(); + string dil = args["dil"]?.Value(); + string dpdb = args["dpdb"]?.Value(); + var moduleId = await context.SdbAgent.GetModuleId(moduleGUID, token); + var applyUpdates = await context.SdbAgent.ApplyUpdates(moduleId, dmeta, dil, dpdb, token); + return applyUpdates; + } + private void SetJustMyCode(MessageId id, JObject args, CancellationToken token) { var isEnabled = args["enabled"]?.Value(); diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 3b1dc557259b6..1d62e94f556f1 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -139,7 +139,8 @@ internal enum CmdVM { StopBuffering = 15, VmReadMemory = 16, VmWriteMemory = 17, - GetAssemblyByName = 18 + GetAssemblyByName = 18, + GetModuleByGUID = 19 } internal enum CmdFrame { @@ -483,8 +484,7 @@ public MonoBinaryWriter() : base(new MemoryStream(20)) {} public override void Write(string val) { var bytes = Encoding.UTF8.GetBytes(val); - Write(bytes.Length); - Write(bytes); + WriteByteArray(bytes); } public override void Write(long val) => WriteBigEndian(val); @@ -520,6 +520,13 @@ public void WriteObj(DotnetObjectId objectId, MonoSDBHelper SdbHelper) Write(SdbHelper.valueTypes[objectId.Value].valueTypeBuffer); } } + + public void WriteByteArray(byte[] bytes) + { + Write(bytes.Length); + Write(bytes); + } + public async Task WriteConst(LiteralExpressionSyntax constValue, MonoSDBHelper SdbHelper, CancellationToken token) { switch (constValue.Kind()) @@ -996,6 +1003,16 @@ public async Task GetAssemblyId(string asm_name, CancellationToken token) return retDebuggerCmdReader.ReadInt32(); } + public async Task GetModuleId(string moduleGuid, CancellationToken token) + { + using var commandParamsWriter = new MonoBinaryWriter(); + var guidArray = Convert.FromBase64String(moduleGuid); + commandParamsWriter.WriteByteArray(guidArray); + + using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdVM.GetModuleByGUID, commandParamsWriter, token); + return retDebuggerCmdReader.ReadInt32(); + } + public async Task GetAssemblyNameFromModule(int moduleId, CancellationToken token) { using var command_params_writer = new MonoBinaryWriter(); @@ -2665,6 +2682,39 @@ public async Task SetVariableValue(int thread_id, int frame_id, int varId, return false; return true; } + + public async Task CreateByteArray(string diff, CancellationToken token) + { + var diffArr = Convert.FromBase64String(diff); + using var commandParamsWriter = new MonoBinaryWriter(); + using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdAppDomain.GetRootDomain, commandParamsWriter, token); + var root = retDebuggerCmdReader.ReadInt32(); + + commandParamsWriter.Write(root); + commandParamsWriter.WriteByteArray(diffArr); + using var arrayDebuggerCmdReader = await SendDebuggerAgentCommand(CmdAppDomain.CreateByteArray, commandParamsWriter, token); + return arrayDebuggerCmdReader.ReadInt32(); + } + + public async Task ApplyUpdates(int moduleId, string dmeta, string dil, string dpdb, CancellationToken token) + { + int dpdbId = -1; + var dmetaId = await CreateByteArray(dmeta, token); + var dilId = await CreateByteArray(dil, token); + if (dpdb != null) + dpdbId = await CreateByteArray(dpdb, token); + + using var commandParamsWriter = new MonoBinaryWriter(); + commandParamsWriter.Write(moduleId); + commandParamsWriter.Write(dmetaId); + commandParamsWriter.Write(dilId); + if (dpdbId != -1) + commandParamsWriter.Write(dpdbId); + else + commandParamsWriter.Write((byte)ValueTypeId.Null); + await SendDebuggerAgentCommand(CmdModule.ApplyChanges, commandParamsWriter, token); + return true; + } } internal static class HelperExtensions diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs index b8c58a27f1e5f..3dc2bc246364c 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs @@ -707,7 +707,190 @@ await SendCommandAndCheck(null, "Debugger.resume", 8, "VisibleMethodDebuggerBreak"); } + + [Fact] + public async Task DebugHotReloadMethodChangedUserBreakUsingSDB() + { + string asm_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll"); + string pdb_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb"); + string asm_file_hot_reload = Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll"); + + var pause_location = await LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges( + asm_file, pdb_file, "MethodBody1", "StaticMethod1"); + + var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "a", 10); + pause_location = await LoadAssemblyAndTestHotReloadUsingSDB( + asm_file_hot_reload, "MethodBody1", "StaticMethod1", 1); + + JToken top_frame = pause_location["callFrames"]?[0]; + AssertEqual("StaticMethod1", top_frame?["functionName"]?.Value(), top_frame?.ToString()); + CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 12, 16, scripts, top_frame["location"]); + + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "b", 15); + pause_location = await LoadAssemblyAndTestHotReloadUsingSDB( + asm_file_hot_reload, "MethodBody1", "StaticMethod1", 2); + + top_frame = pause_location["callFrames"]?[0]; + AssertEqual("StaticMethod1", top_frame?["functionName"]?.Value(), top_frame?.ToString()); + CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 12, 12, scripts, top_frame["location"]); + + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + await CheckBool(locals, "c", true); + } + + [Fact] + public async Task DebugHotReloadMethodUnchangedUsingSDB() + { + string asm_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll"); + string pdb_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb"); + string asm_file_hot_reload = Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll"); + + var pause_location = await LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges( + asm_file, pdb_file, "MethodBody2", "StaticMethod1"); + + var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "a", 10); + pause_location = await LoadAssemblyAndTestHotReloadUsingSDB( + asm_file_hot_reload, "MethodBody2", "StaticMethod1", 1); + + JToken top_frame = pause_location["callFrames"]?[0]; + AssertEqual("StaticMethod1", top_frame?["functionName"]?.Value(), top_frame?.ToString()); + CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 21, 12, scripts, top_frame["location"]); + + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "a", 10); + pause_location = await LoadAssemblyAndTestHotReloadUsingSDB( + asm_file_hot_reload, "MethodBody2", "StaticMethod1", 2); + + top_frame = pause_location["callFrames"]?[0]; + AssertEqual("StaticMethod1", top_frame?["functionName"]?.Value(), top_frame?.ToString()); + CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 21, 12, scripts, top_frame["location"]); + } + + [Fact] + public async Task DebugHotReloadMethodAddBreakpointUsingSDB() + { + string asm_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll"); + string pdb_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb"); + string asm_file_hot_reload = Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll"); + int line = 30; + await SetBreakpoint(".*/MethodBody1.cs$", line, 12, use_regex: true); + var pause_location = await LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges( + asm_file, pdb_file, "MethodBody3", "StaticMethod3"); + + var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "a", 10); + + //apply first update + pause_location = await LoadAssemblyAndTestHotReloadUsingSDB( + asm_file_hot_reload, "MethodBody3", "StaticMethod3", 1); + + JToken top_frame = pause_location["callFrames"]?[0]; + AssertEqual("StaticMethod3", top_frame?["functionName"]?.Value(), top_frame?.ToString()); + CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 30, 12, scripts, top_frame["location"]); + + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + CheckNumber(locals, "b", 15); + + //apply second update + pause_location = await LoadAssemblyAndTestHotReloadUsingSDB( + asm_file_hot_reload, "MethodBody3", "StaticMethod3", 2); + + top_frame = pause_location["callFrames"]?[0]; + AssertEqual("StaticMethod3", top_frame?["functionName"]?.Value(), top_frame?.ToString()); + CheckLocation("dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 30, 12, scripts, top_frame["location"]); + + locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + await CheckBool(locals, "c", true); + + await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 31, 12, "StaticMethod3", + locals_fn: async (locals) => + { + CheckNumber(locals, "d", 10); + await Task.CompletedTask; + } + ); + await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 32, 12, "StaticMethod3", + locals_fn: async (locals) => + { + CheckNumber(locals, "d", 10); + CheckNumber(locals, "e", 20); + await Task.CompletedTask; + } + ); + await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 33, 8, "StaticMethod3", + locals_fn: async (locals) => + { + CheckNumber(locals, "d", 10); + CheckNumber(locals, "e", 20); + CheckNumber(locals, "f", 50); + await Task.CompletedTask; + } + ); + } + + + [Fact] + public async Task DebugHotReloadMethodEmptyUsingSDB() + { + string asm_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.dll"); + string pdb_file = Path.Combine(DebuggerTestAppPath, "ApplyUpdateReferencedAssembly.pdb"); + string asm_file_hot_reload = Path.Combine(DebuggerTestAppPath, "../wasm/ApplyUpdateReferencedAssembly.dll"); + + int line = 38; + await SetBreakpoint(".*/MethodBody1.cs$", line, 0, use_regex: true); + var pause_location = await LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges( + asm_file, pdb_file, "MethodBody4", "StaticMethod4"); + + //apply first update + pause_location = await LoadAssemblyAndTestHotReloadUsingSDB( + asm_file_hot_reload, "MethodBody4", "StaticMethod4", 1); + + await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 39, 12, "StaticMethod4", + locals_fn: async (locals) => + { + CheckNumber(locals, "a", 10); + await Task.CompletedTask; + } + ); + await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 40, 12, "StaticMethod4", + locals_fn: async (locals) => + { + CheckNumber(locals, "a", 10); + CheckNumber(locals, "b", 20); + await Task.CompletedTask; + } + ); + await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 41, 12, "StaticMethod4", + locals_fn: async (locals) => + { + CheckNumber(locals, "a", 10); + CheckNumber(locals, "b", 20); + await Task.CompletedTask; + } + ); + await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 42, 12, "StaticMethod4", + locals_fn: async (locals) => + { + CheckNumber(locals, "a", 10); + CheckNumber(locals, "b", 20); + await Task.CompletedTask; + } + ); + await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 43, 8, "StaticMethod4", + locals_fn: async (locals) => + { + CheckNumber(locals, "a", 10); + CheckNumber(locals, "b", 20); + await Task.CompletedTask; + } + ); + //pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 38, 8, "StaticMethod4"); + } + [Theory] [InlineData(false, "RunStepThrough")] [InlineData(true, "RunStepThrough")] diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index d49a2331e2a11..cf4eade5a8193 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -1189,9 +1189,72 @@ internal async Task LoadAssemblyDynamicallyALCAndRunMethod(string asm_f return await insp.WaitFor(Inspector.PAUSE); } + internal async Task LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges(string asm_file, string pdb_file, string class_name, string method_name) + { + byte[] bytes = File.ReadAllBytes(asm_file); + string asm_base64 = Convert.ToBase64String(bytes); + bytes = File.ReadAllBytes(pdb_file); + string pdb_base64 = Convert.ToBase64String(bytes); + + string expression = $"let asm_b64 = '{asm_base64}'; let pdb_b64 = '{pdb_base64}';"; + expression = $"{{ {expression} invoke_static_method('[debugger-test] TestHotReloadUsingSDB:LoadLazyHotReload', asm_b64, pdb_b64); }}"; + var load_assemblies = JObject.FromObject(new + { + expression + }); + + Result load_assemblies_res = await cli.SendCommand("Runtime.evaluate", load_assemblies, token); + + Thread.Sleep(1000); + var run_method = JObject.FromObject(new + { + expression = "window.setTimeout(function() { invoke_static_method('[debugger-test] TestHotReloadUsingSDB:RunMethod', '" + class_name + "', '" + method_name + "'); }, 1);" + }); + + await cli.SendCommand("Runtime.evaluate", run_method, token); + return await insp.WaitFor(Inspector.PAUSE); + } + + internal async Task LoadAssemblyAndTestHotReloadUsingSDB(string asm_file_hot_reload, string class_name, string method_name, int id) + { + await cli.SendCommand("Debugger.resume", null, token); + var bytes = File.ReadAllBytes($"{asm_file_hot_reload}.{id}.dmeta"); + string dmeta1 = Convert.ToBase64String(bytes); + + bytes = File.ReadAllBytes($"{asm_file_hot_reload}.{id}.dil"); + string dil1 = Convert.ToBase64String(bytes); + + bytes = File.ReadAllBytes($"{asm_file_hot_reload}.{id}.dpdb"); + string dpdb1 = Convert.ToBase64String(bytes); + + var run_method = JObject.FromObject(new + { + expression = "invoke_static_method('[debugger-test] TestHotReloadUsingSDB:GetModuleGUID');" + }); + + var moduleGUID_res = await cli.SendCommand("Runtime.evaluate", run_method, token); + + Assert.True(moduleGUID_res.IsOk); + var moduleGUID = moduleGUID_res.Value["result"]["value"]; + + var applyUpdates = JObject.FromObject(new + { + moduleGUID, + dmeta = dmeta1, + dil = dil1, + dpdb = dpdb1 + }); + await cli.SendCommand("DotnetDebugger.applyUpdates", applyUpdates, token); + run_method = JObject.FromObject(new + { + expression = "window.setTimeout(function() { invoke_static_method('[debugger-test] TestHotReloadUsingSDB:RunMethod', '" + class_name + "', '" + method_name + "'); }, 1);" + }); + await cli.SendCommand("Runtime.evaluate", run_method, token); + return await insp.WaitFor(Inspector.PAUSE); + } + internal async Task LoadAssemblyAndTestHotReload(string asm_file, string pdb_file, string asm_file_hot_reload, string class_name, string method_name) { - // Simulate loading an assembly into the framework byte[] bytes = File.ReadAllBytes(asm_file); string asm_base64 = Convert.ToBase64String(bytes); bytes = File.ReadAllBytes(pdb_file); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 3ecd2869fa210..2c956cd31bbb6 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -925,3 +925,29 @@ public static void CallToEvaluateLocal() System.Diagnostics.Debugger.Break(); } } + +public class TestHotReloadUsingSDB { + static System.Reflection.Assembly loadedAssembly; + public static string LoadLazyHotReload(string asm_base64, string pdb_base64) + { + byte[] asm_bytes = Convert.FromBase64String(asm_base64); + byte[] pdb_bytes = Convert.FromBase64String(pdb_base64); + + loadedAssembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(new System.IO.MemoryStream(asm_bytes), new System.IO.MemoryStream(pdb_bytes)); + var GUID = loadedAssembly.Modules.FirstOrDefault()?.ModuleVersionId.ToByteArray(); + return Convert.ToBase64String(GUID); + } + + public static string GetModuleGUID() + { + var GUID = loadedAssembly.Modules.FirstOrDefault()?.ModuleVersionId.ToByteArray(); + return Convert.ToBase64String(GUID); + } + + public static void RunMethod(string className, string methodName) + { + var myType = loadedAssembly.GetType($"ApplyUpdateReferencedAssembly.{className}"); + var myMethod = myType.GetMethod(methodName); + myMethod.Invoke(null, null); + } +} \ No newline at end of file From 0b8204f7a3b284a069fcbc021d4d744dd6e4fd4d Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 21 Jan 2022 11:44:37 -0800 Subject: [PATCH 122/308] Fixed IsFloatPositiveZero from returning 'true' on non-constant double operands (#64083) * Fixed IsFloatPositiveZero from returning 'true' on non-constant double operands * Update src/coreclr/jit/gentree.h Co-authored-by: Egor Bogatov Co-authored-by: Egor Bogatov --- src/coreclr/jit/gentree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 7eeb3b0f57bd2..992a2cb1c0f38 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -7661,7 +7661,7 @@ inline bool GenTree::IsSIMDZero() const // inline bool GenTree::IsFloatPositiveZero() const { - return !(IsCnsNonZeroFltOrDbl()); + return IsCnsFltOrDbl() && !IsCnsNonZeroFltOrDbl(); } //------------------------------------------------------------------- From 96a7478a29d1711eae808746db9d409ed83104e4 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 21 Jan 2022 11:46:21 -0800 Subject: [PATCH 123/308] Ensure several helper intrinsics are correctly imported and handled (#63972) * Ensure several helper intrinsics are correctly imported and handled * Ensure that Sum for TYP_INT/UINT on Arm64 is correctly handled * Respond to PR feedback and ensure ExtractMostSignificantBits for Vector64 on Arm64 also uses AddPairwise * Applying formatting patch * Ensure the clsHnd is correct * Fix the remaining musl failures * Ensure that we aren't sign-extending TYP_BYTE (System.SByte) for ExtractMostSignificantBits * Ensure an assert is correct on x64 * Ensure Vector64.Dot on Arm64 uses AddPairwise, not AddAcross * Apply formatting patch --- src/coreclr/jit/gentree.cpp | 94 ++++++---- src/coreclr/jit/hwintrinsicarm64.cpp | 104 ++++++----- src/coreclr/jit/hwintrinsiclistarm64.h | 68 +++---- src/coreclr/jit/hwintrinsiclistxarch.h | 68 +++---- src/coreclr/jit/hwintrinsicxarch.cpp | 167 +++++++++++++++--- src/coreclr/jit/lowerarmarch.cpp | 131 +++++++++----- src/coreclr/jit/lowerxarch.cpp | 8 +- .../System/Runtime/Intrinsics/Vector256.cs | 11 +- .../General/Shared/VectorDotTest.template | 10 +- .../General/Vector128/Dot.Byte.cs | 10 +- .../General/Vector128/Dot.Double.cs | 10 +- .../General/Vector128/Dot.Int16.cs | 10 +- .../General/Vector128/Dot.Int32.cs | 10 +- .../General/Vector128/Dot.Int64.cs | 10 +- .../General/Vector128/Dot.SByte.cs | 10 +- .../General/Vector128/Dot.Single.cs | 10 +- .../General/Vector128/Dot.UInt16.cs | 10 +- .../General/Vector128/Dot.UInt32.cs | 10 +- .../General/Vector128/Dot.UInt64.cs | 10 +- .../General/Vector256/Dot.Byte.cs | 10 +- .../General/Vector256/Dot.Double.cs | 10 +- .../General/Vector256/Dot.Int16.cs | 10 +- .../General/Vector256/Dot.Int32.cs | 10 +- .../General/Vector256/Dot.Int64.cs | 10 +- .../General/Vector256/Dot.SByte.cs | 10 +- .../General/Vector256/Dot.Single.cs | 10 +- .../General/Vector256/Dot.UInt16.cs | 10 +- .../General/Vector256/Dot.UInt32.cs | 10 +- .../General/Vector256/Dot.UInt64.cs | 10 +- .../General/Vector64/Dot.Byte.cs | 10 +- .../General/Vector64/Dot.Double.cs | 10 +- .../General/Vector64/Dot.Int16.cs | 10 +- .../General/Vector64/Dot.Int32.cs | 10 +- .../General/Vector64/Dot.Int64.cs | 10 +- .../General/Vector64/Dot.SByte.cs | 10 +- .../General/Vector64/Dot.Single.cs | 10 +- .../General/Vector64/Dot.UInt16.cs | 10 +- .../General/Vector64/Dot.UInt32.cs | 10 +- .../General/Vector64/Dot.UInt64.cs | 10 +- 39 files changed, 715 insertions(+), 246 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index be664b41d8cfc..b8897e81dc8e3 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17948,7 +17948,7 @@ GenTree* Compiler::gtNewSimdAbsNode( if ((simdBaseType != TYP_LONG) && ((simdSize == 32) || compOpportunisticallyDependsOn(InstructionSet_SSSE3))) { NamedIntrinsic intrinsic = (simdSize == 32) ? NI_AVX2_Abs : NI_SSSE3_Abs; - return gtNewSimdAsHWIntrinsicNode(type, op1, intrinsic, simdBaseJitType, simdSize); + return gtNewSimdHWIntrinsicNode(type, op1, intrinsic, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); } else { @@ -19414,7 +19414,7 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, getAllBitsSet = NI_Vector128_get_AllBitsSet; } - op1 = gtNewSimdCmpOpNode(op, simdBaseType, op1, op2, simdBaseJitType, simdSize, + op1 = gtNewSimdCmpOpNode(op, simdType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); if (simdBaseType == TYP_FLOAT) @@ -19428,7 +19428,7 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, simdBaseJitType = CORINFO_TYPE_LONG; } - op2 = gtNewSimdHWIntrinsicNode(simdBaseType, getAllBitsSet, simdBaseJitType, simdSize); + op2 = gtNewSimdHWIntrinsicNode(simdType, getAllBitsSet, simdBaseJitType, simdSize); break; } #elif defined(TARGET_ARM64) @@ -19459,7 +19459,7 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, getAllBitsSet = NI_Vector128_get_AllBitsSet; } - op1 = gtNewSimdCmpOpNode(op, simdBaseType, op1, op2, simdBaseJitType, simdSize, + op1 = gtNewSimdCmpOpNode(op, simdType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); if (simdBaseType == TYP_FLOAT) @@ -19473,7 +19473,7 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, simdBaseJitType = CORINFO_TYPE_LONG; } - op2 = gtNewSimdHWIntrinsicNode(simdBaseType, getAllBitsSet, simdBaseJitType, simdSize); + op2 = gtNewSimdHWIntrinsicNode(simdType, getAllBitsSet, simdBaseJitType, simdSize); break; } #else @@ -19537,7 +19537,7 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, intrinsic = (simdSize == 32) ? NI_Vector256_op_Inequality : NI_Vector128_op_Inequality; - op1 = gtNewSimdCmpOpNode(op, simdBaseType, op1, op2, simdBaseJitType, simdSize, + op1 = gtNewSimdCmpOpNode(op, simdType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); if (simdBaseType == TYP_FLOAT) @@ -19551,7 +19551,7 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, simdBaseJitType = CORINFO_TYPE_LONG; } - op2 = gtNewSimdZeroNode(simdBaseType, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); + op2 = gtNewSimdZeroNode(simdType, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); break; } @@ -19572,7 +19572,7 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, intrinsic = (simdSize == 8) ? NI_Vector64_op_Inequality : NI_Vector128_op_Inequality; - op1 = gtNewSimdCmpOpNode(op, simdBaseType, op1, op2, simdBaseJitType, simdSize, + op1 = gtNewSimdCmpOpNode(op, simdType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); if (simdBaseType == TYP_FLOAT) @@ -19586,7 +19586,7 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, simdBaseJitType = CORINFO_TYPE_LONG; } - op2 = gtNewSimdZeroNode(simdBaseType, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); + op2 = gtNewSimdZeroNode(simdType, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); break; } @@ -19659,7 +19659,8 @@ GenTree* Compiler::gtNewSimdCndSelNode(var_types type, // result = op2 | op3 return gtNewSimdBinOpNode(GT_OR, type, op2, op3, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); #elif defined(TARGET_ARM64) - return gtNewSimdAsHWIntrinsicNode(type, op1, op2, op3, NI_AdvSimd_BitwiseSelect, simdBaseJitType, simdSize); + return gtNewSimdHWIntrinsicNode(type, op1, op2, op3, NI_AdvSimd_BitwiseSelect, simdBaseJitType, simdSize, + isSimdAsHWIntrinsic); #else #error Unsupported platform #endif // !TARGET_XARCH && !TARGET_ARM64 @@ -19718,7 +19719,7 @@ GenTree* Compiler::gtNewSimdDotProdNode(var_types type, assert(op2->TypeIs(simdType)); var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); - assert(genActualType(simdBaseType) == type); + assert(JITtype2varType(simdBaseJitType) == type); NamedIntrinsic intrinsic = NI_Illegal; @@ -20751,7 +20752,7 @@ GenTree* Compiler::gtNewSimdSumNode( for (int i = 0; i < haddCount; i++) { op1 = impCloneExpr(op1, &tmp, clsHnd, (unsigned)CHECK_SPILL_ALL, nullptr DEBUGARG("Clone op1 for vector sum")); - op1 = gtNewSimdAsHWIntrinsicNode(simdType, op1, tmp, intrinsic, simdBaseJitType, simdSize); + op1 = gtNewSimdHWIntrinsicNode(simdType, op1, tmp, intrinsic, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); } if (simdSize == 32) @@ -20759,14 +20760,15 @@ GenTree* Compiler::gtNewSimdSumNode( intrinsic = (simdBaseType == TYP_FLOAT) ? NI_SSE_Add : NI_SSE2_Add; op1 = impCloneExpr(op1, &tmp, clsHnd, (unsigned)CHECK_SPILL_ALL, nullptr DEBUGARG("Clone op1 for vector sum")); - op1 = gtNewSimdAsHWIntrinsicNode(TYP_SIMD16, op1, gtNewIconNode(0x01, TYP_INT), NI_AVX_ExtractVector128, - simdBaseJitType, simdSize); + op1 = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, gtNewIconNode(0x01, TYP_INT), NI_AVX_ExtractVector128, + simdBaseJitType, simdSize, isSimdAsHWIntrinsic); - tmp = gtNewSimdAsHWIntrinsicNode(simdType, tmp, NI_Vector256_GetLower, simdBaseJitType, simdSize); - op1 = gtNewSimdAsHWIntrinsicNode(TYP_SIMD16, op1, tmp, intrinsic, simdBaseJitType, 16); + tmp = gtNewSimdHWIntrinsicNode(simdType, tmp, NI_Vector256_GetLower, simdBaseJitType, simdSize, + isSimdAsHWIntrinsic); + op1 = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, tmp, intrinsic, simdBaseJitType, 16, isSimdAsHWIntrinsic); } - return gtNewSimdAsHWIntrinsicNode(type, op1, NI_Vector128_ToScalar, simdBaseJitType, simdSize); + return gtNewSimdHWIntrinsicNode(type, op1, NI_Vector128_ToScalar, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); #elif defined(TARGET_ARM64) switch (simdBaseType) { @@ -20774,34 +20776,64 @@ GenTree* Compiler::gtNewSimdSumNode( case TYP_UBYTE: case TYP_SHORT: case TYP_USHORT: + { + tmp = gtNewSimdHWIntrinsicNode(simdType, op1, NI_AdvSimd_Arm64_AddAcross, simdBaseJitType, simdSize, + isSimdAsHWIntrinsic); + return gtNewSimdHWIntrinsicNode(type, tmp, NI_Vector64_ToScalar, simdBaseJitType, 8, isSimdAsHWIntrinsic); + } + case TYP_INT: case TYP_UINT: { - tmp = gtNewSimdAsHWIntrinsicNode(simdType, op1, NI_AdvSimd_Arm64_AddAcross, simdBaseJitType, simdSize); - return gtNewSimdAsHWIntrinsicNode(type, tmp, NI_Vector64_ToScalar, simdBaseJitType, 8); + if (simdSize == 8) + { + op1 = impCloneExpr(op1, &tmp, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for vector sum")); + tmp = gtNewSimdHWIntrinsicNode(simdType, op1, tmp, NI_AdvSimd_AddPairwise, simdBaseJitType, simdSize, + isSimdAsHWIntrinsic); + } + else + { + tmp = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, NI_AdvSimd_Arm64_AddAcross, simdBaseJitType, 16, + isSimdAsHWIntrinsic); + } + return gtNewSimdHWIntrinsicNode(type, tmp, NI_Vector64_ToScalar, simdBaseJitType, 8, isSimdAsHWIntrinsic); } + case TYP_FLOAT: { - unsigned vectorLength = getSIMDVectorLength(simdSize, simdBaseType); - int haddCount = genLog2(vectorLength); - - for (int i = 0; i < haddCount; i++) + if (simdSize == 8) { - op1 = impCloneExpr(op1, &tmp, clsHnd, (unsigned)CHECK_SPILL_ALL, - nullptr DEBUGARG("Clone op1 for vector sum")); - op1 = gtNewSimdAsHWIntrinsicNode(simdType, op1, tmp, NI_AdvSimd_Arm64_AddPairwise, simdBaseJitType, - simdSize); + op1 = gtNewSimdHWIntrinsicNode(TYP_SIMD8, op1, NI_AdvSimd_Arm64_AddPairwiseScalar, simdBaseJitType, + simdSize, isSimdAsHWIntrinsic); } + else + { + unsigned vectorLength = getSIMDVectorLength(simdSize, simdBaseType); + int haddCount = genLog2(vectorLength); - return gtNewSimdAsHWIntrinsicNode(type, op1, NI_Vector128_ToScalar, simdBaseJitType, simdSize); + for (int i = 0; i < haddCount; i++) + { + op1 = impCloneExpr(op1, &tmp, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for vector sum")); + op1 = gtNewSimdHWIntrinsicNode(simdType, op1, tmp, NI_AdvSimd_Arm64_AddPairwise, simdBaseJitType, + simdSize, isSimdAsHWIntrinsic); + } + } + return gtNewSimdHWIntrinsicNode(type, op1, NI_Vector128_ToScalar, simdBaseJitType, simdSize, + isSimdAsHWIntrinsic); } + case TYP_DOUBLE: case TYP_LONG: case TYP_ULONG: { - op1 = gtNewSimdAsHWIntrinsicNode(TYP_SIMD8, op1, NI_AdvSimd_Arm64_AddPairwiseScalar, simdBaseJitType, - simdSize); - return gtNewSimdAsHWIntrinsicNode(type, op1, NI_Vector64_ToScalar, simdBaseJitType, 8); + if (simdSize == 16) + { + op1 = gtNewSimdHWIntrinsicNode(TYP_SIMD8, op1, NI_AdvSimd_Arm64_AddPairwiseScalar, simdBaseJitType, + simdSize, isSimdAsHWIntrinsic); + } + return gtNewSimdHWIntrinsicNode(type, op1, NI_Vector64_ToScalar, simdBaseJitType, 8, isSimdAsHWIntrinsic); } default: { diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 0c1b01e64ed93..3e5c612236050 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -339,6 +339,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, GenTree* op1 = nullptr; GenTree* op2 = nullptr; GenTree* op3 = nullptr; + GenTree* op4 = nullptr; switch (intrinsic) { @@ -601,11 +602,16 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - op2 = impSIMDPopStack(retType); - op1 = impSIMDPopStack(retType); + if (!varTypeIsLong(simdBaseType)) + { + var_types simdType = getSIMDTypeForSize(simdSize); - retNode = - gtNewSimdDotProdNode(retType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); + op2 = impSIMDPopStack(simdType); + op1 = impSIMDPopStack(simdType); + + retNode = gtNewSimdDotProdNode(retType, op1, op2, simdBaseJitType, simdSize, + /* isSimdAsHWIntrinsic */ false); + } break; } @@ -681,6 +687,8 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case TYP_UBYTE: { op2 = gtNewIconNode(0x80); + simdBaseType = TYP_UBYTE; + simdBaseJitType = CORINFO_TYPE_UBYTE; vectorCreateOp1 = gtNewLconNode(0x00FFFEFDFCFBFAF9); if (simdSize == 16) @@ -705,30 +713,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case TYP_INT: case TYP_UINT: - { - op2 = gtNewIconNode(0x80000000); - vectorCreateOp1 = gtNewLconNode(0xFFFFFFE2FFFFFFE1); - - if (simdSize == 16) - { - vectorCreateOp2 = gtNewLconNode(0xFFFFFFE4FFFFFFE3); - } - break; - } - - case TYP_LONG: - case TYP_ULONG: - { - op2 = gtNewLconNode(0x8000000000000000); - vectorCreateOp1 = gtNewLconNode(0xFFFFFFFFFFFFFFC1); - - if (simdSize == 16) - { - vectorCreateOp2 = gtNewLconNode(0xFFFFFFFFFFFFFFC2); - } - break; - } - case TYP_FLOAT: { op2 = gtNewIconNode(0x80000000); @@ -743,6 +727,8 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case TYP_LONG: + case TYP_ULONG: case TYP_DOUBLE: { op2 = gtNewLconNode(0x8000000000000000); @@ -774,17 +760,27 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, gtNewSimdHWIntrinsicNode(simdType, vectorCreateOp1, NI_Vector64_Create, vectorCreateType, simdSize); } + op2 = + gtNewSimdCreateBroadcastNode(simdType, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); + op1 = gtNewSimdHWIntrinsicNode(simdType, op1, op2, NI_AdvSimd_And, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); - op1 = gtNewSimdHWIntrinsicNode(simdType, op1, op3, NI_AdvSimd_ShiftLogical, simdBaseJitType, simdSize, + NamedIntrinsic shiftIntrinsic = NI_AdvSimd_ShiftLogical; + + if ((simdSize == 8) && varTypeIsLong(simdBaseType)) + { + shiftIntrinsic = NI_AdvSimd_ShiftLogicalScalar; + } + + op1 = gtNewSimdHWIntrinsicNode(simdType, op1, op3, shiftIntrinsic, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); if (varTypeIsByte(simdBaseType) && (simdSize == 16)) { - CORINFO_CLASS_HANDLE clsHnd = gtGetStructHandleForSIMD(simdType, simdBaseJitType); + CORINFO_CLASS_HANDLE simdClsHnd = gtGetStructHandleForSIMD(simdType, simdBaseJitType); - op1 = impCloneExpr(op1, &op2, clsHnd, (unsigned)CHECK_SPILL_ALL, + op1 = impCloneExpr(op1, &op2, simdClsHnd, (unsigned)CHECK_SPILL_ALL, nullptr DEBUGARG("Clone op1 for vector extractmostsignificantbits")); op1 = gtNewSimdHWIntrinsicNode(TYP_SIMD8, op1, NI_Vector128_GetLower, simdBaseJitType, simdSize, @@ -793,9 +789,9 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, /* isSimdAsHWIntrinsic */ false); op1 = gtNewSimdHWIntrinsicNode(simdBaseType, op1, NI_Vector64_ToScalar, simdBaseJitType, 8, /* isSimdAsHWIntrinsic */ false); - op1 = gtNewCastNode(TYP_INT, op1, /* isUnsigned */ true, simdBaseType); + op1 = gtNewCastNode(TYP_INT, op1, /* isUnsigned */ true, TYP_INT); - GenTree* zero = gtNewSimdHWIntrinsicNode(retType, NI_Vector128_get_Zero, simdBaseJitType, simdSize); + GenTree* zero = gtNewSimdZeroNode(simdType, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); ssize_t index = 8 / genTypeSize(simdBaseType); op2 = gtNewSimdHWIntrinsicNode(simdType, op2, zero, gtNewIconNode(index), NI_AdvSimd_ExtractVector128, @@ -806,7 +802,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, /* isSimdAsHWIntrinsic */ false); op2 = gtNewSimdHWIntrinsicNode(simdBaseType, op2, NI_Vector64_ToScalar, simdBaseJitType, 8, /* isSimdAsHWIntrinsic */ false); - op2 = gtNewCastNode(TYP_INT, op2, /* isUnsigned */ true, simdBaseType); + op2 = gtNewCastNode(TYP_INT, op2, /* isUnsigned */ true, TYP_INT); op2 = gtNewOperNode(GT_LSH, TYP_INT, op2, gtNewIconNode(8)); retNode = gtNewOperNode(GT_OR, TYP_INT, op1, op2); @@ -815,8 +811,20 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, { if (!varTypeIsLong(simdBaseType)) { - op1 = gtNewSimdHWIntrinsicNode(TYP_SIMD8, op1, NI_AdvSimd_Arm64_AddAcross, simdBaseJitType, - simdSize, /* isSimdAsHWIntrinsic */ false); + if ((simdSize == 8) && ((simdBaseType == TYP_INT) || (simdBaseType == TYP_UINT))) + { + CORINFO_CLASS_HANDLE simdClsHnd = gtGetStructHandleForSIMD(simdType, simdBaseJitType); + + op1 = impCloneExpr(op1, &op2, simdClsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for vector extractmostsignificantbits")); + op1 = gtNewSimdHWIntrinsicNode(TYP_SIMD8, op1, op2, NI_AdvSimd_AddPairwise, simdBaseJitType, + simdSize, /* isSimdAsHWIntrinsic */ false); + } + else + { + op1 = gtNewSimdHWIntrinsicNode(TYP_SIMD8, op1, NI_AdvSimd_Arm64_AddAcross, simdBaseJitType, + simdSize, /* isSimdAsHWIntrinsic */ false); + } } else if (simdSize == 16) { @@ -829,7 +837,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, if ((simdBaseType != TYP_INT) && (simdBaseType != TYP_UINT)) { - retNode = gtNewCastNode(TYP_INT, retNode, /* isUnsigned */ true, simdBaseType); + retNode = gtNewCastNode(TYP_INT, retNode, /* isUnsigned */ true, TYP_INT); } } break; @@ -1398,9 +1406,10 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_Store: { assert(sig->numArgs == 2); + var_types simdType = getSIMDTypeForSize(simdSize); op2 = impPopStack().val; - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); retNode = gtNewSimdHWIntrinsicNode(retType, op2, op1, NI_AdvSimd_Store, simdBaseJitType, simdSize); break; @@ -1410,6 +1419,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_StoreAligned: { assert(sig->numArgs == 2); + var_types simdType = getSIMDTypeForSize(simdSize); if (!opts.MinOpts()) { @@ -1419,7 +1429,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, } op2 = impPopStack().val; - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); retNode = gtNewSimdHWIntrinsicNode(retType, op2, op1, NI_AdvSimd_Store, simdBaseJitType, simdSize); break; @@ -1429,6 +1439,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_StoreAlignedNonTemporal: { assert(sig->numArgs == 2); + var_types simdType = getSIMDTypeForSize(simdSize); if (!opts.MinOpts()) { @@ -1438,7 +1449,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, } op2 = impPopStack().val; - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); // ARM64 has non-temporal stores (STNP) but we don't currently support them @@ -1449,6 +1460,8 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector64_StoreUnsafe: case NI_Vector128_StoreUnsafe: { + var_types simdType = getSIMDTypeForSize(simdSize); + if (sig->numArgs == 3) { op3 = impPopStack().val; @@ -1459,13 +1472,13 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, } op2 = impPopStack().val; - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); if (sig->numArgs == 3) { - op3 = gtNewIconNode(genTypeSize(simdBaseType), op2->TypeGet()); - op2 = gtNewOperNode(GT_MUL, op2->TypeGet(), op2, op3); - op2 = gtNewOperNode(GT_ADD, op1->TypeGet(), op1, op2); + op4 = gtNewIconNode(genTypeSize(simdBaseType), op3->TypeGet()); + op3 = gtNewOperNode(GT_MUL, op3->TypeGet(), op3, op4); + op2 = gtNewOperNode(GT_ADD, op2->TypeGet(), op2, op3); } retNode = gtNewSimdHWIntrinsicNode(retType, op2, op1, NI_AdvSimd_Store, simdBaseJitType, simdSize); @@ -1476,8 +1489,9 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_Sum: { assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); retNode = gtNewSimdSumNode(retType, op1, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); break; } diff --git a/src/coreclr/jit/hwintrinsiclistarm64.h b/src/coreclr/jit/hwintrinsiclistarm64.h index e119a38948a05..7d4582db97616 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/jit/hwintrinsiclistarm64.h @@ -42,28 +42,28 @@ HARDWARE_INTRINSIC(Vector64, ConvertToUInt64, HARDWARE_INTRINSIC(Vector64, Create, 8, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov, INS_mov, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(Vector64, CreateScalarUnsafe, 8, 1, {INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_invalid, INS_invalid, INS_fmov, INS_invalid}, HW_Category_SIMD, HW_Flag_SpecialCodeGen|HW_Flag_SupportsContainment) HARDWARE_INTRINSIC(Vector64, Divide, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, Dot, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, Dot, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, Equals, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, EqualsAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, EqualsAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, ExtractMostSignificantBits, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, EqualsAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, EqualsAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, ExtractMostSignificantBits, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, Floor, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, get_AllBitsSet, 8, 0, {INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni}, HW_Category_Helper, HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(Vector64, get_Count, 8, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(Vector64, get_Zero, 8, 0, {INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi}, HW_Category_Helper, HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(Vector64, GetElement, 8, 2, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, GreaterThan, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, GreaterThanAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, GreaterThanAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, GreaterThanAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, GreaterThanAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, GreaterThanOrEqual, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, GreaterThanOrEqualAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, GreaterThanOrEqualAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, GreaterThanOrEqualAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, GreaterThanOrEqualAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, LessThan, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, LessThanAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, LessThanAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, LessThanAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, LessThanAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, LessThanOrEqual, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, LessThanOrEqualAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, LessThanOrEqualAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, LessThanOrEqualAll, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, LessThanOrEqualAny, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, Load, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, LoadAligned, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, LoadAlignedNonTemporal, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) @@ -90,12 +90,12 @@ HARDWARE_INTRINSIC(Vector64, ShiftLeft, HARDWARE_INTRINSIC(Vector64, ShiftRightArithmetic, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, ShiftRightLogical, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, Sqrt, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, Store, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, StoreAligned, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, StoreAlignedNonTemporal, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, StoreUnsafe, 8, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, Store, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, StoreAligned, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, StoreAlignedNonTemporal, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, StoreUnsafe, 8, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, Subtract, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector64, Sum, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, Sum, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, ToScalar, 8, 1, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SIMDScalar|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector64, ToVector128, 8, 1, {INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov}, HW_Category_SIMD, HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector64, ToVector128Unsafe, 8, 1, {INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov}, HW_Category_SIMD, HW_Flag_SpecialCodeGen) @@ -140,11 +140,11 @@ HARDWARE_INTRINSIC(Vector128, ConvertToUInt64, HARDWARE_INTRINSIC(Vector128, Create, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(Vector128, CreateScalarUnsafe, 16, 1, {INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_fmov, INS_fmov}, HW_Category_SIMD, HW_Flag_SpecialCodeGen|HW_Flag_SupportsContainment) HARDWARE_INTRINSIC(Vector128, Divide, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, Dot, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, Dot, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Equals, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, EqualsAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, EqualsAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, ExtractMostSignificantBits, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, EqualsAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, EqualsAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, ExtractMostSignificantBits, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Floor, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, get_AllBitsSet, 16, 0, {INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni}, HW_Category_Helper, HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(Vector128, get_Count, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen|HW_Flag_SpecialImport) @@ -153,17 +153,17 @@ HARDWARE_INTRINSIC(Vector128, GetElement, HARDWARE_INTRINSIC(Vector128, GetLower, 16, 1, {INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov}, HW_Category_SIMD, HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector128, GetUpper, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(Vector128, GreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, GreaterThanAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, GreaterThanAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, GreaterThanAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, GreaterThanAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, LessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, LessThanAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, LessThanAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, LessThanAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, LessThanAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, LessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, LessThanOrEqualAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, LessThanOrEqualAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, LessThanOrEqualAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, LessThanOrEqualAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Load, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, LoadAligned, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, LoadAlignedNonTemporal, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) @@ -190,12 +190,12 @@ HARDWARE_INTRINSIC(Vector128, ShiftLeft, HARDWARE_INTRINSIC(Vector128, ShiftRightArithmetic, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, ShiftRightLogical, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Sqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, Store, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, StoreAligned, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, StoreAlignedNonTemporal, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, StoreUnsafe, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, Store, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, StoreAligned, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, StoreAlignedNonTemporal, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, StoreUnsafe, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Subtract, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, Sum, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, Sum, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, ToScalar, 16, 1, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SIMDScalar|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector128, WidenLower, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, WidenUpper, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index b0571e1f40f0c..7c80de358cf4e 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -59,28 +59,28 @@ HARDWARE_INTRINSIC(Vector128, ConvertToUInt64, HARDWARE_INTRINSIC(Vector128, Create, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, CreateScalarUnsafe, 16, 1, {INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movss, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector128, Divide, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, Dot, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, Dot, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Equals, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, EqualsAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, EqualsAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, ExtractMostSignificantBits, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, EqualsAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, EqualsAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, ExtractMostSignificantBits, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Floor, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, get_AllBitsSet, 16, 0, {INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_cmpps, INS_cmpps}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector128, get_Count, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, get_Zero, 16, 0, {INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector128, GetElement, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, GreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, GreaterThanAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, GreaterThanAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, GreaterThanAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, GreaterThanAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, LessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, LessThanAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, LessThanAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, LessThanAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, LessThanAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, LessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, LessThanOrEqualAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, LessThanOrEqualAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, LessThanOrEqualAll, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, LessThanOrEqualAny, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Load, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, LoadAligned, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, LoadAlignedNonTemporal, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) @@ -107,12 +107,12 @@ HARDWARE_INTRINSIC(Vector128, ShiftLeft, HARDWARE_INTRINSIC(Vector128, ShiftRightArithmetic, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, ShiftRightLogical, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Sqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, Store, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, StoreAligned, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, StoreAlignedNonTemporal, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, StoreUnsafe, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, Store, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, StoreAligned, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, StoreAlignedNonTemporal, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, StoreUnsafe, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, Subtract, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector128, Sum, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, Sum, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, ToScalar, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_movsdsse2}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector128, ToVector256, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector128, ToVector256Unsafe, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) @@ -155,11 +155,11 @@ HARDWARE_INTRINSIC(Vector256, ConvertToUInt64, HARDWARE_INTRINSIC(Vector256, Create, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, CreateScalarUnsafe, 32, 1, {INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movss, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector256, Divide, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, Dot, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, Dot, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, Equals, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, EqualsAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, EqualsAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, ExtractMostSignificantBits, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, EqualsAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, EqualsAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, ExtractMostSignificantBits, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, Floor, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, get_AllBitsSet, 32, 0, {INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_cmpps, INS_cmpps}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector256, get_Count, 32, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) @@ -167,17 +167,17 @@ HARDWARE_INTRINSIC(Vector256, get_Zero, HARDWARE_INTRINSIC(Vector256, GetElement, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, GetLower, 32, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector256, GreaterThan, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, GreaterThanAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, GreaterThanAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, GreaterThanAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, GreaterThanAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, GreaterThanOrEqual, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, GreaterThanOrEqualAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, GreaterThanOrEqualAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, GreaterThanOrEqualAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, GreaterThanOrEqualAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, LessThan, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, LessThanAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, LessThanAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, LessThanAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, LessThanAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, LessThanOrEqual, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, LessThanOrEqualAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, LessThanOrEqualAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, LessThanOrEqualAll, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, LessThanOrEqualAny, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, Load, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, LoadAligned, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, LoadAlignedNonTemporal, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) @@ -204,12 +204,12 @@ HARDWARE_INTRINSIC(Vector256, ShiftLeft, HARDWARE_INTRINSIC(Vector256, ShiftRightArithmetic, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, ShiftRightLogical, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, Sqrt, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, Store, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, StoreAligned, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, StoreAlignedNonTemporal, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, StoreUnsafe, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, Store, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, StoreAligned, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, StoreAlignedNonTemporal, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, StoreUnsafe, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, Subtract, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector256, Sum, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, Sum, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector256, ToScalar, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_movsdsse2}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector256, WidenLower, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, WidenUpper, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index e6f499588c528..f1b84825f2176 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -535,6 +535,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, GenTree* op1 = nullptr; GenTree* op2 = nullptr; GenTree* op3 = nullptr; + GenTree* op4 = nullptr; if (!featureSIMD || !IsBaselineSimdIsaSupported()) { @@ -947,6 +948,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case NI_Vector256_Dot: { assert(sig->numArgs == 2); + var_types simdType = getSIMDTypeForSize(simdSize); if (varTypeIsByte(simdBaseType) || varTypeIsLong(simdBaseType)) { @@ -973,8 +975,8 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, } } - op2 = impSIMDPopStack(retType); - op1 = impSIMDPopStack(retType); + op2 = impSIMDPopStack(simdType); + op1 = impSIMDPopStack(simdType); retNode = gtNewSimdDotProdNode(retType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); @@ -1044,24 +1046,137 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { var_types simdType = getSIMDTypeForSize(simdSize); - op1 = impSIMDPopStack(simdType); - NamedIntrinsic moveMaskIntrinsic = NI_Illegal; + NamedIntrinsic shuffleIntrinsic = NI_Illegal; + NamedIntrinsic createIntrinsic = NI_Illegal; - if (simdBaseType == TYP_FLOAT) - { - moveMaskIntrinsic = (simdSize == 32) ? NI_AVX_MoveMask : NI_SSE_MoveMask; - } - else if (simdBaseType == TYP_DOUBLE) - { - moveMaskIntrinsic = (simdSize == 32) ? NI_AVX_MoveMask : NI_SSE2_MoveMask; - } - else + switch (simdBaseType) { - moveMaskIntrinsic = (simdSize == 32) ? NI_AVX2_MoveMask : NI_SSE2_MoveMask; - simdBaseJitType = varTypeIsUnsigned(simdBaseType) ? CORINFO_TYPE_UBYTE : CORINFO_TYPE_BYTE; + case TYP_BYTE: + case TYP_UBYTE: + { + op1 = impSIMDPopStack(simdType); + moveMaskIntrinsic = (simdSize == 32) ? NI_AVX2_MoveMask : NI_SSE2_MoveMask; + break; + } + + case TYP_SHORT: + case TYP_USHORT: + { + simdBaseJitType = varTypeIsUnsigned(simdBaseType) ? CORINFO_TYPE_UBYTE : CORINFO_TYPE_BYTE; + + assert((simdSize == 16) || (simdSize == 32)); + IntrinsicNodeBuilder nodeBuilder(getAllocator(CMK_ASTNode), simdSize); + + // We want to tightly pack the most significant byte of each short/ushort + // and then zero the tightly packed least significant bytes + + nodeBuilder.AddOperand(0x00, gtNewIconNode(0x01)); + nodeBuilder.AddOperand(0x01, gtNewIconNode(0x03)); + nodeBuilder.AddOperand(0x02, gtNewIconNode(0x05)); + nodeBuilder.AddOperand(0x03, gtNewIconNode(0x07)); + nodeBuilder.AddOperand(0x04, gtNewIconNode(0x09)); + nodeBuilder.AddOperand(0x05, gtNewIconNode(0x0B)); + nodeBuilder.AddOperand(0x06, gtNewIconNode(0x0D)); + nodeBuilder.AddOperand(0x07, gtNewIconNode(0x0F)); + + for (unsigned i = 0x08; i < 0x10; i++) + { + // The most significant bit being set means zero the value + nodeBuilder.AddOperand(i, gtNewIconNode(0x80)); + } + + if (simdSize == 32) + { + // Vector256 works on 2x128-bit lanes, so repeat the same indices for the upper lane + + nodeBuilder.AddOperand(0x10, gtNewIconNode(0x01)); + nodeBuilder.AddOperand(0x11, gtNewIconNode(0x03)); + nodeBuilder.AddOperand(0x12, gtNewIconNode(0x05)); + nodeBuilder.AddOperand(0x13, gtNewIconNode(0x07)); + nodeBuilder.AddOperand(0x14, gtNewIconNode(0x09)); + nodeBuilder.AddOperand(0x15, gtNewIconNode(0x0B)); + nodeBuilder.AddOperand(0x16, gtNewIconNode(0x0D)); + nodeBuilder.AddOperand(0x17, gtNewIconNode(0x0F)); + + for (unsigned i = 0x18; i < 0x20; i++) + { + // The most significant bit being set means zero the value + nodeBuilder.AddOperand(i, gtNewIconNode(0x80)); + } + + createIntrinsic = NI_Vector256_Create; + shuffleIntrinsic = NI_AVX2_Shuffle; + moveMaskIntrinsic = NI_AVX2_MoveMask; + } + else if (compOpportunisticallyDependsOn(InstructionSet_SSSE3)) + { + createIntrinsic = NI_Vector128_Create; + shuffleIntrinsic = NI_SSSE3_Shuffle; + moveMaskIntrinsic = NI_SSE2_MoveMask; + } + else + { + return nullptr; + } + + op2 = gtNewSimdHWIntrinsicNode(simdType, std::move(nodeBuilder), createIntrinsic, + simdBaseJitType, simdSize); + + op1 = impSIMDPopStack(simdType); + op1 = gtNewSimdHWIntrinsicNode(simdType, op1, op2, shuffleIntrinsic, simdBaseJitType, simdSize); + + if (simdSize == 32) + { + CorInfoType simdOtherJitType; + + // Since Vector256 is 2x128-bit lanes we need a full width permutation so we get the lower + // 64-bits of each lane next to eachother. The upper bits should be zero, but also don't + // matter so we can also then simplify down to a 128-bit move mask. + + simdOtherJitType = (simdBaseType == TYP_UBYTE) ? CORINFO_TYPE_ULONG : CORINFO_TYPE_LONG; + + op1 = gtNewSimdHWIntrinsicNode(simdType, op1, gtNewIconNode(0xD8), NI_AVX2_Permute4x64, + simdOtherJitType, simdSize); + + simdSize = 16; + simdType = TYP_SIMD16; + + op1 = gtNewSimdHWIntrinsicNode(simdType, op1, NI_Vector256_GetLower, simdBaseJitType, + simdSize); + } + break; + } + + case TYP_INT: + case TYP_UINT: + case TYP_FLOAT: + { + simdBaseJitType = CORINFO_TYPE_FLOAT; + op1 = impSIMDPopStack(simdType); + moveMaskIntrinsic = (simdSize == 32) ? NI_AVX_MoveMask : NI_SSE_MoveMask; + break; + } + + case TYP_LONG: + case TYP_ULONG: + case TYP_DOUBLE: + { + simdBaseJitType = CORINFO_TYPE_DOUBLE; + op1 = impSIMDPopStack(simdType); + moveMaskIntrinsic = (simdSize == 32) ? NI_AVX_MoveMask : NI_SSE2_MoveMask; + break; + } + + default: + { + unreached(); + } } + assert(moveMaskIntrinsic != NI_Illegal); + assert(op1 != nullptr); + retNode = gtNewSimdHWIntrinsicNode(retType, op1, moveMaskIntrinsic, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); } @@ -1780,9 +1895,10 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case NI_Vector256_Store: { assert(sig->numArgs == 2); + var_types simdType = getSIMDTypeForSize(simdSize); op2 = impPopStack().val; - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); NamedIntrinsic storeIntrinsic = NI_Illegal; @@ -1807,9 +1923,10 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case NI_Vector256_StoreAligned: { assert(sig->numArgs == 2); + var_types simdType = getSIMDTypeForSize(simdSize); op2 = impPopStack().val; - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); NamedIntrinsic storeIntrinsic = NI_Illegal; @@ -1834,9 +1951,10 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case NI_Vector256_StoreAlignedNonTemporal: { assert(sig->numArgs == 2); + var_types simdType = getSIMDTypeForSize(simdSize); op2 = impPopStack().val; - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); NamedIntrinsic storeIntrinsic = NI_Illegal; @@ -1860,6 +1978,8 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_StoreUnsafe: case NI_Vector256_StoreUnsafe: { + var_types simdType = getSIMDTypeForSize(simdSize); + if (sig->numArgs == 3) { op3 = impPopStack().val; @@ -1870,13 +1990,13 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, } op2 = impPopStack().val; - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); if (sig->numArgs == 3) { - op3 = gtNewIconNode(genTypeSize(simdBaseType), op2->TypeGet()); - op2 = gtNewOperNode(GT_MUL, op2->TypeGet(), op2, op3); - op2 = gtNewOperNode(GT_ADD, op1->TypeGet(), op1, op2); + op4 = gtNewIconNode(genTypeSize(simdBaseType), op3->TypeGet()); + op3 = gtNewOperNode(GT_MUL, op3->TypeGet(), op3, op4); + op2 = gtNewOperNode(GT_ADD, op2->TypeGet(), op2, op3); } NamedIntrinsic storeIntrinsic = NI_Illegal; @@ -1902,6 +2022,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case NI_Vector256_Sum: { assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); if (varTypeIsFloating(simdBaseType)) { @@ -1922,7 +2043,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, break; } - op1 = impSIMDPopStack(retType); + op1 = impSIMDPopStack(simdType); retNode = gtNewSimdSumNode(retType, op1, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); break; } diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index 192c4abfc4386..e1812d7e8df6f 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -874,8 +874,8 @@ void Lowering::LowerHWIntrinsicCmpOp(GenTreeHWIntrinsic* node, genTreeOps cmpOp) GenTree* insCns = comp->gtNewIconNode(-1, TYP_INT); BlockRange().InsertAfter(idxCns, insCns); - GenTree* tmp = comp->gtNewSimdAsHWIntrinsicNode(simdType, cmp, idxCns, insCns, NI_AdvSimd_Insert, - CORINFO_TYPE_INT, simdSize); + GenTree* tmp = comp->gtNewSimdHWIntrinsicNode(simdType, cmp, idxCns, insCns, NI_AdvSimd_Insert, + CORINFO_TYPE_INT, simdSize); BlockRange().InsertAfter(insCns, tmp); LowerNode(tmp); @@ -891,7 +891,7 @@ void Lowering::LowerHWIntrinsicCmpOp(GenTreeHWIntrinsic* node, genTreeOps cmpOp) BlockRange().InsertAfter(msk, zroCns); GenTree* val = - comp->gtNewSimdAsHWIntrinsicNode(TYP_UBYTE, msk, zroCns, NI_AdvSimd_Extract, CORINFO_TYPE_UBYTE, simdSize); + comp->gtNewSimdHWIntrinsicNode(TYP_UBYTE, msk, zroCns, NI_AdvSimd_Extract, CORINFO_TYPE_UBYTE, simdSize); BlockRange().InsertAfter(zroCns, val); LowerNode(val); @@ -1169,7 +1169,7 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) BlockRange().InsertAfter(idx, tmp1); LowerNode(tmp1); - op1 = comp->gtNewSimdAsHWIntrinsicNode(simdType, op1, idx, tmp1, NI_AdvSimd_Insert, simdBaseJitType, simdSize); + op1 = comp->gtNewSimdHWIntrinsicNode(simdType, op1, idx, tmp1, NI_AdvSimd_Insert, simdBaseJitType, simdSize); BlockRange().InsertAfter(tmp1, op1); LowerNode(op1); @@ -1180,7 +1180,7 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) BlockRange().InsertAfter(idx, tmp2); LowerNode(tmp2); - op2 = comp->gtNewSimdAsHWIntrinsicNode(simdType, op2, idx, tmp2, NI_AdvSimd_Insert, simdBaseJitType, simdSize); + op2 = comp->gtNewSimdHWIntrinsicNode(simdType, op2, idx, tmp2, NI_AdvSimd_Insert, simdBaseJitType, simdSize); BlockRange().InsertAfter(tmp2, op2); LowerNode(op2); } @@ -1205,32 +1205,35 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) } assert(!varTypeIsLong(simdBaseType)); - tmp1 = comp->gtNewSimdAsHWIntrinsicNode(simdType, op1, op2, multiply, simdBaseJitType, simdSize); + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, op1, op2, multiply, simdBaseJitType, simdSize); BlockRange().InsertBefore(node, tmp1); LowerNode(tmp1); if (varTypeIsFloating(simdBaseType)) { - // We will be constructing the following parts: - // ... - // /--* tmp1 simd16 - // * STORE_LCL_VAR simd16 - // tmp1 = LCL_VAR simd16 - // tmp2 = LCL_VAR simd16 - // ... + if ((simdSize != 8) || (simdBaseType == TYP_FLOAT)) + { + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // * STORE_LCL_VAR simd16 + // tmp1 = LCL_VAR simd16 + // tmp2 = LCL_VAR simd16 + // ... - // This is roughly the following managed code: - // ... - // var tmp2 = tmp1; - // ... + // This is roughly the following managed code: + // ... + // var tmp2 = tmp1; + // ... - node->Op(1) = tmp1; - LIR::Use tmp1Use(BlockRange(), &node->Op(1), node); - ReplaceWithLclVar(tmp1Use); - tmp1 = node->Op(1); + node->Op(1) = tmp1; + LIR::Use tmp1Use(BlockRange(), &node->Op(1), node); + ReplaceWithLclVar(tmp1Use); + tmp1 = node->Op(1); - tmp2 = comp->gtClone(tmp1); - BlockRange().InsertAfter(tmp1, tmp2); + tmp2 = comp->gtClone(tmp1); + BlockRange().InsertAfter(tmp1, tmp2); + } if (simdSize == 8) { @@ -1248,8 +1251,8 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) // var tmp1 = AdvSimd.AddPairwise(tmp1, tmp2); // ... - tmp1 = comp->gtNewSimdAsHWIntrinsicNode(simdType, tmp1, tmp2, NI_AdvSimd_AddPairwise, simdBaseJitType, - simdSize); + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, tmp2, NI_AdvSimd_AddPairwise, simdBaseJitType, + simdSize); BlockRange().InsertAfter(tmp2, tmp1); LowerNode(tmp1); } @@ -1274,8 +1277,8 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) // var tmp1 = AdvSimd.Arm64.AddPairwise(tmp1, tmp2); // ... - tmp1 = comp->gtNewSimdAsHWIntrinsicNode(simdType, tmp1, tmp2, NI_AdvSimd_Arm64_AddPairwise, simdBaseJitType, - simdSize); + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, tmp2, NI_AdvSimd_Arm64_AddPairwise, simdBaseJitType, + simdSize); BlockRange().InsertAfter(tmp2, tmp1); LowerNode(tmp1); @@ -1313,8 +1316,8 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) tmp2 = comp->gtClone(tmp1); BlockRange().InsertAfter(tmp1, tmp2); - tmp1 = comp->gtNewSimdAsHWIntrinsicNode(simdType, tmp1, tmp2, NI_AdvSimd_Arm64_AddPairwise, - simdBaseJitType, simdSize); + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, tmp2, NI_AdvSimd_Arm64_AddPairwise, + simdBaseJitType, simdSize); BlockRange().InsertAfter(tmp2, tmp1); LowerNode(tmp1); } @@ -1326,20 +1329,66 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) { assert(varTypeIsIntegral(simdBaseType)); - // We will be constructing the following parts: - // ... - // /--* tmp1 simd16 - // tmp2 = * HWINTRINSIC simd16 T AddAcross - // ... + if ((simdSize == 8) && ((simdBaseType == TYP_INT) || (simdBaseType == TYP_UINT))) + { + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // * STORE_LCL_VAR simd16 + // tmp1 = LCL_VAR simd16 + // tmp2 = LCL_VAR simd16 + // ... - // This is roughly the following managed code: - // ... - // var tmp2 = AdvSimd.Arm64.AddAcross(tmp1); - // ... + // This is roughly the following managed code: + // ... + // var tmp2 = tmp1; + // ... - tmp2 = comp->gtNewSimdAsHWIntrinsicNode(simdType, tmp1, NI_AdvSimd_Arm64_AddAcross, simdBaseJitType, simdSize); - BlockRange().InsertAfter(tmp1, tmp2); - LowerNode(tmp2); + node->Op(1) = tmp1; + LIR::Use tmp1Use(BlockRange(), &node->Op(1), node); + ReplaceWithLclVar(tmp1Use); + tmp1 = node->Op(1); + + tmp2 = comp->gtClone(tmp1); + BlockRange().InsertAfter(tmp1, tmp2); + + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // /--* tmp2 simd16 + // tmp2 = * HWINTRINSIC simd8 T AddPairwise + // ... + + // This is roughly the following managed code: + // ... + // var tmp2 = AdvSimd.AddPairwise(tmp1, tmp2); + // ... + + tmp1 = + comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, tmp2, NI_AdvSimd_AddPairwise, simdBaseJitType, simdSize); + BlockRange().InsertAfter(tmp2, tmp1); + LowerNode(tmp1); + + tmp2 = tmp1; + } + else + { + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // tmp2 = * HWINTRINSIC simd16 T AddAcross + // ... + + // This is roughly the following managed code: + // ... + // var tmp2 = AdvSimd.Arm64.AddAcross(tmp1); + // ... + + tmp2 = + comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, NI_AdvSimd_Arm64_AddAcross, simdBaseJitType, simdSize); + BlockRange().InsertAfter(tmp1, tmp2); + LowerNode(tmp2); + } } // We will be constructing the following parts: diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 0d2acef315a98..413e4ba74a6a4 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -3047,8 +3047,6 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) if (simdSize == 32) { - assert(comp->compIsaSupportedDebugOnly(InstructionSet_AVX2)); - switch (simdBaseType) { case TYP_SHORT: @@ -3056,6 +3054,8 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) case TYP_INT: case TYP_UINT: { + assert(comp->compIsaSupportedDebugOnly(InstructionSet_AVX2)); + multiply = NI_AVX2_MultiplyLow; horizontalAdd = NI_AVX2_HorizontalAdd; add = NI_AVX2_Add; @@ -3064,6 +3064,8 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) case TYP_FLOAT: { + assert(comp->compIsaSupportedDebugOnly(InstructionSet_AVX)); + // We will be constructing the following parts: // idx = CNS_INT int 0xF1 // /--* op1 simd16 @@ -3127,6 +3129,8 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) case TYP_DOUBLE: { + assert(comp->compIsaSupportedDebugOnly(InstructionSet_AVX)); + multiply = NI_AVX_Multiply; horizontalAdd = NI_AVX_HorizontalAdd; add = NI_AVX_Add; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 6d82ccc8aad53..9dba4bcf29c18 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -2389,11 +2389,12 @@ public static T Dot(Vector256 left, Vector256 right) { T result = default; - for (int index = 0; index < Vector256.Count; index++) - { - T value = Scalar.Multiply(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); - result = Scalar.Add(result, value); - } + // Doing this as Dot(lower) + Dot(upper) is important for floating-point determinism + // This is because the underlying dpps instruction on x86/x64 will do this equivalently + // and otherwise the software vs accelerated implementations may differ in returned result. + + result = Scalar.Add(result, Vector128.Dot(left.GetLower(), right.GetLower())); + result = Scalar.Add(result, Vector128.Dot(left.GetUpper(), right.GetUpper())); return result; } diff --git a/src/tests/JIT/HardwareIntrinsics/General/Shared/VectorDotTest.template b/src/tests/JIT/HardwareIntrinsics/General/Shared/VectorDotTest.template index 1ce27afea848f..4c1a118bf4ffd 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Shared/VectorDotTest.template +++ b/src/tests/JIT/HardwareIntrinsics/General/Shared/VectorDotTest.template @@ -292,12 +292,20 @@ namespace JIT.HardwareIntrinsics.General bool succeeded = true; {RetBaseType} actualResult = default; + {RetBaseType} intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += ({RetBaseType})(left[i] * right[i]); + if ((i % Vector128<{Op1BaseType}>.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += ({RetBaseType})(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Byte.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Byte.cs index b47e148e18b67..1b5ea700a92bd 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Byte.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Byte.cs @@ -292,12 +292,20 @@ private void ValidateResult(Byte[] left, Byte[] right, Byte result, [CallerMembe bool succeeded = true; Byte actualResult = default; + Byte intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Byte)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Byte)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Double.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Double.cs index 83c5af2fadf54..3536b176fd1e1 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Double.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Double.cs @@ -292,12 +292,20 @@ private void ValidateResult(Double[] left, Double[] right, Double result, [Calle bool succeeded = true; Double actualResult = default; + Double intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Double)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Double)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int16.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int16.cs index 76fda4aba92fd..81309878d06ca 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int16.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int16.cs @@ -292,12 +292,20 @@ private void ValidateResult(Int16[] left, Int16[] right, Int16 result, [CallerMe bool succeeded = true; Int16 actualResult = default; + Int16 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Int16)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Int16)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int32.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int32.cs index 4c009089fab18..8d43f641710e2 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int32.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int32.cs @@ -292,12 +292,20 @@ private void ValidateResult(Int32[] left, Int32[] right, Int32 result, [CallerMe bool succeeded = true; Int32 actualResult = default; + Int32 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Int32)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Int32)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int64.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int64.cs index fb06bc4a819e2..58290b2dacb86 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int64.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Int64.cs @@ -292,12 +292,20 @@ private void ValidateResult(Int64[] left, Int64[] right, Int64 result, [CallerMe bool succeeded = true; Int64 actualResult = default; + Int64 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Int64)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Int64)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.SByte.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.SByte.cs index f48ccd4a2b7de..cff451915fbdf 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.SByte.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.SByte.cs @@ -292,12 +292,20 @@ private void ValidateResult(SByte[] left, SByte[] right, SByte result, [CallerMe bool succeeded = true; SByte actualResult = default; + SByte intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (SByte)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (SByte)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Single.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Single.cs index fa8cc2f3d1cf9..7d8da79078983 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Single.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.Single.cs @@ -292,12 +292,20 @@ private void ValidateResult(Single[] left, Single[] right, Single result, [Calle bool succeeded = true; Single actualResult = default; + Single intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Single)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Single)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt16.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt16.cs index 69a9398548ffb..24b2373f0389f 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt16.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt16.cs @@ -292,12 +292,20 @@ private void ValidateResult(UInt16[] left, UInt16[] right, UInt16 result, [Calle bool succeeded = true; UInt16 actualResult = default; + UInt16 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (UInt16)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (UInt16)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt32.cs index a64294fd81ce3..2d3938ee276ec 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt32.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt32.cs @@ -292,12 +292,20 @@ private void ValidateResult(UInt32[] left, UInt32[] right, UInt32 result, [Calle bool succeeded = true; UInt32 actualResult = default; + UInt32 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (UInt32)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (UInt32)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt64.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt64.cs index 107e290548444..857fc0b40cc5b 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt64.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector128/Dot.UInt64.cs @@ -292,12 +292,20 @@ private void ValidateResult(UInt64[] left, UInt64[] right, UInt64 result, [Calle bool succeeded = true; UInt64 actualResult = default; + UInt64 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (UInt64)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (UInt64)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Byte.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Byte.cs index 83747a6dceac9..5caa395f64971 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Byte.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Byte.cs @@ -292,12 +292,20 @@ private void ValidateResult(Byte[] left, Byte[] right, Byte result, [CallerMembe bool succeeded = true; Byte actualResult = default; + Byte intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Byte)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Byte)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Double.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Double.cs index ab68e695516e2..a23b1243101d1 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Double.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Double.cs @@ -292,12 +292,20 @@ private void ValidateResult(Double[] left, Double[] right, Double result, [Calle bool succeeded = true; Double actualResult = default; + Double intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Double)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Double)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int16.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int16.cs index 2ddda2b99ba9b..9a7eabec83c22 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int16.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int16.cs @@ -292,12 +292,20 @@ private void ValidateResult(Int16[] left, Int16[] right, Int16 result, [CallerMe bool succeeded = true; Int16 actualResult = default; + Int16 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Int16)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Int16)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int32.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int32.cs index 2ccb11f221fac..50c9043847421 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int32.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int32.cs @@ -292,12 +292,20 @@ private void ValidateResult(Int32[] left, Int32[] right, Int32 result, [CallerMe bool succeeded = true; Int32 actualResult = default; + Int32 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Int32)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Int32)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int64.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int64.cs index 986f169835cc8..f60de061554ff 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int64.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Int64.cs @@ -292,12 +292,20 @@ private void ValidateResult(Int64[] left, Int64[] right, Int64 result, [CallerMe bool succeeded = true; Int64 actualResult = default; + Int64 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Int64)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Int64)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.SByte.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.SByte.cs index b911d6f1386dd..ee6db7af26a83 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.SByte.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.SByte.cs @@ -292,12 +292,20 @@ private void ValidateResult(SByte[] left, SByte[] right, SByte result, [CallerMe bool succeeded = true; SByte actualResult = default; + SByte intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (SByte)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (SByte)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Single.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Single.cs index b79bd666e1918..a67955e62e58c 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Single.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.Single.cs @@ -292,12 +292,20 @@ private void ValidateResult(Single[] left, Single[] right, Single result, [Calle bool succeeded = true; Single actualResult = default; + Single intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Single)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Single)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt16.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt16.cs index 8f1dd9dc151ff..41d65f320ebae 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt16.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt16.cs @@ -292,12 +292,20 @@ private void ValidateResult(UInt16[] left, UInt16[] right, UInt16 result, [Calle bool succeeded = true; UInt16 actualResult = default; + UInt16 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (UInt16)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (UInt16)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt32.cs index 6e4896091879a..51bead414374b 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt32.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt32.cs @@ -292,12 +292,20 @@ private void ValidateResult(UInt32[] left, UInt32[] right, UInt32 result, [Calle bool succeeded = true; UInt32 actualResult = default; + UInt32 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (UInt32)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (UInt32)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt64.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt64.cs index 06efcedd2a21f..dd4bbf866cb1b 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt64.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Dot.UInt64.cs @@ -292,12 +292,20 @@ private void ValidateResult(UInt64[] left, UInt64[] right, UInt64 result, [Calle bool succeeded = true; UInt64 actualResult = default; + UInt64 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (UInt64)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (UInt64)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Byte.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Byte.cs index ff7cb0002b986..4a8fedd70e41b 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Byte.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Byte.cs @@ -292,12 +292,20 @@ private void ValidateResult(Byte[] left, Byte[] right, Byte result, [CallerMembe bool succeeded = true; Byte actualResult = default; + Byte intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Byte)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Byte)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Double.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Double.cs index 0d45f6141701e..f2dc915d8f5f0 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Double.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Double.cs @@ -292,12 +292,20 @@ private void ValidateResult(Double[] left, Double[] right, Double result, [Calle bool succeeded = true; Double actualResult = default; + Double intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Double)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Double)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int16.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int16.cs index 9157e7e74ef04..5284a97fb9ae6 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int16.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int16.cs @@ -292,12 +292,20 @@ private void ValidateResult(Int16[] left, Int16[] right, Int16 result, [CallerMe bool succeeded = true; Int16 actualResult = default; + Int16 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Int16)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Int16)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int32.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int32.cs index a679da2b0b0d1..475030d60dc2c 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int32.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int32.cs @@ -292,12 +292,20 @@ private void ValidateResult(Int32[] left, Int32[] right, Int32 result, [CallerMe bool succeeded = true; Int32 actualResult = default; + Int32 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Int32)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Int32)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int64.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int64.cs index d75a81fa8e6ee..4a4a585c0bd24 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int64.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Int64.cs @@ -292,12 +292,20 @@ private void ValidateResult(Int64[] left, Int64[] right, Int64 result, [CallerMe bool succeeded = true; Int64 actualResult = default; + Int64 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Int64)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Int64)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.SByte.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.SByte.cs index 8e0702b107d84..ede755893fa9e 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.SByte.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.SByte.cs @@ -292,12 +292,20 @@ private void ValidateResult(SByte[] left, SByte[] right, SByte result, [CallerMe bool succeeded = true; SByte actualResult = default; + SByte intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (SByte)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (SByte)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Single.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Single.cs index 5ec606f2ebe8d..35458c0ea7233 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Single.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.Single.cs @@ -292,12 +292,20 @@ private void ValidateResult(Single[] left, Single[] right, Single result, [Calle bool succeeded = true; Single actualResult = default; + Single intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (Single)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (Single)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt16.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt16.cs index 44bb84adf3168..48281f753dd49 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt16.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt16.cs @@ -292,12 +292,20 @@ private void ValidateResult(UInt16[] left, UInt16[] right, UInt16 result, [Calle bool succeeded = true; UInt16 actualResult = default; + UInt16 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (UInt16)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (UInt16)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt32.cs index 47cf417978b53..f5fad8875afb6 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt32.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt32.cs @@ -292,12 +292,20 @@ private void ValidateResult(UInt32[] left, UInt32[] right, UInt32 result, [Calle bool succeeded = true; UInt32 actualResult = default; + UInt32 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (UInt32)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (UInt32)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt64.cs b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt64.cs index 448ae871bb2ca..d3ad3662cfbcc 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt64.cs +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Dot.UInt64.cs @@ -292,12 +292,20 @@ private void ValidateResult(UInt64[] left, UInt64[] right, UInt64 result, [Calle bool succeeded = true; UInt64 actualResult = default; + UInt64 intermResult = default; for (var i = 0; i < Op1ElementCount; i++) { - actualResult += (UInt64)(left[i] * right[i]); + if ((i % Vector128.Count) == 0) + { + actualResult += intermResult; + intermResult = default; + } + intermResult += (UInt64)(left[i] * right[i]); } + actualResult += intermResult; + if (actualResult != result) { succeeded = false; From 11f9949bf2509dd9abd3e8c44a4823b71a7b2b5a Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 21 Jan 2022 15:10:28 -0500 Subject: [PATCH 124/308] RegexNode cleanup (#64074) No functional changes, just code cleanup: - Move node types into a RegexNodeKind enum - Rename some of the kinds to make them more descriptive - Rename node.Next to node.Parent to better describe its purpose - Add a bunch of comments about node kinds --- .../gen/RegexGenerator.Emitter.cs | 320 ++--- .../gen/Resources/Strings.resx | 3 - .../gen/Resources/xlf/Strings.cs.xlf | 5 - .../gen/Resources/xlf/Strings.de.xlf | 5 - .../gen/Resources/xlf/Strings.es.xlf | 5 - .../gen/Resources/xlf/Strings.fr.xlf | 5 - .../gen/Resources/xlf/Strings.it.xlf | 5 - .../gen/Resources/xlf/Strings.ja.xlf | 5 - .../gen/Resources/xlf/Strings.ko.xlf | 5 - .../gen/Resources/xlf/Strings.pl.xlf | 5 - .../gen/Resources/xlf/Strings.pt-BR.xlf | 5 - .../gen/Resources/xlf/Strings.ru.xlf | 5 - .../gen/Resources/xlf/Strings.tr.xlf | 5 - .../gen/Resources/xlf/Strings.zh-Hans.xlf | 5 - .../gen/Resources/xlf/Strings.zh-Hant.xlf | 5 - ...m.Text.RegularExpressions.Generator.csproj | 1 + .../src/Resources/Strings.resx | 3 - .../src/System.Text.RegularExpressions.csproj | 1 + .../Text/RegularExpressions/RegexCode.cs | 3 +- .../Text/RegularExpressions/RegexCompiler.cs | 178 +-- .../RegexFindOptimizations.cs | 2 +- .../Text/RegularExpressions/RegexNode.cs | 1063 ++++++++--------- .../Text/RegularExpressions/RegexNodeKind.cs | 182 +++ .../Text/RegularExpressions/RegexParser.cs | 133 +-- .../RegularExpressions/RegexPrefixAnalyzer.cs | 277 ++--- .../RegularExpressions/RegexReplacement.cs | 10 +- .../Text/RegularExpressions/RegexWriter.cs | 144 +-- .../Symbolic/RegexNodeToSymbolicConverter.cs | 111 +- 28 files changed, 1252 insertions(+), 1244 deletions(-) create mode 100644 src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNodeKind.cs diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index d3b724985d2c1..fabe62f5262ec 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -592,7 +592,7 @@ void EmitLiteralAfterAtomicLoop() Debug.Assert(code.FindOptimizations.LiteralAfterLoop is not null); (RegexNode LoopNode, (char Char, string? String, char[]? Chars) Literal) target = code.FindOptimizations.LiteralAfterLoop.Value; - Debug.Assert(target.LoopNode.Type is RegexNode.Setloop or RegexNode.Setlazy or RegexNode.Setloopatomic); + Debug.Assert(target.LoopNode.Kind is RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic); Debug.Assert(target.LoopNode.N == int.MaxValue); using (EmitBlock(writer, "while (true)")) @@ -705,24 +705,24 @@ private static RequiredHelperFunctions EmitGo(IndentedTextWriter writer, RegexMe // Every RegexTree is rooted in the implicit Capture for the whole expression. // Skip the Capture node. We handle the implicit root capture specially. RegexNode node = code.Tree.Root; - Debug.Assert(node.Type == RegexNode.Capture, "Every generated tree should begin with a capture node"); + Debug.Assert(node.Kind == RegexNodeKind.Capture, "Every generated tree should begin with a capture node"); Debug.Assert(node.ChildCount() == 1, "Capture nodes should have one child"); node = node.Child(0); // In some limited cases, FindFirstChar will only return true if it successfully matched the whole expression. // We can special case these to do essentially nothing in Go other than emit the capture. - switch (node.Type) + switch (node.Kind) { - case RegexNode.Multi or RegexNode.Notone or RegexNode.One or RegexNode.Set when !IsCaseInsensitive(node): + case RegexNodeKind.Multi or RegexNodeKind.Notone or RegexNodeKind.One or RegexNodeKind.Set when !IsCaseInsensitive(node): // This is the case for single and multiple characters, though the whole thing is only guaranteed // to have been validated in FindFirstChar when doing case-sensitive comparison. writer.WriteLine($"int start = base.runtextpos;"); - writer.WriteLine($"int end = start + {(node.Type == RegexNode.Multi ? node.Str!.Length : 1)};"); + writer.WriteLine($"int end = start + {(node.Kind == RegexNodeKind.Multi ? node.Str!.Length : 1)};"); writer.WriteLine("base.Capture(0, start, end);"); writer.WriteLine("base.runtextpos = end;"); return requiredHelpers; - case RegexNode.Empty: + case RegexNodeKind.Empty: // This case isn't common in production, but it's very common when first getting started with the // source generator and seeing what happens as you add more to expressions. When approaching // it from a learning perspective, this is very common, as it's the empty string you start with. @@ -881,7 +881,7 @@ void TransferSliceStaticPosToPos() // Emits the code for an alternation. void EmitAlternation(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Alternate, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Alternate, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() >= 2, $"Expected at least 2 children, found {node.ChildCount()}"); int childCount = node.ChildCount(); @@ -892,7 +892,7 @@ void EmitAlternation(RegexNode node) // Both atomic and non-atomic are supported. While a parent RegexNode.Atomic node will itself // successfully prevent backtracking into this child node, we can emit better / cheaper code // for an Alternate when it is atomic, so we still take it into account here. - Debug.Assert(node.Next is not null); + Debug.Assert(node.Parent is not null); bool isAtomic = node.IsAtomicByParent(); // If no child branch overlaps with another child branch, we can emit more streamlined code @@ -938,7 +938,7 @@ void EmitAlternation(RegexNode node) // If it's a One or a Multi, get the first character and add it to the set. // If it was already in the set, we can't apply this optimization. - if (oneMultiOrSet.Type is RegexNode.One or RegexNode.Multi) + if (oneMultiOrSet.Kind is RegexNodeKind.One or RegexNodeKind.Multi) { if (!seenChars.Add(oneMultiOrSet.FirstCharOfOneOrMulti())) { @@ -950,7 +950,7 @@ void EmitAlternation(RegexNode node) { // The branch begins with a set. Make sure it's a set of only a few characters // and get them. If we can't, we can't apply this optimization. - Debug.Assert(oneMultiOrSet.Type is RegexNode.Set); + Debug.Assert(oneMultiOrSet.Kind is RegexNodeKind.Set); int numChars; if (RegexCharClass.IsNegated(oneMultiOrSet.Str!) || (numChars = RegexCharClass.GetSetChars(oneMultiOrSet.Str!, setChars)) == 0) @@ -1006,14 +1006,14 @@ void EmitSwitchedBranches() sliceStaticPos = startingSliceStaticPos; RegexNode child = node.Child(i); - Debug.Assert(child.Type is RegexNode.One or RegexNode.Multi or RegexNode.Set or RegexNode.Concatenate, DescribeNode(child, rm.Code)); - Debug.Assert(child.Type is not RegexNode.Concatenate || (child.ChildCount() >= 2 && child.Child(0).Type is RegexNode.One or RegexNode.Multi or RegexNode.Set)); + Debug.Assert(child.Kind is RegexNodeKind.One or RegexNodeKind.Multi or RegexNodeKind.Set or RegexNodeKind.Concatenate, DescribeNode(child, rm.Code)); + Debug.Assert(child.Kind is not RegexNodeKind.Concatenate || (child.ChildCount() >= 2 && child.Child(0).Kind is RegexNodeKind.One or RegexNodeKind.Multi or RegexNodeKind.Set)); RegexNode? childStart = child.FindBranchOneMultiOrSetStart(); Debug.Assert(childStart is not null, "Unexpectedly couldn't find the branch starting node."); Debug.Assert((childStart.Options & RegexOptions.IgnoreCase) == 0, "Expected only to find non-IgnoreCase branch starts"); - if (childStart.Type is RegexNode.Set) + if (childStart.Kind is RegexNodeKind.Set) { int numChars = RegexCharClass.GetSetChars(childStart.Str!, setChars); Debug.Assert(numChars != 0); @@ -1026,16 +1026,16 @@ void EmitSwitchedBranches() writer.Indent++; // Emit the code for the branch, without the first character that was already matched in the switch. - switch (child.Type) + switch (child.Kind) { - case RegexNode.Multi: + case RegexNodeKind.Multi: EmitNode(CloneMultiWithoutFirstChar(child)); writer.WriteLine(); break; - case RegexNode.Concatenate: - var newConcat = new RegexNode(RegexNode.Concatenate, child.Options); - if (childStart.Type == RegexNode.Multi) + case RegexNodeKind.Concatenate: + var newConcat = new RegexNode(RegexNodeKind.Concatenate, child.Options); + if (childStart.Kind == RegexNodeKind.Multi) { newConcat.AddChild(CloneMultiWithoutFirstChar(childStart)); } @@ -1050,11 +1050,11 @@ void EmitSwitchedBranches() static RegexNode CloneMultiWithoutFirstChar(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Multi); + Debug.Assert(node.Kind is RegexNodeKind.Multi); Debug.Assert(node.Str!.Length >= 2); return node.Str!.Length == 2 ? - new RegexNode(RegexNode.One, node.Options, node.Str![1]) : - new RegexNode(RegexNode.Multi, node.Options, node.Str!.Substring(1)); + new RegexNode(RegexNodeKind.One, node.Options, node.Str![1]) : + new RegexNode(RegexNodeKind.Multi, node.Options, node.Str!.Substring(1)); } } @@ -1240,7 +1240,7 @@ void EmitAllBranches() // Emits the code to handle a backreference. void EmitBackreference(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Ref, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Backreference, $"Unexpected type: {node.Kind}"); int capnum = RegexParser.MapCaptureNumber(node.M, rm.Code.Caps); @@ -1317,7 +1317,7 @@ void EmitWhenHasCapture() // Emits the code for an if(backreference)-then-else conditional. void EmitBackreferenceConditional(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Testref, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.BackreferenceConditional, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 2, $"Expected 2 children, found {node.ChildCount()}"); // We're branching in a complicated fashion. Make sure sliceStaticPos is 0. @@ -1329,7 +1329,7 @@ void EmitBackreferenceConditional(RegexNode node) // Get the "yes" branch and the "no" branch. The "no" branch is optional in syntax and is thus // somewhat likely to be Empty. RegexNode yesBranch = node.Child(0); - RegexNode? noBranch = node.Child(1) is { Type: not RegexNode.Empty } childNo ? childNo : null; + RegexNode? noBranch = node.Child(1) is { Kind: not RegexNodeKind.Empty } childNo ? childNo : null; string originalDoneLabel = doneLabel; // If the child branches might backtrack, we can't emit the branches inside constructs that @@ -1474,7 +1474,7 @@ void EmitBackreferenceConditional(RegexNode node) // Emits the code for an if(expression)-then-else conditional. void EmitExpressionConditional(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Testgroup, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.ExpressionConditional, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 3, $"Expected 3 children, found {node.ChildCount()}"); bool isAtomic = node.IsAtomicByParent(); @@ -1490,7 +1490,7 @@ void EmitExpressionConditional(RegexNode node) // Get the "yes" branch and the "no" branch. The "no" branch is optional in syntax and is thus // somewhat likely to be Empty. RegexNode yesBranch = node.Child(1); - RegexNode? noBranch = node.Child(2) is { Type: not RegexNode.Empty } childNo ? childNo : null; + RegexNode? noBranch = node.Child(2) is { Kind: not RegexNodeKind.Empty } childNo ? childNo : null; string originalDoneLabel = doneLabel; string expressionNotMatched = ReserveName("ConditionalExpressionNotMatched"); @@ -1632,7 +1632,7 @@ void EmitExpressionConditional(RegexNode node) // Emits the code for a Capture node. void EmitCapture(RegexNode node, RegexNode? subsequent = null) { - Debug.Assert(node.Type is RegexNode.Capture, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Capture, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); int capnum = RegexParser.MapCaptureNumber(node.M, rm.Code.Caps); @@ -1706,7 +1706,7 @@ void EmitCapture(RegexNode node, RegexNode? subsequent = null) // Emits the code to handle a positive lookahead assertion. void EmitPositiveLookaheadAssertion(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Require, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.PositiveLookaround, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); // Lookarounds are implicitly atomic. Store the original done label to reset at the end. @@ -1734,7 +1734,7 @@ void EmitPositiveLookaheadAssertion(RegexNode node) // Emits the code to handle a negative lookahead assertion. void EmitNegativeLookaheadAssertion(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Prevent, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.NegativeLookaround, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); // Lookarounds are implicitly atomic. Store the original done label to reset at the end. @@ -1770,15 +1770,15 @@ void EmitNegativeLookaheadAssertion(RegexNode node) static bool PossiblyBacktracks(RegexNode node) => !( // Certain nodes will never backtrack out of them - node.Type is RegexNode.Atomic or // atomic nodes by definition don't give up anything - RegexNode.Oneloopatomic or RegexNode.Notoneloopatomic or RegexNode.Setloopatomic or // same for atomic loops - RegexNode.One or RegexNode.Notone or RegexNode.Set or // individual characters don't backtrack - RegexNode.Multi or // multiple characters don't backtrack - RegexNode.Ref or // backreferences don't backtrack - RegexNode.Beginning or RegexNode.Bol or RegexNode.Start or RegexNode.End or RegexNode.EndZ or RegexNode.Eol or RegexNode.Boundary or RegexNode.NonBoundary or RegexNode.ECMABoundary or RegexNode.NonECMABoundary or // anchors don't backtrack - RegexNode.Nothing or RegexNode.Empty or RegexNode.UpdateBumpalong // empty/nothing don't do anything + node.Kind is RegexNodeKind.Atomic or // atomic nodes by definition don't give up anything + RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloopatomic or // same for atomic loops + RegexNodeKind.One or RegexNodeKind.Notone or RegexNodeKind.Set or // individual characters don't backtrack + RegexNodeKind.Multi or // multiple characters don't backtrack + RegexNodeKind.Backreference or // backreferences don't backtrack + RegexNodeKind.Beginning or RegexNodeKind.Bol or RegexNodeKind.Start or RegexNodeKind.End or RegexNodeKind.EndZ or RegexNodeKind.Eol or RegexNodeKind.Boundary or RegexNodeKind.NonBoundary or RegexNodeKind.ECMABoundary or RegexNodeKind.NonECMABoundary or // anchors don't backtrack + RegexNodeKind.Nothing or RegexNodeKind.Empty or RegexNodeKind.UpdateBumpalong // empty/nothing don't do anything // Fixed-size repeaters of single characters or atomic don't backtrack - || node.Type is RegexNode.Oneloop or RegexNode.Notoneloop or RegexNode.Setloop or RegexNode.Onelazy or RegexNode.Notonelazy or RegexNode.Setlazy && node.M == node.N + || node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop or RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy && node.M == node.N ); // Emits the code for the node. @@ -1791,25 +1791,25 @@ void EmitNode(RegexNode node, RegexNode? subsequent = null, bool emitLengthCheck } // Separate out several node types that, for conciseness, don't need a header and scope written into the source. - switch (node.Type) + switch (node.Kind) { // Nothing is written for an empty - case RegexNode.Empty: + case RegexNodeKind.Empty: return; // A match failure doesn't need a scope. - case RegexNode.Nothing: + case RegexNodeKind.Nothing: writer.WriteLine($"goto {doneLabel};"); return; // Atomic is invisible in the generated source, other than its impact on the targets of jumps - case RegexNode.Atomic: + case RegexNodeKind.Atomic: EmitAtomic(node, subsequent); return; // Concatenate is a simplification in the node tree so that a series of children can be represented as one. // We don't need its presence visible in the source. - case RegexNode.Concatenate: + case RegexNodeKind.Concatenate: EmitConcatenation(node, subsequent, emitLengthChecksIfRequired); return; } @@ -1818,94 +1818,94 @@ void EmitNode(RegexNode node, RegexNode? subsequent = null, bool emitLengthCheck // be visible outside of its scope, the scope is still emitted for clarity but is commented out. using (EmitScope(writer, DescribeNode(node, rm.Code), faux: PossiblyBacktracks(node) && !node.IsAtomicByParent())) { - switch (node.Type) + switch (node.Kind) { - case RegexNode.Beginning: - case RegexNode.Start: - case RegexNode.Bol: - case RegexNode.Eol: - case RegexNode.End: - case RegexNode.EndZ: + case RegexNodeKind.Beginning: + case RegexNodeKind.Start: + case RegexNodeKind.Bol: + case RegexNodeKind.Eol: + case RegexNodeKind.End: + case RegexNodeKind.EndZ: EmitAnchors(node); break; - case RegexNode.Boundary: - case RegexNode.NonBoundary: - case RegexNode.ECMABoundary: - case RegexNode.NonECMABoundary: + case RegexNodeKind.Boundary: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.ECMABoundary: + case RegexNodeKind.NonECMABoundary: EmitBoundary(node); break; - case RegexNode.Multi: + case RegexNodeKind.Multi: EmitMultiChar(node, emitLengthChecksIfRequired); break; - case RegexNode.One: - case RegexNode.Notone: - case RegexNode.Set: + case RegexNodeKind.One: + case RegexNodeKind.Notone: + case RegexNodeKind.Set: EmitSingleChar(node, emitLengthChecksIfRequired); break; - case RegexNode.Oneloop: - case RegexNode.Notoneloop: - case RegexNode.Setloop: + case RegexNodeKind.Oneloop: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Setloop: EmitSingleCharLoop(node, subsequent, emitLengthChecksIfRequired); break; - case RegexNode.Onelazy: - case RegexNode.Notonelazy: - case RegexNode.Setlazy: + case RegexNodeKind.Onelazy: + case RegexNodeKind.Notonelazy: + case RegexNodeKind.Setlazy: EmitSingleCharLazy(node, subsequent, emitLengthChecksIfRequired); break; - case RegexNode.Oneloopatomic: - case RegexNode.Notoneloopatomic: - case RegexNode.Setloopatomic: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.Setloopatomic: EmitSingleCharAtomicLoop(node, emitLengthChecksIfRequired); break; - case RegexNode.Loop: + case RegexNodeKind.Loop: EmitLoop(node); break; - case RegexNode.Lazyloop: + case RegexNodeKind.Lazyloop: EmitLazy(node); break; - case RegexNode.Alternate: + case RegexNodeKind.Alternate: EmitAlternation(node); break; - case RegexNode.Ref: + case RegexNodeKind.Backreference: EmitBackreference(node); break; - case RegexNode.Testref: + case RegexNodeKind.BackreferenceConditional: EmitBackreferenceConditional(node); break; - case RegexNode.Testgroup: + case RegexNodeKind.ExpressionConditional: EmitExpressionConditional(node); break; - case RegexNode.Capture: + case RegexNodeKind.Capture: EmitCapture(node, subsequent); break; - case RegexNode.Require: + case RegexNodeKind.PositiveLookaround: EmitPositiveLookaheadAssertion(node); break; - case RegexNode.Prevent: + case RegexNodeKind.NegativeLookaround: EmitNegativeLookaheadAssertion(node); break; - case RegexNode.UpdateBumpalong: + case RegexNodeKind.UpdateBumpalong: EmitUpdateBumpalong(node); break; default: - Debug.Fail($"Unexpected node type: {node.Type}"); + Debug.Fail($"Unexpected node type: {node.Kind}"); break; } } @@ -1914,7 +1914,7 @@ void EmitNode(RegexNode node, RegexNode? subsequent = null, bool emitLengthCheck // Emits the node for an atomic. void EmitAtomic(RegexNode node, RegexNode? subsequent) { - Debug.Assert(node.Type is RegexNode.Atomic, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Atomic, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); // Atomic simply outputs the code for the child, but it ensures that any done label left @@ -1930,7 +1930,7 @@ void EmitAtomic(RegexNode node, RegexNode? subsequent) // it should bump from this location rather than from the original location. void EmitUpdateBumpalong(RegexNode node) { - Debug.Assert(node.Type is RegexNode.UpdateBumpalong, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.UpdateBumpalong, $"Unexpected type: {node.Kind}"); TransferSliceStaticPosToPos(); using (EmitBlock(writer, "if (base.runtextpos < pos)")) @@ -1942,7 +1942,7 @@ void EmitUpdateBumpalong(RegexNode node) // Emits code for a concatenation void EmitConcatenation(RegexNode node, RegexNode? subsequent, bool emitLengthChecksIfRequired) { - Debug.Assert(node.Type is RegexNode.Concatenate, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Concatenate, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() >= 2, $"Expected at least 2 children, found {node.ChildCount()}"); // Emit the code for each child one after the other. @@ -1979,13 +1979,13 @@ void WriteSingleCharChild(RegexNode child, bool includeDescription = true) } RegexNode child = node.Child(i); - if (child.Type is RegexNode.One or RegexNode.Notone or RegexNode.Set) + if (child.Kind is RegexNodeKind.One or RegexNodeKind.Notone or RegexNodeKind.Set) { WriteSingleCharChild(child); } - else if (child.Type is RegexNode.Oneloop or RegexNode.Onelazy or RegexNode.Oneloopatomic or - RegexNode.Setloop or RegexNode.Setlazy or RegexNode.Setloopatomic or - RegexNode.Notoneloop or RegexNode.Notonelazy or RegexNode.Notoneloopatomic && + else if (child.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Onelazy or RegexNodeKind.Oneloopatomic or + RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic or + RegexNodeKind.Notoneloop or RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloopatomic && child.M == child.N && child.M <= MaxUnrollSize) { @@ -2046,7 +2046,7 @@ RegexNode.Notoneloop or RegexNode.Notonelazy or RegexNode.Notoneloopatomic && for (int i = index + 1; i < childCount; i++) { RegexNode next = node.Child(i); - if (next.Type is not RegexNode.UpdateBumpalong) // skip node types that don't have a semantic impact + if (next.Kind is not RegexNodeKind.UpdateBumpalong) // skip node types that don't have a semantic impact { return next; } @@ -2059,7 +2059,7 @@ RegexNode.Notoneloop or RegexNode.Notonelazy or RegexNode.Notoneloopatomic && // Emits the code to handle a single-character match. void EmitSingleChar(RegexNode node, bool emitLengthCheck = true, string? offset = null, bool clauseOnly = false) { - Debug.Assert(node.IsOneFamily || node.IsNotoneFamily || node.IsSetFamily, $"Unexpected type: {node.Type}"); + Debug.Assert(node.IsOneFamily || node.IsNotoneFamily || node.IsSetFamily, $"Unexpected type: {node.Kind}"); // This only emits a single check, but it's called from the looping constructs in a loop // to generate the code for a single check, so we map those looping constructs to the @@ -2095,13 +2095,13 @@ void EmitSingleChar(RegexNode node, bool emitLengthCheck = true, string? offset // Emits the code to handle a boundary check on a character. void EmitBoundary(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Boundary or RegexNode.NonBoundary or RegexNode.ECMABoundary or RegexNode.NonECMABoundary, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Boundary or RegexNodeKind.NonBoundary or RegexNodeKind.ECMABoundary or RegexNodeKind.NonECMABoundary, $"Unexpected type: {node.Kind}"); - string call = node.Type switch + string call = node.Kind switch { - RegexNode.Boundary => "!base.IsBoundary", - RegexNode.NonBoundary => "base.IsBoundary", - RegexNode.ECMABoundary => "!base.IsECMABoundary", + RegexNodeKind.Boundary => "!base.IsBoundary", + RegexNodeKind.NonBoundary => "base.IsBoundary", + RegexNodeKind.ECMABoundary => "!base.IsECMABoundary", _ => "base.IsECMABoundary", }; @@ -2114,13 +2114,13 @@ void EmitBoundary(RegexNode node) // Emits the code to handle various anchors. void EmitAnchors(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Beginning or RegexNode.Start or RegexNode.Bol or RegexNode.End or RegexNode.EndZ or RegexNode.Eol, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Beginning or RegexNodeKind.Start or RegexNodeKind.Bol or RegexNodeKind.End or RegexNodeKind.EndZ or RegexNodeKind.Eol, $"Unexpected type: {node.Kind}"); Debug.Assert(sliceStaticPos >= 0); - switch (node.Type) + switch (node.Kind) { - case RegexNode.Beginning: - case RegexNode.Start: + case RegexNodeKind.Beginning: + case RegexNodeKind.Start: if (sliceStaticPos > 0) { // If we statically know we've already matched part of the regex, there's no way we're at the @@ -2129,15 +2129,15 @@ void EmitAnchors(RegexNode node) } else { - additionalDeclarations.Add(node.Type == RegexNode.Beginning ? "int beginning = base.runtextbeg;" : "int start = base.runtextstart;"); - using (EmitBlock(writer, node.Type == RegexNode.Beginning ? "if (pos != beginning)" : "if (pos != start)")) + additionalDeclarations.Add(node.Kind == RegexNodeKind.Beginning ? "int beginning = base.runtextbeg;" : "int start = base.runtextstart;"); + using (EmitBlock(writer, node.Kind == RegexNodeKind.Beginning ? "if (pos != beginning)" : "if (pos != start)")) { writer.WriteLine($"goto {doneLabel};"); } } break; - case RegexNode.Bol: + case RegexNodeKind.Bol: if (sliceStaticPos > 0) { using (EmitBlock(writer, $"if ({sliceSpan}[{sliceStaticPos - 1}] != '\\n')")) @@ -2156,14 +2156,14 @@ void EmitAnchors(RegexNode node) } break; - case RegexNode.End: + case RegexNodeKind.End: using (EmitBlock(writer, $"if ({IsSliceLengthGreaterThanSliceStaticPos()})")) { writer.WriteLine($"goto {doneLabel};"); } break; - case RegexNode.EndZ: + case RegexNodeKind.EndZ: writer.WriteLine($"if ({sliceSpan}.Length > {sliceStaticPos + 1} || ({IsSliceLengthGreaterThanSliceStaticPos()} && {sliceSpan}[{sliceStaticPos}] != '\\n'))"); using (EmitBlock(writer, null)) { @@ -2171,7 +2171,7 @@ void EmitAnchors(RegexNode node) } break; - case RegexNode.Eol: + case RegexNodeKind.Eol: using (EmitBlock(writer, $"if ({IsSliceLengthGreaterThanSliceStaticPos()} && {sliceSpan}[{sliceStaticPos}] != '\\n')")) { writer.WriteLine($"goto {doneLabel};"); @@ -2187,7 +2187,7 @@ string IsSliceLengthGreaterThanSliceStaticPos() => // Emits the code to handle a multiple-character match. void EmitMultiChar(RegexNode node, bool emitLengthCheck = true) { - Debug.Assert(node.Type is RegexNode.Multi, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Multi, $"Unexpected type: {node.Kind}"); bool caseInsensitive = IsCaseInsensitive(node); @@ -2297,7 +2297,7 @@ void EmitOr() void EmitSingleCharLoop(RegexNode node, RegexNode? subsequent = null, bool emitLengthChecksIfRequired = true) { - Debug.Assert(node.Type is RegexNode.Oneloop or RegexNode.Notoneloop or RegexNode.Setloop, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop, $"Unexpected type: {node.Kind}"); // If this is actually a repeater, emit that instead; no backtracking necessary. if (node.M == node.N) @@ -2382,7 +2382,7 @@ void EmitSingleCharLoop(RegexNode node, RegexNode? subsequent = null, bool emitL void EmitSingleCharLazy(RegexNode node, RegexNode? subsequent = null, bool emitLengthChecksIfRequired = true) { - Debug.Assert(node.Type is RegexNode.Onelazy or RegexNode.Notonelazy or RegexNode.Setlazy, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy, $"Unexpected type: {node.Kind}"); // Emit the min iterations as a repeater. Any failures here don't necessitate backtracking, // as the lazy itself failed to match, and there's no backtracking possible by the individual @@ -2471,7 +2471,7 @@ void EmitSingleCharLazy(RegexNode node, RegexNode? subsequent = null, bool emitL // Now that we've appropriately advanced by one character and are set for what comes after the loop, // see if we can skip ahead more iterations by doing a search for a following literal. if (iterationCount is null && - node.Type is RegexNode.Notonelazy && + node.Kind is RegexNodeKind.Notonelazy && !IsCaseInsensitive(node) && subsequent?.FindStartingCharacterOrString() is ValueTuple literal && (literal.Item2?[0] ?? literal.Item1) != node.Ch) @@ -2489,7 +2489,7 @@ node.Type is RegexNode.Notonelazy && SliceInputSpan(writer); } else if (iterationCount is null && - node.Type is RegexNode.Setlazy && + node.Kind is RegexNodeKind.Setlazy && node.Str == RegexCharClass.AnyClass && subsequent?.FindStartingCharacterOrString() is ValueTuple literal2) { @@ -2559,7 +2559,7 @@ node.Type is RegexNode.Setlazy && void EmitLazy(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Lazyloop, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Lazyloop, $"Unexpected type: {node.Kind}"); Debug.Assert(node.M < int.MaxValue, $"Unexpected M={node.M}"); Debug.Assert(node.N >= node.M, $"Unexpected M={node.M}, N={node.N}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); @@ -2744,7 +2744,7 @@ void EmitLazy(RegexNode node) // RegexNode.M is used for the number of iterations; RegexNode.N is ignored. void EmitSingleCharFixedRepeater(RegexNode node, bool emitLengthCheck = true) { - Debug.Assert(node.IsOneFamily || node.IsNotoneFamily || node.IsSetFamily, $"Unexpected type: {node.Type}"); + Debug.Assert(node.IsOneFamily || node.IsNotoneFamily || node.IsSetFamily, $"Unexpected type: {node.Kind}"); int iterations = node.M; if (iterations == 0) @@ -2810,7 +2810,7 @@ void EmitSingleCharFixedRepeater(RegexNode node, bool emitLengthCheck = true) // Emits the code to handle a non-backtracking, variable-length loop around a single character comparison. void EmitSingleCharAtomicLoop(RegexNode node, bool emitLengthChecksIfRequired = true) { - Debug.Assert(node.Type is RegexNode.Oneloop or RegexNode.Oneloopatomic or RegexNode.Notoneloop or RegexNode.Notoneloopatomic or RegexNode.Setloop or RegexNode.Setloopatomic, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic, $"Unexpected type: {node.Kind}"); // If this is actually a repeater, emit that instead. if (node.M == node.N) @@ -2953,7 +2953,7 @@ void EmitSingleCharAtomicLoop(RegexNode node, bool emitLengthChecksIfRequired = // Emits the code to handle a non-backtracking optional zero-or-one loop. void EmitAtomicSingleCharZeroOrOne(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Oneloop or RegexNode.Oneloopatomic or RegexNode.Notoneloop or RegexNode.Notoneloopatomic or RegexNode.Setloop or RegexNode.Setloopatomic, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic, $"Unexpected type: {node.Kind}"); Debug.Assert(node.M == 0 && node.N == 1); string expr = $"{sliceSpan}[{sliceStaticPos}]"; @@ -2977,7 +2977,7 @@ void EmitAtomicSingleCharZeroOrOne(RegexNode node) void EmitLoop(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Loop or RegexNode.Lazyloop, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop, $"Unexpected type: {node.Kind}"); Debug.Assert(node.M < int.MaxValue, $"Unexpected M={node.M}"); Debug.Assert(node.N >= node.M, $"Unexpected M={node.M}, N={node.N}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); @@ -3565,41 +3565,41 @@ private static string Literal(RegexOptions options) /// Gets a textual description of the node fit for rendering in a comment in source. private static string DescribeNode(RegexNode node, RegexCode regexCode) => - node.Type switch - { - RegexNode.Alternate => $"Match with {node.ChildCount()} alternative expressions{(node.IsAtomicByParent() ? ", atomically" : "")}.", - RegexNode.Atomic => $"Atomic group.", - RegexNode.Beginning => "Match if at the beginning of the string.", - RegexNode.Bol => "Match if at the beginning of a line.", - RegexNode.Boundary => $"Match if at a word boundary.", - RegexNode.Capture when node.M == -1 && node.N != -1 => $"Non-capturing balancing group. Uncaptures the {DescribeCapture(node.N, regexCode)}.", - RegexNode.Capture when node.N != -1 => $"Balancing group. Captures the {DescribeCapture(node.M, regexCode)} and uncaptures the {DescribeCapture(node.N, regexCode)}.", - RegexNode.Capture when node.N == -1 => $"{DescribeCapture(node.M, regexCode)}.", - RegexNode.Concatenate => "Match a sequence of expressions.", - RegexNode.ECMABoundary => $"Match if at a word boundary (according to ECMAScript rules).", - RegexNode.Empty => $"Match an empty string.", - RegexNode.End => "Match if at the end of the string.", - RegexNode.EndZ => "Match if at the end of the string or if before an ending newline.", - RegexNode.Eol => "Match if at the end of a line.", - RegexNode.Loop or RegexNode.Lazyloop => node.M == 0 && node.N == 1 ? $"Optional ({(node.Type is RegexNode.Loop ? "greedy" : "lazy")})." : $"Loop {DescribeLoop(node)}.", - RegexNode.Multi => $"Match the string {Literal(node.Str!)}.", - RegexNode.NonBoundary => $"Match if at anything other than a word boundary.", - RegexNode.NonECMABoundary => $"Match if at anything other than a word boundary (according to ECMAScript rules).", - RegexNode.Nothing => $"Fail to match.", - RegexNode.Notone => $"Match any character other than {Literal(node.Ch)}.", - RegexNode.Notoneloop or RegexNode.Notoneloopatomic or RegexNode.Notonelazy => $"Match a character other than {Literal(node.Ch)} {DescribeLoop(node)}.", - RegexNode.One => $"Match {Literal(node.Ch)}.", - RegexNode.Oneloop or RegexNode.Oneloopatomic or RegexNode.Onelazy => $"Match {Literal(node.Ch)} {DescribeLoop(node)}.", - RegexNode.Prevent => $"Zero-width negative lookahead assertion.", - RegexNode.Ref => $"Match the same text as matched by the {DescribeCapture(node.M, regexCode)}.", - RegexNode.Require => $"Zero-width positive lookahead assertion.", - RegexNode.Set => $"Match {DescribeSet(node.Str!)}.", - RegexNode.Setloop or RegexNode.Setloopatomic or RegexNode.Setlazy => $"Match {DescribeSet(node.Str!)} {DescribeLoop(node)}.", - RegexNode.Start => "Match if at the start position.", - RegexNode.Testgroup => $"Conditionally match one of two expressions depending on whether an initial expression matches.", - RegexNode.Testref => $"Conditionally match one of two expressions depending on whether the {DescribeCapture(node.M, regexCode)} matched.", - RegexNode.UpdateBumpalong => $"Advance the next matching position.", - _ => $"Unknown node type {node.Type}", + node.Kind switch + { + RegexNodeKind.Alternate => $"Match with {node.ChildCount()} alternative expressions{(node.IsAtomicByParent() ? ", atomically" : "")}.", + RegexNodeKind.Atomic => $"Atomic group.", + RegexNodeKind.Beginning => "Match if at the beginning of the string.", + RegexNodeKind.Bol => "Match if at the beginning of a line.", + RegexNodeKind.Boundary => $"Match if at a word boundary.", + RegexNodeKind.Capture when node.M == -1 && node.N != -1 => $"Non-capturing balancing group. Uncaptures the {DescribeCapture(node.N, regexCode)}.", + RegexNodeKind.Capture when node.N != -1 => $"Balancing group. Captures the {DescribeCapture(node.M, regexCode)} and uncaptures the {DescribeCapture(node.N, regexCode)}.", + RegexNodeKind.Capture when node.N == -1 => $"{DescribeCapture(node.M, regexCode)}.", + RegexNodeKind.Concatenate => "Match a sequence of expressions.", + RegexNodeKind.ECMABoundary => $"Match if at a word boundary (according to ECMAScript rules).", + RegexNodeKind.Empty => $"Match an empty string.", + RegexNodeKind.End => "Match if at the end of the string.", + RegexNodeKind.EndZ => "Match if at the end of the string or if before an ending newline.", + RegexNodeKind.Eol => "Match if at the end of a line.", + RegexNodeKind.Loop or RegexNodeKind.Lazyloop => node.M == 0 && node.N == 1 ? $"Optional ({(node.Kind is RegexNodeKind.Loop ? "greedy" : "lazy")})." : $"Loop {DescribeLoop(node)}.", + RegexNodeKind.Multi => $"Match the string {Literal(node.Str!)}.", + RegexNodeKind.NonBoundary => $"Match if at anything other than a word boundary.", + RegexNodeKind.NonECMABoundary => $"Match if at anything other than a word boundary (according to ECMAScript rules).", + RegexNodeKind.Nothing => $"Fail to match.", + RegexNodeKind.Notone => $"Match any character other than {Literal(node.Ch)}.", + RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy => $"Match a character other than {Literal(node.Ch)} {DescribeLoop(node)}.", + RegexNodeKind.One => $"Match {Literal(node.Ch)}.", + RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy => $"Match {Literal(node.Ch)} {DescribeLoop(node)}.", + RegexNodeKind.NegativeLookaround => $"Zero-width negative lookahead assertion.", + RegexNodeKind.Backreference => $"Match the same text as matched by the {DescribeCapture(node.M, regexCode)}.", + RegexNodeKind.PositiveLookaround => $"Zero-width positive lookahead assertion.", + RegexNodeKind.Set => $"Match {DescribeSet(node.Str!)}.", + RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy => $"Match {DescribeSet(node.Str!)} {DescribeLoop(node)}.", + RegexNodeKind.Start => "Match if at the start position.", + RegexNodeKind.ExpressionConditional => $"Conditionally match one of two expressions depending on whether an initial expression matches.", + RegexNodeKind.BackreferenceConditional => $"Conditionally match one of two expressions depending on whether the {DescribeCapture(node.M, regexCode)} matched.", + RegexNodeKind.UpdateBumpalong => $"Advance the next matching position.", + _ => $"Unknown node type {node.Kind}", }; /// Gets an identifer to describe a capture group. @@ -3657,14 +3657,14 @@ private static string DescribeSet(string charClass) => /// The depth of the current node. private static void DescribeExpression(TextWriter writer, RegexNode node, string prefix, RegexCode regexCode, int depth = 0) { - bool skip = node.Type switch + bool skip = node.Kind switch { // For concatenations, flatten the contents into the parent, but only if the parent isn't a form of alternation, // where each branch is considered to be independent rather than a concatenation. - RegexNode.Concatenate when node.Next is not { Type: RegexNode.Alternate or RegexNode.Testref or RegexNode.Testgroup } => true, + RegexNodeKind.Concatenate when node.Parent is not { Kind: RegexNodeKind.Alternate or RegexNodeKind.BackreferenceConditional or RegexNodeKind.ExpressionConditional } => true, // For atomic, skip the node if we'll instead render the atomic label as part of rendering the child. - RegexNode.Atomic when node.Child(0).Type is RegexNode.Loop or RegexNode.Lazyloop or RegexNode.Alternate => true, + RegexNodeKind.Atomic when node.Child(0).Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop or RegexNodeKind.Alternate => true, // Don't skip anything else. _ => false, @@ -3672,14 +3672,14 @@ RegexNode.Atomic when node.Child(0).Type is RegexNode.Loop or RegexNode.Lazyloop if (!skip) { - string tag = node.Next?.Type switch + string tag = node.Parent?.Kind switch { - RegexNode.Testgroup when node.Next.Child(0) == node => "Condition: ", - RegexNode.Testgroup when node.Next.Child(1) == node => "Matched: ", - RegexNode.Testgroup when node.Next.Child(2) == node => "Not Matched: ", + RegexNodeKind.ExpressionConditional when node.Parent.Child(0) == node => "Condition: ", + RegexNodeKind.ExpressionConditional when node.Parent.Child(1) == node => "Matched: ", + RegexNodeKind.ExpressionConditional when node.Parent.Child(2) == node => "Not Matched: ", - RegexNode.Testref when node.Next.Child(0) == node => "Matched: ", - RegexNode.Testref when node.Next.Child(1) == node => "Not Matched: ", + RegexNodeKind.BackreferenceConditional when node.Parent.Child(0) == node => "Matched: ", + RegexNodeKind.BackreferenceConditional when node.Parent.Child(1) == node => "Not Matched: ", _ => "", }; @@ -3701,13 +3701,13 @@ RegexNode.Testref when node.Next.Child(1) == node => "Not Matched: ", /// Gets a textual description of a loop's style and bounds. private static string DescribeLoop(RegexNode node) { - string style = node.Type switch + string style = node.Kind switch { _ when node.M == node.N => "exactly", - RegexNode.Oneloopatomic or RegexNode.Notoneloopatomic or RegexNode.Setloopatomic => "atomically", - RegexNode.Oneloop or RegexNode.Notoneloop or RegexNode.Setloop => "greedily", - RegexNode.Onelazy or RegexNode.Notonelazy or RegexNode.Setlazy => "lazily", - RegexNode.Loop => node.IsAtomicByParent() ? "greedily and atomically" : "greedily", + RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloopatomic => "atomically", + RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop => "greedily", + RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy => "lazily", + RegexNodeKind.Loop => node.IsAtomicByParent() ? "greedily and atomically" : "greedily", _ /* RegexNode.Lazy */ => node.IsAtomicByParent() ? "lazily and atomically" : "lazily", }; diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/Strings.resx b/src/libraries/System.Text.RegularExpressions/gen/Resources/Strings.resx index 2ce09c60fb6e5..72dedb53b0b91 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/Strings.resx +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/Strings.resx @@ -289,9 +289,6 @@ Alternation has a reference to undefined group. - - Unexpected opcode in regular expression generation: {0}. - Unknown property '{0}'. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.cs.xlf index 3907e73e7ca2b..670114d466a8f 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.cs.xlf @@ -292,11 +292,6 @@ Znak \\ na konci vzorku je neplatný. - - Unexpected opcode in regular expression generation: {0}. - Při generování regulárního výrazu byl nalezen neočekávaný operační kód: {0}. - - Unrecognized control character. Nerozpoznaný řídicí znak. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.de.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.de.xlf index 67beed526576d..decb3d41eecab 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.de.xlf @@ -292,11 +292,6 @@ Unzulässiger \\ am Ende des Musters. - - Unexpected opcode in regular expression generation: {0}. - Unerwarteter "opcode" bei Generierung von regulärem Ausdruck: {0}. - - Unrecognized control character. Unbekanntes Steuerzeichen. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.es.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.es.xlf index e97ec8feaf1b2..dfcb4b46eb8cb 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.es.xlf @@ -292,11 +292,6 @@ \\ no válido al final del patrón. - - Unexpected opcode in regular expression generation: {0}. - Código de operación inesperado en la generación de expresión regular: {0}. - - Unrecognized control character. Carácter de control no reconocido. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.fr.xlf index 16efb2d977b0e..0413c2f369728 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.fr.xlf @@ -292,11 +292,6 @@ \\ non conforme à la fin du modèle. - - Unexpected opcode in regular expression generation: {0}. - opcode inattendu dans la génération d'expressions régulières : {0}. - - Unrecognized control character. Caractère de contrôle non reconnu. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.it.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.it.xlf index f7d730755b846..2f32980d35f71 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.it.xlf @@ -292,11 +292,6 @@ Carattere \\ non valido alla fine del criterio. - - Unexpected opcode in regular expression generation: {0}. - Codice operativo imprevisto nella generazione dell'espressione regolare: {0}. - - Unrecognized control character. Carattere di controllo non riconosciuto. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ja.xlf index f14f085a8f42c..8dddebb2d887e 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ja.xlf @@ -292,11 +292,6 @@ パターンの末尾に無効な \\ があります。 - - Unexpected opcode in regular expression generation: {0}. - 正規表現の生成中に予期しない Opcode: {0} が発生しました。 - - Unrecognized control character. 認識されない制御文字です。 diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ko.xlf index 618b1067b0eba..369483d521ad6 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ko.xlf @@ -292,11 +292,6 @@ 패턴 끝에 잘못된 \\가 있습니다. - - Unexpected opcode in regular expression generation: {0}. - 정규식 생성에 예기치 않은 opcode가 있습니다. {0} - - Unrecognized control character. 인식할 수 없는 제어 문자입니다. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.pl.xlf index f8cde42177c71..01efb83445bb5 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.pl.xlf @@ -292,11 +292,6 @@ Niedozwolony znak \\ na końcu wzorca. - - Unexpected opcode in regular expression generation: {0}. - Nieoczekiwany kod operacji podczas generowania wyrażenia regularnego: {0}. - - Unrecognized control character. Nierozpoznany znak kontrolny. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.pt-BR.xlf index 6991eccb5b9cf..9f039335387e4 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.pt-BR.xlf @@ -292,11 +292,6 @@ \\ incorreto no final do padrão. - - Unexpected opcode in regular expression generation: {0}. - Opcode inesperado na geração de expressão regular: {0}. - - Unrecognized control character. Caractere de controle não reconhecido. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ru.xlf index 4f777ba7d0ccd..5adb41132357c 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.ru.xlf @@ -292,11 +292,6 @@ Недопустимая обратная косая черта \\ в конце образца. - - Unexpected opcode in regular expression generation: {0}. - Неожиданный код операции при создании регулярного выражения: {0}. - - Unrecognized control character. Нераспознанный управляющий знак. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.tr.xlf index c1492d873c5f5..9622b266daee2 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.tr.xlf @@ -292,11 +292,6 @@ Desenin sonunda geçersiz \\. - - Unexpected opcode in regular expression generation: {0}. - Normal ifade oluşturmada beklenmeyen işlem kodu: {0}. - - Unrecognized control character. Tanınmayan denetim karakteri. diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.zh-Hans.xlf index 8bc7e9656e5be..6b007977907ab 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -292,11 +292,6 @@ \\ 在模式末尾非法。 - - Unexpected opcode in regular expression generation: {0}. - 生成正则表达式时出现意外的操作码: {0}。 - - Unrecognized control character. 无法识别的控制字符。 diff --git a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.zh-Hant.xlf index 4e598383d8266..7972b6b990e62 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Text.RegularExpressions/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -292,11 +292,6 @@ 模式結尾有不合法的 \\。 - - Unexpected opcode in regular expression generation: {0}. - 在規則運算式產生中發生未預期的作業碼: {0}。 - - Unrecognized control character. 無法識別的控制字元。 diff --git a/src/libraries/System.Text.RegularExpressions/gen/System.Text.RegularExpressions.Generator.csproj b/src/libraries/System.Text.RegularExpressions/gen/System.Text.RegularExpressions.Generator.csproj index 56f7899f081db..8f24e872e2266 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/System.Text.RegularExpressions.Generator.csproj +++ b/src/libraries/System.Text.RegularExpressions/gen/System.Text.RegularExpressions.Generator.csproj @@ -35,6 +35,7 @@ + diff --git a/src/libraries/System.Text.RegularExpressions/src/Resources/Strings.resx b/src/libraries/System.Text.RegularExpressions/src/Resources/Strings.resx index ba430db54c5a3..52b6616648dd2 100644 --- a/src/libraries/System.Text.RegularExpressions/src/Resources/Strings.resx +++ b/src/libraries/System.Text.RegularExpressions/src/Resources/Strings.resx @@ -200,9 +200,6 @@ Alternation has a reference to undefined group. - - Unexpected opcode in regular expression generation: {0}. - Unknown property '{0}'. diff --git a/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj b/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj index 8537fd70de527..acda3098b795c 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj +++ b/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj @@ -32,6 +32,7 @@ + diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs index 6f6c8cd8f8852..d51ca826fd71c 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs @@ -210,7 +210,8 @@ public static int OpcodeSize(int opcode) return 3; default: - throw new ArgumentException(SR.Format(SR.UnexpectedOpcode, opcode.ToString())); + Debug.Fail($"Unexpected opcode: {opcode}"); + return 0; } } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs index 07a3d1b927cd3..2145a5dec334d 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs @@ -300,8 +300,8 @@ private void Mvfldloc(FieldInfo ft, LocalBuilder lt) /// Returned a rented local to the pool. private struct RentedLocalBuilder : IDisposable { - private Stack _pool; - private LocalBuilder _local; + private readonly Stack _pool; + private readonly LocalBuilder _local; internal RentedLocalBuilder(Stack pool, LocalBuilder local) { @@ -773,7 +773,7 @@ void EmitFixedSet_LeftToRight() // if (!CharInClass(slice[i + 1], prefix[1], "...")) continue; // if (!CharInClass(slice[i + 2], prefix[2], "...")) continue; // ... - Debug.Assert(setIndex == 0 || setIndex == 1); + Debug.Assert(setIndex is 0 or 1); for ( ; setIndex < sets.Count; setIndex++) { Debug.Assert(needLoop); @@ -834,7 +834,7 @@ void EmitLiteralAfterAtomicLoop() Debug.Assert(_code.FindOptimizations.LiteralAfterLoop is not null); (RegexNode LoopNode, (char Char, string? String, char[]? Chars) Literal) target = _code.FindOptimizations.LiteralAfterLoop.Value; - Debug.Assert(target.LoopNode.Type is RegexNode.Setloop or RegexNode.Setlazy or RegexNode.Setloopatomic); + Debug.Assert(target.LoopNode.Kind is RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic); Debug.Assert(target.LoopNode.N == int.MaxValue); // while (true) @@ -1003,7 +1003,7 @@ protected void EmitGo() // Get the root Capture node of the tree. RegexNode node = _code.Tree.Root; - Debug.Assert(node.Type == RegexNode.Capture, "Every generated tree should begin with a capture node"); + Debug.Assert(node.Kind == RegexNodeKind.Capture, "Every generated tree should begin with a capture node"); Debug.Assert(node.ChildCount() == 1, "Capture nodes should have one child"); // Skip the Capture node. We handle the implicit root capture specially. @@ -1012,9 +1012,9 @@ protected void EmitGo() // In some limited cases, FindFirstChar will only return true if it successfully matched the whole expression. // We can special case these to do essentially nothing in Go other than emit the capture. - switch (node.Type) + switch (node.Kind) { - case RegexNode.Multi or RegexNode.Notone or RegexNode.One or RegexNode.Set when !IsCaseInsensitive(node): + case RegexNodeKind.Multi or RegexNodeKind.Notone or RegexNodeKind.One or RegexNodeKind.Set when !IsCaseInsensitive(node): // This is the case for single and multiple characters, though the whole thing is only guaranteed // to have been validated in FindFirstChar when doing case-sensitive comparison. // base.Capture(0, base.runtextpos, base.runtextpos + node.Str.Length); @@ -1025,11 +1025,11 @@ protected void EmitGo() Ldc(0); Ldthisfld(s_runtextposField); Dup(); - Ldc(node.Type == RegexNode.Multi ? node.Str!.Length : 1); + Ldc(node.Kind == RegexNodeKind.Multi ? node.Str!.Length : 1); Add(); Call(s_captureMethod); Ldthisfld(s_runtextposField); - Ldc(node.Type == RegexNode.Multi ? node.Str!.Length : 1); + Ldc(node.Kind == RegexNodeKind.Multi ? node.Str!.Length : 1); Add(); Stfld(s_runtextposField); Ret(); @@ -1227,7 +1227,7 @@ void TransferSliceStaticPosToPos() // Emits the code for an alternation. void EmitAlternation(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Alternate, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Alternate, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() >= 2, $"Expected at least 2 children, found {node.ChildCount()}"); int childCount = node.ChildCount(); @@ -1238,7 +1238,7 @@ void EmitAlternation(RegexNode node) // Both atomic and non-atomic are supported. While a parent RegexNode.Atomic node will itself // successfully prevent backtracking into this child node, we can emit better / cheaper code // for an Alternate when it is atomic, so we still take it into account here. - Debug.Assert(node.Next is not null); + Debug.Assert(node.Parent is not null); bool isAtomic = node.IsAtomicByParent(); // Label to jump to when any branch completes successfully. @@ -1404,7 +1404,7 @@ void EmitAlternation(RegexNode node) // Emits the code to handle a backreference. void EmitBackreference(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Ref, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Backreference, $"Unexpected type: {node.Kind}"); int capnum = RegexParser.MapCaptureNumber(node.M, _code!.Caps); @@ -1496,7 +1496,7 @@ void EmitBackreference(RegexNode node) // Emits the code for an if(backreference)-then-else conditional. void EmitBackreferenceConditional(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Testref, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.BackreferenceConditional, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 2, $"Expected 2 children, found {node.ChildCount()}"); bool isAtomic = node.IsAtomicByParent(); @@ -1510,7 +1510,7 @@ void EmitBackreferenceConditional(RegexNode node) // Get the "yes" branch and the "no" branch. The "no" branch is optional in syntax and is thus // somewhat likely to be Empty. RegexNode yesBranch = node.Child(0); - RegexNode? noBranch = node.Child(1) is { Type: not RegexNode.Empty } childNo ? childNo : null; + RegexNode? noBranch = node.Child(1) is { Kind: not RegexNodeKind.Empty } childNo ? childNo : null; Label originalDoneLabel = doneLabel; Label refNotMatched = DefineLabel(); @@ -1642,7 +1642,7 @@ void EmitBackreferenceConditional(RegexNode node) // Emits the code for an if(expression)-then-else conditional. void EmitExpressionConditional(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Testgroup, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.ExpressionConditional, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 3, $"Expected 3 children, found {node.ChildCount()}"); bool isAtomic = node.IsAtomicByParent(); @@ -1658,7 +1658,7 @@ void EmitExpressionConditional(RegexNode node) // Get the "yes" branch and the "no" branch. The "no" branch is optional in syntax and is thus // somewhat likely to be Empty. RegexNode yesBranch = node.Child(1); - RegexNode? noBranch = node.Child(2) is { Type: not RegexNode.Empty } childNo ? childNo : null; + RegexNode? noBranch = node.Child(2) is { Kind: not RegexNodeKind.Empty } childNo ? childNo : null; Label originalDoneLabel = doneLabel; Label expressionNotMatched = DefineLabel(); @@ -1822,7 +1822,7 @@ void EmitExpressionConditional(RegexNode node) // Emits the code for a Capture node. void EmitCapture(RegexNode node, RegexNode? subsequent = null) { - Debug.Assert(node.Type is RegexNode.Capture, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Capture, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); int capnum = RegexParser.MapCaptureNumber(node.M, _code!.Caps); @@ -1939,7 +1939,7 @@ void EmitUncaptureUntil(LocalBuilder startingCapturePos) // Emits the code to handle a positive lookahead assertion. void EmitPositiveLookaheadAssertion(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Require, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.PositiveLookaround, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); // Lookarounds are implicitly atomic. Store the original done label to reset at the end. @@ -1970,7 +1970,7 @@ void EmitPositiveLookaheadAssertion(RegexNode node) // Emits the code to handle a negative lookahead assertion. void EmitNegativeLookaheadAssertion(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Prevent, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.NegativeLookaround, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); // Lookarounds are implicitly atomic. Store the original done label to reset at the end. @@ -2020,110 +2020,110 @@ void EmitNode(RegexNode node, RegexNode? subsequent = null, bool emitLengthCheck return; } - switch (node.Type) + switch (node.Kind) { - case RegexNode.Beginning: - case RegexNode.Start: - case RegexNode.Bol: - case RegexNode.Eol: - case RegexNode.End: - case RegexNode.EndZ: + case RegexNodeKind.Beginning: + case RegexNodeKind.Start: + case RegexNodeKind.Bol: + case RegexNodeKind.Eol: + case RegexNodeKind.End: + case RegexNodeKind.EndZ: EmitAnchors(node); break; - case RegexNode.Boundary: - case RegexNode.NonBoundary: - case RegexNode.ECMABoundary: - case RegexNode.NonECMABoundary: + case RegexNodeKind.Boundary: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.ECMABoundary: + case RegexNodeKind.NonECMABoundary: EmitBoundary(node); break; - case RegexNode.Multi: + case RegexNodeKind.Multi: EmitMultiChar(node, emitLengthChecksIfRequired); break; - case RegexNode.One: - case RegexNode.Notone: - case RegexNode.Set: + case RegexNodeKind.One: + case RegexNodeKind.Notone: + case RegexNodeKind.Set: EmitSingleChar(node, emitLengthChecksIfRequired); break; - case RegexNode.Oneloop: - case RegexNode.Notoneloop: - case RegexNode.Setloop: + case RegexNodeKind.Oneloop: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Setloop: EmitSingleCharLoop(node, subsequent, emitLengthChecksIfRequired); break; - case RegexNode.Onelazy: - case RegexNode.Notonelazy: - case RegexNode.Setlazy: + case RegexNodeKind.Onelazy: + case RegexNodeKind.Notonelazy: + case RegexNodeKind.Setlazy: EmitSingleCharLazy(node, subsequent, emitLengthChecksIfRequired); break; - case RegexNode.Oneloopatomic: - case RegexNode.Notoneloopatomic: - case RegexNode.Setloopatomic: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.Setloopatomic: EmitSingleCharAtomicLoop(node); break; - case RegexNode.Loop: + case RegexNodeKind.Loop: EmitLoop(node); break; - case RegexNode.Lazyloop: + case RegexNodeKind.Lazyloop: EmitLazy(node); break; - case RegexNode.Alternate: + case RegexNodeKind.Alternate: EmitAlternation(node); break; - case RegexNode.Concatenate: + case RegexNodeKind.Concatenate: EmitConcatenation(node, subsequent, emitLengthChecksIfRequired); break; - case RegexNode.Atomic: + case RegexNodeKind.Atomic: EmitAtomic(node, subsequent); break; - case RegexNode.Ref: + case RegexNodeKind.Backreference: EmitBackreference(node); break; - case RegexNode.Testref: + case RegexNodeKind.BackreferenceConditional: EmitBackreferenceConditional(node); break; - case RegexNode.Testgroup: + case RegexNodeKind.ExpressionConditional: EmitExpressionConditional(node); break; - case RegexNode.Capture: + case RegexNodeKind.Capture: EmitCapture(node, subsequent); break; - case RegexNode.Require: + case RegexNodeKind.PositiveLookaround: EmitPositiveLookaheadAssertion(node); break; - case RegexNode.Prevent: + case RegexNodeKind.NegativeLookaround: EmitNegativeLookaheadAssertion(node); break; - case RegexNode.Nothing: + case RegexNodeKind.Nothing: BrFar(doneLabel); break; - case RegexNode.Empty: + case RegexNodeKind.Empty: // Emit nothing. break; - case RegexNode.UpdateBumpalong: + case RegexNodeKind.UpdateBumpalong: EmitUpdateBumpalong(node); break; default: - Debug.Fail($"Unexpected node type: {node.Type}"); + Debug.Fail($"Unexpected node type: {node.Kind}"); break; } } @@ -2131,7 +2131,7 @@ void EmitNode(RegexNode node, RegexNode? subsequent = null, bool emitLengthCheck // Emits the node for an atomic. void EmitAtomic(RegexNode node, RegexNode? subsequent) { - Debug.Assert(node.Type is RegexNode.Atomic, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Atomic, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); // Atomic simply outputs the code for the child, but it ensures that any done label left @@ -2147,7 +2147,7 @@ void EmitAtomic(RegexNode node, RegexNode? subsequent) // it should bump from this location rather than from the original location. void EmitUpdateBumpalong(RegexNode node) { - Debug.Assert(node.Type is RegexNode.UpdateBumpalong, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.UpdateBumpalong, $"Unexpected type: {node.Kind}"); // if (base.runtextpos < pos) // { @@ -2167,7 +2167,7 @@ void EmitUpdateBumpalong(RegexNode node) // Emits code for a concatenation void EmitConcatenation(RegexNode node, RegexNode? subsequent, bool emitLengthChecksIfRequired) { - Debug.Assert(node.Type is RegexNode.Concatenate, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Concatenate, $"Unexpected type: {node.Kind}"); Debug.Assert(node.ChildCount() >= 2, $"Expected at least 2 children, found {node.ChildCount()}"); // Emit the code for each child one after the other. @@ -2198,7 +2198,7 @@ void EmitConcatenation(RegexNode node, RegexNode? subsequent, bool emitLengthChe for (int i = index + 1; i < childCount; i++) { RegexNode next = node.Child(i); - if (next.Type is not RegexNode.UpdateBumpalong) // skip node types that don't have a semantic impact + if (next.Kind is not RegexNodeKind.UpdateBumpalong) // skip node types that don't have a semantic impact { return next; } @@ -2211,7 +2211,7 @@ void EmitConcatenation(RegexNode node, RegexNode? subsequent, bool emitLengthChe // Emits the code to handle a single-character match. void EmitSingleChar(RegexNode node, bool emitLengthCheck = true, LocalBuilder? offset = null) { - Debug.Assert(node.IsOneFamily || node.IsNotoneFamily || node.IsSetFamily, $"Unexpected type: {node.Type}"); + Debug.Assert(node.IsOneFamily || node.IsNotoneFamily || node.IsSetFamily, $"Unexpected type: {node.Kind}"); // This only emits a single check, but it's called from the looping constructs in a loop // to generate the code for a single check, so we check for each "family" (one, notone, set) @@ -2254,7 +2254,7 @@ void EmitSingleChar(RegexNode node, bool emitLengthCheck = true, LocalBuilder? o // Emits the code to handle a boundary check on a character. void EmitBoundary(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Boundary or RegexNode.NonBoundary or RegexNode.ECMABoundary or RegexNode.NonECMABoundary, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Boundary or RegexNodeKind.NonBoundary or RegexNodeKind.ECMABoundary or RegexNodeKind.NonECMABoundary, $"Unexpected type: {node.Kind}"); // if (!IsBoundary(pos + sliceStaticPos, base.runtextbeg, end)) goto doneLabel; Ldthis(); @@ -2266,25 +2266,25 @@ void EmitBoundary(RegexNode node) } Ldthisfld(s_runtextbegField); Ldloc(end); - switch (node.Type) + switch (node.Kind) { - case RegexNode.Boundary: + case RegexNodeKind.Boundary: Call(s_isBoundaryMethod); BrfalseFar(doneLabel); break; - case RegexNode.NonBoundary: + case RegexNodeKind.NonBoundary: Call(s_isBoundaryMethod); BrtrueFar(doneLabel); break; - case RegexNode.ECMABoundary: + case RegexNodeKind.ECMABoundary: Call(s_isECMABoundaryMethod); BrfalseFar(doneLabel); break; default: - Debug.Assert(node.Type == RegexNode.NonECMABoundary); + Debug.Assert(node.Kind == RegexNodeKind.NonECMABoundary); Call(s_isECMABoundaryMethod); BrtrueFar(doneLabel); break; @@ -2294,13 +2294,13 @@ void EmitBoundary(RegexNode node) // Emits the code to handle various anchors. void EmitAnchors(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Beginning or RegexNode.Start or RegexNode.Bol or RegexNode.End or RegexNode.EndZ or RegexNode.Eol, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Beginning or RegexNodeKind.Start or RegexNodeKind.Bol or RegexNodeKind.End or RegexNodeKind.EndZ or RegexNodeKind.Eol, $"Unexpected type: {node.Kind}"); Debug.Assert(sliceStaticPos >= 0); - switch (node.Type) + switch (node.Kind) { - case RegexNode.Beginning: - case RegexNode.Start: + case RegexNodeKind.Beginning: + case RegexNodeKind.Start: if (sliceStaticPos > 0) { // If we statically know we've already matched part of the regex, there's no way we're at the @@ -2311,12 +2311,12 @@ void EmitAnchors(RegexNode node) { // if (pos > base.runtextbeg/start) goto doneLabel; Ldloc(pos); - Ldthisfld(node.Type == RegexNode.Beginning ? s_runtextbegField : s_runtextstartField); + Ldthisfld(node.Kind == RegexNodeKind.Beginning ? s_runtextbegField : s_runtextstartField); BneFar(doneLabel); } break; - case RegexNode.Bol: + case RegexNodeKind.Bol: if (sliceStaticPos > 0) { // if (slice[sliceStaticPos - 1] != '\n') goto doneLabel; @@ -2347,7 +2347,7 @@ void EmitAnchors(RegexNode node) } break; - case RegexNode.End: + case RegexNodeKind.End: // if (sliceStaticPos < slice.Length) goto doneLabel; Ldc(sliceStaticPos); Ldloca(slice); @@ -2355,7 +2355,7 @@ void EmitAnchors(RegexNode node) BltUnFar(doneLabel); break; - case RegexNode.EndZ: + case RegexNodeKind.EndZ: // if (sliceStaticPos < slice.Length - 1) goto doneLabel; Ldc(sliceStaticPos); Ldloca(slice); @@ -2363,9 +2363,9 @@ void EmitAnchors(RegexNode node) Ldc(1); Sub(); BltFar(doneLabel); - goto case RegexNode.Eol; + goto case RegexNodeKind.Eol; - case RegexNode.Eol: + case RegexNodeKind.Eol: // if (sliceStaticPos < slice.Length && slice[sliceStaticPos] != '\n') goto doneLabel; { Label success = DefineLabel(); @@ -2388,7 +2388,7 @@ void EmitAnchors(RegexNode node) // Emits the code to handle a multiple-character match. void EmitMultiChar(RegexNode node, bool emitLengthCheck = true) { - Debug.Assert(node.Type is RegexNode.Multi, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Multi, $"Unexpected type: {node.Kind}"); bool caseInsensitive = IsCaseInsensitive(node); @@ -2485,7 +2485,7 @@ void EmitMultiChar(RegexNode node, bool emitLengthCheck = true) // Emits the code to handle a backtracking, single-character loop. void EmitSingleCharLoop(RegexNode node, RegexNode? subsequent = null, bool emitLengthChecksIfRequired = true) { - Debug.Assert(node.Type is RegexNode.Oneloop or RegexNode.Notoneloop or RegexNode.Setloop, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop, $"Unexpected type: {node.Kind}"); // If this is actually a repeater, emit that instead; no backtracking necessary. if (node.M == node.N) @@ -2646,7 +2646,7 @@ void EmitSingleCharLoop(RegexNode node, RegexNode? subsequent = null, bool emitL void EmitSingleCharLazy(RegexNode node, RegexNode? subsequent = null, bool emitLengthChecksIfRequired = true) { - Debug.Assert(node.Type is RegexNode.Onelazy or RegexNode.Notonelazy or RegexNode.Setlazy, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy, $"Unexpected type: {node.Kind}"); // Emit the min iterations as a repeater. Any failures here don't necessitate backtracking, // as the lazy itself failed to match, and there's no backtracking possible by the individual @@ -2742,7 +2742,7 @@ void EmitSingleCharLazy(RegexNode node, RegexNode? subsequent = null, bool emitL // Now that we've appropriately advanced by one character and are set for what comes after the loop, // see if we can skip ahead more iterations by doing a search for a following literal. if (iterationCount is null && - node.Type is RegexNode.Notonelazy && + node.Kind is RegexNodeKind.Notonelazy && !IsCaseInsensitive(node) && subsequent?.FindStartingCharacterOrString() is ValueTuple literal && (literal.Item2?[0] ?? literal.Item1) != node.Ch) @@ -2782,7 +2782,7 @@ node.Type is RegexNode.Notonelazy && SliceInputSpan(); } else if (iterationCount is null && - node.Type is RegexNode.Setlazy && + node.Kind is RegexNodeKind.Setlazy && node.Str == RegexCharClass.AnyClass && subsequent?.FindStartingCharacterOrString() is ValueTuple literal2) { @@ -2889,7 +2889,7 @@ node.Type is RegexNode.Setlazy && void EmitLazy(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Lazyloop, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Lazyloop, $"Unexpected type: {node.Kind}"); Debug.Assert(node.M < int.MaxValue, $"Unexpected M={node.M}"); Debug.Assert(node.N >= node.M, $"Unexpected M={node.M}, N={node.N}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); @@ -3134,7 +3134,7 @@ void EmitLazy(RegexNode node) // RegexNode.M is used for the number of iterations; RegexNode.N is ignored. void EmitSingleCharFixedRepeater(RegexNode node, bool emitLengthChecksIfRequired = true) { - Debug.Assert(node.IsOneFamily || node.IsNotoneFamily || node.IsSetFamily, $"Unexpected type: {node.Type}"); + Debug.Assert(node.IsOneFamily || node.IsNotoneFamily || node.IsSetFamily, $"Unexpected type: {node.Kind}"); int iterations = node.M; if (iterations == 0) @@ -3218,7 +3218,7 @@ void EmitSingleCharFixedRepeater(RegexNode node, bool emitLengthChecksIfRequired // Emits the code to handle a non-backtracking, variable-length loop around a single character comparison. void EmitSingleCharAtomicLoop(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Oneloop or RegexNode.Oneloopatomic or RegexNode.Notoneloop or RegexNode.Notoneloopatomic or RegexNode.Setloop or RegexNode.Setloopatomic, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic, $"Unexpected type: {node.Kind}"); // If this is actually a repeater, emit that instead. if (node.M == node.N) @@ -3460,7 +3460,7 @@ void EmitSingleCharAtomicLoop(RegexNode node) // Emits the code to handle a non-backtracking optional zero-or-one loop. void EmitAtomicSingleCharZeroOrOne(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Oneloop or RegexNode.Oneloopatomic or RegexNode.Notoneloop or RegexNode.Notoneloopatomic or RegexNode.Setloop or RegexNode.Setloopatomic, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic, $"Unexpected type: {node.Kind}"); Debug.Assert(node.M == 0 && node.N == 1); Label skipUpdatesLabel = DefineLabel(); @@ -3515,7 +3515,7 @@ void EmitAtomicSingleCharZeroOrOne(RegexNode node) void EmitLoop(RegexNode node) { - Debug.Assert(node.Type is RegexNode.Loop or RegexNode.Lazyloop, $"Unexpected type: {node.Type}"); + Debug.Assert(node.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop, $"Unexpected type: {node.Kind}"); Debug.Assert(node.M < int.MaxValue, $"Unexpected M={node.M}"); Debug.Assert(node.N >= node.M, $"Unexpected M={node.M}, N={node.N}"); Debug.Assert(node.ChildCount() == 1, $"Expected 1 child, found {node.ChildCount()}"); diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs index 7f8191e51752c..f3c5552b8404a 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs @@ -626,7 +626,7 @@ public bool TryFindNextStartingPosition(ReadOnlySpan textSpan, ref int pos Debug.Assert(LiteralAfterLoop is not null); (RegexNode loopNode, (char Char, string? String, char[]? Chars) literal) = LiteralAfterLoop.GetValueOrDefault(); - Debug.Assert(loopNode.Type is RegexNode.Setloop or RegexNode.Setlazy or RegexNode.Setloopatomic); + Debug.Assert(loopNode.Kind is RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic); Debug.Assert(loopNode.N == int.MaxValue); int startingPos = pos; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index 121b9d1e4225b..ad760e95e3914 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -1,43 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// This RegexNode class is internal to the Regex package. -// It is built into a parsed tree for a regular expression. - -// Implementation notes: -// -// Since the node tree is a temporary data structure only used -// during compilation of the regexp to integer codes, it's -// designed for clarity and convenience rather than -// space efficiency. -// -// RegexNodes are built into a tree, linked by the _children list. -// Each node also has a _parent and _ichild member indicating -// its parent and which child # it is in its parent's list. -// -// RegexNodes come in as many types as there are constructs in -// a regular expression, for example, "concatenate", "alternate", -// "one", "rept", "group". There are also node types for basic -// peephole optimizations, e.g., "onerep", "notsetrep", etc. -// -// Because perl 5 allows "lookback" groups that scan backwards, -// each node also gets a "direction". Normally the value of -// boolean _backward = false. -// -// During parsing, top-level nodes are also stacked onto a parse -// stack (a stack of trees). For this purpose we have a _next -// pointer. [Note that to save a few bytes, we could overload the -// _parent pointer instead.] -// -// On the parse stack, each tree has a "role" - basically, the -// nonterminal in the grammar that the parser has currently -// assigned to the tree. That code is stored in _role. -// -// Finally, some of the different kinds of nodes have data. -// Two integers (for the looping constructs) are stored in -// _operands, an object (either a string or a set) -// is stored in _data - using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -46,107 +9,75 @@ namespace System.Text.RegularExpressions { + /// Represents a regex subexpression. internal sealed class RegexNode { - // RegexNode types - - // The following are leaves, and correspond to primitive operations - - public const int Oneloop = RegexCode.Oneloop; // c,n a* - public const int Notoneloop = RegexCode.Notoneloop; // c,n .* - public const int Setloop = RegexCode.Setloop; // set,n \d* - - public const int Onelazy = RegexCode.Onelazy; // c,n a*? - public const int Notonelazy = RegexCode.Notonelazy; // c,n .*? - public const int Setlazy = RegexCode.Setlazy; // set,n \d*? - - public const int One = RegexCode.One; // char a - public const int Notone = RegexCode.Notone; // char . [^a] - public const int Set = RegexCode.Set; // set [a-z] \w \s \d - - public const int Multi = RegexCode.Multi; // string abcdef - public const int Ref = RegexCode.Ref; // index \1 - - public const int Bol = RegexCode.Bol; // ^ - public const int Eol = RegexCode.Eol; // $ - public const int Boundary = RegexCode.Boundary; // \b - public const int NonBoundary = RegexCode.NonBoundary; // \B - public const int ECMABoundary = RegexCode.ECMABoundary; // \b - public const int NonECMABoundary = RegexCode.NonECMABoundary; // \B - public const int Beginning = RegexCode.Beginning; // \A - public const int Start = RegexCode.Start; // \G - public const int EndZ = RegexCode.EndZ; // \Z - public const int End = RegexCode.End; // \z - - public const int Oneloopatomic = RegexCode.Oneloopatomic; // c,n (?> a*) - public const int Notoneloopatomic = RegexCode.Notoneloopatomic; // c,n (?> .*) - public const int Setloopatomic = RegexCode.Setloopatomic; // set,n (?> \d*) - public const int UpdateBumpalong = RegexCode.UpdateBumpalong; - - // Interior nodes do not correspond to primitive operations, but - // control structures compositing other operations - - // Concat and alternate take n children, and can run forward or backwards - - public const int Nothing = 22; // [] - public const int Empty = 23; // () - - public const int Alternate = 24; // a|b - public const int Concatenate = 25; // ab - - public const int Loop = 26; // m,x * + ? {,} - public const int Lazyloop = 27; // m,x *? +? ?? {,}? - - public const int Capture = 28; // n () - capturing group - public const int Group = 29; // (?:) - noncapturing group - public const int Require = 30; // (?=) (?<=) - lookahead and lookbehind assertions - public const int Prevent = 31; // (?!) (?) - atomic subexpression - public const int Testref = 33; // (?(n) | ) - alternation, reference - public const int Testgroup = 34; // (?(...) | )- alternation, expression - /// empty bit from the node's options to store data on whether a node contains captures internal const RegexOptions HasCapturesFlag = (RegexOptions)(1 << 31); + /// The node's children. + /// null if no children, a if one child, or a if multiple children. private object? Children; - public int Type { get; private set; } + + /// The kind of expression represented by this node. + public RegexNodeKind Kind { get; private set; } + + /// A string associated with the node. + /// For a , this is the string from the expression. For an node, this is the character class string from . public string? Str { get; private set; } + + /// The character associated with the node. + /// For a or node, the character from the expression. public char Ch { get; private set; } + + /// The minimum number of iterations for a loop, or the capture group number for a capture or backreference. + /// No minimum is represented by 0. No capture group is represented by -1. public int M { get; private set; } + + /// The maximum number of iterations for a loop, or the uncapture group number for a balancing group. + /// No upper bound is represented by . No capture group is represented by -1. public int N { get; private set; } + + /// The options associated with the node. public RegexOptions Options; - public RegexNode? Next; - public RegexNode(int type, RegexOptions options) + /// The node's parent node in the tree. + /// + /// During parsing, top-level nodes are also stacked onto a parse stack (a stack of trees) using . + /// After parsing, is the node in the tree that has this node as or in . + /// + public RegexNode? Parent; + + public RegexNode(RegexNodeKind kind, RegexOptions options) { - Type = type; + Kind = kind; Options = options; } - public RegexNode(int type, RegexOptions options, char ch) + public RegexNode(RegexNodeKind kind, RegexOptions options, char ch) { - Type = type; + Kind = kind; Options = options; Ch = ch; } - public RegexNode(int type, RegexOptions options, string str) + public RegexNode(RegexNodeKind kind, RegexOptions options, string str) { - Type = type; + Kind = kind; Options = options; Str = str; } - public RegexNode(int type, RegexOptions options, int m) + public RegexNode(RegexNodeKind kind, RegexOptions options, int m) { - Type = type; + Kind = kind; Options = options; M = m; } - public RegexNode(int type, RegexOptions options, int m, int n) + public RegexNode(RegexNodeKind kind, RegexOptions options, int m, int n) { - Type = type; + Kind = kind; Options = options; M = m; N = n; @@ -168,7 +99,7 @@ public static RegexNode CreateOneWithCaseConversion(char ch, RegexOptions option // we can simply strip out the IgnoreCase option and make the node case-sensitive. if (!RegexCharClass.ParticipatesInCaseConversion(ch)) { - return new RegexNode(One, options & ~RegexOptions.IgnoreCase, ch); + return new RegexNode(RegexNodeKind.One, options & ~RegexOptions.IgnoreCase, ch); } // Create a set for the character, trying to include all case-insensitive equivalent characters. @@ -177,7 +108,7 @@ public static RegexNode CreateOneWithCaseConversion(char ch, RegexOptions option string stringSet = RegexCharClass.OneToStringClass(ch, culture, out bool resultIsCaseInsensitive); if (!resultIsCaseInsensitive) { - return new RegexNode(Set, options & ~RegexOptions.IgnoreCase, stringSet); + return new RegexNode(RegexNodeKind.Set, options & ~RegexOptions.IgnoreCase, stringSet); } // Otherwise, until we can get rid of ToLower usage at match time entirely (https://github.com/dotnet/runtime/issues/61048), @@ -186,14 +117,14 @@ public static RegexNode CreateOneWithCaseConversion(char ch, RegexOptions option } // Create a One node for the character. - return new RegexNode(One, options, ch); + return new RegexNode(RegexNodeKind.One, options, ch); } /// Reverses all children of a concatenation when in RightToLeft mode. public RegexNode ReverseConcatenationIfRightToLeft() { if ((Options & RegexOptions.RightToLeft) != 0 && - Type == Concatenate && + Kind == RegexNodeKind.Concatenate && ChildCount() > 1) { ((List)Children!).Reverse(); @@ -205,38 +136,38 @@ public RegexNode ReverseConcatenationIfRightToLeft() /// /// Pass type as OneLazy or OneLoop /// - private void MakeRep(int type, int min, int max) + private void MakeRep(RegexNodeKind kind, int min, int max) { - Type += type - One; + Kind += kind - RegexNodeKind.One; M = min; N = max; } private void MakeLoopAtomic() { - switch (Type) + switch (Kind) { - case Oneloop or Notoneloop or Setloop: + case RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop: // For loops, we simply change the Type to the atomic variant. // Atomic greedy loops should consume as many values as they can. - Type += Oneloopatomic - Oneloop; + Kind += RegexNodeKind.Oneloopatomic - RegexNodeKind.Oneloop; break; - case Onelazy or Notonelazy or Setlazy: + case RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy: // For lazy, we not only change the Type, we also lower the max number of iterations // to the minimum number of iterations, as they should end up matching as little as possible. - Type += Oneloopatomic - Onelazy; + Kind += RegexNodeKind.Oneloopatomic - RegexNodeKind.Onelazy; N = M; if (N == 0) { - Type = Empty; + Kind = RegexNodeKind.Empty; Str = null; Ch = '\0'; } break; default: - Debug.Fail($"Unexpected type: {Type}"); + Debug.Fail($"Unexpected type: {Kind}"); break; } } @@ -246,7 +177,7 @@ private void MakeLoopAtomic() [Conditional("DEBUG")] private void ValidateFinalTreeInvariants() { - Debug.Assert(Type == Capture, "Every generated tree should begin with a capture node"); + Debug.Assert(Kind == RegexNodeKind.Capture, "Every generated tree should begin with a capture node"); var toExamine = new Stack(); toExamine.Push(this); @@ -259,90 +190,90 @@ private void ValidateFinalTreeInvariants() for (int i = 0; i < childCount; i++) { RegexNode child = node.Child(i); - Debug.Assert(child.Next == node, $"{child.Description()} missing reference to parent {node.Description()}"); + Debug.Assert(child.Parent == node, $"{child.Description()} missing reference to parent {node.Description()}"); toExamine.Push(child); } // Validate that we never see certain node types. - Debug.Assert(Type != Group, "All Group nodes should have been removed."); + Debug.Assert(Kind != RegexNodeKind.Group, "All Group nodes should have been removed."); // Validate node types and expected child counts. - switch (node.Type) + switch (node.Kind) { - case Group: + case RegexNodeKind.Group: Debug.Fail("All Group nodes should have been removed."); break; - case Beginning: - case Bol: - case Boundary: - case ECMABoundary: - case Empty: - case End: - case EndZ: - case Eol: - case Multi: - case NonBoundary: - case NonECMABoundary: - case Nothing: - case Notone: - case Notonelazy: - case Notoneloop: - case Notoneloopatomic: - case One: - case Onelazy: - case Oneloop: - case Oneloopatomic: - case Ref: - case Set: - case Setlazy: - case Setloop: - case Setloopatomic: - case Start: - case UpdateBumpalong: + case RegexNodeKind.Beginning: + case RegexNodeKind.Bol: + case RegexNodeKind.Boundary: + case RegexNodeKind.ECMABoundary: + case RegexNodeKind.Empty: + case RegexNodeKind.End: + case RegexNodeKind.EndZ: + case RegexNodeKind.Eol: + case RegexNodeKind.Multi: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.NonECMABoundary: + case RegexNodeKind.Nothing: + case RegexNodeKind.Notone: + case RegexNodeKind.Notonelazy: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.One: + case RegexNodeKind.Onelazy: + case RegexNodeKind.Oneloop: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Backreference: + case RegexNodeKind.Set: + case RegexNodeKind.Setlazy: + case RegexNodeKind.Setloop: + case RegexNodeKind.Setloopatomic: + case RegexNodeKind.Start: + case RegexNodeKind.UpdateBumpalong: Debug.Assert(childCount == 0, $"Expected zero children for {node.TypeName}, got {childCount}."); break; - case Atomic: - case Capture: - case Lazyloop: - case Loop: - case Prevent: - case Require: + case RegexNodeKind.Atomic: + case RegexNodeKind.Capture: + case RegexNodeKind.Lazyloop: + case RegexNodeKind.Loop: + case RegexNodeKind.NegativeLookaround: + case RegexNodeKind.PositiveLookaround: Debug.Assert(childCount == 1, $"Expected one and only one child for {node.TypeName}, got {childCount}."); break; - case Testref: + case RegexNodeKind.BackreferenceConditional: Debug.Assert(childCount == 2, $"Expected two children for {node.TypeName}, got {childCount}"); break; - case Testgroup: + case RegexNodeKind.ExpressionConditional: Debug.Assert(childCount == 3, $"Expected three children for {node.TypeName}, got {childCount}"); break; - case Concatenate: - case Alternate: + case RegexNodeKind.Concatenate: + case RegexNodeKind.Alternate: Debug.Assert(childCount >= 2, $"Expected at least two children for {node.TypeName}, got {childCount}."); break; default: - Debug.Fail($"Unexpected node type: {node.Type}"); + Debug.Fail($"Unexpected node type: {node.Kind}"); break; } // Validate node configuration. - switch (node.Type) + switch (node.Kind) { - case Multi: + case RegexNodeKind.Multi: Debug.Assert(node.Str is not null, "Expect non-null multi string"); Debug.Assert(node.Str.Length >= 2, $"Expected {node.Str} to be at least two characters"); break; - case Set: - case Setloop: - case Setloopatomic: - case Setlazy: + case RegexNodeKind.Set: + case RegexNodeKind.Setloop: + case RegexNodeKind.Setloopatomic: + case RegexNodeKind.Setlazy: Debug.Assert(!string.IsNullOrEmpty(node.Str), $"Expected non-null, non-empty string for {node.TypeName}."); break; @@ -364,8 +295,8 @@ private void ValidateFinalTreeInvariants() internal RegexNode FinalOptimize() { RegexNode rootNode = this; - Debug.Assert(rootNode.Type == Capture); - Debug.Assert(rootNode.Next is null); + Debug.Assert(rootNode.Kind == RegexNodeKind.Capture); + Debug.Assert(rootNode.Parent is null); Debug.Assert(rootNode.ChildCount() == 1); // Only apply optimization when LTR to avoid needing additional code for the much rarer RTL case. @@ -404,19 +335,19 @@ internal RegexNode FinalOptimize() RegexNode node = rootNode.Child(0); // skip implicit root capture node while (true) { - switch (node.Type) + switch (node.Kind) { - case Atomic: - case Concatenate: + case RegexNodeKind.Atomic: + case RegexNodeKind.Concatenate: node = node.Child(0); continue; - case Oneloop or Oneloopatomic or Notoneloop or Notoneloopatomic or Setloop or Setloopatomic when node.N == int.MaxValue: - case Onelazy or Notonelazy or Setlazy when node.N == int.MaxValue && !node.IsAtomicByParent(): - RegexNode? parent = node.Next; - if (parent != null && parent.Type == Concatenate) + case RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when node.N == int.MaxValue: + case RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy when node.N == int.MaxValue && !node.IsAtomicByParent(): + RegexNode? parent = node.Parent; + if (parent != null && parent.Kind == RegexNodeKind.Concatenate) { - parent.InsertChild(1, new RegexNode(UpdateBumpalong, node.Options)); + parent.InsertChild(1, new RegexNode(RegexNodeKind.UpdateBumpalong, node.Options)); } break; } @@ -454,19 +385,19 @@ private void EliminateEndingBacktracking() RegexNode node = this; while (true) { - switch (node.Type) + switch (node.Kind) { // {One/Notone/Set}loops can be upgraded to {One/Notone/Set}loopatomic nodes, e.g. [abc]* => (?>[abc]*). // And {One/Notone/Set}lazys can similarly be upgraded to be atomic, which really makes them into repeaters // or even empty nodes. - case Oneloop or Notoneloop or Setloop: - case Onelazy or Notonelazy or Setlazy: + case RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop: + case RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy: node.MakeLoopAtomic(); break; // Just because a particular node is atomic doesn't mean all its descendants are. // Process them as well. - case Atomic: + case RegexNodeKind.Atomic: node = node.Child(0); continue; @@ -476,13 +407,13 @@ private void EliminateEndingBacktracking() // node is atomic based on its parent or grandparent, we don't bother wrapping such a node in // an Atomic one if its grandparent is already Atomic. // e.g. [xyz](?:abc|def) => [xyz](?>abc|def) - case Capture: - case Concatenate: + case RegexNodeKind.Capture: + case RegexNodeKind.Concatenate: RegexNode existingChild = node.Child(node.ChildCount() - 1); - if ((existingChild.Type is Alternate or Testref or Testgroup or Loop or Lazyloop) && - (node.Next is null || node.Next.Type != Atomic)) // validate grandparent isn't atomic + if ((existingChild.Kind is RegexNodeKind.Alternate or RegexNodeKind.BackreferenceConditional or RegexNodeKind.ExpressionConditional or RegexNodeKind.Loop or RegexNodeKind.Lazyloop) && + (node.Parent is null || node.Parent.Kind != RegexNodeKind.Atomic)) // validate grandparent isn't atomic { - var atomic = new RegexNode(Atomic, existingChild.Options); + var atomic = new RegexNode(RegexNodeKind.Atomic, existingChild.Options); atomic.AddChild(existingChild); node.ReplaceChild(node.ChildCount() - 1, atomic); } @@ -492,9 +423,9 @@ private void EliminateEndingBacktracking() // For alternate, we can recur into each branch separately. We use this iteration for the first branch. // Conditionals are just like alternations in this regard. // e.g. abc*|def* => ab(?>c*)|de(?>f*) - case Alternate: - case Testref: - case Testgroup: + case RegexNodeKind.Alternate: + case RegexNodeKind.BackreferenceConditional: + case RegexNodeKind.ExpressionConditional: { int branches = node.ChildCount(); for (int i = 1; i < branches; i++) @@ -502,7 +433,7 @@ private void EliminateEndingBacktracking() node.Child(i).EliminateEndingBacktracking(); } - if (node.Type != Testgroup) // ReduceTestgroup will have already applied ending backtracking removal + if (node.Kind != RegexNodeKind.ExpressionConditional) // ReduceTestgroup will have already applied ending backtracking removal { node = node.Child(0); continue; @@ -517,10 +448,10 @@ private void EliminateEndingBacktracking() // repeater, which results in better code generation. // e.g. (?:abc*)* => (?:ab(?>c*))* // e.g. (abc*?)+? => (ab){1} - case Lazyloop: + case RegexNodeKind.Lazyloop: node.N = node.M; - goto case Loop; - case Loop: + goto case RegexNodeKind.Loop; + case RegexNodeKind.Loop: { if (node.N == 1) { @@ -554,31 +485,31 @@ public bool IsAtomicByParent() { // Walk up the parent hierarchy. RegexNode child = this; - for (RegexNode? parent = child.Next; parent is not null; child = parent, parent = child.Next) + for (RegexNode? parent = child.Parent; parent is not null; child = parent, parent = child.Parent) { - switch (parent.Type) + switch (parent.Kind) { - case Atomic: - case Prevent: - case Require: + case RegexNodeKind.Atomic: + case RegexNodeKind.NegativeLookaround: + case RegexNodeKind.PositiveLookaround: // If the parent is atomic, so is the child. That's the whole purpose // of the Atomic node, and lookarounds are also implicitly atomic. return true; - case Alternate: - case Testref: + case RegexNodeKind.Alternate: + case RegexNodeKind.BackreferenceConditional: // Skip alternations. Each branch is considered independently, // so any atomicity applied to the alternation also applies to // each individual branch. This is true as well for conditional // backreferences, where each of the yes/no branches are independent. - case Testgroup when parent.Child(0) != child: + case RegexNodeKind.ExpressionConditional when parent.Child(0) != child: // As with alternations, each yes/no branch of an expression conditional // are independent from each other, but the conditional expression itself // can be backtracked into from each of the branches, so we can't make // it atomic just because the whole conditional is. - case Capture: + case RegexNodeKind.Capture: // Skip captures. They don't affect atomicity. - case Concatenate when parent.Child(parent.ChildCount() - 1) == child: + case RegexNodeKind.Concatenate when parent.Child(parent.ChildCount() - 1) == child: // If the parent is a concatenation and this is the last node, // any atomicity applying to the concatenation applies to this // node, too. @@ -598,18 +529,18 @@ public bool IsAtomicByParent() /// Removes redundant nodes from the subtree, and returns an optimized subtree. /// internal RegexNode Reduce() => - Type switch - { - Alternate => ReduceAlternation(), - Atomic => ReduceAtomic(), - Concatenate => ReduceConcatenation(), - Group => ReduceGroup(), - Loop or Lazyloop => ReduceLoops(), - Prevent => ReducePrevent(), - Require => ReduceRequire(), - Set or Setloop or Setloopatomic or Setlazy => ReduceSet(), - Testgroup => ReduceTestgroup(), - Testref => ReduceTestref(), + Kind switch + { + RegexNodeKind.Alternate => ReduceAlternation(), + RegexNodeKind.Atomic => ReduceAtomic(), + RegexNodeKind.Concatenate => ReduceConcatenation(), + RegexNodeKind.Group => ReduceGroup(), + RegexNodeKind.Loop or RegexNodeKind.Lazyloop => ReduceLoops(), + RegexNodeKind.NegativeLookaround => ReducePrevent(), + RegexNodeKind.PositiveLookaround => ReduceRequire(), + RegexNodeKind.Set or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy => ReduceSet(), + RegexNodeKind.ExpressionConditional => ReduceTestgroup(), + RegexNodeKind.BackreferenceConditional => ReduceTestref(), _ => this, }; @@ -621,10 +552,10 @@ internal RegexNode Reduce() => /// private RegexNode ReplaceNodeIfUnnecessary() { - Debug.Assert(Type is Alternate or Concatenate); + Debug.Assert(Kind is RegexNodeKind.Alternate or RegexNodeKind.Concatenate); return ChildCount() switch { - 0 => new RegexNode(Type == Alternate ? Nothing : Empty, Options), + 0 => new RegexNode(Kind == RegexNodeKind.Alternate ? RegexNodeKind.Nothing : RegexNodeKind.Empty, Options), 1 => Child(0), _ => this, }; @@ -638,10 +569,10 @@ private RegexNode ReplaceNodeIfUnnecessary() /// private RegexNode ReduceGroup() { - Debug.Assert(Type == Group); + Debug.Assert(Kind == RegexNodeKind.Group); RegexNode u = this; - while (u.Type == Group) + while (u.Kind == RegexNodeKind.Group) { Debug.Assert(u.ChildCount() == 1); u = u.Child(0); @@ -666,45 +597,45 @@ private RegexNode ReduceAtomic() return this; } - Debug.Assert(Type == Atomic); + Debug.Assert(Kind == RegexNodeKind.Atomic); Debug.Assert(ChildCount() == 1); RegexNode atomic = this; RegexNode child = Child(0); - while (child.Type == Atomic) + while (child.Kind == RegexNodeKind.Atomic) { atomic = child; child = atomic.Child(0); } - switch (child.Type) + switch (child.Kind) { // If the child is empty/nothing, there's nothing to be made atomic so the Atomic // node can simply be removed. - case Empty: - case Nothing: + case RegexNodeKind.Empty: + case RegexNodeKind.Nothing: return child; // If the child is already atomic, we can just remove the atomic node. - case Oneloopatomic: - case Notoneloopatomic: - case Setloopatomic: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.Setloopatomic: return child; // If an atomic subexpression contains only a {one/notone/set}{loop/lazy}, // change it to be an {one/notone/set}loopatomic and remove the atomic node. - case Oneloop: - case Notoneloop: - case Setloop: - case Onelazy: - case Notonelazy: - case Setlazy: + case RegexNodeKind.Oneloop: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Setloop: + case RegexNodeKind.Onelazy: + case RegexNodeKind.Notonelazy: + case RegexNodeKind.Setlazy: child.MakeLoopAtomic(); return child; // Alternations have a variety of possible optimizations that can be applied // iff they're atomic. - case Alternate: + case RegexNodeKind.Alternate: if ((Options & RegexOptions.RightToLeft) == 0) { List? branches = child.Children as List; @@ -713,9 +644,9 @@ private RegexNode ReduceAtomic() // If an alternation is atomic and its first branch is Empty, the whole thing // is a nop, as Empty will match everything trivially, and no backtracking // into the node will be performed, making the remaining branches irrelevant. - if (branches[0].Type == Empty) + if (branches[0].Kind == RegexNodeKind.Empty) { - return new RegexNode(Empty, child.Options); + return new RegexNode(RegexNodeKind.Empty, child.Options); } // Similarly, we can trim off any branches after an Empty, as they'll never be used. @@ -724,7 +655,7 @@ private RegexNode ReduceAtomic() // but if the alternation is atomic, such backtracking won't happen. for (int i = 1; i < branches.Count - 1; i++) { - if (branches[i].Type == Empty) + if (branches[i].Kind == RegexNodeKind.Empty) { branches.RemoveRange(i + 1, branches.Count - (i + 1)); break; @@ -828,10 +759,10 @@ private RegexNode ReduceAtomic() /// private RegexNode ReduceLoops() { - Debug.Assert(Type == Loop || Type == Lazyloop); + Debug.Assert(Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop); RegexNode u = this; - int type = Type; + RegexNodeKind kind = Kind; int min = M; int max = N; @@ -841,30 +772,30 @@ private RegexNode ReduceLoops() RegexNode child = u.Child(0); // multiply reps of the same type only - if (child.Type != type) + if (child.Kind != kind) { bool valid = false; - if (type == Loop) + if (kind == RegexNodeKind.Loop) { - switch (child.Type) + switch (child.Kind) { - case Oneloop: - case Oneloopatomic: - case Notoneloop: - case Notoneloopatomic: - case Setloop: - case Setloopatomic: + case RegexNodeKind.Oneloop: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.Setloop: + case RegexNodeKind.Setloopatomic: valid = true; break; } } else // type == Lazyloop { - switch (child.Type) + switch (child.Kind) { - case Onelazy: - case Notonelazy: - case Setlazy: + case RegexNodeKind.Onelazy: + case RegexNodeKind.Notonelazy: + case RegexNodeKind.Setlazy: valid = true; break; } @@ -898,7 +829,7 @@ private RegexNode ReduceLoops() if (min == int.MaxValue) { - return new RegexNode(Nothing, Options); + return new RegexNode(RegexNodeKind.Nothing, Options); } // If the Loop or Lazyloop now only has one child node and its a Set, One, or Notone, @@ -908,12 +839,12 @@ private RegexNode ReduceLoops() if (u.ChildCount() == 1) { RegexNode child = u.Child(0); - switch (child.Type) + switch (child.Kind) { - case One: - case Notone: - case Set: - child.MakeRep(u.Type == Lazyloop ? Onelazy : Oneloop, u.M, u.N); + case RegexNodeKind.One: + case RegexNodeKind.Notone: + case RegexNodeKind.Set: + child.MakeRep(u.Kind == RegexNodeKind.Lazyloop ? RegexNodeKind.Onelazy : RegexNodeKind.Oneloop, u.M, u.N); u = child; break; } @@ -937,33 +868,33 @@ private RegexNode ReduceLoops() private RegexNode ReduceSet() { // Extract empty-set, one, and not-one case as special - Debug.Assert(Type == Set || Type == Setloop || Type == Setloopatomic || Type == Setlazy); + Debug.Assert(Kind is RegexNodeKind.Set or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy); Debug.Assert(!string.IsNullOrEmpty(Str)); if (RegexCharClass.IsEmpty(Str)) { - Type = Nothing; + Kind = RegexNodeKind.Nothing; Str = null; } else if (RegexCharClass.IsSingleton(Str)) { Ch = RegexCharClass.SingletonChar(Str); Str = null; - Type = - Type == Set ? One : - Type == Setloop ? Oneloop : - Type == Setloopatomic ? Oneloopatomic : - Onelazy; + Kind = + Kind == RegexNodeKind.Set ? RegexNodeKind.One : + Kind == RegexNodeKind.Setloop ? RegexNodeKind.Oneloop : + Kind == RegexNodeKind.Setloopatomic ? RegexNodeKind.Oneloopatomic : + RegexNodeKind.Onelazy; } else if (RegexCharClass.IsSingletonInverse(Str)) { Ch = RegexCharClass.SingletonChar(Str); Str = null; - Type = - Type == Set ? Notone : - Type == Setloop ? Notoneloop : - Type == Setloopatomic ? Notoneloopatomic : - Notonelazy; + Kind = + Kind == RegexNodeKind.Set ? RegexNodeKind.Notone : + Kind == RegexNodeKind.Setloop ? RegexNodeKind.Notoneloop : + Kind == RegexNodeKind.Setloopatomic ? RegexNodeKind.Notoneloopatomic : + RegexNodeKind.Notonelazy; } return this; @@ -972,12 +903,12 @@ private RegexNode ReduceSet() /// Optimize an alternation. private RegexNode ReduceAlternation() { - Debug.Assert(Type == Alternate); + Debug.Assert(Kind == RegexNodeKind.Alternate); switch (ChildCount()) { case 0: - return new RegexNode(Nothing, Options); + return new RegexNode(RegexNodeKind.Nothing, Options); case 1: return Child(0); @@ -985,13 +916,13 @@ private RegexNode ReduceAlternation() default: ReduceSingleLetterAndNestedAlternations(); RegexNode node = ReplaceNodeIfUnnecessary(); - if (node.Type == Alternate) + if (node.Kind == RegexNodeKind.Alternate) { node = ExtractCommonPrefixText(node); - if (node.Type == Alternate) + if (node.Kind == RegexNodeKind.Alternate) { node = ExtractCommonPrefixOneNotoneSet(node); - if (node.Type == Alternate) + if (node.Kind == RegexNodeKind.Alternate) { node = RemoveRedundantEmptiesAndNothings(node); } @@ -1026,30 +957,30 @@ void ReduceSingleLetterAndNestedAlternations() while (true) { - if (at.Type == Alternate) + if (at.Kind == RegexNodeKind.Alternate) { if (at.Children is List atChildren) { for (int k = 0; k < atChildren.Count; k++) { - atChildren[k].Next = this; + atChildren[k].Parent = this; } children.InsertRange(i + 1, atChildren); } else { RegexNode atChild = (RegexNode)at.Children!; - atChild.Next = this; + atChild.Parent = this; children.Insert(i + 1, atChild); } j--; } - else if (at.Type == Set || at.Type == One) + else if (at.Kind is RegexNodeKind.Set or RegexNodeKind.One) { // Cannot merge sets if L or I options differ, or if either are negated. optionsAt = at.Options & (RegexOptions.RightToLeft | RegexOptions.IgnoreCase); - if (at.Type == Set) + if (at.Kind == RegexNodeKind.Set) { if (!wasLastSet || optionsLast != optionsAt || lastNodeCannotMerge || !RegexCharClass.IsMergeable(at.Str!)) { @@ -1073,7 +1004,7 @@ void ReduceSingleLetterAndNestedAlternations() prev = children[j]; RegexCharClass prevCharClass; - if (prev.Type == One) + if (prev.Kind == RegexNodeKind.One) { prevCharClass = new RegexCharClass(); prevCharClass.AddChar(prev.Ch); @@ -1083,7 +1014,7 @@ void ReduceSingleLetterAndNestedAlternations() prevCharClass = RegexCharClass.Parse(prev.Str!); } - if (at.Type == One) + if (at.Kind == RegexNodeKind.One) { prevCharClass.AddChar(at.Ch); } @@ -1093,7 +1024,7 @@ void ReduceSingleLetterAndNestedAlternations() prevCharClass.AddCharClass(atCharClass); } - prev.Type = Set; + prev.Kind = RegexNodeKind.Set; prev.Str = prevCharClass.ToStringClass(Options); if ((prev.Options & RegexOptions.IgnoreCase) != 0 && RegexCharClass.MakeCaseSensitiveIfPossible(prev.Str, RegexParser.GetTargetCulture(prev.Options)) is string newSetString) @@ -1102,7 +1033,7 @@ void ReduceSingleLetterAndNestedAlternations() prev.Options &= ~RegexOptions.IgnoreCase; } } - else if (at.Type == Nothing) + else if (at.Kind == RegexNodeKind.Nothing) { j--; } @@ -1126,7 +1057,7 @@ void ReduceSingleLetterAndNestedAlternations() // e.g. \w12|\d34|\d56|\w78|\w90 => \w12|\d(?:34|56)|\w(?:78|90) static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) { - Debug.Assert(alternation.Type == Alternate); + Debug.Assert(alternation.Kind == RegexNodeKind.Alternate); Debug.Assert(alternation.Children is List { Count: >= 2 }); var children = (List)alternation.Children; @@ -1139,7 +1070,7 @@ static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) // Only handle the case where each branch is a concatenation foreach (RegexNode child in children) { - if (child.Type != Concatenate || child.ChildCount() < 2) + if (child.Kind != RegexNodeKind.Concatenate || child.ChildCount() < 2) { return alternation; } @@ -1154,11 +1085,11 @@ static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) // it for non-atomic variable length loops could change behavior as each branch could otherwise have a // different number of characters consumed by the loop based on what's after it. RegexNode required = children[startingIndex].Child(0); - switch (required.Type) + switch (required.Kind) { - case One or Notone or Set: - case Oneloopatomic or Notoneloopatomic or Setloopatomic: - case Oneloop or Notoneloop or Setloop or Onelazy or Notonelazy or Setlazy when required.M == required.N: + case RegexNodeKind.One or RegexNodeKind.Notone or RegexNodeKind.Set: + case RegexNodeKind.Oneloopatomic or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Setloopatomic: + case RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop or RegexNodeKind.Onelazy or RegexNodeKind.Notonelazy or RegexNodeKind.Setlazy when required.M == required.N: break; default: @@ -1170,7 +1101,7 @@ static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) for (; endingIndex < children.Count; endingIndex++) { RegexNode other = children[endingIndex].Child(0); - if (required.Type != other.Type || + if (required.Kind != other.Kind || required.Options != other.Options || required.M != other.M || required.N != other.N || @@ -1188,7 +1119,7 @@ static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) } // Remove the prefix node from every branch, adding it to a new alternation - var newAlternate = new RegexNode(Alternate, alternation.Options); + var newAlternate = new RegexNode(RegexNodeKind.Alternate, alternation.Options); for (int i = startingIndex; i < endingIndex; i++) { ((List)children[i].Children!).RemoveAt(0); @@ -1196,16 +1127,16 @@ static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) } // If this alternation is wrapped as atomic, we need to do the same for the new alternation. - if (alternation.Next is RegexNode parent && parent.Type == Atomic) + if (alternation.Parent is RegexNode { Kind: RegexNodeKind.Atomic } parent) { - var atomic = new RegexNode(Atomic, alternation.Options); + var atomic = new RegexNode(RegexNodeKind.Atomic, alternation.Options); atomic.AddChild(newAlternate); newAlternate = atomic; } // Now create a concatenation of the prefix node with the new alternation for the combined // branches, and replace all of the branches in this alternation with that new concatenation. - var newConcat = new RegexNode(Concatenate, alternation.Options); + var newConcat = new RegexNode(RegexNodeKind.Concatenate, alternation.Options); newConcat.AddChild(required); newConcat.AddChild(newAlternate); alternation.ReplaceChild(startingIndex, newConcat); @@ -1221,7 +1152,7 @@ static RegexNode ExtractCommonPrefixOneNotoneSet(RegexNode alternation) // alternation, and while we don't check for all duplicates, checking for empty is easy. static RegexNode RemoveRedundantEmptiesAndNothings(RegexNode node) { - Debug.Assert(node.Type == Alternate); + Debug.Assert(node.Kind == RegexNodeKind.Alternate); Debug.Assert(node.ChildCount() >= 2); var children = (List)node.Children!; @@ -1230,14 +1161,14 @@ static RegexNode RemoveRedundantEmptiesAndNothings(RegexNode node) while (i < children.Count) { RegexNode child = children[i]; - switch (child.Type) + switch (child.Kind) { - case Empty when !seenEmpty: + case RegexNodeKind.Empty when !seenEmpty: seenEmpty = true; goto default; - case Empty: - case Nothing: + case RegexNodeKind.Empty: + case RegexNodeKind.Nothing: i++; break; @@ -1264,7 +1195,7 @@ static RegexNode RemoveRedundantEmptiesAndNothings(RegexNode node) // e.g. abc|ade => a(?bc|de) static RegexNode ExtractCommonPrefixText(RegexNode alternation) { - Debug.Assert(alternation.Type == Alternate); + Debug.Assert(alternation.Kind == RegexNodeKind.Alternate); Debug.Assert(alternation.Children is List { Count: >= 2 }); var children = (List)alternation.Children; @@ -1292,7 +1223,7 @@ static RegexNode ExtractCommonPrefixText(RegexNode alternation) RegexOptions startingNodeOptions = startingNode.Options; startingSpan = startingNode.Str.AsSpan(); - if (startingNode.Type == One) + if (startingNode.Kind == RegexNodeKind.One) { scratchChar[0] = startingNode.Ch; startingSpan = scratchChar; @@ -1312,7 +1243,7 @@ static RegexNode ExtractCommonPrefixText(RegexNode alternation) // See if the new branch's prefix has a shared prefix with the current one. // If it does, shorten to that; if it doesn't, bail. - if (startingNode.Type == One) + if (startingNode.Kind == RegexNodeKind.One) { if (startingSpan[0] != startingNode.Ch) { @@ -1326,7 +1257,7 @@ static RegexNode ExtractCommonPrefixText(RegexNode alternation) } else { - Debug.Assert(startingNode.Type == Multi); + Debug.Assert(startingNode.Kind == RegexNodeKind.Multi); Debug.Assert(startingNode.Str!.Length > 0); int minLength = Math.Min(startingSpan.Length, startingNode.Str.Length); @@ -1357,13 +1288,13 @@ static RegexNode ExtractCommonPrefixText(RegexNode alternation) // that replaces all these branches in this alternation. var prefix = startingSpan.Length == 1 ? - new RegexNode(One, startingNodeOptions, startingSpan[0]) : - new RegexNode(Multi, startingNodeOptions, startingSpan.ToString()); - var newAlternate = new RegexNode(Alternate, startingNodeOptions); + new RegexNode(RegexNodeKind.One, startingNodeOptions, startingSpan[0]) : + new RegexNode(RegexNodeKind.Multi, startingNodeOptions, startingSpan.ToString()); + var newAlternate = new RegexNode(RegexNodeKind.Alternate, startingNodeOptions); for (int i = startingIndex; i < endingIndex; i++) { RegexNode branch = children[i]; - ProcessOneOrMulti(branch.Type == Concatenate ? branch.Child(0) : branch, startingSpan); + ProcessOneOrMulti(branch.Kind == RegexNodeKind.Concatenate ? branch.Child(0) : branch, startingSpan); branch = branch.Reduce(); newAlternate.AddChild(branch); @@ -1371,25 +1302,25 @@ static RegexNode ExtractCommonPrefixText(RegexNode alternation) // the type of the node to be Empty if the starting text matches the node's full value. static void ProcessOneOrMulti(RegexNode node, ReadOnlySpan startingSpan) { - if (node.Type == One) + if (node.Kind == RegexNodeKind.One) { Debug.Assert(startingSpan.Length == 1); Debug.Assert(startingSpan[0] == node.Ch); - node.Type = Empty; + node.Kind = RegexNodeKind.Empty; node.Ch = '\0'; } else { - Debug.Assert(node.Type == Multi); + Debug.Assert(node.Kind == RegexNodeKind.Multi); Debug.Assert(node.Str.AsSpan().StartsWith(startingSpan, StringComparison.Ordinal)); if (node.Str!.Length == startingSpan.Length) { - node.Type = Empty; + node.Kind = RegexNodeKind.Empty; node.Str = null; } else if (node.Str.Length - 1 == startingSpan.Length) { - node.Type = One; + node.Kind = RegexNodeKind.One; node.Ch = node.Str[node.Str.Length - 1]; node.Str = null; } @@ -1401,14 +1332,14 @@ static void ProcessOneOrMulti(RegexNode node, ReadOnlySpan startingSpan) } } - if (alternation.Next is RegexNode parent && parent.Type == Atomic) + if (alternation.Parent is RegexNode parent && parent.Kind == RegexNodeKind.Atomic) { - var atomic = new RegexNode(Atomic, startingNodeOptions); + var atomic = new RegexNode(RegexNodeKind.Atomic, startingNodeOptions); atomic.AddChild(newAlternate); newAlternate = atomic; } - var newConcat = new RegexNode(Concatenate, startingNodeOptions); + var newConcat = new RegexNode(RegexNodeKind.Concatenate, startingNodeOptions); newConcat.AddChild(prefix); newConcat.AddChild(newAlternate); alternation.ReplaceChild(startingIndex, newConcat); @@ -1428,23 +1359,23 @@ static void ProcessOneOrMulti(RegexNode node, ReadOnlySpan startingSpan) /// public RegexNode? FindBranchOneOrMultiStart() { - RegexNode branch = Type == Concatenate ? Child(0) : this; - return branch.Type is One or Multi ? branch : null; + RegexNode branch = Kind == RegexNodeKind.Concatenate ? Child(0) : this; + return branch.Kind is RegexNodeKind.One or RegexNodeKind.Multi ? branch : null; } /// Same as but also for Sets. public RegexNode? FindBranchOneMultiOrSetStart() { - RegexNode branch = Type == Concatenate ? Child(0) : this; - return branch.Type is One or Multi or Set ? branch : null; + RegexNode branch = Kind == RegexNodeKind.Concatenate ? Child(0) : this; + return branch.Kind is RegexNodeKind.One or RegexNodeKind.Multi or RegexNodeKind.Set ? branch : null; } /// Gets the character that begins a One or Multi. public char FirstCharOfOneOrMulti() { - Debug.Assert(Type is One or Multi); + Debug.Assert(Kind is RegexNodeKind.One or RegexNodeKind.Multi); Debug.Assert((Options & RegexOptions.RightToLeft) == 0); - return Type == One ? Ch : Str![0]; + return Kind == RegexNodeKind.One ? Ch : Str![0]; } /// Finds the guaranteed beginning character of the node, or null if none exists. @@ -1455,29 +1386,29 @@ public char FirstCharOfOneOrMulti() { if (node is not null && (node.Options & RegexOptions.RightToLeft) == 0) { - switch (node.Type) + switch (node.Kind) { - case One: - case Oneloop or Oneloopatomic or Onelazy when node.M > 0: + case RegexNodeKind.One: + case RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy when node.M > 0: if ((node.Options & RegexOptions.IgnoreCase) == 0 || !RegexCharClass.ParticipatesInCaseConversion(node.Ch)) { return (node.Ch, null); } break; - case Multi: + case RegexNodeKind.Multi: if ((node.Options & RegexOptions.IgnoreCase) == 0 || !RegexCharClass.ParticipatesInCaseConversion(node.Str.AsSpan())) { return ('\0', node.Str); } break; - case Atomic: - case Concatenate: - case Capture: - case Group: - case Loop or Lazyloop when node.M > 0: - case Require: + case RegexNodeKind.Atomic: + case RegexNodeKind.Concatenate: + case RegexNodeKind.Capture: + case RegexNodeKind.Group: + case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when node.M > 0: + case RegexNodeKind.PositiveLookaround: node = node.Child(0); continue; } @@ -1494,13 +1425,13 @@ public char FirstCharOfOneOrMulti() /// private RegexNode ReduceConcatenation() { - Debug.Assert(Type == Concatenate); + Debug.Assert(Kind == RegexNodeKind.Concatenate); // If the concat node has zero or only one child, get rid of the concat. switch (ChildCount()) { case 0: - return new RegexNode(Empty, Options); + return new RegexNode(RegexNodeKind.Empty, Options); case 1: return Child(0); } @@ -1523,7 +1454,7 @@ private RegexNode ReduceConcatenation() /// private void ReduceConcatenationWithAdjacentStrings() { - Debug.Assert(Type == Concatenate); + Debug.Assert(Kind == RegexNodeKind.Concatenate); Debug.Assert(Children is List); bool wasLastString = false; @@ -1540,26 +1471,26 @@ private void ReduceConcatenationWithAdjacentStrings() children[j] = at; } - if (at.Type == Concatenate && + if (at.Kind == RegexNodeKind.Concatenate && ((at.Options & RegexOptions.RightToLeft) == (Options & RegexOptions.RightToLeft))) { if (at.Children is List atChildren) { for (int k = 0; k < atChildren.Count; k++) { - atChildren[k].Next = this; + atChildren[k].Parent = this; } children.InsertRange(i + 1, atChildren); } else { RegexNode atChild = (RegexNode)at.Children!; - atChild.Next = this; + atChild.Parent = this; children.Insert(i + 1, atChild); } j--; } - else if (at.Type == Multi || at.Type == One) + else if (at.Kind is RegexNodeKind.Multi or RegexNodeKind.One) { // Cannot merge strings if L or I options differ RegexOptions optionsAt = at.Options & (RegexOptions.RightToLeft | RegexOptions.IgnoreCase); @@ -1573,22 +1504,22 @@ private void ReduceConcatenationWithAdjacentStrings() RegexNode prev = children[--j]; - if (prev.Type == One) + if (prev.Kind == RegexNodeKind.One) { - prev.Type = Multi; + prev.Kind = RegexNodeKind.Multi; prev.Str = prev.Ch.ToString(); } if ((optionsAt & RegexOptions.RightToLeft) == 0) { - prev.Str = (at.Type == One) ? $"{prev.Str}{at.Ch}" : prev.Str + at.Str; + prev.Str = (at.Kind == RegexNodeKind.One) ? $"{prev.Str}{at.Ch}" : prev.Str + at.Str; } else { - prev.Str = (at.Type == One) ? $"{at.Ch}{prev.Str}" : at.Str + prev.Str; + prev.Str = (at.Kind == RegexNodeKind.One) ? $"{at.Ch}{prev.Str}" : at.Str + prev.Str; } } - else if (at.Type == Empty) + else if (at.Kind == RegexNodeKind.Empty) { j--; } @@ -1610,7 +1541,7 @@ private void ReduceConcatenationWithAdjacentStrings() /// private void ReduceConcatenationWithAdjacentLoops() { - Debug.Assert(Type == Concatenate); + Debug.Assert(Kind == RegexNodeKind.Concatenate); Debug.Assert(Children is List); var children = (List)Children!; @@ -1645,11 +1576,11 @@ static bool CanCombineCounts(int nodeMin, int nodeMax, int nextMin, int nextMax) return true; } - switch (currentNode.Type) + switch (currentNode.Kind) { // Coalescing a loop with its same type - case Oneloop or Oneloopatomic or Onelazy or Notoneloop or Notoneloopatomic or Notonelazy when nextNode.Type == currentNode.Type && currentNode.Ch == nextNode.Ch: - case Setloop or Setloopatomic or Setlazy when nextNode.Type == currentNode.Type && currentNode.Str == nextNode.Str: + case RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy when nextNode.Kind == currentNode.Kind && currentNode.Ch == nextNode.Ch: + case RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy when nextNode.Kind == currentNode.Kind && currentNode.Str == nextNode.Str: if (CanCombineCounts(currentNode.M, currentNode.N, nextNode.M, nextNode.N)) { currentNode.M += nextNode.M; @@ -1663,9 +1594,9 @@ static bool CanCombineCounts(int nodeMin, int nodeMax, int nextMin, int nextMax) break; // Coalescing a loop with an additional item of the same type - case Oneloop or Oneloopatomic or Onelazy when nextNode.Type == One && currentNode.Ch == nextNode.Ch: - case Notoneloop or Notoneloopatomic or Notonelazy when nextNode.Type == Notone && currentNode.Ch == nextNode.Ch: - case Setloop or Setloopatomic or Setlazy when nextNode.Type == Set && currentNode.Str == nextNode.Str: + case RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy when nextNode.Kind == RegexNodeKind.One && currentNode.Ch == nextNode.Ch: + case RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy when nextNode.Kind == RegexNodeKind.Notone && currentNode.Ch == nextNode.Ch: + case RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy when nextNode.Kind == RegexNodeKind.Set && currentNode.Str == nextNode.Str: if (CanCombineCounts(currentNode.M, currentNode.N, 1, 1)) { currentNode.M++; @@ -1679,12 +1610,12 @@ static bool CanCombineCounts(int nodeMin, int nodeMax, int nextMin, int nextMax) break; // Coalescing an individual item with a loop. - case One when (nextNode.Type == Oneloop || nextNode.Type == Oneloopatomic || nextNode.Type == Onelazy) && currentNode.Ch == nextNode.Ch: - case Notone when (nextNode.Type == Notoneloop || nextNode.Type == Notoneloopatomic || nextNode.Type == Notonelazy) && currentNode.Ch == nextNode.Ch: - case Set when (nextNode.Type == Setloop || nextNode.Type == Setloopatomic || nextNode.Type == Setlazy) && currentNode.Str == nextNode.Str: + case RegexNodeKind.One when (nextNode.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy) && currentNode.Ch == nextNode.Ch: + case RegexNodeKind.Notone when (nextNode.Kind is RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy) && currentNode.Ch == nextNode.Ch: + case RegexNodeKind.Set when (nextNode.Kind is RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy) && currentNode.Str == nextNode.Str: if (CanCombineCounts(1, 1, nextNode.M, nextNode.N)) { - currentNode.Type = nextNode.Type; + currentNode.Kind = nextNode.Kind; currentNode.M = nextNode.M + 1; currentNode.N = nextNode.N == int.MaxValue ? int.MaxValue : nextNode.N + 1; next++; @@ -1693,9 +1624,9 @@ static bool CanCombineCounts(int nodeMin, int nodeMax, int nextMin, int nextMax) break; // Coalescing an individual item with another individual item. - case One or Notone when nextNode.Type == currentNode.Type && currentNode.Ch == nextNode.Ch: - case Set when nextNode.Type == Set && currentNode.Str == nextNode.Str: - currentNode.MakeRep(Oneloop, 2, 2); + case RegexNodeKind.One or RegexNodeKind.Notone when nextNode.Kind == currentNode.Kind && currentNode.Ch == nextNode.Ch: + case RegexNodeKind.Set when nextNode.Kind == RegexNodeKind.Set && currentNode.Str == nextNode.Str: + currentNode.MakeRep(RegexNodeKind.Oneloop, 2, 2); next++; continue; } @@ -1744,7 +1675,7 @@ private void FindAndMakeLoopsAtomic() } // If this isn't a concatenation, nothing more to do. - if (Type is not Concatenate) + if (Kind is not RegexNodeKind.Concatenate) { return; } @@ -1769,7 +1700,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) while (true) { // We can always recur into captures and into the last node of concatenations. - if (node.Type == Capture || node.Type == Concatenate) + if (node.Kind is RegexNodeKind.Capture or RegexNodeKind.Concatenate) { node = node.Child(node.ChildCount() - 1); continue; @@ -1779,7 +1710,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) // we need to be careful not to just always do so; the ending node of a loop can only // be made atomic if what comes after the loop but also the beginning of the loop are // compatible for the optimization. - if (node.Type == Loop) + if (node.Kind == RegexNodeKind.Loop) { RegexNode? loopDescendent = node.FindLastExpressionInLoopForAutoAtomic(); if (loopDescendent != null) @@ -1794,16 +1725,13 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) } // If the node can be changed to atomic based on what comes after it, do so. - switch (node.Type) + switch (node.Kind) { - case Oneloop when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: true): - case Notoneloop when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: true): - case Setloop when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: true): + case RegexNodeKind.Oneloop or RegexNodeKind.Notoneloop or RegexNodeKind.Setloop when CanBeMadeAtomic(node, subsequent, allowSubsequentIteration: true): node.MakeLoopAtomic(); break; - case Alternate: - case Testref: - case Testgroup: + + case RegexNodeKind.Alternate or RegexNodeKind.BackreferenceConditional or RegexNodeKind.ExpressionConditional: // In the case of alternation, we can't change the alternation node itself // based on what comes after it (at least not with more complicated analysis // that factors in all branches together), but we can look at each individual @@ -1814,7 +1742,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) // itself, as it's already considered atomic and handled as part of ReduceTestgroup. { int alternateBranches = node.ChildCount(); - for (int b = node.Type == Testgroup ? 1 : 0; b < alternateBranches; b++) + for (int b = node.Kind == RegexNodeKind.ExpressionConditional ? 1 : 0; b < alternateBranches; b++) { ProcessNode(node.Child(b), subsequent); } @@ -1834,13 +1762,13 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) { RegexNode node = this; - Debug.Assert(node.Type is Loop or Lazyloop); + Debug.Assert(node.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop); // Start by looking at the loop's sole child. node = node.Child(0); // Skip past captures. - while (node.Type == Capture) + while (node.Kind == RegexNodeKind.Capture) { node = node.Child(0); } @@ -1851,7 +1779,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) // example, in the expression (a+[def])*, the last child is [def] and the first is // a+, which can't possibly overlap with [def]. In contrast, if we had (a+[ade])*, // [ade] could potentially match the starting 'a'. - if (node.Type == Concatenate) + if (node.Kind == RegexNodeKind.Concatenate) { int concatCount = node.ChildCount(); RegexNode lastConcatChild = node.Child(concatCount - 1); @@ -1868,7 +1796,7 @@ static void ProcessNode(RegexNode node, RegexNode subsequent) /// Optimizations for positive lookaheads/behinds. private RegexNode ReduceRequire() { - Debug.Assert(Type == Require); + Debug.Assert(Kind == RegexNodeKind.PositiveLookaround); Debug.Assert(ChildCount() == 1); // A positive lookaround is a zero-width atomic assertion. @@ -1879,9 +1807,9 @@ private RegexNode ReduceRequire() // A positive lookaround wrapped around an empty is a nop, and can just // be made into an empty. A developer typically doesn't write this, but // rather it evolves due to optimizations resulting in empty. - if (Child(0).Type == Empty) + if (Child(0).Kind == RegexNodeKind.Empty) { - Type = Empty; + Kind = RegexNodeKind.Empty; Children = null; } @@ -1891,15 +1819,15 @@ private RegexNode ReduceRequire() /// Optimizations for negative lookaheads/behinds. private RegexNode ReducePrevent() { - Debug.Assert(Type == Prevent); + Debug.Assert(Kind == RegexNodeKind.NegativeLookaround); Debug.Assert(ChildCount() == 1); // A negative lookaround wrapped around an empty child, i.e. (?!), is // sometimes used as a way to insert a guaranteed no-match into the expression. // We can reduce it to simply Nothing. - if (Child(0).Type == Empty) + if (Child(0).Kind == RegexNodeKind.Empty) { - Type = Nothing; + Kind = RegexNodeKind.Nothing; Children = null; } @@ -1909,7 +1837,7 @@ private RegexNode ReducePrevent() /// Optimizations for backreference conditionals. private RegexNode ReduceTestref() { - Debug.Assert(Type == Testref); + Debug.Assert(Kind == RegexNodeKind.BackreferenceConditional); Debug.Assert(ChildCount() is 1 or 2); // This isn't so much an optimization as it is changing the tree for consistency. @@ -1918,7 +1846,7 @@ private RegexNode ReduceTestref() // we add one that will match empty. if (ChildCount() == 1) { - AddChild(new RegexNode(Empty, Options)); + AddChild(new RegexNode(RegexNodeKind.Empty, Options)); } return this; @@ -1927,7 +1855,7 @@ private RegexNode ReduceTestref() /// Optimizations for expression conditionals. private RegexNode ReduceTestgroup() { - Debug.Assert(Type == Testgroup); + Debug.Assert(Kind == RegexNodeKind.ExpressionConditional); Debug.Assert(ChildCount() is 2 or 3); // This isn't so much an optimization as it is changing the tree for consistency. @@ -1936,7 +1864,7 @@ private RegexNode ReduceTestgroup() // we add one that will match empty. if (ChildCount() == 2) { - AddChild(new RegexNode(Empty, Options)); + AddChild(new RegexNode(RegexNodeKind.Empty, Options)); } // It's common for the condition to be an explicit positive lookahead, as specifying @@ -1945,7 +1873,7 @@ private RegexNode ReduceTestgroup() // there's no ambiguity, and we can remove an extra level of positive lookahead, as the // engines need to treat the condition as a zero-width positive, atomic assertion regardless. RegexNode condition = Child(0); - if (condition.Type == Require && (condition.Options & RegexOptions.RightToLeft) == 0) + if (condition.Kind == RegexNodeKind.PositiveLookaround && (condition.Options & RegexOptions.RightToLeft) == 0) { ReplaceChild(0, condition.Child(0)); } @@ -1980,14 +1908,14 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a int childCount; while ((childCount = subsequent.ChildCount()) > 0) { - Debug.Assert(subsequent.Type != Group); - switch (subsequent.Type) + Debug.Assert(subsequent.Kind != RegexNodeKind.Group); + switch (subsequent.Kind) { - case Concatenate: - case Capture: - case Atomic: - case Require when (subsequent.Options & RegexOptions.RightToLeft) == 0: // only lookaheads, not lookbehinds (represented as RTL Require nodes) - case Loop or Lazyloop when subsequent.M > 0: + case RegexNodeKind.Concatenate: + case RegexNodeKind.Capture: + case RegexNodeKind.Atomic: + case RegexNodeKind.PositiveLookaround when (subsequent.Options & RegexOptions.RightToLeft) == 0: // only lookaheads, not lookbehinds (represented as RTL PositiveLookaround nodes) + case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when subsequent.M > 0: subsequent = subsequent.Child(0); continue; } @@ -2008,10 +1936,10 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a // only a yes branch, we'd need to also check whatever comes after the conditional). It doesn't apply to // backreference conditionals, as the condition itself is unknown statically and could overlap with the // loop being considered for atomicity. - switch (subsequent.Type) + switch (subsequent.Kind) { - case Alternate: - case Testgroup when childCount == 3: // condition, yes, and no branch + case RegexNodeKind.Alternate: + case RegexNodeKind.ExpressionConditional when childCount == 3: // condition, yes, and no branch for (int i = 0; i < childCount; i++) { if (!CanBeMadeAtomic(node, subsequent.Child(i), allowSubsequentIteration)) @@ -2025,29 +1953,29 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a // If this node is a {one/notone/set}loop, see if it overlaps with its successor in the concatenation. // If it doesn't, then we can upgrade it to being a {one/notone/set}loopatomic. // Doing so avoids unnecessary backtracking. - switch (node.Type) + switch (node.Kind) { - case Oneloop: - switch (subsequent.Type) + case RegexNodeKind.Oneloop: + switch (subsequent.Kind) { - case One when node.Ch != subsequent.Ch: - case Notone when node.Ch == subsequent.Ch: - case Set when !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch != subsequent.Ch: - case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: - case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): - case Multi when node.Ch != subsequent.Str![0]: - case End: - case EndZ or Eol when node.Ch != '\n': - case Boundary when RegexCharClass.IsBoundaryWordChar(node.Ch): - case NonBoundary when !RegexCharClass.IsBoundaryWordChar(node.Ch): - case ECMABoundary when RegexCharClass.IsECMAWordChar(node.Ch): - case NonECMABoundary when !RegexCharClass.IsECMAWordChar(node.Ch): + case RegexNodeKind.One when node.Ch != subsequent.Ch: + case RegexNodeKind.Notone when node.Ch == subsequent.Ch: + case RegexNodeKind.Set when !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M > 0 && node.Ch != subsequent.Ch: + case RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: + case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + case RegexNodeKind.Multi when node.Ch != subsequent.Str![0]: + case RegexNodeKind.End: + case RegexNodeKind.EndZ or RegexNodeKind.Eol when node.Ch != '\n': + case RegexNodeKind.Boundary when RegexCharClass.IsBoundaryWordChar(node.Ch): + case RegexNodeKind.NonBoundary when !RegexCharClass.IsBoundaryWordChar(node.Ch): + case RegexNodeKind.ECMABoundary when RegexCharClass.IsECMAWordChar(node.Ch): + case RegexNodeKind.NonECMABoundary when !RegexCharClass.IsECMAWordChar(node.Ch): return true; - case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && node.Ch != subsequent.Ch: - case Notonelazy or Notoneloop or Notoneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: - case Setlazy or Setloop or Setloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): + case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M == 0 && node.Ch != subsequent.Ch: + case RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: + case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(node.Ch, subsequent.Str!): // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. break; @@ -2056,16 +1984,16 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a } break; - case Notoneloop: - switch (subsequent.Type) + case RegexNodeKind.Notoneloop: + switch (subsequent.Kind) { - case One when node.Ch == subsequent.Ch: - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: - case Multi when node.Ch == subsequent.Str![0]: - case End: + case RegexNodeKind.One when node.Ch == subsequent.Ch: + case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M > 0 && node.Ch == subsequent.Ch: + case RegexNodeKind.Multi when node.Ch == subsequent.Str![0]: + case RegexNodeKind.End: return true; - case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: + case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M == 0 && node.Ch == subsequent.Ch: // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. break; @@ -2074,24 +2002,24 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a } break; - case Setloop: - switch (subsequent.Type) + case RegexNodeKind.Setloop: + switch (subsequent.Kind) { - case One when !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Set when !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): - case Onelazy or Oneloop or Oneloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Setlazy or Setloop or Setloopatomic when subsequent.M > 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): - case Multi when !RegexCharClass.CharInClass(subsequent.Str![0], node.Str!): - case End: - case EndZ or Eol when !RegexCharClass.CharInClass('\n', node.Str!): - case Boundary when node.Str == RegexCharClass.WordClass || node.Str == RegexCharClass.DigitClass: - case NonBoundary when node.Str == RegexCharClass.NotWordClass || node.Str == RegexCharClass.NotDigitClass: - case ECMABoundary when node.Str == RegexCharClass.ECMAWordClass || node.Str == RegexCharClass.ECMADigitClass: - case NonECMABoundary when node.Str == RegexCharClass.NotECMAWordClass || node.Str == RegexCharClass.NotDigitClass: + case RegexNodeKind.One when !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case RegexNodeKind.Set when !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M > 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M > 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + case RegexNodeKind.Multi when !RegexCharClass.CharInClass(subsequent.Str![0], node.Str!): + case RegexNodeKind.End: + case RegexNodeKind.EndZ or RegexNodeKind.Eol when !RegexCharClass.CharInClass('\n', node.Str!): + case RegexNodeKind.Boundary when node.Str is RegexCharClass.WordClass or RegexCharClass.DigitClass: + case RegexNodeKind.NonBoundary when node.Str is RegexCharClass.NotWordClass or RegexCharClass.NotDigitClass: + case RegexNodeKind.ECMABoundary when node.Str is RegexCharClass.ECMAWordClass or RegexCharClass.ECMADigitClass: + case RegexNodeKind.NonECMABoundary when node.Str is RegexCharClass.NotECMAWordClass or RegexCharClass.NotDigitClass: return true; - case Onelazy or Oneloop or Oneloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): - case Setlazy or Setloop or Setloopatomic when subsequent.M == 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): + case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when subsequent.M == 0 && !RegexCharClass.CharInClass(subsequent.Ch, node.Str!): + case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when subsequent.M == 0 && !RegexCharClass.MayOverlap(node.Str!, subsequent.Str!): // The loop can be made atomic based on this subsequent node, but we'll need to evaluate the next one as well. break; @@ -2106,7 +2034,7 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a // We only get here if the node could be made atomic based on subsequent but subsequent has a lower bound of zero // and thus we need to move subsequent to be the next node in sequence and loop around to try again. - Debug.Assert(subsequent.Type is Oneloop or Oneloopatomic or Onelazy or Notoneloop or Notoneloopatomic or Notonelazy or Setloop or Setloopatomic or Setlazy); + Debug.Assert(subsequent.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy); Debug.Assert(subsequent.M == 0); if (!allowSubsequentIteration) { @@ -2118,16 +2046,16 @@ private static bool CanBeMadeAtomic(RegexNode node, RegexNode subsequent, bool a // which point subsequent becomes whatever node is next in that concatenation. while (true) { - RegexNode? parent = subsequent.Next; - switch (parent?.Type) + RegexNode? parent = subsequent.Parent; + switch (parent?.Kind) { - case Atomic: - case Alternate: - case Capture: + case RegexNodeKind.Atomic: + case RegexNodeKind.Alternate: + case RegexNodeKind.Capture: subsequent = parent; continue; - case Concatenate: + case RegexNodeKind.Concatenate: var peers = (List)parent.Children!; int currentIndex = peers.IndexOf(subsequent); Debug.Assert(currentIndex >= 0, "Node should have been in its parent's child list"); @@ -2170,36 +2098,36 @@ public int ComputeMinLength() return 0; } - switch (Type) + switch (Kind) { - case One: - case Notone: - case Set: + case RegexNodeKind.One: + case RegexNodeKind.Notone: + case RegexNodeKind.Set: // Single character. return 1; - case Multi: + case RegexNodeKind.Multi: // Every character in the string needs to match. return Str!.Length; - case Notonelazy: - case Notoneloop: - case Notoneloopatomic: - case Onelazy: - case Oneloop: - case Oneloopatomic: - case Setlazy: - case Setloop: - case Setloopatomic: + case RegexNodeKind.Notonelazy: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.Onelazy: + case RegexNodeKind.Oneloop: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Setlazy: + case RegexNodeKind.Setloop: + case RegexNodeKind.Setloopatomic: // One character repeated at least M times. return M; - case Lazyloop: - case Loop: + case RegexNodeKind.Lazyloop: + case RegexNodeKind.Loop: // A node graph repeated at least M times. return (int)Math.Min(int.MaxValue, (long)M * Child(0).ComputeMinLength()); - case Alternate: + case RegexNodeKind.Alternate: // The minimum required length for any of the alternation's branches. { int childCount = ChildCount(); @@ -2212,15 +2140,15 @@ public int ComputeMinLength() return min; } - case Testref: + case RegexNodeKind.BackreferenceConditional: // Minimum of its yes and no branches. The backreference doesn't add to the length. return Math.Min(Child(0).ComputeMinLength(), Child(1).ComputeMinLength()); - case Testgroup: + case RegexNodeKind.ExpressionConditional: // Minimum of its yes and no branches. The condition is a zero-width assertion. return Math.Min(Child(1).ComputeMinLength(), Child(2).ComputeMinLength()); - case Concatenate: + case RegexNodeKind.Concatenate: // The sum of all of the concatenation's children. { long sum = 0; @@ -2232,36 +2160,36 @@ public int ComputeMinLength() return (int)Math.Min(int.MaxValue, sum); } - case Atomic: - case Capture: - case Group: + case RegexNodeKind.Atomic: + case RegexNodeKind.Capture: + case RegexNodeKind.Group: // For groups, we just delegate to the sole child. Debug.Assert(ChildCount() == 1); return Child(0).ComputeMinLength(); - case Empty: - case Nothing: - case UpdateBumpalong: + case RegexNodeKind.Empty: + case RegexNodeKind.Nothing: + case RegexNodeKind.UpdateBumpalong: // Nothing to match. In the future, we could potentially use Nothing to say that the min length // is infinite, but that would require a different structure, as that would only apply if the // Nothing match is required in all cases (rather than, say, as one branch of an alternation). - case Beginning: - case Bol: - case Boundary: - case ECMABoundary: - case End: - case EndZ: - case Eol: - case NonBoundary: - case NonECMABoundary: - case Start: + case RegexNodeKind.Beginning: + case RegexNodeKind.Bol: + case RegexNodeKind.Boundary: + case RegexNodeKind.ECMABoundary: + case RegexNodeKind.End: + case RegexNodeKind.EndZ: + case RegexNodeKind.Eol: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.NonECMABoundary: + case RegexNodeKind.Start: // Difficult to glean anything meaningful from boundaries or results only known at run time. - case Prevent: - case Require: + case RegexNodeKind.NegativeLookaround: + case RegexNodeKind.PositiveLookaround: // Lookaheads/behinds could potentially be included in the future, but that will require // a different structure, as they can't be added as part of a concatenation, since they overlap // with what comes after. - case Ref: + case RegexNodeKind.Backreference: // Constructs requiring data at runtime from the matching pattern can't influence min length. return 0; @@ -2269,7 +2197,7 @@ public int ComputeMinLength() #if DEBUG Debug.Fail($"Unknown node: {TypeName}"); #endif - goto case Empty; + goto case RegexNodeKind.Empty; } } @@ -2292,13 +2220,14 @@ public int ComputeMinLength() /// public bool TryGetJoinableLengthCheckChildRange(int childIndex, out int requiredLength, out int exclusiveEnd) { - static bool CanJoinLengthCheck(RegexNode node) => node.Type switch - { - One or Notone or Set => true, - Multi => true, - Oneloop or Onelazy or Oneloopatomic or - Notoneloop or Notonelazy or Notoneloopatomic or - Setloop or Setlazy or Setloopatomic when node.M == node.N => true, + static bool CanJoinLengthCheck(RegexNode node) => node.Kind switch + { + RegexNodeKind.One or RegexNodeKind.Notone or RegexNodeKind.Set => true, + RegexNodeKind.Multi => true, + RegexNodeKind.Oneloop or RegexNodeKind.Onelazy or RegexNodeKind.Oneloopatomic or + RegexNodeKind.Notoneloop or RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloopatomic or + RegexNodeKind.Setloop or RegexNodeKind.Setlazy or RegexNodeKind.Setloopatomic + when node.M == node.N => true, _ => false, }; @@ -2333,21 +2262,21 @@ Notoneloop or Notonelazy or Notoneloopatomic or public RegexNode MakeQuantifier(bool lazy, int min, int max) { if (min == 0 && max == 0) - return new RegexNode(Empty, Options); + return new RegexNode(RegexNodeKind.Empty, Options); if (min == 1 && max == 1) return this; - switch (Type) + switch (Kind) { - case One: - case Notone: - case Set: - MakeRep(lazy ? Onelazy : Oneloop, min, max); + case RegexNodeKind.One: + case RegexNodeKind.Notone: + case RegexNodeKind.Set: + MakeRep(lazy ? RegexNodeKind.Onelazy : RegexNodeKind.Oneloop, min, max); return this; default: - var result = new RegexNode(lazy ? Lazyloop : Loop, Options, min, max); + var result = new RegexNode(lazy ? RegexNodeKind.Lazyloop : RegexNodeKind.Loop, Options, min, max); result.AddChild(this); return result; } @@ -2355,9 +2284,9 @@ public RegexNode MakeQuantifier(bool lazy, int min, int max) public void AddChild(RegexNode newChild) { - newChild.Next = this; // so that the child can see its parent while being reduced + newChild.Parent = this; // so that the child can see its parent while being reduced newChild = newChild.Reduce(); - newChild.Next = this; // in case Reduce returns a different node that needs to be reparented + newChild.Parent = this; // in case Reduce returns a different node that needs to be reparented if (Children is null) { @@ -2377,9 +2306,9 @@ public void InsertChild(int index, RegexNode newChild) { Debug.Assert(Children is List); - newChild.Next = this; // so that the child can see its parent while being reduced + newChild.Parent = this; // so that the child can see its parent while being reduced newChild = newChild.Reduce(); - newChild.Next = this; // in case Reduce returns a different node that needs to be reparented + newChild.Parent = this; // in case Reduce returns a different node that needs to be reparented ((List)Children).Insert(index, newChild); } @@ -2389,9 +2318,9 @@ public void ReplaceChild(int index, RegexNode newChild) Debug.Assert(Children != null); Debug.Assert(index < ChildCount()); - newChild.Next = this; // so that the child can see its parent while being reduced + newChild.Parent = this; // so that the child can see its parent while being reduced newChild = newChild.Reduce(); - newChild.Next = this; // in case Reduce returns a different node that needs to be reparented + newChild.Parent = this; // in case Reduce returns a different node that needs to be reparented if (Children is RegexNode) { @@ -2403,15 +2332,7 @@ public void ReplaceChild(int index, RegexNode newChild) } } - public RegexNode Child(int i) - { - if (Children is RegexNode child) - { - return child; - } - - return ((List)Children!)[i]; - } + public RegexNode Child(int i) => Children is RegexNode child ? child : ((List)Children!)[i]; public int ChildCount() { @@ -2458,10 +2379,10 @@ internal bool SupportsCompilation() // TODO: This should be moved somewhere else, to a pass somewhere where we explicitly // annotate the tree, potentially as part of the final optimization pass. It doesn't // belong in this check. - if (Type == Capture) + if (Kind == RegexNodeKind.Capture) { // If we've found a supported capture, mark all of the nodes in its parent hierarchy as containing a capture. - for (RegexNode? parent = this; parent != null && (parent.Options & HasCapturesFlag) == 0; parent = parent.Next) + for (RegexNode? parent = this; parent != null && (parent.Options & HasCapturesFlag) == 0; parent = parent.Parent) { parent.Options |= HasCapturesFlag; } @@ -2472,20 +2393,20 @@ internal bool SupportsCompilation() } /// Gets whether the node is a Set/Setloop/Setloopatomic/Setlazy node. - public bool IsSetFamily => Type is Set or Setloop or Setloopatomic or Setlazy; + public bool IsSetFamily => Kind is RegexNodeKind.Set or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy; /// Gets whether the node is a One/Oneloop/Oneloopatomic/Onelazy node. - public bool IsOneFamily => Type is One or Oneloop or Oneloopatomic or Onelazy; + public bool IsOneFamily => Kind is RegexNodeKind.One or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy; /// Gets whether the node is a Notone/Notoneloop/Notoneloopatomic/Notonelazy node. - public bool IsNotoneFamily => Type is Notone or Notoneloop or Notoneloopatomic or Notonelazy; + public bool IsNotoneFamily => Kind is RegexNodeKind.Notone or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or RegexNodeKind.Notonelazy; /// Gets whether this node is contained inside of a loop. public bool IsInLoop() { - for (RegexNode? parent = Next; parent is not null; parent = parent.Next) + for (RegexNode? parent = Parent; parent is not null; parent = parent.Parent) { - if (parent.Type is Loop or Lazyloop) + if (parent.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop) { return true; } @@ -2495,49 +2416,7 @@ public bool IsInLoop() } #if DEBUG - private string TypeName => - Type switch - { - Oneloop => nameof(Oneloop), - Notoneloop => nameof(Notoneloop), - Setloop => nameof(Setloop), - Onelazy => nameof(Onelazy), - Notonelazy => nameof(Notonelazy), - Setlazy => nameof(Setlazy), - One => nameof(One), - Notone => nameof(Notone), - Set => nameof(Set), - Multi => nameof(Multi), - Ref => nameof(Ref), - Bol => nameof(Bol), - Eol => nameof(Eol), - Boundary => nameof(Boundary), - NonBoundary => nameof(NonBoundary), - ECMABoundary => nameof(ECMABoundary), - NonECMABoundary => nameof(NonECMABoundary), - Beginning => nameof(Beginning), - Start => nameof(Start), - EndZ => nameof(EndZ), - End => nameof(End), - Oneloopatomic => nameof(Oneloopatomic), - Notoneloopatomic => nameof(Notoneloopatomic), - Setloopatomic => nameof(Setloopatomic), - Nothing => nameof(Nothing), - Empty => nameof(Empty), - Alternate => nameof(Alternate), - Concatenate => nameof(Concatenate), - Loop => nameof(Loop), - Lazyloop => nameof(Lazyloop), - Capture => nameof(Capture), - Group => nameof(Group), - Require => nameof(Require), - Prevent => nameof(Prevent), - Atomic => nameof(Atomic), - Testref => nameof(Testref), - Testgroup => nameof(Testgroup), - UpdateBumpalong => nameof(UpdateBumpalong), - _ => $"(unknown {Type})" - }; + private string TypeName => Kind.ToString(); [ExcludeFromCodeCoverage] public string Description() @@ -2552,53 +2431,53 @@ public string Description() if ((Options & RegexOptions.IgnorePatternWhitespace) != 0) sb.Append("-X"); if ((Options & RegexOptions.ECMAScript) != 0) sb.Append("-E"); - switch (Type) + switch (Kind) { - case Oneloop: - case Oneloopatomic: - case Notoneloop: - case Notoneloopatomic: - case Onelazy: - case Notonelazy: - case One: - case Notone: + case RegexNodeKind.Oneloop: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.Onelazy: + case RegexNodeKind.Notonelazy: + case RegexNodeKind.One: + case RegexNodeKind.Notone: sb.Append(" '").Append(RegexCharClass.CharDescription(Ch)).Append('\''); break; - case Capture: + case RegexNodeKind.Capture: sb.Append(' ').Append($"index = {M}"); if (N != -1) { sb.Append($", unindex = {N}"); } break; - case Ref: - case Testref: + case RegexNodeKind.Backreference: + case RegexNodeKind.BackreferenceConditional: sb.Append(' ').Append($"index = {M}"); break; - case Multi: + case RegexNodeKind.Multi: sb.Append(" \"").Append(Str).Append('"'); break; - case Set: - case Setloop: - case Setloopatomic: - case Setlazy: + case RegexNodeKind.Set: + case RegexNodeKind.Setloop: + case RegexNodeKind.Setloopatomic: + case RegexNodeKind.Setlazy: sb.Append(' ').Append(RegexCharClass.SetDescription(Str!)); break; } - switch (Type) - { - case Oneloop: - case Oneloopatomic: - case Notoneloop: - case Notoneloopatomic: - case Onelazy: - case Notonelazy: - case Setloop: - case Setloopatomic: - case Setlazy: - case Loop: - case Lazyloop: + switch (Kind) + { + case RegexNodeKind.Oneloop: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.Onelazy: + case RegexNodeKind.Notonelazy: + case RegexNodeKind.Setloop: + case RegexNodeKind.Setloopatomic: + case RegexNodeKind.Setlazy: + case RegexNodeKind.Loop: + case RegexNodeKind.Lazyloop: sb.Append( (M == 0 && N == int.MaxValue) ? "*" : (M == 0 && N == 1) ? "?" : @@ -2641,7 +2520,7 @@ public override string ToString() curChild = stack[stack.Count - 1]; stack.RemoveAt(stack.Count - 1); - curNode = curNode.Next; + curNode = curNode.Parent; } } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNodeKind.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNodeKind.cs new file mode 100644 index 0000000000000..ab4ea881087c5 --- /dev/null +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNodeKind.cs @@ -0,0 +1,182 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Threading; + +namespace System.Text.RegularExpressions +{ + /// Specifies the kind of a . + internal enum RegexNodeKind + { + // The following are leaves (no children) and correspond to primitive operations in the regular expression. + + /// A specific character, e.g. `a`. + /// The character is specified in . + One = RegexCode.One, + /// Anything other than a specific character, e.g. `.` when not in mode, or `[^a]`. + /// The character is specified in . + Notone = RegexCode.Notone, + /// A character class / set, e.g. `[a-z1-9]` or `\w`. + /// The set string is specified in . + Set = RegexCode.Set, + + /// A sequence of at least two specific characters, e.g. `abc`. + /// The characters are specified in . This is purely a representational optimization, equivalent to multiple nodes concatenated together. + Multi = RegexCode.Multi, + + /// A loop around a specific character, e.g. `a*`. + /// + /// The character is specified in , the minimum number of iterations in , and the maximum number of iterations in . + /// This is purely a representational optimization, equivalent to a wrapped around a . + /// + Oneloop = RegexCode.Oneloop, + /// A loop around anything other than a specific character, e.g. `.*` when not in mode, or `[^a]*`. + /// The character is specified in , the minimum number of iterations in , and the maximum number of iterations in . + /// This is purely a representational optimization, equivalent to a wrapped around a . + Notoneloop = RegexCode.Notoneloop, + /// A loop around a character class / set, e.g. `[a-z1-9]*` or `\w*`. + /// The set string is specified in , the minimum number of iterations in , and the maximum number of iterations in . + /// This is purely a representational optimization, equivalent to a wrapped around a . + Setloop = RegexCode.Setloop, + + /// A lazy loop around a specific character, e.g. `a*?`. + /// The character is specified in , the minimum number of iterations in , and the maximum number of iterations in . + /// This is purely a representational optimization, equivalent to a wrapped around a . + Onelazy = RegexCode.Onelazy, + /// A lazy loop around anything other than a specific character, e.g. `.*?` when not in mode, or `[^a]*?`. + /// The character is specified in , the minimum number of iterations in , and the maximum number of iterations in . + /// This is purely a representational optimization, equivalent to a wrapped around a . + Notonelazy = RegexCode.Notonelazy, + /// A lazy loop around a character class / set, e.g. `[a-z1-9]*?` or `\w?`. + /// The set string is specified in , the minimum number of iterations in , and the maximum number of iterations in . + /// This is purely a representational optimization, equivalent to a wrapped around a . + Setlazy = RegexCode.Setlazy, + + /// An atomic loop around a specific character, e.g. `(?> a*)`. + /// + /// The character is specified in , the minimum number of iterations in , and the maximum number of iterations in . + /// This is purely a representational optimization, equivalent to a wrapped around a . + /// + Oneloopatomic = RegexCode.Oneloopatomic, + /// An atomic loop around anything other than a specific character, e.g. `(?>.*)` when not in mode. + /// + /// The character is specified in , the minimum number of iterations in , and the maximum number of iterations in . + /// This is purely a representational optimization, equivalent to a wrapped around a . + /// + Notoneloopatomic = RegexCode.Notoneloopatomic, + /// An atomic loop around a character class / set, e.g. `(?>\d*)`. + /// + /// The set string is specified in , the minimum number of iterations in , and the maximum number of iterations in . + /// This is purely a representational optimization, equivalent to a wrapped around a . + /// + Setloopatomic = RegexCode.Setloopatomic, + + /// A backreference, e.g. `\1`. + /// The capture group number referenced is stored in . + Backreference = RegexCode.Ref, + + /// A beginning-of-line anchor, e.g. `^` in mode. + Bol = RegexCode.Bol, + /// An end-of-line anchor, e.g. `$` in mode. + Eol = RegexCode.Eol, + /// A word boundary anchor, e.g. `\b`. + Boundary = RegexCode.Boundary, + /// Not a word boundary anchor, e.g. `\B`. + NonBoundary = RegexCode.NonBoundary, + /// A word boundary anchor, e.g. `\b` in mode. + ECMABoundary = RegexCode.ECMABoundary, + /// Not a word boundary anchor, e.g. `\B` in mode.. + NonECMABoundary = RegexCode.NonECMABoundary, + /// A beginning-of-string anchor, e.g. `\A`, or `^` when not in mode. + Beginning = RegexCode.Beginning, + /// A start anchor, e.g. `\G`. + Start = RegexCode.Start, + /// A end-of-string-or-before-ending-newline anchor, e.g. `\Z`, or `$` when not in mode. + EndZ = RegexCode.EndZ, + /// A end-of-string-only anchor, e.g. `\z`. + End = RegexCode.End, + + /// A fabricated node injected during analyses to signal a location in the matching where the engine may set the next bumpalong position to the current position. + UpdateBumpalong = RegexCode.UpdateBumpalong, + + /// Fails when matching an empty string, e.g. `(?!)`. + Nothing = 22, + /// Matches the empty string, e.g. ``. + Empty = 23, + + // The following are interior nodes (have at least one child) and correspond to control structures composing other operations. + + /// An alternation between branches, e.g. `ab|cd`. + /// + /// Each child represents one branch, in lexical order. A valid alternation contains at + /// least two children: if an alternation contains only a single child, it can be replaced + /// by that child, and if an alternation has no children, it can be replaced by . + /// + Alternate = 24, + /// A sequence / concatenation of nodes, e.g. a[bc]. + /// + /// Each child represents one node in the sequence, in lexical order. A valid concatenation contains at + /// least two children: if a concatenation contains only a single child, it can be replaced + /// by that child, and if a concatenation has no children, it can be replaced by . + /// + Concatenate = 25, + + /// A loop around an arbitrary , e.g. `(ab|cd)*`. + /// + /// One and only one child, the expression in the loop. The minimum number of iterations is in , + /// and the maximum number of iterations is in . + /// + Loop = 26, // m,x * + ? {,} + /// A lazy loop around an arbitrary , e.g. `(ab|cd)*?`. + /// + /// One and only one child, the expression in the loop. The minimum number of iterations is in , + /// and the maximum number of iterations is in . + /// + Lazyloop = 27, + + /// A capture group, e.g. `(\w*)`. + /// + /// One and only one child, the expression in the capture. is the number of the capture, and if a balancing + /// group, is the uncapture. + /// + Capture = 28, + /// A non-capturing group, e.g. `(?:ab|cd)`. + /// + /// One and only one child, the expression in the group. Groups are irrelevant after parsing and can be replaced entirely by their child. + /// These should not be in a valid tree returned from the parsing / reduction phases of processing. + /// + Group = 29, + /// An atomic group, e.g. `(?>ab|cd)`. + /// One and only one child, the expression in the group. + Atomic = 32, + + /// + /// A positive lookaround assertion: lookahead if is not set and lookbehind if + /// is set, e.g. `(?=abc)` or `(?<=abc)`. + /// One and only one child, the expression in the assertion. + PositiveLookaround = 30, + /// + /// A negative lookaround assertion: lookahead if is not set and lookbehind if + /// is set, e.g. `(?!abc)` or `(?<!abc)`. + /// One and only one child, the expression in the assertion. + NegativeLookaround = 31, + + /// A backreference conditional, e.g. `(?(1)abc|def)`. + /// + /// Two children, the first to use if the reference capture group matched and the second to use if it didn't. + /// The referenced capture group number is stored in . + /// + BackreferenceConditional = 33, + /// An expression conditional, e.g. `(?(\d{3})123456|abc)`. + /// + /// Three children. The first is the expression to evaluate as a positive lookahead assertion, the second is + /// the expression to match if the positive lookahead assertion was successful, and the third is the expression + /// to match if the positive lookahead assertion was unsuccessful. + /// + ExpressionConditional = 34, + } +} diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs index 02b4f1408e679..9c7f8bdb3cc94 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs @@ -255,7 +255,7 @@ private RegexNode ScanRegex() char ch; bool isQuantifier = false; - StartGroup(new RegexNode(RegexNode.Capture, _options, 0, -1)); + StartGroup(new RegexNode(RegexNodeKind.Capture, _options, 0, -1)); while (CharsRight() > 0) { @@ -326,8 +326,8 @@ private RegexNode ScanRegex() { string setString = ScanCharClass(UseOptionI(), scanOnly: false)!.ToStringClass(_options); _unit = UseOptionI() && RegexCharClass.MakeCaseSensitiveIfPossible(setString, _culture) is string newSetString ? - new RegexNode(RegexNode.Set, _options & ~RegexOptions.IgnoreCase, newSetString) : - new RegexNode(RegexNode.Set, _options, setString); + new RegexNode(RegexNodeKind.Set, _options & ~RegexOptions.IgnoreCase, newSetString) : + new RegexNode(RegexNodeKind.Set, _options, setString); } break; @@ -379,17 +379,17 @@ private RegexNode ScanRegex() break; case '^': - AddUnitType(UseOptionM() ? RegexNode.Bol : RegexNode.Beginning); + AddUnitType(UseOptionM() ? RegexNodeKind.Bol : RegexNodeKind.Beginning); break; case '$': - AddUnitType(UseOptionM() ? RegexNode.Eol : RegexNode.EndZ); + AddUnitType(UseOptionM() ? RegexNodeKind.Eol : RegexNodeKind.EndZ); break; case '.': _unit = UseOptionS() ? - new RegexNode(RegexNode.Set, _options & ~RegexOptions.IgnoreCase, RegexCharClass.AnyClass) : - new RegexNode(RegexNode.Notone, _options & ~RegexOptions.IgnoreCase, '\n'); + new RegexNode(RegexNodeKind.Set, _options & ~RegexOptions.IgnoreCase, RegexCharClass.AnyClass) : + new RegexNode(RegexNodeKind.Notone, _options & ~RegexOptions.IgnoreCase, '\n'); break; case '{': @@ -451,10 +451,7 @@ private RegexNode ScanRegex() if (CharsRight() > 0 && RightChar() == ',') { MoveRight(); - if (CharsRight() == 0 || RightChar() == '}') - max = int.MaxValue; - else - max = ScanDecimal(); + max = CharsRight() == 0 || RightChar() == '}' ? int.MaxValue : ScanDecimal(); } } @@ -511,7 +508,7 @@ private RegexNode ScanRegex() */ private RegexNode ScanReplacement() { - _concatenation = new RegexNode(RegexNode.Concatenate, _options); + _concatenation = new RegexNode(RegexNodeKind.Concatenate, _options); while (true) { @@ -541,7 +538,7 @@ private RegexNode ScanReplacement() // groups are unsupported. However, the replacement patterns that refer to the left/right portion // or all of the input as well as referring to group 0 (i.e. the whole match) are supported. if ((_options & RegexOptions.NonBacktracking) != 0 && - node.Type == RegexNode.Ref && + node.Kind == RegexNodeKind.Backreference && node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortion or RegexReplacement.WholeString)) { throw new NotSupportedException(SR.NotSupported_NonBacktrackingAndReplacementsWithSubstitutionsOfGroups); @@ -788,11 +785,11 @@ node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortio if (UseOptionN() || _ignoreNextParen) { _ignoreNextParen = false; - return new RegexNode(RegexNode.Group, _options); + return new RegexNode(RegexNodeKind.Group, _options); } else { - return new RegexNode(RegexNode.Capture, _options, _autocap++, -1); + return new RegexNode(RegexNodeKind.Capture, _options, _autocap++, -1); } } @@ -805,31 +802,31 @@ node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortio break; } - int nodeType; + RegexNodeKind nodeType; char close = '>'; char ch = RightCharMoveRight(); switch (ch) { case ':': // noncapturing group - nodeType = RegexNode.Group; + nodeType = RegexNodeKind.Group; break; case '=': // lookahead assertion _options &= ~RegexOptions.RightToLeft; - nodeType = RegexNode.Require; + nodeType = RegexNodeKind.PositiveLookaround; break; case '!': // negative lookahead assertion _options &= ~RegexOptions.RightToLeft; - nodeType = RegexNode.Prevent; + nodeType = RegexNodeKind.NegativeLookaround; break; case '>': // atomic subexpression - nodeType = RegexNode.Atomic; + nodeType = RegexNodeKind.Atomic; break; case '\'': @@ -852,7 +849,7 @@ node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortio // lookbehind assertion _options |= RegexOptions.RightToLeft; - nodeType = RegexNode.Require; + nodeType = RegexNodeKind.PositiveLookaround; break; case '!': @@ -863,7 +860,7 @@ node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortio // negative lookbehind assertion _options |= RegexOptions.RightToLeft; - nodeType = RegexNode.Prevent; + nodeType = RegexNodeKind.NegativeLookaround; break; default: @@ -921,7 +918,7 @@ node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortio // grab part after - if any - if ((capnum != -1 || proceed == true) && CharsRight() > 1 && RightChar() == '-') + if ((capnum != -1 || proceed) && CharsRight() > 1 && RightChar() == '-') { MoveRight(); ch = RightChar(); @@ -971,7 +968,7 @@ node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortio if ((capnum != -1 || uncapnum != -1) && CharsRight() > 0 && RightCharMoveRight() == close) { - return new RegexNode(RegexNode.Capture, _options, capnum, uncapnum); + return new RegexNode(RegexNodeKind.Capture, _options, capnum, uncapnum); } goto BreakRecognize; } @@ -993,7 +990,7 @@ node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortio { if (IsCaptureSlot(capnum)) { - return new RegexNode(RegexNode.Testref, _options, capnum); + return new RegexNode(RegexNodeKind.BackreferenceConditional, _options, capnum); } throw MakeException(RegexParseError.AlternationHasUndefinedReference, SR.Format(SR.AlternationHasUndefinedReference, capnum.ToString())); @@ -1007,12 +1004,12 @@ node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortio if (IsCaptureName(capname) && CharsRight() > 0 && RightCharMoveRight() == ')') { - return new RegexNode(RegexNode.Testref, _options, CaptureSlotFromName(capname)); + return new RegexNode(RegexNodeKind.BackreferenceConditional, _options, CaptureSlotFromName(capname)); } } } // not a backref - nodeType = RegexNode.Testgroup; + nodeType = RegexNodeKind.ExpressionConditional; Textto(parenPos - 1); // jump to the start of the parentheses _ignoreNextParen = true; // but make sure we don't try to capture the insides @@ -1044,9 +1041,9 @@ node.M is not (0 or RegexReplacement.LeftPortion or RegexReplacement.RightPortio default: MoveLeft(); - nodeType = RegexNode.Group; + nodeType = RegexNodeKind.Group; // Disallow options in the children of a testgroup node - if (_group!.Type != RegexNode.Testgroup) + if (_group!.Kind != RegexNodeKind.ExpressionConditional) { ScanOptions(); } @@ -1173,32 +1170,32 @@ private void ScanBlank() case 'w': MoveRight(); return scanOnly ? null : - new RegexNode(RegexNode.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.ECMAWordClass : RegexCharClass.WordClass); + new RegexNode(RegexNodeKind.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.ECMAWordClass : RegexCharClass.WordClass); case 'W': MoveRight(); return scanOnly ? null : - new RegexNode(RegexNode.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.NotECMAWordClass : RegexCharClass.NotWordClass); + new RegexNode(RegexNodeKind.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.NotECMAWordClass : RegexCharClass.NotWordClass); case 's': MoveRight(); return scanOnly ? null : - new RegexNode(RegexNode.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.ECMASpaceClass : RegexCharClass.SpaceClass); + new RegexNode(RegexNodeKind.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.ECMASpaceClass : RegexCharClass.SpaceClass); case 'S': MoveRight(); return scanOnly ? null : - new RegexNode(RegexNode.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.NotECMASpaceClass : RegexCharClass.NotSpaceClass); + new RegexNode(RegexNodeKind.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.NotECMASpaceClass : RegexCharClass.NotSpaceClass); case 'd': MoveRight(); return scanOnly ? null : - new RegexNode(RegexNode.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.ECMADigitClass : RegexCharClass.DigitClass); + new RegexNode(RegexNodeKind.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.ECMADigitClass : RegexCharClass.DigitClass); case 'D': MoveRight(); return scanOnly ? null : - new RegexNode(RegexNode.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.NotECMADigitClass : RegexCharClass.NotDigitClass); + new RegexNode(RegexNodeKind.Set, RemoveIgnoreCaseIfNotEcma(_options), UseOptionE() ? RegexCharClass.NotECMADigitClass : RegexCharClass.NotDigitClass); case 'p': case 'P': @@ -1215,7 +1212,7 @@ private void ScanBlank() cc.AddLowercase(_culture); } - return new RegexNode(RegexNode.Set, _options, cc.ToStringClass(_options)); + return new RegexNode(RegexNodeKind.Set, _options, cc.ToStringClass(_options)); default: return ScanBasicBackslash(scanOnly); @@ -1259,7 +1256,7 @@ static RegexOptions RemoveIgnoreCaseIfNotEcma(RegexOptions options) { MoveRight(); ch = RightCharMoveRight(); - if (ch == '<' || ch == '\'') + if (ch is '<' or '\'') { angled = true; close = (ch == '\'') ? '\'' : '>'; @@ -1294,7 +1291,7 @@ static RegexOptions RemoveIgnoreCaseIfNotEcma(RegexOptions options) { return scanOnly ? null : - IsCaptureSlot(capnum) ? new RegexNode(RegexNode.Ref, _options, capnum) : + IsCaptureSlot(capnum) ? new RegexNode(RegexNodeKind.Backreference, _options, capnum) : throw MakeException(RegexParseError.UndefinedNumberedReference, SR.Format(SR.UndefinedNumberedReference, capnum.ToString())); } } @@ -1326,7 +1323,7 @@ static RegexOptions RemoveIgnoreCaseIfNotEcma(RegexOptions options) if (capnum >= 0) { - return scanOnly ? null : new RegexNode(RegexNode.Ref, _options, capnum); + return scanOnly ? null : new RegexNode(RegexNodeKind.Backreference, _options, capnum); } } else @@ -1340,7 +1337,7 @@ static RegexOptions RemoveIgnoreCaseIfNotEcma(RegexOptions options) if (IsCaptureSlot(capnum)) { - return new RegexNode(RegexNode.Ref, _options, capnum); + return new RegexNode(RegexNodeKind.Backreference, _options, capnum); } if (capnum <= 9) @@ -1360,7 +1357,7 @@ static RegexOptions RemoveIgnoreCaseIfNotEcma(RegexOptions options) { return scanOnly ? null : - IsCaptureName(capname) ? new RegexNode(RegexNode.Ref, _options, CaptureSlotFromName(capname)) : + IsCaptureName(capname) ? new RegexNode(RegexNodeKind.Backreference, _options, CaptureSlotFromName(capname)) : throw MakeException(RegexParseError.UndefinedNamedReference, SR.Format(SR.UndefinedNamedReference, capname)); } } @@ -1440,7 +1437,7 @@ private RegexNode ScanDollar() Textto(lastEndPos); if (capnum >= 0) { - return new RegexNode(RegexNode.Ref, _options, capnum); + return new RegexNode(RegexNodeKind.Backreference, _options, capnum); } } else @@ -1451,7 +1448,7 @@ private RegexNode ScanDollar() CheckUnsupportedNonBacktrackingNumericRef(capnum); if (IsCaptureSlot(capnum)) { - return new RegexNode(RegexNode.Ref, _options, capnum); + return new RegexNode(RegexNodeKind.Backreference, _options, capnum); } } } @@ -1470,7 +1467,7 @@ private RegexNode ScanDollar() if (IsCaptureName(capname)) { - return new RegexNode(RegexNode.Ref, _options, CaptureSlotFromName(capname)); + return new RegexNode(RegexNodeKind.Backreference, _options, CaptureSlotFromName(capname)); } } } @@ -1508,7 +1505,7 @@ private RegexNode ScanDollar() if (capnum != 1) { MoveRight(); - return new RegexNode(RegexNode.Ref, _options, capnum); + return new RegexNode(RegexNodeKind.Backreference, _options, capnum); } } @@ -1787,16 +1784,16 @@ private string ParseProperty() } /// Returns ReNode type for zero-length assertions with a \ code. - private int TypeFromCode(char ch) => + private RegexNodeKind TypeFromCode(char ch) => ch switch { - 'b' => UseOptionE() ? RegexNode.ECMABoundary : RegexNode.Boundary, - 'B' => UseOptionE() ? RegexNode.NonECMABoundary : RegexNode.NonBoundary, - 'A' => RegexNode.Beginning, - 'G' => RegexNode.Start, - 'Z' => RegexNode.EndZ, - 'z' => RegexNode.End, - _ => RegexNode.Nothing, + 'b' => UseOptionE() ? RegexNodeKind.ECMABoundary : RegexNodeKind.Boundary, + 'B' => UseOptionE() ? RegexNodeKind.NonECMABoundary : RegexNodeKind.NonBoundary, + 'A' => RegexNodeKind.Beginning, + 'G' => RegexNodeKind.Start, + 'Z' => RegexNodeKind.EndZ, + 'z' => RegexNodeKind.End, + _ => RegexNodeKind.Nothing, }; /// Returns option bit from single-char (?cimsx) code. @@ -2183,7 +2180,7 @@ private void AddConcatenate(int pos, int cch, bool isReplacement) break; case > 1 when !UseOptionI() || isReplacement || !RegexCharClass.ParticipatesInCaseConversion(_pattern.AsSpan(pos, cch)): - _concatenation!.AddChild(new RegexNode(RegexNode.Multi, _options & ~RegexOptions.IgnoreCase, _pattern.Substring(pos, cch))); + _concatenation!.AddChild(new RegexNode(RegexNodeKind.Multi, _options & ~RegexOptions.IgnoreCase, _pattern.Substring(pos, cch))); break; default: @@ -2198,9 +2195,9 @@ private void AddConcatenate(int pos, int cch, bool isReplacement) /// Push the parser state (in response to an open paren) private void PushGroup() { - _group!.Next = _stack; - _alternation!.Next = _group; - _concatenation!.Next = _alternation; + _group!.Parent = _stack; + _alternation!.Parent = _group; + _concatenation!.Parent = _alternation; _stack = _concatenation; } @@ -2208,12 +2205,12 @@ private void PushGroup() private void PopGroup() { _concatenation = _stack; - _alternation = _concatenation!.Next; - _group = _alternation!.Next; - _stack = _group!.Next; + _alternation = _concatenation!.Parent; + _group = _alternation!.Parent; + _stack = _group!.Parent; // The first () inside a Testgroup group goes directly to the group - if (_group.Type == RegexNode.Testgroup && _group.ChildCount() == 0) + if (_group.Kind == RegexNodeKind.ExpressionConditional && _group.ChildCount() == 0) { if (_unit == null) { @@ -2232,8 +2229,8 @@ private void PopGroup() private void StartGroup(RegexNode openGroup) { _group = openGroup; - _alternation = new RegexNode(RegexNode.Alternate, _options); - _concatenation = new RegexNode(RegexNode.Concatenate, _options); + _alternation = new RegexNode(RegexNodeKind.Alternate, _options); + _concatenation = new RegexNode(RegexNodeKind.Concatenate, _options); } /// Finish the current concatenation (in response to a |) @@ -2241,7 +2238,7 @@ private void AddAlternate() { // The | parts inside a Testgroup group go directly to the group - if (_group!.Type == RegexNode.Testgroup || _group.Type == RegexNode.Testref) + if (_group!.Kind is RegexNodeKind.ExpressionConditional or RegexNodeKind.BackreferenceConditional) { _group.AddChild(_concatenation!.ReverseConcatenationIfRightToLeft()); } @@ -2250,7 +2247,7 @@ private void AddAlternate() _alternation!.AddChild(_concatenation!.ReverseConcatenationIfRightToLeft()); } - _concatenation = new RegexNode(RegexNode.Concatenate, _options); + _concatenation = new RegexNode(RegexNodeKind.Concatenate, _options); } /// Finish the current quantifiable (when a quantifier is not found or is not possible) @@ -2279,16 +2276,16 @@ private void AddConcatenate(bool lazy, int min, int max) private void AddUnitNode(RegexNode node) => _unit = node; /// Sets the current unit to an assertion of the specified type - private void AddUnitType(int type) => _unit = new RegexNode(type, _options); + private void AddUnitType(RegexNodeKind type) => _unit = new RegexNode(type, _options); /// Finish the current group (in response to a ')' or end) private void AddGroup() { - if (_group!.Type == RegexNode.Testgroup || _group.Type == RegexNode.Testref) + if (_group!.Kind is RegexNodeKind.ExpressionConditional or RegexNodeKind.BackreferenceConditional) { _group.AddChild(_concatenation!.ReverseConcatenationIfRightToLeft()); - if (_group.Type == RegexNode.Testref && _group.ChildCount() > 2 || _group.ChildCount() > 3) + if (_group.Kind == RegexNodeKind.BackreferenceConditional && _group.ChildCount() > 2 || _group.ChildCount() > 3) { throw MakeException(RegexParseError.AlternationHasTooManyConditions, SR.AlternationHasTooManyConditions); } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs index ceabbef99af6c..869b5cc5aa285 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs @@ -14,8 +14,8 @@ namespace System.Text.RegularExpressions internal ref struct RegexPrefixAnalyzer { private const int StackBufferSize = 32; - private const int BeforeChild = 64; - private const int AfterChild = 128; + private const RegexNodeKind BeforeChild = (RegexNodeKind)64; + private const RegexNodeKind AfterChild = (RegexNodeKind)128; // where the regex can be pegged public const int Beginning = 0x0001; @@ -33,6 +33,14 @@ internal ref struct RegexPrefixAnalyzer private bool _skipchild; // don't process the current child. private bool _failed; +#if DEBUG + static RegexPrefixAnalyzer() + { + Debug.Assert(!Enum.IsDefined(typeof(RegexNodeKind), BeforeChild)); + Debug.Assert(!Enum.IsDefined(typeof(RegexNodeKind), AfterChild)); + } +#endif + private RegexPrefixAnalyzer(Span intStack) { _fcStack = new List(StackBufferSize); @@ -63,10 +71,10 @@ static bool Process(RegexNode node, ref ValueStringBuilder vsb) // when handling RightToLeft. bool rtl = (node.Options & RegexOptions.RightToLeft) != 0; - switch (node.Type) + switch (node.Kind) { // Concatenation - case RegexNode.Concatenate: + case RegexNodeKind.Concatenate: { int childCount = node.ChildCount(); for (int i = 0; i < childCount; i++) @@ -80,24 +88,24 @@ static bool Process(RegexNode node, ref ValueStringBuilder vsb) } // One character - case RegexNode.One when (node.Options & RegexOptions.IgnoreCase) == 0: + case RegexNodeKind.One when (node.Options & RegexOptions.IgnoreCase) == 0: vsb.Append(node.Ch); return !rtl; // Multiple characters - case RegexNode.Multi when (node.Options & RegexOptions.IgnoreCase) == 0: + case RegexNodeKind.Multi when (node.Options & RegexOptions.IgnoreCase) == 0: vsb.Append(node.Str); return !rtl; // Loop of one character - case RegexNode.Oneloop or RegexNode.Oneloopatomic or RegexNode.Onelazy when node.M > 0 && (node.Options & RegexOptions.IgnoreCase) == 0: + case RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy when node.M > 0 && (node.Options & RegexOptions.IgnoreCase) == 0: const int SingleCharIterationLimit = 32; // arbitrary cut-off to avoid creating super long strings unnecessarily int count = Math.Min(node.M, SingleCharIterationLimit); vsb.Append(node.Ch, count); return count == node.N && !rtl; // Loop of a node - case RegexNode.Loop or RegexNode.Lazyloop when node.M > 0: + case RegexNodeKind.Loop or RegexNodeKind.Lazyloop when node.M > 0: { const int NodeIterationLimit = 4; // arbitrary cut-off to avoid creating super long strings unnecessarily int limit = Math.Min(node.M, NodeIterationLimit); @@ -112,25 +120,25 @@ static bool Process(RegexNode node, ref ValueStringBuilder vsb) } // Grouping nodes for which we only care about their single child - case RegexNode.Atomic: - case RegexNode.Capture: + case RegexNodeKind.Atomic: + case RegexNodeKind.Capture: return Process(node.Child(0), ref vsb); // Zero-width anchors and assertions - case RegexNode.Bol: - case RegexNode.Eol: - case RegexNode.Boundary: - case RegexNode.ECMABoundary: - case RegexNode.NonBoundary: - case RegexNode.NonECMABoundary: - case RegexNode.Beginning: - case RegexNode.Start: - case RegexNode.EndZ: - case RegexNode.End: - case RegexNode.Empty: - case RegexNode.UpdateBumpalong: - case RegexNode.Require: - case RegexNode.Prevent: + case RegexNodeKind.Bol: + case RegexNodeKind.Eol: + case RegexNodeKind.Boundary: + case RegexNodeKind.ECMABoundary: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.NonECMABoundary: + case RegexNodeKind.Beginning: + case RegexNodeKind.Start: + case RegexNodeKind.EndZ: + case RegexNodeKind.End: + case RegexNodeKind.Empty: + case RegexNodeKind.UpdateBumpalong: + case RegexNodeKind.PositiveLookaround: + case RegexNodeKind.NegativeLookaround: return true; // Give up for anything else @@ -293,9 +301,9 @@ static bool TryFindFixedSets(RegexNode node, List<(char[]? Chars, string Set, in bool caseInsensitive = (node.Options & RegexOptions.IgnoreCase) != 0; - switch (node.Type) + switch (node.Kind) { - case RegexNode.One: + case RegexNodeKind.One: if (results.Count < MaxFixedResults) { string setString = RegexCharClass.OneToStringClass(node.Ch, caseInsensitive ? culture : null, out bool resultIsCaseInsensitive); @@ -304,7 +312,7 @@ static bool TryFindFixedSets(RegexNode node, List<(char[]? Chars, string Set, in } return false; - case RegexNode.Onelazy or RegexNode.Oneloop or RegexNode.Oneloopatomic when node.M > 0: + case RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic when node.M > 0: { string setString = RegexCharClass.OneToStringClass(node.Ch, caseInsensitive ? culture : null, out bool resultIsCaseInsensitive); int minIterations = Math.Min(node.M, MaxLoopExpansion); @@ -316,7 +324,7 @@ static bool TryFindFixedSets(RegexNode node, List<(char[]? Chars, string Set, in return i == node.M && i == node.N; } - case RegexNode.Multi: + case RegexNodeKind.Multi: { string s = node.Str!; int i = 0; @@ -328,7 +336,7 @@ static bool TryFindFixedSets(RegexNode node, List<(char[]? Chars, string Set, in return i == s.Length; } - case RegexNode.Set: + case RegexNodeKind.Set: if (results.Count < MaxFixedResults) { results.Add((null, node.Str!, distance++, caseInsensitive)); @@ -336,7 +344,7 @@ static bool TryFindFixedSets(RegexNode node, List<(char[]? Chars, string Set, in } return false; - case RegexNode.Setlazy or RegexNode.Setloop or RegexNode.Setloopatomic when node.M > 0: + case RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic when node.M > 0: { int minIterations = Math.Min(node.M, MaxLoopExpansion); int i = 0; @@ -347,41 +355,41 @@ static bool TryFindFixedSets(RegexNode node, List<(char[]? Chars, string Set, in return i == node.M && i == node.N; } - case RegexNode.Notone: + case RegexNodeKind.Notone: // We could create a set out of Notone, but it will be of little value in helping to improve // the speed of finding the first place to match, as almost every character will match it. distance++; return true; - case RegexNode.Notonelazy or RegexNode.Notoneloop or RegexNode.Notoneloopatomic when node.M == node.N: + case RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic when node.M == node.N: distance += node.M; return true; - case RegexNode.Beginning: - case RegexNode.Bol: - case RegexNode.Boundary: - case RegexNode.ECMABoundary: - case RegexNode.Empty: - case RegexNode.End: - case RegexNode.EndZ: - case RegexNode.Eol: - case RegexNode.NonBoundary: - case RegexNode.NonECMABoundary: - case RegexNode.UpdateBumpalong: - case RegexNode.Start: - case RegexNode.Prevent: - case RegexNode.Require: - // Zero-width anchors and assertions. In theory for Prevent and Require we could also investigate - // them and use the learned knowledge to impact the generated sets, at least for lookaheads. + case RegexNodeKind.Beginning: + case RegexNodeKind.Bol: + case RegexNodeKind.Boundary: + case RegexNodeKind.ECMABoundary: + case RegexNodeKind.Empty: + case RegexNodeKind.End: + case RegexNodeKind.EndZ: + case RegexNodeKind.Eol: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.NonECMABoundary: + case RegexNodeKind.UpdateBumpalong: + case RegexNodeKind.Start: + case RegexNodeKind.NegativeLookaround: + case RegexNodeKind.PositiveLookaround: + // Zero-width anchors and assertions. In theory, for PositiveLookaround and NegativeLookaround we could also + // investigate them and use the learned knowledge to impact the generated sets, at least for lookaheads. // For now, we don't bother. return true; - case RegexNode.Atomic: - case RegexNode.Group: - case RegexNode.Capture: + case RegexNodeKind.Atomic: + case RegexNodeKind.Group: + case RegexNodeKind.Capture: return TryFindFixedSets(node.Child(0), results, ref distance, culture, thorough); - case RegexNode.Lazyloop or RegexNode.Loop when node.M > 0: + case RegexNodeKind.Lazyloop or RegexNodeKind.Loop when node.M > 0: // This effectively only iterates the loop once. If deemed valuable, // it could be updated in the future to duplicate the found results // (updated to incorporate distance from previous iterations) and @@ -391,7 +399,7 @@ static bool TryFindFixedSets(RegexNode node, List<(char[]? Chars, string Set, in TryFindFixedSets(node.Child(0), results, ref distance, culture, thorough); return false; - case RegexNode.Concatenate: + case RegexNodeKind.Concatenate: { int childCount = node.ChildCount(); for (int i = 0; i < childCount; i++) @@ -404,7 +412,7 @@ static bool TryFindFixedSets(RegexNode node, List<(char[]? Chars, string Set, in return true; } - case RegexNode.Alternate when thorough: + case RegexNodeKind.Alternate when thorough: { int childCount = node.ChildCount(); bool allSameSize = true; @@ -523,11 +531,11 @@ public static (RegexNode LoopNode, (char Char, string? String, char[]? Chars) Li } // Find the first concatenation. - while ((node.Type is RegexNode.Atomic or RegexNode.Capture) || (node.Type is RegexNode.Loop or RegexNode.Lazyloop && node.M > 0)) + while ((node.Kind is RegexNodeKind.Atomic or RegexNodeKind.Capture) || (node.Kind is RegexNodeKind.Loop or RegexNodeKind.Lazyloop && node.M > 0)) { node = node.Child(0); } - if (node.Type != RegexNode.Concatenate) + if (node.Kind != RegexNodeKind.Concatenate) { return null; } @@ -540,7 +548,7 @@ public static (RegexNode LoopNode, (char Char, string? String, char[]? Chars) Li // could also be made to support Oneloopatomic and Notoneloopatomic, but the scenarios for that are rare. Debug.Assert(node.ChildCount() >= 2); RegexNode firstChild = node.Child(0); - if (firstChild.Type is not (RegexNode.Setloop or RegexNode.Setloopatomic or RegexNode.Setlazy) || firstChild.N != int.MaxValue) + if (firstChild.Kind is not (RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic or RegexNodeKind.Setlazy) || firstChild.N != int.MaxValue) { return null; } @@ -548,7 +556,7 @@ public static (RegexNode LoopNode, (char Char, string? String, char[]? Chars) Li // Get the subsequent node. An UpdateBumpalong may have been added as an optimization, but it doesn't have an // impact on semantics and we can skip it. RegexNode nextChild = node.Child(1); - if (nextChild.Type == RegexNode.UpdateBumpalong) + if (nextChild.Kind == RegexNodeKind.UpdateBumpalong) { if (node.ChildCount() == 2) { @@ -562,15 +570,15 @@ public static (RegexNode LoopNode, (char Char, string? String, char[]? Chars) Li // and they're both case-sensitive, we have a winner. if (((firstChild.Options | nextChild.Options) & RegexOptions.IgnoreCase) == 0) { - switch (nextChild.Type) + switch (nextChild.Kind) { - case RegexNode.One when !RegexCharClass.CharInClass(nextChild.Ch, firstChild.Str!): + case RegexNodeKind.One when !RegexCharClass.CharInClass(nextChild.Ch, firstChild.Str!): return (firstChild, (nextChild.Ch, null, null)); - case RegexNode.Multi when !RegexCharClass.CharInClass(nextChild.Str![0], firstChild.Str!): + case RegexNodeKind.Multi when !RegexCharClass.CharInClass(nextChild.Str![0], firstChild.Str!): return (firstChild, ('\0', nextChild.Str, null)); - case RegexNode.Set when !RegexCharClass.IsNegated(nextChild.Str!): + case RegexNodeKind.Set when !RegexCharClass.IsNegated(nextChild.Str!): Span chars = stackalloc char[5]; // maximum number of chars optimized by IndexOfAny chars = chars.Slice(0, RegexCharClass.GetSetChars(nextChild.Str!, chars)); if (!chars.IsEmpty) @@ -602,33 +610,33 @@ public static int FindLeadingAnchor(RegexTree tree) while (true) { - switch (curNode.Type) + switch (curNode.Kind) { - case RegexNode.Bol: + case RegexNodeKind.Bol: return Bol; - case RegexNode.Eol: + case RegexNodeKind.Eol: return Eol; - case RegexNode.Boundary: + case RegexNodeKind.Boundary: return Boundary; - case RegexNode.ECMABoundary: + case RegexNodeKind.ECMABoundary: return ECMABoundary; - case RegexNode.Beginning: + case RegexNodeKind.Beginning: return Beginning; - case RegexNode.Start: + case RegexNodeKind.Start: return Start; - case RegexNode.EndZ: + case RegexNodeKind.EndZ: return EndZ; - case RegexNode.End: + case RegexNodeKind.End: return End; - case RegexNode.Concatenate: + case RegexNodeKind.Concatenate: if (curNode.ChildCount() > 0) { concatNode = curNode; @@ -636,15 +644,15 @@ public static int FindLeadingAnchor(RegexTree tree) } break; - case RegexNode.Atomic: - case RegexNode.Capture: + case RegexNodeKind.Atomic: + case RegexNodeKind.Capture: curNode = curNode.Child(0); concatNode = null; continue; - case RegexNode.Empty: - case RegexNode.Require: - case RegexNode.Prevent: + case RegexNodeKind.Empty: + case RegexNodeKind.PositiveLookaround: + case RegexNodeKind.NegativeLookaround: break; default: @@ -727,12 +735,12 @@ private RegexFC PopFC() if (curNodeChildCount == 0) { // This is a leaf node - CalculateFC(curNode.Type, curNode, 0); + CalculateFC(curNode.Kind, curNode, 0); } else if (curChild < curNodeChildCount && !_skipAllChildren) { // This is an interior node, and we have more children to analyze - CalculateFC(curNode.Type | BeforeChild, curNode, curChild); + CalculateFC(curNode.Kind | BeforeChild, curNode, curChild); if (!_skipchild) { @@ -757,9 +765,9 @@ private RegexFC PopFC() break; curChild = PopInt(); - curNode = curNode.Next; + curNode = curNode.Parent; - CalculateFC(curNode!.Type | AfterChild, curNode, curChild); + CalculateFC(curNode!.Kind | AfterChild, curNode, curChild); if (_failed) return null; @@ -780,30 +788,30 @@ private RegexFC PopFC() /// /// FC computation and shortcut cases for each node type /// - private void CalculateFC(int NodeType, RegexNode node, int CurIndex) + private void CalculateFC(RegexNodeKind nodeType, RegexNode node, int CurIndex) { bool ci = (node.Options & RegexOptions.IgnoreCase) != 0; bool rtl = (node.Options & RegexOptions.RightToLeft) != 0; - switch (NodeType) + switch (nodeType) { - case RegexNode.Concatenate | BeforeChild: - case RegexNode.Alternate | BeforeChild: - case RegexNode.Testref | BeforeChild: - case RegexNode.Loop | BeforeChild: - case RegexNode.Lazyloop | BeforeChild: + case RegexNodeKind.Concatenate | BeforeChild: + case RegexNodeKind.Alternate | BeforeChild: + case RegexNodeKind.BackreferenceConditional | BeforeChild: + case RegexNodeKind.Loop | BeforeChild: + case RegexNodeKind.Lazyloop | BeforeChild: break; - case RegexNode.Testgroup | BeforeChild: + case RegexNodeKind.ExpressionConditional | BeforeChild: if (CurIndex == 0) SkipChild(); break; - case RegexNode.Empty: + case RegexNodeKind.Empty: PushFC(new RegexFC(true)); break; - case RegexNode.Concatenate | AfterChild: + case RegexNodeKind.Concatenate | AfterChild: if (CurIndex != 0) { RegexFC child = PopFC(); @@ -816,7 +824,7 @@ private void CalculateFC(int NodeType, RegexNode node, int CurIndex) _skipAllChildren = true; break; - case RegexNode.Testgroup | AfterChild: + case RegexNodeKind.ExpressionConditional | AfterChild: if (CurIndex > 1) { RegexFC child = PopFC(); @@ -826,8 +834,8 @@ private void CalculateFC(int NodeType, RegexNode node, int CurIndex) } break; - case RegexNode.Alternate | AfterChild: - case RegexNode.Testref | AfterChild: + case RegexNodeKind.Alternate | AfterChild: + case RegexNodeKind.BackreferenceConditional | AfterChild: if (CurIndex != 0) { RegexFC child = PopFC(); @@ -837,48 +845,48 @@ private void CalculateFC(int NodeType, RegexNode node, int CurIndex) } break; - case RegexNode.Loop | AfterChild: - case RegexNode.Lazyloop | AfterChild: + case RegexNodeKind.Loop | AfterChild: + case RegexNodeKind.Lazyloop | AfterChild: if (node.M == 0) TopFC()._nullable = true; break; - case RegexNode.Group | BeforeChild: - case RegexNode.Group | AfterChild: - case RegexNode.Capture | BeforeChild: - case RegexNode.Capture | AfterChild: - case RegexNode.Atomic | BeforeChild: - case RegexNode.Atomic | AfterChild: + case RegexNodeKind.Group | BeforeChild: + case RegexNodeKind.Group | AfterChild: + case RegexNodeKind.Capture | BeforeChild: + case RegexNodeKind.Capture | AfterChild: + case RegexNodeKind.Atomic | BeforeChild: + case RegexNodeKind.Atomic | AfterChild: break; - case RegexNode.Require | BeforeChild: - case RegexNode.Prevent | BeforeChild: + case RegexNodeKind.PositiveLookaround | BeforeChild: + case RegexNodeKind.NegativeLookaround | BeforeChild: SkipChild(); PushFC(new RegexFC(true)); break; - case RegexNode.Require | AfterChild: - case RegexNode.Prevent | AfterChild: + case RegexNodeKind.PositiveLookaround | AfterChild: + case RegexNodeKind.NegativeLookaround | AfterChild: break; - case RegexNode.One: - case RegexNode.Notone: - PushFC(new RegexFC(node.Ch, NodeType == RegexNode.Notone, false, ci)); + case RegexNodeKind.One: + case RegexNodeKind.Notone: + PushFC(new RegexFC(node.Ch, nodeType == RegexNodeKind.Notone, false, ci)); break; - case RegexNode.Oneloop: - case RegexNode.Oneloopatomic: - case RegexNode.Onelazy: + case RegexNodeKind.Oneloop: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Onelazy: PushFC(new RegexFC(node.Ch, false, node.M == 0, ci)); break; - case RegexNode.Notoneloop: - case RegexNode.Notoneloopatomic: - case RegexNode.Notonelazy: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.Notonelazy: PushFC(new RegexFC(node.Ch, true, node.M == 0, ci)); break; - case RegexNode.Multi: + case RegexNodeKind.Multi: if (node.Str!.Length == 0) PushFC(new RegexFC(true)); else if (!rtl) @@ -887,37 +895,38 @@ private void CalculateFC(int NodeType, RegexNode node, int CurIndex) PushFC(new RegexFC(node.Str[node.Str.Length - 1], false, false, ci)); break; - case RegexNode.Set: + case RegexNodeKind.Set: PushFC(new RegexFC(node.Str!, false, ci)); break; - case RegexNode.Setloop: - case RegexNode.Setloopatomic: - case RegexNode.Setlazy: + case RegexNodeKind.Setloop: + case RegexNodeKind.Setloopatomic: + case RegexNodeKind.Setlazy: PushFC(new RegexFC(node.Str!, node.M == 0, ci)); break; - case RegexNode.Ref: + case RegexNodeKind.Backreference: PushFC(new RegexFC(RegexCharClass.AnyClass, true, false)); break; - case RegexNode.Nothing: - case RegexNode.Bol: - case RegexNode.Eol: - case RegexNode.Boundary: - case RegexNode.NonBoundary: - case RegexNode.ECMABoundary: - case RegexNode.NonECMABoundary: - case RegexNode.Beginning: - case RegexNode.Start: - case RegexNode.EndZ: - case RegexNode.End: - case RegexNode.UpdateBumpalong: + case RegexNodeKind.Nothing: + case RegexNodeKind.Bol: + case RegexNodeKind.Eol: + case RegexNodeKind.Boundary: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.ECMABoundary: + case RegexNodeKind.NonECMABoundary: + case RegexNodeKind.Beginning: + case RegexNodeKind.Start: + case RegexNodeKind.EndZ: + case RegexNodeKind.End: + case RegexNodeKind.UpdateBumpalong: PushFC(new RegexFC(true)); break; default: - throw new ArgumentException(SR.Format(SR.UnexpectedOpcode, NodeType.ToString(CultureInfo.CurrentCulture))); + Debug.Fail($"Unexpected node: {nodeType}"); + break; } } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs index 814f05e5aeb11..2027763780d2c 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs @@ -31,7 +31,7 @@ internal sealed class RegexReplacement /// public RegexReplacement(string rep, RegexNode concat, Hashtable _caps) { - if (concat.Type != RegexNode.Concatenate) + if (concat.Kind != RegexNodeKind.Concatenate) { throw ThrowHelper.CreateArgumentException(ExceptionResource.ReplacementError); } @@ -47,17 +47,17 @@ public RegexReplacement(string rep, RegexNode concat, Hashtable _caps) { RegexNode child = concat.Child(i); - switch (child.Type) + switch (child.Kind) { - case RegexNode.Multi: + case RegexNodeKind.Multi: vsb.Append(child.Str!); break; - case RegexNode.One: + case RegexNodeKind.One: vsb.Append(child.Ch); break; - case RegexNode.Ref: + case RegexNodeKind.Backreference: if (vsb.Length > 0) { rules.Append(strings.Length); diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs index d3caec254a94f..3a1da357d804a 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; @@ -12,8 +13,8 @@ namespace System.Text.RegularExpressions internal ref struct RegexWriter { // These must be unused RegexNode type bits. - private const int BeforeChild = 64; - private const int AfterChild = 128; + private const RegexNodeKind BeforeChild = (RegexNodeKind)64; + private const RegexNodeKind AfterChild = (RegexNodeKind)128; // Distribution of common patterns indicates an average amount of 56 op codes. Since we're stackalloc'ing, // we can afford to make it a bit higher and a power of two for simplicity. @@ -26,6 +27,14 @@ internal ref struct RegexWriter private Hashtable? _caps; private int _trackCount; +#if DEBUG + static RegexWriter() + { + Debug.Assert(!Enum.IsDefined(typeof(RegexNodeKind), BeforeChild)); + Debug.Assert(!Enum.IsDefined(typeof(RegexNodeKind), AfterChild)); + } +#endif + private RegexWriter(Span emittedSpan, Span intStackSpan) { _emitted = new ValueListBuilder(emittedSpan); @@ -103,11 +112,11 @@ public RegexCode RegexCodeFromRegexTree(RegexTree tree, CultureInfo culture) int curNodeChildCount = curNode.ChildCount(); if (curNodeChildCount == 0) { - EmitFragment(curNode.Type, curNode, 0); + EmitFragment(curNode.Kind, curNode, 0); } else if (curChild < curNodeChildCount) { - EmitFragment(curNode.Type | BeforeChild, curNode, curChild); + EmitFragment(curNode.Kind | BeforeChild, curNode, curChild); curNode = curNode.Child(curChild); _intStack.Append(curChild); @@ -121,9 +130,9 @@ public RegexCode RegexCodeFromRegexTree(RegexTree tree, CultureInfo culture) } curChild = _intStack.Pop(); - curNode = curNode.Next!; + curNode = curNode.Parent!; - EmitFragment(curNode.Type | AfterChild, curNode, curChild); + EmitFragment(curNode.Kind | AfterChild, curNode, curChild); curChild++; } @@ -219,7 +228,7 @@ private int StringCode(string str) /// through the tree and calls EmitFragment to emits code before /// and after each child of an interior node, and at each leaf. /// - private void EmitFragment(int nodetype, RegexNode node, int curIndex) + private void EmitFragment(RegexNodeKind nodeType, RegexNode node, int curIndex) { int bits = 0; if ((node.Options & RegexOptions.RightToLeft) != 0) @@ -231,14 +240,14 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) bits |= RegexCode.Ci; } - switch (nodetype) + switch (nodeType) { - case RegexNode.Concatenate | BeforeChild: - case RegexNode.Concatenate | AfterChild: - case RegexNode.Empty: + case RegexNodeKind.Concatenate | BeforeChild: + case RegexNodeKind.Concatenate | AfterChild: + case RegexNodeKind.Empty: break; - case RegexNode.Alternate | BeforeChild: + case RegexNodeKind.Alternate | BeforeChild: if (curIndex < node.ChildCount() - 1) { _intStack.Append(_emitted.Length); @@ -246,7 +255,7 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) } break; - case RegexNode.Alternate | AfterChild: + case RegexNodeKind.Alternate | AfterChild: { if (curIndex < node.ChildCount() - 1) { @@ -265,7 +274,7 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) break; } - case RegexNode.Testref | BeforeChild: + case RegexNodeKind.BackreferenceConditional | BeforeChild: switch (curIndex) { case 0: @@ -278,7 +287,7 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) } break; - case RegexNode.Testref | AfterChild: + case RegexNodeKind.BackreferenceConditional | AfterChild: switch (curIndex) { case 0: @@ -296,7 +305,7 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) } break; - case RegexNode.Testgroup | BeforeChild: + case RegexNodeKind.ExpressionConditional | BeforeChild: switch (curIndex) { case 0: @@ -308,7 +317,7 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) } break; - case RegexNode.Testgroup | AfterChild: + case RegexNodeKind.ExpressionConditional | AfterChild: switch (curIndex) { case 0: @@ -329,8 +338,8 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) } break; - case RegexNode.Loop | BeforeChild: - case RegexNode.Lazyloop | BeforeChild: + case RegexNodeKind.Loop | BeforeChild: + case RegexNodeKind.Lazyloop | BeforeChild: if (node.N < int.MaxValue || node.M > 1) Emit(node.M == 0 ? RegexCode.Nullcount : RegexCode.Setcount, node.M == 0 ? 0 : 1 - node.M); @@ -345,11 +354,11 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) _intStack.Append(_emitted.Length); break; - case RegexNode.Loop | AfterChild: - case RegexNode.Lazyloop | AfterChild: + case RegexNodeKind.Loop | AfterChild: + case RegexNodeKind.Lazyloop | AfterChild: { int StartJumpPos = _emitted.Length; - int Lazy = (nodetype - (RegexNode.Loop | AfterChild)); + int Lazy = (nodeType - (RegexNodeKind.Loop | AfterChild)); if (node.N < int.MaxValue || node.M > 1) Emit(RegexCode.Branchcount + Lazy, _intStack.Pop(), node.N == int.MaxValue ? int.MaxValue : node.N - node.M); @@ -361,73 +370,73 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) } break; - case RegexNode.Group | BeforeChild: - case RegexNode.Group | AfterChild: + case RegexNodeKind.Group | BeforeChild: + case RegexNodeKind.Group | AfterChild: break; - case RegexNode.Capture | BeforeChild: + case RegexNodeKind.Capture | BeforeChild: Emit(RegexCode.Setmark); break; - case RegexNode.Capture | AfterChild: + case RegexNodeKind.Capture | AfterChild: Emit(RegexCode.Capturemark, RegexParser.MapCaptureNumber(node.M, _caps), RegexParser.MapCaptureNumber(node.N, _caps)); break; - case RegexNode.Require | BeforeChild: + case RegexNodeKind.PositiveLookaround | BeforeChild: Emit(RegexCode.Setjump); // causes lookahead/lookbehind to be non-backtracking Emit(RegexCode.Setmark); break; - case RegexNode.Require | AfterChild: + case RegexNodeKind.PositiveLookaround | AfterChild: Emit(RegexCode.Getmark); Emit(RegexCode.Forejump); // causes lookahead/lookbehind to be non-backtracking break; - case RegexNode.Prevent | BeforeChild: + case RegexNodeKind.NegativeLookaround | BeforeChild: Emit(RegexCode.Setjump); _intStack.Append(_emitted.Length); Emit(RegexCode.Lazybranch, 0); break; - case RegexNode.Prevent | AfterChild: + case RegexNodeKind.NegativeLookaround | AfterChild: Emit(RegexCode.Backjump); PatchJump(_intStack.Pop(), _emitted.Length); Emit(RegexCode.Forejump); break; - case RegexNode.Atomic | BeforeChild: + case RegexNodeKind.Atomic | BeforeChild: Emit(RegexCode.Setjump); break; - case RegexNode.Atomic | AfterChild: + case RegexNodeKind.Atomic | AfterChild: Emit(RegexCode.Forejump); break; - case RegexNode.One: - case RegexNode.Notone: - Emit(node.Type | bits, node.Ch); + case RegexNodeKind.One: + case RegexNodeKind.Notone: + Emit((int)node.Kind | bits, node.Ch); break; - case RegexNode.Notoneloop: - case RegexNode.Notoneloopatomic: - case RegexNode.Notonelazy: - case RegexNode.Oneloop: - case RegexNode.Oneloopatomic: - case RegexNode.Onelazy: + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Notoneloopatomic: + case RegexNodeKind.Notonelazy: + case RegexNodeKind.Oneloop: + case RegexNodeKind.Oneloopatomic: + case RegexNodeKind.Onelazy: if (node.M > 0) { - Emit(((node.Type == RegexNode.Oneloop || node.Type == RegexNode.Oneloopatomic || node.Type == RegexNode.Onelazy) ? + Emit(((node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or RegexNodeKind.Onelazy) ? RegexCode.Onerep : RegexCode.Notonerep) | bits, node.Ch, node.M); } if (node.N > node.M) { - Emit(node.Type | bits, node.Ch, node.N == int.MaxValue ? int.MaxValue : node.N - node.M); + Emit((int)node.Kind | bits, node.Ch, node.N == int.MaxValue ? int.MaxValue : node.N - node.M); } break; - case RegexNode.Setloop: - case RegexNode.Setloopatomic: - case RegexNode.Setlazy: + case RegexNodeKind.Setloop: + case RegexNodeKind.Setloopatomic: + case RegexNodeKind.Setlazy: { int stringCode = StringCode(node.Str!); if (node.M > 0) @@ -436,40 +445,41 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) } if (node.N > node.M) { - Emit(node.Type | bits, stringCode, (node.N == int.MaxValue) ? int.MaxValue : node.N - node.M); + Emit((int)node.Kind | bits, stringCode, (node.N == int.MaxValue) ? int.MaxValue : node.N - node.M); } } break; - case RegexNode.Multi: - Emit(node.Type | bits, StringCode(node.Str!)); + case RegexNodeKind.Multi: + Emit((int)node.Kind | bits, StringCode(node.Str!)); break; - case RegexNode.Set: - Emit(node.Type | bits, StringCode(node.Str!)); + case RegexNodeKind.Set: + Emit((int)node.Kind | bits, StringCode(node.Str!)); break; - case RegexNode.Ref: - Emit(node.Type | bits, RegexParser.MapCaptureNumber(node.M, _caps)); + case RegexNodeKind.Backreference: + Emit((int)node.Kind | bits, RegexParser.MapCaptureNumber(node.M, _caps)); break; - case RegexNode.Nothing: - case RegexNode.Bol: - case RegexNode.Eol: - case RegexNode.Boundary: - case RegexNode.NonBoundary: - case RegexNode.ECMABoundary: - case RegexNode.NonECMABoundary: - case RegexNode.Beginning: - case RegexNode.Start: - case RegexNode.EndZ: - case RegexNode.End: - case RegexNode.UpdateBumpalong: - Emit(node.Type); + case RegexNodeKind.Nothing: + case RegexNodeKind.Bol: + case RegexNodeKind.Eol: + case RegexNodeKind.Boundary: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.ECMABoundary: + case RegexNodeKind.NonECMABoundary: + case RegexNodeKind.Beginning: + case RegexNodeKind.Start: + case RegexNodeKind.EndZ: + case RegexNodeKind.End: + case RegexNodeKind.UpdateBumpalong: + Emit((int)node.Kind); break; default: - throw new ArgumentException(SR.Format(SR.UnexpectedOpcode, nodetype.ToString())); + Debug.Fail($"Unexpected node: {nodeType}"); + break; } } } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/RegexNodeToSymbolicConverter.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/RegexNodeToSymbolicConverter.cs index 6c299578983d7..cdafb9114882a 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/RegexNodeToSymbolicConverter.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/RegexNodeToSymbolicConverter.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; -using System.Runtime.CompilerServices; using System.Threading; namespace System.Text.RegularExpressions.Symbolic @@ -212,9 +211,9 @@ public SymbolicRegexNode Convert(RegexNode node, bool topLevel) return StackHelper.CallOnEmptyStack(Convert, node, topLevel); } - switch (node.Type) + switch (node.Kind) { - case RegexNode.Alternate: + case RegexNodeKind.Alternate: { var nested = new SymbolicRegexNode[node.ChildCount()]; for (int i = 0; i < nested.Length; i++) @@ -224,17 +223,17 @@ public SymbolicRegexNode Convert(RegexNode node, bool topLevel) return _builder.MkOr(nested); } - case RegexNode.Beginning: + case RegexNodeKind.Beginning: return _builder._startAnchor; - case RegexNode.Bol: + case RegexNodeKind.Bol: EnsureNewlinePredicateInitialized(); return _builder._bolAnchor; - case RegexNode.Capture when node.N == -1: + case RegexNodeKind.Capture when node.N == -1: return Convert(node.Child(0), topLevel); // treat as non-capturing group (...) - case RegexNode.Concatenate: + case RegexNodeKind.Concatenate: { List nested = FlattenNestedConcatenations(node); var converted = new SymbolicRegexNode[nested.Count]; @@ -245,68 +244,68 @@ public SymbolicRegexNode Convert(RegexNode node, bool topLevel) return _builder.MkConcat(converted, topLevel); } - case RegexNode.Empty: - case RegexNode.UpdateBumpalong: // optional directive that behaves the same as Empty + case RegexNodeKind.Empty: + case RegexNodeKind.UpdateBumpalong: // optional directive that behaves the same as Empty return _builder._epsilon; - case RegexNode.End: // \z anchor + case RegexNodeKind.End: // \z anchor return _builder._endAnchor; - case RegexNode.EndZ: // \Z anchor + case RegexNodeKind.EndZ: // \Z anchor EnsureNewlinePredicateInitialized(); return _builder._endAnchorZ; - case RegexNode.Eol: + case RegexNodeKind.Eol: EnsureNewlinePredicateInitialized(); return _builder._eolAnchor; - case RegexNode.Loop: + case RegexNodeKind.Loop: return _builder.MkLoop(Convert(node.Child(0), topLevel: false), isLazy: false, node.M, node.N); - case RegexNode.Lazyloop: + case RegexNodeKind.Lazyloop: return _builder.MkLoop(Convert(node.Child(0), topLevel: false), isLazy: true, node.M, node.N); - case RegexNode.Multi: + case RegexNodeKind.Multi: return ConvertMulti(node, topLevel); - case RegexNode.Notone: + case RegexNodeKind.Notone: return _builder.MkSingleton(Solver.Not(Solver.CharConstraint(node.Ch, (node.Options & RegexOptions.IgnoreCase) != 0, _culture.Name))); - case RegexNode.Notoneloop: - case RegexNode.Notonelazy: - return ConvertNotoneloop(node, node.Type == RegexNode.Notonelazy); + case RegexNodeKind.Notoneloop: + case RegexNodeKind.Notonelazy: + return ConvertNotoneloop(node, node.Kind == RegexNodeKind.Notonelazy); - case RegexNode.One: + case RegexNodeKind.One: return _builder.MkSingleton(Solver.CharConstraint(node.Ch, (node.Options & RegexOptions.IgnoreCase) != 0, _culture.Name)); - case RegexNode.Oneloop: - case RegexNode.Onelazy: - return ConvertOneloop(node, node.Type == RegexNode.Onelazy); + case RegexNodeKind.Oneloop: + case RegexNodeKind.Onelazy: + return ConvertOneloop(node, node.Kind == RegexNodeKind.Onelazy); - case RegexNode.Set: + case RegexNodeKind.Set: return ConvertSet(node); - case RegexNode.Setloop: - case RegexNode.Setlazy: - return ConvertSetloop(node, node.Type == RegexNode.Setlazy); + case RegexNodeKind.Setloop: + case RegexNodeKind.Setlazy: + return ConvertSetloop(node, node.Kind == RegexNodeKind.Setlazy); // TBD: ECMA case intersect predicate with ascii range ? - case RegexNode.Boundary: - case RegexNode.ECMABoundary: + case RegexNodeKind.Boundary: + case RegexNodeKind.ECMABoundary: EnsureWordLetterPredicateInitialized(); return _builder._wbAnchor; // TBD: ECMA case intersect predicate with ascii range ? - case RegexNode.NonBoundary: - case RegexNode.NonECMABoundary: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.NonECMABoundary: EnsureWordLetterPredicateInitialized(); return _builder._nwbAnchor; - case RegexNode.Nothing: + case RegexNodeKind.Nothing: return _builder._nothing; #if DEBUG - case RegexNode.Testgroup: + case RegexNodeKind.ExpressionConditional: // Try to extract the special case representing complement or intersection if (IsComplementedNode(node)) { @@ -327,19 +326,19 @@ public SymbolicRegexNode Convert(RegexNode node, bool topLevel) #endif default: - throw new NotSupportedException(SR.Format(SR.NotSupported_NonBacktrackingConflictingExpression, node.Type switch + throw new NotSupportedException(SR.Format(SR.NotSupported_NonBacktrackingConflictingExpression, node.Kind switch { - RegexNode.Capture => SR.ExpressionDescription_BalancingGroup, - RegexNode.Testgroup => SR.ExpressionDescription_IfThenElse, - RegexNode.Ref => SR.ExpressionDescription_Backreference, - RegexNode.Testref => SR.ExpressionDescription_Conditional, - RegexNode.Require => SR.ExpressionDescription_PositiveLookaround, - RegexNode.Prevent => SR.ExpressionDescription_NegativeLookaround, - RegexNode.Start => SR.ExpressionDescription_ContiguousMatches, - RegexNode.Atomic or - RegexNode.Setloopatomic or - RegexNode.Oneloopatomic or - RegexNode.Notoneloopatomic => SR.ExpressionDescription_AtomicSubexpressions, + RegexNodeKind.Capture => SR.ExpressionDescription_BalancingGroup, + RegexNodeKind.ExpressionConditional => SR.ExpressionDescription_IfThenElse, + RegexNodeKind.Backreference => SR.ExpressionDescription_Backreference, + RegexNodeKind.BackreferenceConditional => SR.ExpressionDescription_Conditional, + RegexNodeKind.PositiveLookaround => SR.ExpressionDescription_PositiveLookaround, + RegexNodeKind.NegativeLookaround => SR.ExpressionDescription_NegativeLookaround, + RegexNodeKind.Start => SR.ExpressionDescription_ContiguousMatches, + RegexNodeKind.Atomic or + RegexNodeKind.Setloopatomic or + RegexNodeKind.Oneloopatomic or + RegexNodeKind.Notoneloopatomic => SR.ExpressionDescription_AtomicSubexpressions, _ => UnexpectedNodeType(node) })); @@ -347,7 +346,7 @@ static string UnexpectedNodeType(RegexNode node) { // The default should never arise, since other node types are either supported // or have been removed (e.g. Group) from the final parse tree. - string description = $"Unexpected node type ({nameof(RegexNode)}:{node.Type})"; + string description = $"Unexpected node type ({nameof(RegexNode)}:{node.Kind})"; Debug.Fail(description); return description; } @@ -381,7 +380,7 @@ List FlattenNestedConcatenations(RegexNode concat) while (todo.TryPop(out RegexNode? node)) { - if (node.Type == RegexNode.Concatenate) + if (node.Kind == RegexNodeKind.Concatenate) { // Flatten nested concatenations for (int i = node.ChildCount() - 1; i >= 0; i--) @@ -389,7 +388,7 @@ List FlattenNestedConcatenations(RegexNode concat) todo.Push(node.Child(i)); } } - else if (node.Type == RegexNode.Capture) + else if (node.Kind == RegexNodeKind.Capture) { if (node.N == -1) { @@ -413,7 +412,7 @@ List FlattenNestedConcatenations(RegexNode concat) SymbolicRegexNode ConvertMulti(RegexNode node, bool topLevel) { - Debug.Assert(node.Type == RegexNode.Multi); + Debug.Assert(node.Kind == RegexNodeKind.Multi); string? sequence = node.Str; Debug.Assert(sequence is not null); @@ -431,7 +430,7 @@ SymbolicRegexNode ConvertMulti(RegexNode node, bool topLevel) SymbolicRegexNode ConvertOneloop(RegexNode node, bool isLazy) { - Debug.Assert(node.Type is RegexNode.Oneloop or RegexNode.Onelazy); + Debug.Assert(node.Kind is RegexNodeKind.Oneloop or RegexNodeKind.Onelazy); bool ignoreCase = (node.Options & RegexOptions.IgnoreCase) != 0; BDD cond = Solver.CharConstraint(node.Ch, ignoreCase, _culture.Name); @@ -443,7 +442,7 @@ SymbolicRegexNode ConvertOneloop(RegexNode node, bool isLazy) SymbolicRegexNode ConvertNotoneloop(RegexNode node, bool isLazy) { - Debug.Assert(node.Type is RegexNode.Notoneloop or RegexNode.Notonelazy); + Debug.Assert(node.Kind is RegexNodeKind.Notoneloop or RegexNodeKind.Notonelazy); bool ignoreCase = (node.Options & RegexOptions.IgnoreCase) != 0; BDD cond = Solver.Not(Solver.CharConstraint(node.Ch, ignoreCase, _culture.Name)); @@ -455,7 +454,7 @@ SymbolicRegexNode ConvertNotoneloop(RegexNode node, bool isLazy) SymbolicRegexNode ConvertSet(RegexNode node) { - Debug.Assert(node.Type == RegexNode.Set); + Debug.Assert(node.Kind == RegexNodeKind.Set); string? set = node.Str; Debug.Assert(set is not null); @@ -467,7 +466,7 @@ SymbolicRegexNode ConvertSet(RegexNode node) SymbolicRegexNode ConvertSetloop(RegexNode node, bool isLazy) { - Debug.Assert(node.Type is RegexNode.Setloop or RegexNode.Setlazy); + Debug.Assert(node.Kind is RegexNodeKind.Setloop or RegexNodeKind.Setlazy); string? set = node.Str; Debug.Assert(set is not null); @@ -480,11 +479,11 @@ SymbolicRegexNode ConvertSetloop(RegexNode node, bool isLazy) #if DEBUG // TODO-NONBACKTRACKING: recognizing strictly only [] (RegexNode.Nothing), for example [0-[0]] would not be recognized - bool IsNothing(RegexNode node) => node.Type == RegexNode.Nothing || (node.Type == RegexNode.Set && ConvertSet(node).IsNothing); + bool IsNothing(RegexNode node) => node.Kind == RegexNodeKind.Nothing || (node.Kind == RegexNodeKind.Set && ConvertSet(node).IsNothing); - bool IsDotStar(RegexNode node) => node.Type == RegexNode.Setloop && Convert(node, topLevel: false).IsAnyStar; + bool IsDotStar(RegexNode node) => node.Kind == RegexNodeKind.Setloop && Convert(node, topLevel: false).IsAnyStar; - bool IsIntersect(RegexNode node) => node.Type == RegexNode.Testgroup && IsNothing(node.Child(2)); + bool IsIntersect(RegexNode node) => node.Kind == RegexNodeKind.ExpressionConditional && IsNothing(node.Child(2)); bool TryGetIntersection(RegexNode node, [Diagnostics.CodeAnalysis.NotNullWhen(true)] out List? conjuncts) { From 132cc2f2d00e00b7f0dfd43498077da65cc27d29 Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Fri, 21 Jan 2022 23:58:20 +0300 Subject: [PATCH 125/308] Refactor optimizing morph for commutative operations (#63251) * Create "fgOptimizeCommutativeArithmetic" And just move code from "fgMorphSmpOp" to it. Just one diff: better comma throw propagation in an ILGEN method. * Refactor the function Split it into specialized variants for each operator, delete redundant code, fix up one case of wrong typing for a constant in the MUL -> SHIFT optimization. One CSE diff due to different VNs because of the typing change for the constant (int -> long). Many text diffs: "mov x3, 5" => "mov w3, 5". --- src/coreclr/jit/compiler.h | 6 +- src/coreclr/jit/morph.cpp | 721 ++++++++++++++++++++----------------- 2 files changed, 386 insertions(+), 341 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index ea29174e05769..0f395e7dae899 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6409,6 +6409,10 @@ class Compiler GenTree* fgOptimizeCast(GenTreeCast* cast); GenTree* fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp); GenTree* fgOptimizeRelationalComparisonWithConst(GenTreeOp* cmp); + GenTree* fgOptimizeCommutativeArithmetic(GenTreeOp* tree); + GenTree* fgOptimizeAddition(GenTreeOp* add); + GenTree* fgOptimizeMultiply(GenTreeOp* mul); + GenTree* fgOptimizeBitwiseAnd(GenTreeOp* andOp); GenTree* fgPropagateCommaThrow(GenTree* parent, GenTreeOp* commaThrow, GenTreeFlags precedingSideEffects); GenTree* fgMorphRetInd(GenTreeUnOp* tree); GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree); @@ -6419,7 +6423,7 @@ class Compiler bool fgMorphCanUseLclFldForCopy(unsigned lclNum1, unsigned lclNum2); GenTreeLclVar* fgMorphTryFoldObjAsLclVar(GenTreeObj* obj); - GenTree* fgMorphCommutative(GenTreeOp* tree); + GenTreeOp* fgMorphCommutative(GenTreeOp* tree); GenTree* fgMorphCastedBitwiseOp(GenTreeOp* tree); GenTree* fgMorphReduceAddOps(GenTree* tree); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 138e46358065e..c5fb83306e035 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -10771,7 +10771,7 @@ GenTree* Compiler::fgMorphFieldAssignToSimdSetElement(GenTree* tree) // A folded GenTree* instance or nullptr if something prevents folding. // -GenTree* Compiler::fgMorphCommutative(GenTreeOp* tree) +GenTreeOp* Compiler::fgMorphCommutative(GenTreeOp* tree) { assert(varTypeIsIntegralOrI(tree->TypeGet())); assert(tree->OperIs(GT_ADD, GT_MUL, GT_OR, GT_AND, GT_XOR)); @@ -10843,7 +10843,7 @@ GenTree* Compiler::fgMorphCommutative(GenTreeOp* tree) DEBUG_DESTROY_NODE(foldedCns); INDEBUG(cns1->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); - return op1; + return op1->AsOp(); } //------------------------------------------------------------------------------ @@ -10856,6 +10856,8 @@ GenTree* Compiler::fgMorphCommutative(GenTreeOp* tree) // A folded GenTree* instance, or nullptr if it couldn't be folded GenTree* Compiler::fgMorphCastedBitwiseOp(GenTreeOp* tree) { + // This transform does not preserve VNs and deletes a node. + assert(fgGlobalMorph); assert(varTypeIsIntegralOrI(tree)); assert(tree->OperIs(GT_OR, GT_AND, GT_XOR)); @@ -11842,7 +11844,9 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) } } // if (op2) +#ifndef TARGET_64BIT DONE_MORPHING_CHILDREN: +#endif // !TARGET_64BIT if (tree->OperIsIndirOrArrLength()) { @@ -11977,8 +11981,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) */ GenTree* temp; - GenTree* cns1; - GenTree* cns2; size_t ival1; GenTree* lclVarTree; GenTree* effectiveOp1; @@ -12229,335 +12231,15 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) case GT_OR: case GT_XOR: case GT_AND: - - /* Commute any non-REF constants to the right */ - - noway_assert(op1); - if (op1->OperIsConst() && (op1->gtType != TYP_REF)) - { - // TODO-Review: We used to assert here that - // noway_assert(!op2->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD)); - // With modifications to AddrTaken==>AddrExposed, we did more assertion propagation, - // and would sometimes hit this assertion. This may indicate a missed "remorph". - // Task is to re-enable this assertion and investigate. - - /* Swap the operands */ - tree->AsOp()->gtOp1 = op2; - tree->AsOp()->gtOp2 = op1; - - op1 = op2; - op2 = tree->AsOp()->gtOp2; - } - - // Fold "cmp & 1" to just "cmp" - if (tree->OperIs(GT_AND) && tree->TypeIs(TYP_INT) && op1->OperIsCompare() && op2->IsIntegralConst(1) && - !gtIsActiveCSE_Candidate(tree) && !gtIsActiveCSE_Candidate(op2)) - { - DEBUG_DESTROY_NODE(op2); - DEBUG_DESTROY_NODE(tree); - return op1; - } - - // See if we can fold floating point operations (can regress minopts mode) - if (opts.OptimizationEnabled() && varTypeIsFloating(tree->TypeGet()) && !optValnumCSE_phase) - { - if ((oper == GT_MUL) && !op1->IsCnsFltOrDbl() && op2->IsCnsFltOrDbl()) - { - if (op2->AsDblCon()->gtDconVal == 2.0) - { - bool needsComma = !op1->OperIsLeaf() && !op1->IsLocal(); - // if op1 is not a leaf/local we have to introduce a temp via GT_COMMA. - // Unfortunately, it's not optHoistLoopCode-friendly yet so let's do it later. - if (!needsComma || (fgOrder == FGOrderLinear)) - { - // Fold "x*2.0" to "x+x" - op2 = fgMakeMultiUse(&tree->AsOp()->gtOp1); - op1 = tree->AsOp()->gtOp1; - oper = GT_ADD; - tree = gtNewOperNode(oper, tree->TypeGet(), op1, op2); - INDEBUG(tree->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); - } - } - else if (op2->AsDblCon()->gtDconVal == 1.0) - { - // Fold "x*1.0" to "x" - DEBUG_DESTROY_NODE(op2); - DEBUG_DESTROY_NODE(tree); - return op1; - } - } - } - - /* See if we can fold GT_ADD nodes. */ - - if (oper == GT_ADD) - { - /* Fold "((x+icon1)+(y+icon2)) to ((x+y)+(icon1+icon2))" */ - - if (op1->gtOper == GT_ADD && op2->gtOper == GT_ADD && !gtIsActiveCSE_Candidate(op2) && - op1->AsOp()->gtOp2->gtOper == GT_CNS_INT && op2->AsOp()->gtOp2->gtOper == GT_CNS_INT && - !op1->gtOverflow() && !op2->gtOverflow()) - { - // Don't create a byref pointer that may point outside of the ref object. - // If a GC happens, the byref won't get updated. This can happen if one - // of the int components is negative. It also requires the address generation - // be in a fully-interruptible code region. - if (!varTypeIsGC(op1->AsOp()->gtOp1->TypeGet()) && !varTypeIsGC(op2->AsOp()->gtOp1->TypeGet())) - { - cns1 = op1->AsOp()->gtOp2; - cns2 = op2->AsOp()->gtOp2; - - ssize_t value = cns1->AsIntCon()->IconValue() + cns2->AsIntCon()->IconValue(); - cns1->AsIntCon()->SetValueTruncating(value); - - tree->AsOp()->gtOp2 = cns1; - DEBUG_DESTROY_NODE(cns2); - - op1->AsOp()->gtOp2 = op2->AsOp()->gtOp1; - op1->gtFlags |= (op1->AsOp()->gtOp2->gtFlags & GTF_ALL_EFFECT); - DEBUG_DESTROY_NODE(op2); - op2 = tree->AsOp()->gtOp2; - } - } - - if (op2->IsCnsIntOrI() && varTypeIsIntegralOrI(typ)) - { - // Fold (x + 0). - if ((op2->AsIntConCommon()->IconValue() == 0) && !gtIsActiveCSE_Candidate(tree)) - { - // Remove the addition iff it won't change the tree type - // to TYP_REF. - - if (!gtIsActiveCSE_Candidate(op2) && - ((op1->TypeGet() == tree->TypeGet()) || (op1->TypeGet() != TYP_REF))) - { - if (fgGlobalMorph && (op2->OperGet() == GT_CNS_INT) && - (op2->AsIntCon()->gtFieldSeq != nullptr) && - (op2->AsIntCon()->gtFieldSeq != FieldSeqStore::NotAField())) - { - fgAddFieldSeqForZeroOffset(op1, op2->AsIntCon()->gtFieldSeq); - } - - DEBUG_DESTROY_NODE(op2); - DEBUG_DESTROY_NODE(tree); - - return op1; - } - } - } - - if (opts.OptimizationEnabled() && fgGlobalMorph) - { - // - a + b = > b - a - // ADD((NEG(a), b) => SUB(b, a) - - // Skip optimization if non-NEG operand is constant. - if (op1->OperIs(GT_NEG) && !op2->OperIs(GT_NEG) && !op2->IsIntegralConst() && - gtCanSwapOrder(op1, op2)) - { - // tree: ADD - // op1: NEG - // op2: b - // op1Child: a - - GenTree* op1Child = op1->AsOp()->gtOp1; // a - oper = GT_SUB; - tree->SetOper(oper, GenTree::PRESERVE_VN); - tree->AsOp()->gtOp1 = op2; - tree->AsOp()->gtOp2 = op1Child; - - DEBUG_DESTROY_NODE(op1); - - op1 = op2; - op2 = op1Child; - } - // a + -b = > a - b - // ADD(a, (NEG(b)) => SUB(a, b) - else if (!op1->OperIs(GT_NEG) && op2->OperIs(GT_NEG)) - { - // a is non constant because it was already canonicalized to have - // variable on the left and constant on the right. - - // tree: ADD - // op1: a - // op2: NEG - // op2Child: b - - GenTree* op2Child = op2->AsOp()->gtOp1; // a - oper = GT_SUB; - tree->SetOper(oper, GenTree::PRESERVE_VN); - tree->AsOp()->gtOp2 = op2Child; - - DEBUG_DESTROY_NODE(op2); - - op2 = op2Child; - } - } - } - /* See if we can fold GT_MUL by const nodes */ - else if (oper == GT_MUL && op2->IsCnsIntOrI() && !optValnumCSE_phase) - { -#ifndef TARGET_64BIT - noway_assert(typ <= TYP_UINT); -#endif // TARGET_64BIT - noway_assert(!tree->gtOverflow()); - - ssize_t mult = op2->AsIntConCommon()->IconValue(); - bool op2IsConstIndex = op2->OperGet() == GT_CNS_INT && op2->AsIntCon()->gtFieldSeq != nullptr && - op2->AsIntCon()->gtFieldSeq->IsConstantIndexFieldSeq(); - - assert(!op2IsConstIndex || op2->AsIntCon()->gtFieldSeq->m_next == nullptr); - - if (mult == 0) - { - // We may be able to throw away op1 (unless it has side-effects) - - if ((op1->gtFlags & GTF_SIDE_EFFECT) == 0) - { - DEBUG_DESTROY_NODE(op1); - DEBUG_DESTROY_NODE(tree); - return op2; // Just return the "0" node - } - - // We need to keep op1 for the side-effects. Hang it off - // a GT_COMMA node - - tree->ChangeOper(GT_COMMA); - return tree; - } - - size_t abs_mult = (mult >= 0) ? mult : -mult; - size_t lowestBit = genFindLowestBit(abs_mult); - bool changeToShift = false; - - // is it a power of two? (positive or negative) - if (abs_mult == lowestBit) - { - // if negative negate (min-int does not need negation) - if (mult < 0 && mult != SSIZE_T_MIN) - { - // The type of the new GT_NEG node cannot just be op1->TypeGet(). - // Otherwise we may sign-extend incorrectly in cases where the GT_NEG - // node ends up feeding directly a cast, for example in - // GT_CAST(GT_MUL(-1, s_1.ubyte)) - tree->AsOp()->gtOp1 = op1 = gtNewOperNode(GT_NEG, genActualType(op1->TypeGet()), op1); - fgMorphTreeDone(op1); - } - - // If "op2" is a constant array index, the other multiplicand must be a constant. - // Transfer the annotation to the other one. - if (op2->OperGet() == GT_CNS_INT && op2->AsIntCon()->gtFieldSeq != nullptr && - op2->AsIntCon()->gtFieldSeq->IsConstantIndexFieldSeq()) - { - assert(op2->AsIntCon()->gtFieldSeq->m_next == nullptr); - GenTree* otherOp = op1; - if (otherOp->OperGet() == GT_NEG) - { - otherOp = otherOp->AsOp()->gtOp1; - } - assert(otherOp->OperGet() == GT_CNS_INT); - assert(otherOp->AsIntCon()->gtFieldSeq == FieldSeqStore::NotAField()); - otherOp->AsIntCon()->gtFieldSeq = op2->AsIntCon()->gtFieldSeq; - } - - if (abs_mult == 1) - { - DEBUG_DESTROY_NODE(op2); - DEBUG_DESTROY_NODE(tree); - return op1; - } - - /* Change the multiplication into a shift by log2(val) bits */ - op2->AsIntConCommon()->SetIconValue(genLog2(abs_mult)); - changeToShift = true; - } - else if ((lowestBit > 1) && jitIsScaleIndexMul(lowestBit) && optAvoidIntMult()) - { - int shift = genLog2(lowestBit); - ssize_t factor = abs_mult >> shift; - - if (factor == 3 || factor == 5 || factor == 9) - { - // if negative negate (min-int does not need negation) - if (mult < 0 && mult != SSIZE_T_MIN) - { - tree->AsOp()->gtOp1 = op1 = gtNewOperNode(GT_NEG, genActualType(op1->TypeGet()), op1); - fgMorphTreeDone(op1); - } - - GenTree* factorIcon = gtNewIconNode(factor, TYP_I_IMPL); - if (op2IsConstIndex) - { - factorIcon->AsIntCon()->gtFieldSeq = - GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField); - } - - // change the multiplication into a smaller multiplication (by 3, 5 or 9) and a shift - tree->AsOp()->gtOp1 = op1 = gtNewOperNode(GT_MUL, tree->gtType, op1, factorIcon); - fgMorphTreeDone(op1); - - op2->AsIntConCommon()->SetIconValue(shift); - changeToShift = true; - } - } - if (changeToShift) - { - // vnStore is null before the ValueNumber phase has run - if (vnStore != nullptr) - { - // Update the ValueNumber for 'op2', as we just changed the constant - fgValueNumberTreeConst(op2); - } - oper = GT_LSH; - // Keep the old ValueNumber for 'tree' as the new expr - // will still compute the same value as before - tree->ChangeOper(oper, GenTree::PRESERVE_VN); - - goto DONE_MORPHING_CHILDREN; - } - } - else if (fgOperIsBitwiseRotationRoot(oper)) - { - tree = fgRecognizeAndMorphBitwiseRotation(tree); - - // fgRecognizeAndMorphBitwiseRotation may return a new tree - oper = tree->OperGet(); - typ = tree->TypeGet(); - op1 = tree->AsOp()->gtOp1; - op2 = tree->AsOp()->gtOp2; - } - - if (fgGlobalMorph && varTypeIsIntegralOrI(tree) && tree->OperIs(GT_AND, GT_OR, GT_XOR)) - { - GenTree* result = fgMorphCastedBitwiseOp(tree->AsOp()); - if (result != nullptr) - { - assert(result->OperIs(GT_CAST)); - assert(result->AsOp()->gtOp2 == nullptr); - // tree got folded to a unary (cast) op - tree = result; - oper = tree->OperGet(); - typ = tree->TypeGet(); - op1 = tree->AsOp()->gtGetOp1(); - op2 = nullptr; - } - } - - if (varTypeIsIntegralOrI(tree->TypeGet()) && tree->OperIs(GT_ADD, GT_MUL, GT_AND, GT_OR, GT_XOR)) + tree = fgOptimizeCommutativeArithmetic(tree->AsOp()); + if (!tree->OperIsSimple()) { - GenTree* foldedTree = fgMorphCommutative(tree->AsOp()); - if (foldedTree != nullptr) - { - tree = foldedTree; - op1 = tree->gtGetOp1(); - op2 = tree->gtGetOp2(); - if (!tree->OperIs(oper)) - { - return tree; - } - } + return tree; } - + typ = tree->TypeGet(); + oper = tree->OperGet(); + op1 = tree->gtGetOp1(); + op2 = tree->gtGetOp2IfPresent(); break; case GT_NOT: @@ -13736,11 +13418,369 @@ GenTree* Compiler::fgOptimizeRelationalComparisonWithConst(GenTreeOp* cmp) return cmp; } +//------------------------------------------------------------------------ +// fgOptimizeCommutativeArithmetic: Optimizes commutative operations. +// +// Arguments: +// tree - the unchecked GT_ADD/GT_MUL/GT_OR/GT_XOR/GT_AND tree to optimize. +// +// Return Value: +// The optimized tree that can have any shape. +// +GenTree* Compiler::fgOptimizeCommutativeArithmetic(GenTreeOp* tree) +{ + assert(tree->OperIs(GT_ADD, GT_MUL, GT_OR, GT_XOR, GT_AND)); + assert(!tree->gtOverflowEx()); + + // Commute constants to the right. + if (tree->gtGetOp1()->OperIsConst() && !tree->gtGetOp1()->TypeIs(TYP_REF)) + { + // TODO-Review: We used to assert here that "(!op2->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD))". + // This may indicate a missed "remorph". Task is to re-enable this assertion and investigate. + std::swap(tree->gtOp1, tree->gtOp2); + } + + if (!optValnumCSE_phase) + { + GenTree* optimizedTree = nullptr; + if (tree->OperIs(GT_ADD)) + { + optimizedTree = fgOptimizeAddition(tree); + } + else if (tree->OperIs(GT_MUL)) + { + optimizedTree = fgOptimizeMultiply(tree); + } + else if (tree->OperIs(GT_AND)) + { + optimizedTree = fgOptimizeBitwiseAnd(tree); + } + + if (optimizedTree != nullptr) + { + return optimizedTree; + } + } + + if (fgOperIsBitwiseRotationRoot(tree->OperGet())) + { + GenTree* rotationTree = fgRecognizeAndMorphBitwiseRotation(tree); + if (rotationTree != nullptr) + { + return rotationTree; + } + } + + if (fgGlobalMorph && tree->OperIs(GT_AND, GT_OR, GT_XOR)) + { + GenTree* castTree = fgMorphCastedBitwiseOp(tree->AsOp()); + if (castTree != nullptr) + { + return castTree; + } + } + + if (varTypeIsIntegralOrI(tree)) + { + GenTreeOp* optimizedTree = fgMorphCommutative(tree->AsOp()); + if (optimizedTree != nullptr) + { + return optimizedTree; + } + } + + return tree; +} + +//------------------------------------------------------------------------ +// fgOptimizeAddition: optimizes addition. +// +// Arguments: +// add - the unchecked GT_ADD tree to optimize. +// +// Return Value: +// The optimized tree, that can have any shape, in case any transformations +// were performed. Otherwise, "nullptr", guaranteeing no state change. +// +GenTree* Compiler::fgOptimizeAddition(GenTreeOp* add) +{ + assert(add->OperIs(GT_ADD) && !add->gtOverflow()); + assert(!optValnumCSE_phase); + + GenTree* op1 = add->gtGetOp1(); + GenTree* op2 = add->gtGetOp2(); + + // Fold "((x + icon1) + (y + icon2))" to ((x + y) + (icon1 + icon2))". + // Be careful not to create a byref pointer that may point outside of the ref object. + // Only do this in global morph as we don't recompute the VN for "(x + y)", the new "op2". + if (op1->OperIs(GT_ADD) && op2->OperIs(GT_ADD) && !op1->gtOverflow() && !op2->gtOverflow() && + op1->AsOp()->gtGetOp2()->IsCnsIntOrI() && op2->AsOp()->gtGetOp2()->IsCnsIntOrI() && + !varTypeIsGC(op1->AsOp()->gtGetOp1()) && !varTypeIsGC(op2->AsOp()->gtGetOp1()) && fgGlobalMorph) + { + GenTreeOp* addOne = op1->AsOp(); + GenTreeOp* addTwo = op2->AsOp(); + GenTreeIntCon* constOne = addOne->gtGetOp2()->AsIntCon(); + GenTreeIntCon* constTwo = addTwo->gtGetOp2()->AsIntCon(); + + addOne->gtOp2 = addTwo->gtGetOp1(); + addOne->SetAllEffectsFlags(addOne->gtGetOp1(), addOne->gtGetOp2()); + DEBUG_DESTROY_NODE(addTwo); + + constOne->SetValueTruncating(constOne->IconValue() + constTwo->IconValue()); + op2 = constOne; + add->gtOp2 = constOne; + DEBUG_DESTROY_NODE(constTwo); + } + + // Fold (x + 0) - given it won't change the tree type to TYP_REF. + // TODO-Bug: this code will lose the GC-ness of a tree like "native int + byref(0)". + if (op2->IsCnsIntOrI() && (op2->AsIntCon()->IconValue() == 0) && + ((add->TypeGet() == op1->TypeGet()) || !op1->TypeIs(TYP_REF))) + { + if (op2->IsCnsIntOrI() && (op2->AsIntCon()->gtFieldSeq != nullptr) && + (op2->AsIntCon()->gtFieldSeq != FieldSeqStore::NotAField())) + { + fgAddFieldSeqForZeroOffset(op1, op2->AsIntCon()->gtFieldSeq); + } + + DEBUG_DESTROY_NODE(op2); + DEBUG_DESTROY_NODE(add); + + return op1; + } + + // TODO-CQ: this transform preserves VNs and can be enabled outside global morph. + // Note that these transformations are legal for floating-point ADDs as well. + if (opts.OptimizationEnabled() && fgGlobalMorph) + { + // - a + b = > b - a + // ADD((NEG(a), b) => SUB(b, a) + + // Do not do this if "op2" is constant for canonicalization purposes. + if (op1->OperIs(GT_NEG) && !op2->OperIs(GT_NEG) && !op2->IsIntegralConst() && gtCanSwapOrder(op1, op2)) + { + add->SetOper(GT_SUB); + add->gtOp1 = op2; + add->gtOp2 = op1->AsOp()->gtGetOp1(); + + DEBUG_DESTROY_NODE(op1); + + return add; + } + + // a + -b = > a - b + // ADD(a, (NEG(b)) => SUB(a, b) + if (!op1->OperIs(GT_NEG) && op2->OperIs(GT_NEG)) + { + add->SetOper(GT_SUB); + add->gtOp2 = op2->AsOp()->gtGetOp1(); + + DEBUG_DESTROY_NODE(op2); + + return add; + } + } + + return nullptr; +} + +//------------------------------------------------------------------------ +// fgOptimizeMultiply: optimizes multiplication. +// +// Arguments: +// mul - the unchecked TYP_I_IMPL/TYP_INT GT_MUL tree to optimize. +// +// Return Value: +// The optimized tree, that can have any shape, in case any transformations +// were performed. Otherwise, "nullptr", guaranteeing no state change. +// +GenTree* Compiler::fgOptimizeMultiply(GenTreeOp* mul) +{ + assert(mul->OperIs(GT_MUL)); + assert(varTypeIsIntOrI(mul) || varTypeIsFloating(mul)); + assert(!mul->gtOverflow()); + assert(!optValnumCSE_phase); + + GenTree* op1 = mul->gtGetOp1(); + GenTree* op2 = mul->gtGetOp2(); + + assert(mul->TypeGet() == genActualType(op1)); + assert(mul->TypeGet() == genActualType(op2)); + + if (opts.OptimizationEnabled() && op2->IsCnsFltOrDbl()) + { + double multiplierValue = op2->AsDblCon()->gtDconVal; + + if (multiplierValue == 1.0) + { + // Fold "x * 1.0" to "x". + DEBUG_DESTROY_NODE(op2); + DEBUG_DESTROY_NODE(mul); + + return op1; + } + + // Fold "x * 2.0" to "x + x". + // If op1 is not a local we will have to introduce a temporary via GT_COMMA. + // Unfortunately, it's not optHoistLoopCode-friendly (yet), so we'll only do + // this for locals / after hoisting has run (when rationalization remorphs + // math INTRINSICSs into calls...). + if ((multiplierValue == 2.0) && (op1->IsLocal() || (fgOrder == FGOrderLinear))) + { + op2 = fgMakeMultiUse(&op1); + GenTree* add = gtNewOperNode(GT_ADD, mul->TypeGet(), op1, op2); + INDEBUG(add->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); + + return add; + } + } + + if (op2->IsIntegralConst()) + { + ssize_t mult = op2->AsIntConCommon()->IconValue(); + bool op2IsConstIndex = op2->OperGet() == GT_CNS_INT && op2->AsIntCon()->gtFieldSeq != nullptr && + op2->AsIntCon()->gtFieldSeq->IsConstantIndexFieldSeq(); + + assert(!op2IsConstIndex || op2->AsIntCon()->gtFieldSeq->m_next == nullptr); + + if (mult == 0) + { + // We may be able to throw away op1 (unless it has side-effects) + + if ((op1->gtFlags & GTF_SIDE_EFFECT) == 0) + { + DEBUG_DESTROY_NODE(op1); + DEBUG_DESTROY_NODE(mul); + + return op2; // Just return the "0" node + } + + // We need to keep op1 for the side-effects. Hang it off a GT_COMMA node. + mul->ChangeOper(GT_COMMA, GenTree::PRESERVE_VN); + return mul; + } + + size_t abs_mult = (mult >= 0) ? mult : -mult; + size_t lowestBit = genFindLowestBit(abs_mult); + bool changeToShift = false; + + // is it a power of two? (positive or negative) + if (abs_mult == lowestBit) + { + // if negative negate (min-int does not need negation) + if (mult < 0 && mult != SSIZE_T_MIN) + { + op1 = gtNewOperNode(GT_NEG, genActualType(op1), op1); + mul->gtOp1 = op1; + fgMorphTreeDone(op1); + } + + // If "op2" is a constant array index, the other multiplicand must be a constant. + // Transfer the annotation to the other one. + if (op2->OperGet() == GT_CNS_INT && op2->AsIntCon()->gtFieldSeq != nullptr && + op2->AsIntCon()->gtFieldSeq->IsConstantIndexFieldSeq()) + { + assert(op2->AsIntCon()->gtFieldSeq->m_next == nullptr); + GenTree* otherOp = op1; + if (otherOp->OperGet() == GT_NEG) + { + otherOp = otherOp->AsOp()->gtOp1; + } + assert(otherOp->OperGet() == GT_CNS_INT); + assert(otherOp->AsIntCon()->gtFieldSeq == FieldSeqStore::NotAField()); + otherOp->AsIntCon()->gtFieldSeq = op2->AsIntCon()->gtFieldSeq; + } + + if (abs_mult == 1) + { + DEBUG_DESTROY_NODE(op2); + DEBUG_DESTROY_NODE(mul); + return op1; + } + + // Change the multiplication into a shift by log2(val) bits. + op2->AsIntConCommon()->SetIconValue(genLog2(abs_mult)); + changeToShift = true; + } + else if ((lowestBit > 1) && jitIsScaleIndexMul(lowestBit) && optAvoidIntMult()) + { + int shift = genLog2(lowestBit); + ssize_t factor = abs_mult >> shift; + + if (factor == 3 || factor == 5 || factor == 9) + { + // if negative negate (min-int does not need negation) + if (mult < 0 && mult != SSIZE_T_MIN) + { + op1 = gtNewOperNode(GT_NEG, genActualType(op1), op1); + mul->gtOp1 = op1; + fgMorphTreeDone(op1); + } + + GenTree* factorIcon = gtNewIconNode(factor, mul->TypeGet()); + if (op2IsConstIndex) + { + factorIcon->AsIntCon()->gtFieldSeq = + GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField); + } + + // change the multiplication into a smaller multiplication (by 3, 5 or 9) and a shift + op1 = gtNewOperNode(GT_MUL, mul->TypeGet(), op1, factorIcon); + mul->gtOp1 = op1; + fgMorphTreeDone(op1); + + op2->AsIntConCommon()->SetIconValue(shift); + changeToShift = true; + } + } + + if (changeToShift) + { + fgUpdateConstTreeValueNumber(op2); + mul->ChangeOper(GT_LSH, GenTree::PRESERVE_VN); + + return mul; + } + } + + return nullptr; +} + +//------------------------------------------------------------------------ +// fgOptimizeBitwiseAnd: optimizes the "and" operation. +// +// Arguments: +// andOp - the GT_AND tree to optimize. +// +// Return Value: +// The optimized tree, currently always a relop, in case any transformations +// were performed. Otherwise, "nullptr", guaranteeing no state change. +// +GenTree* Compiler::fgOptimizeBitwiseAnd(GenTreeOp* andOp) +{ + assert(andOp->OperIs(GT_AND)); + assert(!optValnumCSE_phase); + + GenTree* op1 = andOp->gtGetOp1(); + GenTree* op2 = andOp->gtGetOp2(); + + // Fold "cmp & 1" to just "cmp". + if (andOp->TypeIs(TYP_INT) && op1->OperIsCompare() && op2->IsIntegralConst(1)) + { + DEBUG_DESTROY_NODE(op2); + DEBUG_DESTROY_NODE(andOp); + + return op1; + } + + return nullptr; +} + //------------------------------------------------------------------------ // fgPropagateCommaThrow: propagate a "comma throw" up the tree. // // "Comma throws" in the compiler represent the canonical form of an always -// throwing expression. They have the shape of COMMA(THROW, ZERO), to satsify +// throwing expression. They have the shape of COMMA(THROW, ZERO), to satisfy // the semantic that the original expression produced some value and are // generated by "gtFoldExprConst" when it encounters checked arithmetic that // will determinably overflow. @@ -14379,7 +14419,7 @@ bool Compiler::fgOperIsBitwiseRotationRoot(genTreeOps oper) // tree - tree to check for a rotation pattern // // Return Value: -// An equivalent GT_ROL or GT_ROR tree if a pattern is found; original tree otherwise. +// An equivalent GT_ROL or GT_ROR tree if a pattern is found; "nullptr" otherwise. // // Assumption: // The input is a GT_OR or a GT_XOR tree. @@ -14429,7 +14469,7 @@ GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree) // We can't do anything if the tree has assignments, calls, or volatile // reads. Note that we allow GTF_EXCEPT side effect since any exceptions // thrown by the original tree will be thrown by the transformed tree as well. - return tree; + return nullptr; } genTreeOps oper = tree->OperGet(); @@ -14452,7 +14492,7 @@ GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree) } else { - return tree; + return nullptr; } // Check if the trees representing the value to shift are identical. @@ -14484,7 +14524,7 @@ GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree) } else { - return tree; + return nullptr; } } @@ -14497,7 +14537,7 @@ GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree) } else { - return tree; + return nullptr; } } @@ -14507,7 +14547,7 @@ GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree) // something like (x << y & 15) or // (x >> (32 - y) & 15 with 32 bit x. // The transformation is not valid. - return tree; + return nullptr; } GenTree* shiftIndexWithAdd = nullptr; @@ -14553,7 +14593,7 @@ GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree) // TODO-X86-CQ: we need to handle variable-sized long shifts specially on x86. // GT_LSH, GT_RSH, and GT_RSZ have helpers for this case. We may need // to add helpers for GT_ROL and GT_ROR. - return tree; + return nullptr; } #endif @@ -14607,7 +14647,8 @@ GenTree* Compiler::fgRecognizeAndMorphBitwiseRotation(GenTree* tree) return tree; } } - return tree; + + return nullptr; } #if !defined(TARGET_64BIT) From 1d3c23d04666f0a1e740b25e7de40fb6b338ec3a Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Sat, 22 Jan 2022 00:02:55 +0300 Subject: [PATCH 126/308] Do not set GTF_NO_CSE for sources of block copies (#63462) It is not necessary, the compiler fully supports locals on the RHS of a struct assignment. Not marking these results in a CQ improvement, from struct (including SIMD) CSEs and global constant propagation into promoted fields. --- src/coreclr/jit/gentree.cpp | 9 ++------- src/coreclr/jit/morph.cpp | 4 ---- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index b8897e81dc8e3..ead4be3295769 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -6827,24 +6827,19 @@ void Compiler::gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVa // gtNewBlkOpNode: Creates a GenTree for a block (struct) assignment. // // Arguments: -// dst - Destination or target to copy to / initialize the buffer. -// srcOrFillVall - the size of the buffer to copy/initialize or zero, in the case of CpObj. +// dst - The destination node: local var / block node. +// srcOrFillVall - The value to assign for CopyBlk, the integer "fill" for InitBlk // isVolatile - Whether this is a volatile memory operation or not. // isCopyBlock - True if this is a block copy (rather than a block init). // // Return Value: // Returns the newly constructed and initialized block operation. // -// Notes: -// If size is zero, the dst must be a GT_OBJ with the class handle. -// 'dst' must be a block node or lclVar. -// GenTree* Compiler::gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, bool isVolatile, bool isCopyBlock) { assert(dst->OperIsBlk() || dst->OperIsLocal()); if (isCopyBlock) { - srcOrFillVal->gtFlags |= GTF_DONT_CSE; if (srcOrFillVal->OperIsIndir() && (srcOrFillVal->gtGetOp1()->gtOper == GT_ADDR)) { srcOrFillVal = srcOrFillVal->gtGetOp1()->gtGetOp1(); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index c5fb83306e035..48007f56ca860 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -4866,10 +4866,6 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, GenTreeCall::Use* argx->gtFlags &= ~(GTF_ALL_EFFECT) | (argx->AsBlk()->Addr()->gtFlags & GTF_ALL_EFFECT); argx->SetIndirExceptionFlags(this); } - else - { - argx->gtFlags |= GTF_DONT_CSE; - } // Copy the valuetype to the temp GenTree* copyBlk = gtNewBlkOpNode(dest, argx, false /* not volatile */, true /* copyBlock */); From 651fa6d037656f474b7160a6ca954854345ebc76 Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Sat, 22 Jan 2022 00:08:44 +0300 Subject: [PATCH 127/308] Handle embedded assignments in copy propagation (#63447) * Clean things up a little Delete redundant conditions, use "LclVarDsc*", rename locals for clarity. * Delete a redundant condition For actual def nodes, GTF_VAR_CAST will never be set, it is only set in "optNarrowTree" for uses. For "def nodes" that are actually uses (parameters), the VNs will never match anyway. * Handle embedded assignments in copy propagation Previously, as the comments in copy propagation tell us, it did not handle "intervening", or not-top-level definitions of locals, instead opting to maintain a dedicated kill set of them. This is obviously a CQ problem, but also a TP one, as it meant there had to be a second pass over the statement's IR, where the definitions would be pushed on the stack. This change does away with that, instead pushing new definitions as they are encountered in execution order, and simultaneously propagating on uses. Notably, this means the code now needs to look at the real definition nodes, i. e. ASGs, not the LHS locals, as those are encountered first in canonical execution order, i. e. for a tree like: ``` ASG LCL_VAR V00 "def" ADD LCL_VAR V00 LCL_VAR V00 ``` Were we to use the "def" as the definition point, we would wrongly push it as the definition on the stack, even as the assignments itself hasn't happened yet at that point. There are nice diffs with this change, all resulting from unblocked propagations, and mostly coming from setup arguments under calls. * Simplify optIsSsaLocal --- src/coreclr/jit/compiler.h | 7 +- src/coreclr/jit/copyprop.cpp | 234 ++++++++++++++--------------------- 2 files changed, 93 insertions(+), 148 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 0f395e7dae899..cfee3b00519f5 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7384,14 +7384,11 @@ class Compiler typedef ArrayStack GenTreePtrStack; typedef JitHashTable, GenTreePtrStack*> LclNumToGenTreePtrStack; - // Kill set to track variables with intervening definitions. - VARSET_TP optCopyPropKillSet; - // Copy propagation functions. - void optCopyProp(BasicBlock* block, Statement* stmt, GenTree* tree, LclNumToGenTreePtrStack* curSsaName); + void optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned lclNum, LclNumToGenTreePtrStack* curSsaName); void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName); void optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName); - unsigned optIsSsaLocal(GenTree* tree); + unsigned optIsSsaLocal(GenTreeLclVarCommon* lclNode); int optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2); void optVnCopyProp(); INDEBUG(void optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName)); diff --git a/src/coreclr/jit/copyprop.cpp b/src/coreclr/jit/copyprop.cpp index 1c80436902f90..52c765a12dc41 100644 --- a/src/coreclr/jit/copyprop.cpp +++ b/src/coreclr/jit/copyprop.cpp @@ -32,17 +32,16 @@ void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrSt { for (GenTree* const tree : stmt->TreeList()) { - if (!tree->IsLocal()) - { - continue; - } - const unsigned lclNum = optIsSsaLocal(tree); - if (lclNum == BAD_VAR_NUM) - { - continue; - } - if (tree->gtFlags & GTF_VAR_DEF) + GenTreeLclVarCommon* lclDefNode = nullptr; + if (tree->OperIs(GT_ASG) && tree->DefinesLocal(this, &lclDefNode)) { + const unsigned lclNum = optIsSsaLocal(lclDefNode); + + if (lclNum == BAD_VAR_NUM) + { + continue; + } + GenTreePtrStack* stack = nullptr; curSsaName->Lookup(lclNum, &stack); stack->Pop(); @@ -123,97 +122,67 @@ int Compiler::optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDs // definitions share the same value number. If so, then we can make the replacement. // // Arguments: -// block - Block the tree belongs to // stmt - Statement the tree belongs to -// tree - The tree to perform copy propagation on +// tree - The local tree to perform copy propagation on +// lclNum - The local number of said tree // curSsaName - The map from lclNum to its recently live definitions as a stack -void Compiler::optCopyProp(BasicBlock* block, Statement* stmt, GenTree* tree, LclNumToGenTreePtrStack* curSsaName) +void Compiler::optCopyProp(Statement* stmt, + GenTreeLclVarCommon* tree, + unsigned lclNum, + LclNumToGenTreePtrStack* curSsaName) { - // TODO-Review: EH successor/predecessor iteration seems broken. - if (block->bbCatchTyp == BBCT_FINALLY || block->bbCatchTyp == BBCT_FAULT) - { - return; - } - - // If not local nothing to do. - if (!tree->IsLocal()) - { - return; - } - if (tree->OperGet() == GT_PHI_ARG || tree->OperGet() == GT_LCL_FLD) - { - return; - } - - // Propagate only on uses. - if (tree->gtFlags & GTF_VAR_DEF) - { - return; - } - const unsigned lclNum = optIsSsaLocal(tree); - - // Skip non-SSA variables. - if (lclNum == BAD_VAR_NUM) - { - return; - } - + assert((lclNum != BAD_VAR_NUM) && (optIsSsaLocal(tree) == lclNum) && ((tree->gtFlags & GTF_VAR_DEF) == 0)); assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN); for (LclNumToGenTreePtrStack::KeyIterator iter = curSsaName->Begin(); !iter.Equal(curSsaName->End()); ++iter) { unsigned newLclNum = iter.Get(); - GenTree* op = iter.GetValue()->Top(); - // Nothing to do if same. if (lclNum == newLclNum) { continue; } - // Skip variables with assignments embedded in the statement (i.e., with a comma). Because we - // are not currently updating their SSA names as live in the copy-prop pass of the stmt. - if (VarSetOps::IsMember(this, optCopyPropKillSet, lvaTable[newLclNum].lvVarIndex)) - { - continue; - } + LclVarDsc* varDsc = lvaGetDesc(lclNum); + LclVarDsc* newLclVarDsc = lvaGetDesc(newLclNum); + GenTree* newLclDefNode = iter.GetValue()->Top(); // Note that this "def" node can actually be a use (for + // parameters and other use-before-def locals). // Do not copy propagate if the old and new lclVar have different 'doNotEnregister' settings. // This is primarily to avoid copy propagating to IND(ADDR(LCL_VAR)) where the replacement lclVar // is not marked 'lvDoNotEnregister'. // However, in addition, it may not be profitable to propagate a 'doNotEnregister' lclVar to an // existing use of an enregisterable lclVar. - - if (lvaTable[lclNum].lvDoNotEnregister != lvaTable[newLclNum].lvDoNotEnregister) + if (varDsc->lvDoNotEnregister != newLclVarDsc->lvDoNotEnregister) { continue; } - if (op->gtFlags & GTF_VAR_CAST) + if ((gsShadowVarInfo != nullptr) && newLclVarDsc->lvIsParam && + (gsShadowVarInfo[newLclNum].shadowCopy == lclNum)) { continue; } - if (gsShadowVarInfo != nullptr && lvaTable[newLclNum].lvIsParam && - gsShadowVarInfo[newLclNum].shadowCopy == lclNum) - { - continue; - } - ValueNum opVN = GetUseAsgDefVNOrTreeVN(op); - if (opVN == ValueNumStore::NoVN) + + ValueNum newLclDefVN = GetUseAsgDefVNOrTreeVN(newLclDefNode); + if (newLclDefVN == ValueNumStore::NoVN) { continue; } - if (op->TypeGet() != tree->TypeGet()) + + if (newLclDefNode->TypeGet() != tree->TypeGet()) { continue; } - if (opVN != tree->gtVNPair.GetConservative()) + + if (newLclDefVN != tree->gtVNPair.GetConservative()) { continue; } - if (optCopyProp_LclVarScore(lvaGetDesc(lclNum), lvaGetDesc(newLclNum), true) <= 0) + + if (optCopyProp_LclVarScore(varDsc, newLclVarDsc, true) <= 0) { continue; } @@ -230,34 +199,25 @@ void Compiler::optCopyProp(BasicBlock* block, Statement* stmt, GenTree* tree, Lc // node x2 = phi(x0, x1) which can then be used to substitute 'c' with. But because of pruning // there would be no such phi node. To solve this we'll check if 'x' is live, before replacing // 'c' with 'x.' - if (!lvaTable[newLclNum].lvVerTypeInfo.IsThisPtr()) - { - if (lvaTable[newLclNum].IsAddressExposed()) - { - continue; - } - // We compute liveness only on tracked variables. So skip untracked locals. - if (!lvaTable[newLclNum].lvTracked) - { - continue; - } + // We compute liveness only on tracked variables. And all SSA locals are tracked. + assert(lvaGetDesc(newLclNum)->lvTracked); - // Because of this dependence on live variable analysis, CopyProp phase is immediately - // after Liveness, SSA and VN. - if (!VarSetOps::IsMember(this, compCurLife, lvaTable[newLclNum].lvVarIndex)) - { - continue; - } + // Because of this dependence on live variable analysis, CopyProp phase is immediately + // after Liveness, SSA and VN. + if ((newLclNum != info.compThisArg) && !VarSetOps::IsMember(this, compCurLife, newLclVarDsc->lvVarIndex)) + { + continue; } + unsigned newSsaNum = SsaConfig::RESERVED_SSA_NUM; - if (op->gtFlags & GTF_VAR_DEF) + if (newLclDefNode->gtFlags & GTF_VAR_DEF) { - newSsaNum = GetSsaNumForLocalVarDef(op); + newSsaNum = GetSsaNumForLocalVarDef(newLclDefNode); } else // parameters, this pointer etc. { - newSsaNum = op->AsLclVarCommon()->GetSsaNum(); + newSsaNum = newLclDefNode->AsLclVarCommon()->GetSsaNum(); } if (newSsaNum == SsaConfig::RESERVED_SSA_NUM) @@ -271,48 +231,42 @@ void Compiler::optCopyProp(BasicBlock* block, Statement* stmt, GenTree* tree, Lc JITDUMP("VN based copy assertion for "); printTreeID(tree); printf(" V%02d " FMT_VN " by ", lclNum, tree->GetVN(VNK_Conservative)); - printTreeID(op); - printf(" V%02d " FMT_VN ".\n", newLclNum, op->GetVN(VNK_Conservative)); - gtDispTree(tree, nullptr, nullptr, true); + printTreeID(newLclDefNode); + printf(" V%02d " FMT_VN ".\n", newLclNum, newLclDefNode->GetVN(VNK_Conservative)); + DISPNODE(tree); } #endif tree->AsLclVarCommon()->SetLclNum(newLclNum); tree->AsLclVarCommon()->SetSsaNum(newSsaNum); gtUpdateSideEffects(stmt, tree); + #ifdef DEBUG if (verbose) { printf("copy propagated to:\n"); - gtDispTree(tree, nullptr, nullptr, true); + DISPNODE(tree); } #endif break; } - return; } //------------------------------------------------------------------------------ // optIsSsaLocal : helper to check if the tree is a local that participates in SSA numbering. // // Arguments: -// tree - The tree to perform the check on; +// lclNode - The local tree to perform the check on; // // Returns: // - lclNum if the local is participating in SSA; // - fieldLclNum if the parent local can be replaced by its only field; // - BAD_VAR_NUM otherwise. // -unsigned Compiler::optIsSsaLocal(GenTree* tree) +unsigned Compiler::optIsSsaLocal(GenTreeLclVarCommon* lclNode) { - if (!tree->IsLocal()) - { - return BAD_VAR_NUM; - } - - GenTreeLclVarCommon* lclNode = tree->AsLclVarCommon(); - unsigned lclNum = lclNode->GetLclNum(); - LclVarDsc* varDsc = lvaGetDesc(lclNum); + unsigned lclNum = lclNode->GetLclNum(); + LclVarDsc* varDsc = lvaGetDesc(lclNum); if (!lvaInSsa(lclNum) && varDsc->CanBeReplacedWithItsField(this)) { @@ -355,68 +309,63 @@ void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curS VarSetOps::Assign(this, compCurLife, block->bbLiveIn); for (Statement* const stmt : block->Statements()) { - VarSetOps::ClearD(this, optCopyPropKillSet); - // Walk the tree to find if any local variable can be replaced with current live definitions. + // Simultaneously, push live definitions on the stack - that logic must be in sync with the + // SSA renaming process. for (GenTree* const tree : stmt->TreeList()) { treeLifeUpdater.UpdateLife(tree); - optCopyProp(block, stmt, tree, curSsaName); - - // TODO-Review: Merge this loop with the following loop to correctly update the - // live SSA num while also propagating copies. - // - // 1. This loop performs copy prop with currently live (on-top-of-stack) SSA num. - // 2. The subsequent loop maintains a stack for each lclNum with - // currently active SSA numbers when definitions are encountered. - // - // If there is an embedded definition using a "comma" in a stmt, then the currently - // live SSA number will get updated only in the next loop (2). However, this new - // definition is now supposed to be live (on tos). If we did not update the stacks - // using (2), copy prop (1) will use a SSA num defined outside the stmt ignoring the - // embedded update. Killing the variable is a simplification to produce 0 ASM diffs - // for an update release. - // - const unsigned lclNum = optIsSsaLocal(tree); - if ((lclNum != BAD_VAR_NUM) && (tree->gtFlags & GTF_VAR_DEF)) + GenTreeLclVarCommon* lclDefNode = nullptr; + if (tree->OperIs(GT_ASG) && tree->DefinesLocal(this, &lclDefNode)) { - VarSetOps::AddElemD(this, optCopyPropKillSet, lvaTable[lclNum].lvVarIndex); - } - } + const unsigned lclNum = optIsSsaLocal(lclDefNode); - // This logic must be in sync with SSA renaming process. - for (GenTree* const tree : stmt->TreeList()) - { - const unsigned lclNum = optIsSsaLocal(tree); - if (lclNum == BAD_VAR_NUM) - { - continue; - } + if (lclNum == BAD_VAR_NUM) + { + continue; + } - // As we encounter a definition add it to the stack as a live definition. - if (tree->gtFlags & GTF_VAR_DEF) - { GenTreePtrStack* stack; if (!curSsaName->Lookup(lclNum, &stack)) { stack = new (curSsaName->GetAllocator()) GenTreePtrStack(curSsaName->GetAllocator()); } - stack->Push(tree); + stack->Push(lclDefNode); curSsaName->Set(lclNum, stack, LclNumToGenTreePtrStack::Overwrite); } - // If we encounter first use of a param or this pointer add it as a live definition. - // Since they are always live, do it only once. - else if ((tree->gtOper == GT_LCL_VAR) && !(tree->gtFlags & GTF_VAR_USEASG) && - (lvaTable[lclNum].lvIsParam || lvaTable[lclNum].lvVerTypeInfo.IsThisPtr())) + // TODO-CQ: propagate on LCL_FLDs too. + else if (tree->OperIs(GT_LCL_VAR) && ((tree->gtFlags & GTF_VAR_DEF) == 0)) { - GenTreePtrStack* stack; - if (!curSsaName->Lookup(lclNum, &stack)) + const unsigned lclNum = optIsSsaLocal(tree->AsLclVarCommon()); + + if (lclNum == BAD_VAR_NUM) { - stack = new (curSsaName->GetAllocator()) GenTreePtrStack(curSsaName->GetAllocator()); - stack->Push(tree); - curSsaName->Set(lclNum, stack); + continue; + } + + // If we encounter first use of a param or this pointer add it as a live definition. + // Since they are always live, we'll do it only once. + if (lvaGetDesc(lclNum)->lvIsParam || (lclNum == info.compThisArg)) + { + GenTreePtrStack* stack; + if (!curSsaName->Lookup(lclNum, &stack)) + { + assert(tree->AsLclVarCommon()->GetSsaNum() == SsaConfig::FIRST_SSA_NUM); + + stack = new (curSsaName->GetAllocator()) GenTreePtrStack(curSsaName->GetAllocator()); + stack->Push(tree); + curSsaName->Set(lclNum, stack); + } } + + // TODO-Review: EH successor/predecessor iteration seems broken. + if ((block->bbCatchTyp == BBCT_FINALLY) || (block->bbCatchTyp == BBCT_FAULT)) + { + continue; + } + + optCopyProp(stmt, tree->AsLclVarCommon(), lclNum, curSsaName); } } } @@ -462,7 +411,6 @@ void Compiler::optVnCopyProp() } VarSetOps::AssignNoCopy(this, compCurLife, VarSetOps::MakeEmpty(this)); - VarSetOps::AssignNoCopy(this, optCopyPropKillSet, VarSetOps::MakeEmpty(this)); class CopyPropDomTreeVisitor : public DomTreeVisitor { From 968746b87ecc1161c8026a48844af1333426029d Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 21 Jan 2022 13:32:26 -0800 Subject: [PATCH 128/308] Update format script permissions so it can be called on Unix systems directly. (#64107) --- eng/formatting/format.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 eng/formatting/format.sh diff --git a/eng/formatting/format.sh b/eng/formatting/format.sh old mode 100644 new mode 100755 From 83f8df4e7882a885a81c334eaa5ad6ec072b5bed Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Fri, 21 Jan 2022 13:32:37 -0800 Subject: [PATCH 129/308] Revert "Enable System.Text.Json tests on netfx (#63803)" (#64108) This reverts commit 34794bc5f2bcdbaa9057bb07b8764e2bb6a411a2. --- docs/coding-guidelines/project-guidelines.md | 2 +- .../tests/Common/PropertyVisibilityTests.cs | 1 - .../ContextClasses.cs | 3 ++- .../JsonSerializerContextTests.cs | 1 - .../MetadataAndSerializationContextTests.cs | 2 -- .../MetadataContextTests.cs | 3 --- .../MixedModeContextTests.cs | 2 -- .../Serialization/PropertyVisibilityTests.cs | 4 ---- .../SerializationContextTests.cs | 4 ---- .../System.Text.Json.SourceGeneration.Tests.targets | 13 +------------ .../CompilationHelper.cs | 6 +----- .../JsonSourceGeneratorTests.cs | 2 -- ...em.Text.Json.SourceGeneration.Unit.Tests.targets | 6 +----- 13 files changed, 6 insertions(+), 43 deletions(-) diff --git a/docs/coding-guidelines/project-guidelines.md b/docs/coding-guidelines/project-guidelines.md index 2e3e47dec4724..5f27836900e25 100644 --- a/docs/coding-guidelines/project-guidelines.md +++ b/docs/coding-guidelines/project-guidelines.md @@ -52,7 +52,7 @@ Pure netstandard configuration: All supported targets with unique windows/unix build for netcoreapp: ``` - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetFrameworkMinimum) + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetFrameworkCurrent) ``` diff --git a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs index 302923a104c28..8c0f57b422a55 100644 --- a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs @@ -1227,7 +1227,6 @@ public async Task JsonIgnoreAttribute_UnsupportedCollection() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/63802", TargetFrameworkMonikers.NetFramework)] public async Task JsonIgnoreAttribute_UnsupportedBigInteger() { string json = @"{""MyBigInteger"":1}"; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs index 75ada92a87303..c01499f7fef3e 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/ContextClasses.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Reflection; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; @@ -10,7 +11,7 @@ namespace System.Text.Json.SourceGeneration.Tests public interface ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode { get; } - public bool IsIncludeFieldsEnabled { get; } + public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; public JsonTypeInfo Location { get; } public JsonTypeInfo NumberTypes { get; } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs index fd735e182d5fe..7bc91507d9ad5 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs @@ -21,7 +21,6 @@ public static void VariousNestingAndVisibilityLevelsAreSupported() } [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/63802", TargetFrameworkMonikers.NetFramework)] public static void Converters_AndTypeInfoCreator_NotRooted_WhenMetadataNotPresent() { RemoteExecutor.Invoke( diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs index a8eeee6f8768b..57abdf04808a0 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataAndSerializationContextTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; -using System.Reflection; using Xunit; namespace System.Text.Json.SourceGeneration.Tests @@ -45,7 +44,6 @@ namespace System.Text.Json.SourceGeneration.Tests internal partial class MetadataAndSerializationContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Default; - public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } public sealed class MetadataAndSerializationContextTests : RealWorldContextTests diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs index 89c5035700bea..d0c3023b41ae9 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MetadataContextTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; -using System.Reflection; using Xunit; namespace System.Text.Json.SourceGeneration.Tests @@ -44,7 +43,6 @@ namespace System.Text.Json.SourceGeneration.Tests internal partial class MetadataWithPerTypeAttributeContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Metadata; - public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } public sealed class MetadataWithPerTypeAttributeContextTests : RealWorldContextTests @@ -129,7 +127,6 @@ public override void EnsureFastPathGeneratedAsExpected() internal partial class MetadataContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Metadata; - public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } [JsonConverter(typeof(JsonStringEnumConverter))] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs index 51e9e23b80d7b..d547551569935 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/MixedModeContextTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; -using System.Reflection; using Xunit; namespace System.Text.Json.SourceGeneration.Tests @@ -45,7 +44,6 @@ namespace System.Text.Json.SourceGeneration.Tests internal partial class MixedModeContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Metadata | JsonSourceGenerationMode.Serialization; - public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } public sealed class MixedModeContextTests : RealWorldContextTests diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs index 1c80d9046a7c4..a698165e3f967 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs @@ -249,12 +249,10 @@ public override async Task HonorJsonPropertyName_PrivateSetter() [JsonSerializable(typeof(ClassWithNewSlotAttributedDecimalProperty))] [JsonSerializable(typeof(ClassWithNewSlotDecimalProperty))] [JsonSerializable(typeof(LargeStructWithValueAndReferenceTypes))] -#if !NETFRAMEWORK [JsonSerializable(typeof(ClassWithUnsupportedBigInteger))] [JsonSerializable(typeof(WrapperForClassWithUnsupportedBigInteger))] [JsonSerializable(typeof(ClassWithIgnoredUnsupportedBigInteger))] [JsonSerializable(typeof(WrapperForClassWithIgnoredUnsupportedBigInteger))] -#endif [JsonSerializable(typeof(ClassWithThingsToIgnore))] [JsonSerializable(typeof(ClassWithMixedPropertyAccessors_PropertyAttributes))] [JsonSerializable(typeof(ClassWithPropertyPolicyConflictWhichThrows))] @@ -424,12 +422,10 @@ public override async Task JsonIgnoreCondition_WhenWritingNull_OnValueType_Fail_ [JsonSerializable(typeof(ClassWithNewSlotAttributedDecimalProperty))] [JsonSerializable(typeof(ClassWithNewSlotDecimalProperty))] [JsonSerializable(typeof(LargeStructWithValueAndReferenceTypes))] -#if !NETFRAMEWORK [JsonSerializable(typeof(ClassWithUnsupportedBigInteger))] [JsonSerializable(typeof(WrapperForClassWithUnsupportedBigInteger))] [JsonSerializable(typeof(ClassWithIgnoredUnsupportedBigInteger))] [JsonSerializable(typeof(WrapperForClassWithIgnoredUnsupportedBigInteger))] -#endif [JsonSerializable(typeof(ClassWithThingsToIgnore))] [JsonSerializable(typeof(ClassWithMixedPropertyAccessors_PropertyAttributes))] [JsonSerializable(typeof(ClassWithPropertyPolicyConflictWhichThrows))] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs index f955070f74cb5..b51ba070be188 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationContextTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; -using System.Reflection; using Xunit; namespace System.Text.Json.SourceGeneration.Tests @@ -45,7 +44,6 @@ namespace System.Text.Json.SourceGeneration.Tests internal partial class SerializationContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Serialization; - public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } [JsonSerializable(typeof(Location), GenerationMode = JsonSourceGenerationMode.Serialization)] @@ -85,7 +83,6 @@ internal partial class SerializationContext : JsonSerializerContext, ITestContex internal partial class SerializationWithPerTypeAttributeContext : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Serialization; - public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } [JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, IncludeFields = true)] @@ -126,7 +123,6 @@ internal partial class SerializationWithPerTypeAttributeContext : JsonSerializer internal partial class SerializationContextWithCamelCase : JsonSerializerContext, ITestContext { public JsonSourceGenerationMode JsonSourceGenerationMode => JsonSourceGenerationMode.Serialization; - public bool IsIncludeFieldsEnabled => GetType().GetCustomAttribute()?.IncludeFields ?? false; } public class SerializationContextTests : RealWorldContextTests diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets index 16f8d544794b8..2f977168e8043 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.targets @@ -1,6 +1,6 @@ - $(NetCoreAppCurrent);$(NetFrameworkMinimum) + $(NetCoreAppCurrent);$(NetFrameworkCurrent) true true @@ -86,17 +86,6 @@ - - - - - - - - - - - diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs index 4381422afb7f4..485a79cd333cd 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.CodeDom.Compiler; using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; @@ -32,7 +31,6 @@ public static Compilation CreateCompilation( // Bypass System.Runtime error. Assembly systemRuntimeAssembly = Assembly.Load("System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); Assembly systemCollectionsAssembly = Assembly.Load("System.Collections, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); - // Needed on netfx string systemRuntimeAssemblyPath = systemRuntimeAssembly.Location; string systemCollectionsAssemblyPath = systemCollectionsAssembly.Location; @@ -40,11 +38,9 @@ public static Compilation CreateCompilation( MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location), MetadataReference.CreateFromFile(typeof(Type).Assembly.Location), - MetadataReference.CreateFromFile(typeof(KeyValuePair<,>).Assembly.Location), + MetadataReference.CreateFromFile(typeof(KeyValuePair).Assembly.Location), MetadataReference.CreateFromFile(typeof(ContractNamespaceAttribute).Assembly.Location), MetadataReference.CreateFromFile(typeof(JavaScriptEncoder).Assembly.Location), - MetadataReference.CreateFromFile(typeof(GeneratedCodeAttribute).Assembly.Location), - MetadataReference.CreateFromFile(typeof(ReadOnlySpan<>).Assembly.Location), MetadataReference.CreateFromFile(systemRuntimeAssemblyPath), MetadataReference.CreateFromFile(systemCollectionsAssemblyPath), }; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs index f1d5b1973fd6c..f8c0a34e57c80 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs @@ -450,7 +450,6 @@ public void UsePrivates() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/63802", TargetFrameworkMonikers.NetFramework)] public void Record() { // Compile the referenced assembly first. @@ -512,7 +511,6 @@ public record AppRecord(int Id) } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/63802", TargetFrameworkMonikers.NetFramework)] public void RecordInExternalAssembly() { // Compile the referenced assembly first. diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets index 08f362de05e7a..da4a8b8d65997 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets @@ -1,6 +1,6 @@ - $(NetCoreAppCurrent);$(NetFrameworkMinimum) + $(NetCoreAppCurrent);$(NetFrameworkCurrent) true @@ -17,10 +17,6 @@ - - - - From 35482cb277ee617375bfa764a19a8917bfa7e391 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Fri, 21 Jan 2022 22:39:07 +0100 Subject: [PATCH 130/308] Make ApiCompat.proj incrementally buildable (#64037) * Make ApiCompat.proj incrementally buildable In https://github.com/dotnet/runtime/pull/64000, I noticed that ApiCompat.proj never builds incrementally. Even though the RunApiCompat target has Inputs and Outputs, those aren't defined too late inside the target to have any effect. Moving them out and declare the generated response file as an output. Also simplifying some msbuild logic and renaming some properties as underscore prefixes in project files don't make sense if the property isn't reserved in any way. * Update ApiCompat.proj --- src/libraries/shims/ApiCompat.proj | 71 ++++++++++++++---------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/src/libraries/shims/ApiCompat.proj b/src/libraries/shims/ApiCompat.proj index 70170e5de70b7..3b2c6ceae57c0 100644 --- a/src/libraries/shims/ApiCompat.proj +++ b/src/libraries/shims/ApiCompat.proj @@ -1,7 +1,7 @@ + - @@ -14,95 +14,90 @@ - - + - $(IntermediateOutputPath)apicompat.rsp $(MSBuildThisFileDirectory)ApiCompatBaseline.netcoreapp.netfx461.txt $(MSBuildThisFileDirectory)ApiCompatBaseline.netcoreapp.netfx461.ignore.txt $(MSBuildThisFileDirectory)ApiCompatBaseline.netcoreapp.netstandard.txt $(MSBuildThisFileDirectory)ApiCompatBaseline.netcoreapp.netstandardOnly.txt + $(MSBuildThisFileDirectory)ApiCompatBaseline.PreviousNetCoreApp.txt + $(BaseIntermediateOutputPath)marker.txt + + + + - + Inputs="@(NetCoreAppCurrentRefFile);$(ApiCompatBaselineFile);$(ApiCompatBaselineIgnoreFile);$(ApiCompatNSBaselineFile);$(ApiCompatNSOnlyBaselineFile);$(PreviousNetCoreAppBaselineFile)" + Outputs="$(ApiCompatMarkerFile)"> - $(NetCoreAppCurrentRefPath.TrimEnd('\/')) - $(ApiCompatArgs) --exclude-attributes "$(ApiCompatExcludeAttributeList)" - $(ApiCompatArgs) --impl-dirs "$(ApiCompatImplementationDirs)" - --baseline "$(ApiCompatBaselineIgnoreFile)" + $(BaseIntermediateOutputPath)apicompat.rsp 0 + --impl-dirs "$(NetCoreAppCurrentRefPath.TrimEnd('\/'))" + $(ApiCompatArgs) --exclude-attributes "$(ApiCompatExcludeAttributeList)" - - + - - - - + - False - <_netStandardLibrary20RefPath>$([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)', 'netstandard.library', '$(NetStandardLibraryVersion)', 'build', 'netstandard2.0', 'ref')) - <_netStandard21OnlyRef>$(NETStandard21RefPath)netstandard.dll - <_netStandard21BaselineModifer>--baseline - <_netStandard21BaselineModifer Condition="$(UpdateNETStandardBaseline)">> + $([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)', 'netstandard.library', '$(NetStandardLibraryVersion)', 'build', 'netstandard2.0', 'ref')) + $(NETStandard21RefPath)netstandard.dll + --baseline + > - - - - + $([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)', 'microsoft.netcore.app.ref', '$(NetCoreAppLatestStablePackageBaselineVersion)', 'ref', '$(NetCoreAppLatestStable)')) - <_previousNetCoreAppBaselineFile>$(MSBuildThisFileDirectory)ApiCompatBaseline.PreviousNetCoreApp.txt - <_previousNetCoreAppBaselineParam>--baseline "$(_previousNetCoreAppBaselineFile)" - <_previousNetCoreAppBaselineParam Condition="'$(UpdatePreviousNetCoreAppBaseline)' == 'true'">> "$(_previousNetCoreAppBaselineFile)" + --baseline + > - - - - - - + + + From 7ed266eba93f82bdb8fc41e9b7e8ed9685f6128f Mon Sep 17 00:00:00 2001 From: Santiago Fernandez Madero Date: Fri, 21 Jan 2022 13:40:27 -0800 Subject: [PATCH 131/308] Remove enable drawing on unix switch (#64084) * Remove enable drawing on unix switch * Update some tests and not run tests that need Drawing on non Windows * PR Feedback, just turn off the switch --- .../TestUtilities/System/PlatformDetection.cs | 30 ++----------------- .../Drawing/LocalAppContextSwitches.Unix.cs | 8 ++--- .../tests/System.Drawing.Common.Tests.csproj | 2 +- .../tests/runtimeconfig.template.json | 5 ---- .../tests/runtimeconfig.template.json | 5 ---- .../tests/BinaryFormatterTestData.cs | 6 ++-- .../tests/runtimeconfig.template.json | 5 ---- 7 files changed, 8 insertions(+), 53 deletions(-) delete mode 100644 src/libraries/System.Drawing.Common/tests/runtimeconfig.template.json delete mode 100644 src/libraries/System.Resources.Extensions/tests/runtimeconfig.template.json delete mode 100644 src/libraries/System.Runtime.Serialization.Formatters/tests/runtimeconfig.template.json diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index f9b929480ab30..1cbd9c19f6915 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -87,34 +87,8 @@ private static bool GetLinqExpressionsBuiltWithIsInterpretingOnly() return !(bool)typeof(LambdaExpression).GetMethod("get_CanCompileToIL").Invoke(null, Array.Empty()); } - // 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 - public static bool IsDrawingSupported - { - get - { -#if NETCOREAPP - if (!IsWindows) - { - if (IsMobile) - { - return false; - } - else if (IsOSX) - { - return NativeLibrary.TryLoad("libgdiplus.dylib", out _); - } - else - { - return NativeLibrary.TryLoad("libgdiplus.so", out _) || NativeLibrary.TryLoad("libgdiplus.so.0", out _); - } - } -#endif - - return IsNotWindowsNanoServer && IsNotWindowsServerCore; - - } - } + // Drawing is not supported on non windows platforms in .NET 7.0+. + public static bool IsDrawingSupported => IsWindows && IsNotWindowsNanoServer && IsNotWindowsServerCore; public static bool IsAsyncFileIOSupported => !IsBrowser && !(IsWindows && IsMonoRuntime); // https://github.com/dotnet/runtime/issues/34582 diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/LocalAppContextSwitches.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/LocalAppContextSwitches.Unix.cs index 44fe88b2f6ea9..59d9b10bb98f7 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/LocalAppContextSwitches.Unix.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/LocalAppContextSwitches.Unix.cs @@ -7,14 +7,10 @@ namespace System { internal static partial class LocalAppContextSwitches { - private static int s_enableUnixSupport; public static bool EnableUnixSupport { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return GetCachedSwitchValue(@"System.Drawing.EnableUnixSupport", ref s_enableUnixSupport); - } + get => false; } } -} +} \ No newline at end of file diff --git a/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj b/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj index ac1fa3b57cfdc..58fe9b144c8fd 100644 --- a/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj +++ b/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj @@ -2,7 +2,7 @@ true true - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;net48 + $(NetCoreAppCurrent)-windows;net48 true diff --git a/src/libraries/System.Drawing.Common/tests/runtimeconfig.template.json b/src/libraries/System.Drawing.Common/tests/runtimeconfig.template.json deleted file mode 100644 index e3ad204dd9e51..0000000000000 --- a/src/libraries/System.Drawing.Common/tests/runtimeconfig.template.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "configProperties": { - "System.Drawing.EnableUnixSupport": true - } -} \ No newline at end of file diff --git a/src/libraries/System.Resources.Extensions/tests/runtimeconfig.template.json b/src/libraries/System.Resources.Extensions/tests/runtimeconfig.template.json deleted file mode 100644 index e3ad204dd9e51..0000000000000 --- a/src/libraries/System.Resources.Extensions/tests/runtimeconfig.template.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "configProperties": { - "System.Drawing.EnableUnixSupport": true - } -} \ No newline at end of file diff --git a/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs b/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs index ad4d0aef0dd1e..f239ccb1a53ab 100644 --- a/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs +++ b/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs @@ -1189,7 +1189,7 @@ public static IEnumerable SerializableObjects() yield return new object[] { ContentAlignment.BottomCenter, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAAB9TeXN0ZW0uRHJhd2luZy5Db250ZW50QWxpZ25tZW50AQAAAAd2YWx1ZV9fAAgCAAAAAAIAAAs=", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAAB9TeXN0ZW0uRHJhd2luZy5Db250ZW50QWxpZ25tZW50AQAAAAd2YWx1ZV9fAAgCAAAAAAIAAAs=", TargetFrameworkMoniker.netfx461) } }; yield return new object[] { LinearGradientMode.BackwardDiagonal, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAACtTeXN0ZW0uRHJhd2luZy5EcmF3aW5nMkQuTGluZWFyR3JhZGllbnRNb2RlAQAAAAd2YWx1ZV9fAAgCAAAAAwAAAAs=", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAACtTeXN0ZW0uRHJhd2luZy5EcmF3aW5nMkQuTGluZWFyR3JhZGllbnRNb2RlAQAAAAd2YWx1ZV9fAAgCAAAAAwAAAAs=", TargetFrameworkMoniker.netfx461) } }; yield return new object[] { FontStyle.Bold, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABhTeXN0ZW0uRHJhd2luZy5Gb250U3R5bGUBAAAAB3ZhbHVlX18ACAIAAAABAAAACw==", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABhTeXN0ZW0uRHJhd2luZy5Gb250U3R5bGUBAAAAB3ZhbHVlX18ACAIAAAABAAAACw==", TargetFrameworkMoniker.netfx461) } }; - // libgdiplus is not supported on some Windows variants. + // Drawing is not supported on all platforms if (PlatformDetection.IsDrawingSupported) { yield return new object[] { new Font("coreFxAwesomeFont", 8.5f, FontStyle.Strikeout, GraphicsUnit.Pixel), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABNTeXN0ZW0uRHJhd2luZy5Gb250BAAAAAROYW1lBFNpemUFU3R5bGUEVW5pdAEABAQLGFN5c3RlbS5EcmF3aW5nLkZvbnRTdHlsZQIAAAAbU3lzdGVtLkRyYXdpbmcuR3JhcGhpY3NVbml0AgAAAAIAAAAGAwAAABFjb3JlRnhBd2Vzb21lRm9udAAACEEF/P///xhTeXN0ZW0uRHJhd2luZy5Gb250U3R5bGUBAAAAB3ZhbHVlX18ACAIAAAAIAAAABfv///8bU3lzdGVtLkRyYXdpbmcuR3JhcGhpY3NVbml0AQAAAAd2YWx1ZV9fAAgCAAAAAgAAAAs=", TargetFrameworkMoniker.netcoreapp30), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABNTeXN0ZW0uRHJhd2luZy5Gb250BAAAAAROYW1lBFNpemUFU3R5bGUEVW5pdAEABAQLGFN5c3RlbS5EcmF3aW5nLkZvbnRTdHlsZQIAAAAbU3lzdGVtLkRyYXdpbmcuR3JhcGhpY3NVbml0AgAAAAIAAAAGAwAAABFjb3JlRnhBd2Vzb21lRm9udAAACEEF/P///xhTeXN0ZW0uRHJhd2luZy5Gb250U3R5bGUBAAAAB3ZhbHVlX18ACAIAAAAIAAAABfv///8bU3lzdGVtLkRyYXdpbmcuR3JhcGhpY3NVbml0AQAAAAd2YWx1ZV9fAAgCAAAAAgAAAAs=", TargetFrameworkMoniker.netfx461) } }; @@ -1346,8 +1346,8 @@ public static IEnumerable SerializableObjects() // System.Drawing.Common // Since this code paths use GDI+ we need to validate it is available - // libgdiplus versions before 6.0 do not roundtrip bitmaps reliably - if (PlatformDetection.IsDrawingSupported && Helpers.GetIsWindowsOrAtLeastLibgdiplus6()) + // Drawing is not supported on all platforms + if (PlatformDetection.IsDrawingSupported) { const string InlineJpegImage = "iVBORw0KGgoAAAANSUhEUgAAAG4AAABkCAIAAADoopLKAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAIABJREFUeJzcuQdUU+u67825Z++z99qrr2VvCCi9954EQkioCQRCEgiE3nvvvfeOgEhXQBCkiKJiAcSCUqSDNJGO9G7ug9nbs+65e5xx7rjfGHecb47/eMczZxKc+c3/U97IYpLxRD24go0UwE0Ldrn1vHhk/dbUVvWnXcuCO9d7p28NzmW0vLn+6E3ti/6WrtHXo4t3X3d/YjA+bO5UtDzaZDA2GV8Wt9d3GIe7DAZoj8HYP2LsHzAYX0BHoL2d3aODw6+n/6v+mx9f/reDxbWsK+jusHX+Y83QQu2IAmLcDfPcmujWbv/6tpqpjfrpjett/TVvx1/PbkxsMNYYjN6VrUUG49XUXErZrWUGY/XoaP3L4Q6DMbd+uPUVJWA8+jupI8bB/h85Hu4fHOztfzk8+v8nSufCp3Eto6F3u+lp1Wr+aVK2QWivWNfSRp+qx1VjK5VD84kN7XkPXz8Zmx9aOwJ2M1/1aGgqurBsaufw08EhXPzMYPR8mJvdONj5SvPw77Y72t/b+eO/vbOzs7W1tbu7e3h4+P+Mwf9Hxz9B2Tx79HiJUTO6UdrzqWpoJa9zNPVxT3nfJ6vMirLe2ar3n8Ju3g8vrS9qfdX8fuLN3EbfLqN7nfH4w1Jm/aPxPcbwxu7E7uHw6vrLkemptd0NBgO8uXXEpHm0f7h3+JUsaP/L0ebuzsbO9s7B/n97kP8U5RSDMcFgdG0w3m0xPjAYL5YZNX2fWiY3bVJvNk1svlhh5Lb2pDW1Vb4ZePRh7tXS1vNlRsvU1sOpzZyHr14t7j6dWBjcOnr/ea9rcm5q6wDsuXLIWNre2TjcO2AcHTKO9r76FLTNOFw/2IXrzNP/7sc/QVnXO/hsZvHF/Pqrxe2OT9vFT/uym149GF51zax+OnvYu82oejtV3TPxcnW3a+Pg5erOw0VGac/87YHlhMYXtf1zt7s/DO4zhvYY7WPT4xu7kOxz+4cz6+sre1t7xxyPmO1om3G0dri7vLv5+WCHeeW/+/HPEnzg/euFhf6NnfEDRv/6l+rO4dLW3q75L6FFDx6ObT4Y+ZzZ/Lrm/dT7A0bbymbJm97bH/aj7/fmdE7E3XtbN7Ja0//p/T6jbX6v9uXbt58WPx0y5g6PPm5tLuxtbjMOdhlHO8ccv6wd7S1sr898Xvq4try8t7UFHem/+fFPUI7ubfZvrHZ+nO1d3Rjc+HK7oz+h7P6N5rdZDW9bhteLnw0GFtaXvxnuO2TcHZ3yLa3MfjXnXPwosXUou328bZ3xcHb/7Raj/PV4XsP91qGxid39+aMvs3s7SwfbG4y9Tcb+1teBaflwZ2ptaXh+BjSxuvBpe+3/NYr/2+OfoJxd25heWZ/+vN0zvQCVLvZG5fXGpy9n1kqf9rWOrebee+kUfz3zbtu7ZcbbpS8NPTNFr0cbx5bCbjVW94zf7Ox5t7w1ecgY2zuqefYcUnt0cWV2a3fnGN/fx8yZ/Z25L4ftI+NvJudejS89H5hb/drxp9bXt5mNHkam7eORCT4FL0GXZ97rwcHB5ubm0dGxf6Hp/9Mvw3z1v/7lYXKAj8B68PWAAC7+/eXD4zs5nuOOvhx+OYImuXecUkffho39/f29vb8X+eObhN4Jb/465H05/ugXlq6hseG5xY+be0NLG68+zEVeryh/0jW+y4i7eb+pb/ZW+2B0aVPN6/FpGMsPGW1Tm+VdH+59WImqbK7vn6rs7O2cXelb3e5eWK1ufT6xvv16ZOLN6OTI3Er/9Dz4cecrNRC0+NHPO28ml+o7+t9NbXdNbM9sbu7+AyUUVJjq1w6OZre3v1E7/Hr856b4P0LJhPjtg3D8O0cmysMvDMC7DxPGwS7oeF7+97/PfADM+Pgx7O79fUZm3g+DwfKsZwC+/7vJuZHV3azb93MbnpY9fdc+ue6dUd7Y+7G5fy4H2kvXRO/nY45AtnFkGSpjWv2zR+OLtzv7Hg5OPh780NTVl11e/Xb84+N3A+0D491T87DObB2uMBgf948WGIw3U5/g73d//NzYOfBuev3t1Mb4ysrml7+jZHyd2dcPv8z8w4ZMF3z7qt++w/8lSvg7/wu+Px6wS9s7gKa4vbm1tbO9tbe7cwS1/t/fDJb89pjh3sCYcOWPD5vlxdBEa+/wo56R2UNGXGld18JucWtPdlOnRWh69auxlqFFyPGbbQPPJtbBpIWP3j39uPv2MyP/4evXc9t3u4budQ3VtnWVP3jqG53S8rK3tXsI3D2zy3g5+Wl0Y29yn9E5NvN64lNDZ8/b6aW30yv3Xg8Mr+xNbTH6Z2eXtnf/iBLy/SM0pH+wg/uGFb4/BJ8/f/7fOTKP/yJHZnb/8fH8xwP+ta2drbX11eWVlc+ra1ub24f7gJL5FOGz6+vra2tr8Bcg3t7eBtB7R4dQB+DewZtf9g9YChse3Wxpe9Q3CdvB2NLGSQYjs+llakOnrnPojYdv695Opt15WvKk9+WnPaiV7dNbLSOrHTPb1xrauxf34VOPesYaX/TUPXsVGnftfntfy+uhwaWd6QPGk/HZN4sbPRv7IyuH7+c3m171A0coIHeev3k//3l658uH1dXP+4d/RLm6dzC8sMC8b+Ydf/v+cBz94fivoPwPLzEtCT5iPp5/8n4o8WsbKwuLc7OfPs3PLX1e3dzf3fv6QeYtAUd4ovAXmE939x+75IOjw93tna3VNRY9O0/X2MzSx8cuc0kuejq145lTU9r5wdg/ETpP5Yvh0ILaxMqHkOxPxj8/HF6qbB+52zUZV9r47uP2s/6Z9v7p5z1jbb2j2Tfu3m8bKGtsv/9uvH1q5ebLvqax2WeLG2DAgYW95tfD/QtbfXNrTa+7x9a3mAX0W62EO9rbZ8ysfH49Ogo3CbnzLXH+WPW/9YpvNP8TG/6xFH57JMw//h+8yXz1cGN7Y3l1/uPs5IeJianJuaXFjb2dvT+8h+nKbybd/Lqvg2J6vIVb/bzycY6FYOOBt/VySciNLG5wTim5P7ZhFnOjum/RJ/Mm9OvbL0chCMy9DakNaX68Phm43T4ckVf9anz14duxR6+HWl70PXszkJpdfau2PT63urzlzcPhuRvt3bcHJ+unF99N7XYMLde19UFeQ+d52PN+cnsHOK79A+XhzhdoO9DB59Y3uycnYZP+rYlDMDc3B1+A8bVUwcEE+q17/Cco/0j8myXhD25sbEB6fntC8Cqz8B3AA15YmpmYHBkaHhkbnZn7tL67vfe11MB74CPz8/NwMzBUwN+B0xXGwSpjH3Ycqxvr4OWFD9MsKZX3KO5hWja+ZO/YlPoXsIl0yaquGfgcnF8DPQcaTlBedUzZPQiYp/VvphteTUTl1bwYWap/3lt9/0VFfeud+889/FKSsqoCE25UPOmGDeXt9x9uj85Uf5h9Pb79vH+prq1/7POXkdXt2vbO11MTYxufoSwu7+xtbO5tfd452v17rYQJ6Y+1fHZ29vXr1319fSsrK7tfD2aGfsP0f4SSaUlIUsDxzZjwNrgOz29/bXN1fnFq/MNg/8DQyPD0p9m1HdiwMVZXV8GPCwsLY2Njo6OjQBNuZnFxcfZgc3ZvY35rbXF1ZfHT3ML4FEtxfde1yrbYvPq4/NrU0vra5z2vPixMbB7ZR2YllDS+GFu5cfdJQ1sP+Ll/evHRi+6bz1+UP+2ML7/TNb9Z2vIy587TtFuPwq/VxGSWZVe2xJQ01XRNvV3aH1w97iArW8u961sPRz/cevFq/IgxsL2X3/L4wfAYxFBPe2cWV9bXvu7ON6A2jSxtPB2eHZie7PnQP/55eGT9fX5Drp4z3cTX53pja/fw+8W15QPG1/GDqcOvH2XsHjH2v3z9Ye94voMpFcrFHmNv4wge0tbn7eMXv8C79zfXFqYnhj6OD+6uLTK+wNPb3VtfWp2b2liaPdxaXZp5uzDe/rH3wcTLhuGO5pE3rydHPn6cha3u6iawm5wa7X4/MjA4s7w0d7Q7zdjrWv/ct7I8ND0z9K6798nj3pZGlsK613nV7bcedBc1tDe/HoH+AM0BFJR5Pe/ug86Juazb9/LvPhpeP7z3brTofntBa2d9z2hqdXPv4s79rqGSxqdJ+RXx2WWugfERmWX+meUwML38tNW3uAb0P63N96xtv1laq+8d7Fpeb/0wk9lw/97AKMQfthjD8ytQ2iHRjxPocH92a7+1fxLOx+c/ltSXOwTbkxwNjdxhdVcxtAWU86uL0DFhfv4Dyi9fUe7BQPjtN2Xw9P4+AyB+Xlz7vLi6u7kBfZhxtL2+OjszObg0PXq0uQynIAg2F2d2V+cYu2vz4y9nB1on3zQMP7898OTuQGf7SP/YxIfl+Y9Tq58+zo2OD73p7ut6NzI5ObGxBlvEyeM572B2cWW87/3bB/efVZWxxOTW+ieWFNS2BaUWgiVTy2oaOt/devg8Lje78lFLx+hYclVN1M2a+sGZwhcD8U0dfkW1sI/0yylpeNXf2PY6q6DI0cklKCDQ0NLZOTjBITz9+oM3bVPrfcub6wzG0u7m+42D0X3G04m5l3Of63uG02qbmwc+dH5afT+3OrYAnoE0O9g7OK5Ky/uMppfdr3qG27u6K+rvxuakxxfkVj1+9vDdeOOr8e7hgdmlheMf6L4wW/7RsQN3do+OtuBJgOn+PgccszxGt7a4vPxpfvHjx7Wluf3t5YOdpbXlybmP/TPD3etzHxhbS0cbC59nx+Y/9K/MjGwvTX8c7Jh4+2DoWdX7+6U9DyrfP2/pf9czNDgx0v9udmxwdnCwv+Plq6cdXT3v3898Aj/2f14bXlqZmPw41t3b/6S1q6mWpebJ+6SiuzVPu10j0hpf9iYVV3RNzz0fGg2I8Stvqrj/9kVydVXYzerCN4O5b8ciHnbFNrS3LezHlNc9fDfwbnD4TtWtIA/7krQ4Y3NbJ/8IC7+Y1JonzUNzb+Y3j39wYzAGto51/Fvc9vGaWf/o4cjHkT3G4Ow87FnBg1tfjhY3j4OZ1bXCmro7d1syrxVfK7z14Pmr1jf9N+48TC68m1sFCT40NTe7sbN9CJyOwe0zDrcZe2uH+ytfDtaPXQZXvhwxUcJIsDH/afXj9PLMh7W5DzurM3vrU5vLI6tz76f73yxPDGzNfVj/ODo/2jsz0LUw1rc2MzLT1zbe2dj/oOxd/fXueyW9Txrev+7o6+nte/1k6v2b2b6e/mcdHS1PO1+8ez00CZvgjuHxzp6Bl22vOptbXty503GngqVt8NONu0+bXg46hydUPm4PSs9q6e6pe9Fu5miUXZJZ2FCRcLM4uLg04d7jtGfdnhX3IquaH47N+aZdu9V07/GTRyW56f72xmXJoT6+gSHRyTZ+MZGFdcVP++52j47vHA4sLb+e32kZ+lTVOTC6x+ha3EuvfXx/4ONHBmMDdmZfd5arR4wx2LmvbXT29oXFx5WVVzo7exvSbONTix6/GGpo7YlKLzV3D+seGhmbnl7ZWD38cvzj59HBytH+IuNg8WDr09HOImMXOurW8U9RsAPdg6Q/2JifAPetz41uLo7urIKGN5fery28+zzRu/VxcG9+FNaV8e7lsXcb0/37C2Mfu9tH2xq6G268rcnuabzR/+RO38vWnjcd3S+aP3S3T797/f7Js1cP2jrbu1/2fHjePzU8vdDdPfSk8VFdftHNxKSiuAiWu+19uTX3q1o7vePTMipuW/j6BaSl2IUE4inakanRoSmxgSlJXkkpXunZkOYmoXEOEVEppWUkC4u4lKTEhOhAD3srfY1QZ/OEmNik1Cz7gKjAnIrk2qeZjc/uD3yoftnV1Ddzq70/7U7ro5HF5v7ZxMoHd99N9KyCew42jw7XvjCmt4/eTs13jUzW3m/28HKNiwtLTEwMCIhwdQ+7UXpvfv14fJte2+wZHhsan1xYXTw6Ho039nZnd7c/MI5mtlc/7H6ePtiY+7K1xNhZZ2xvMrZA25uzQ9tzI3tLI/vLw3vL77cX3q3NvlyZblscfLk09Ar0qQ8APZ3pfgZX1j90f+xqH35U11Wd8+pWcndt9vvHN3vbG7pe3O/rqB979XC840nfg8ddDzvetg+0vxpvbh+a+fR5sGf0ef2jhryiqqSUkoQoljvP38Jup6q1I/1WdWr5TdfoSLtQf0M3B6wOwScs1MLJ2cHL2yUgwMU/MDEn18zROSQuNDUnxcHZqrKqJDsjMTEqJNTHNdLPI8THKyo61t43LCy/KqOxI+tex93e8dKnLys6huq7pxMqWmLLm+Nu3odpH8ZVaE0jI72Pnj9tefXu2dBMS8/Yg5dvK2trQkN9szJD792rvnOnzt8/2tUjvKaxdXFna4dxACj7R8Y/Qf88tvLa9vb41uYg4wvk78DGwtDO8uT+59nDtcWj9ZWj9c+HMPJMvNv+1He4PHi0MrC3+G5tun1+tOXjYOPEq/vjnfeG2+rft9b0PKyCdexF03TXw4mO1r7Gyo6S5LbCqK6q5J77N7oe3+xovd3fUTfwvKHvQf3bhns9LZ19L0afPh+qbHzd3TX06vGrZ7ebH5dUPiosvl+cz5JQWBFXcDM4Pdc3KdUqwM/YwxVvRdcwo2IIJFe/UB2ysZm1naubh5eXx42CXE9Xp8AAu9BgFwc7WmP9zdSEqNiIkMiQQE9nZxtjI29vXxvPoPiyhrKO4Vtvxp7PrkOvv9U2/OrTYfqdNvPgDMvQLAhaBpfjyltKCrODw8PC0nNhKqh6/q72aWdtQ/21rMTy8rjUlKCw0ODo6NT0zKKiitutr559WBrpGfrQNzT6cWH26Nimq5ubw5sbfYwvY58/9q7P9m/Nj+wtTx6szB6uLB6uLIOWRjo3p98eLr0/Wu7bmXu1NPZoqq92tKty6k0LoBx6frf30W1ACYkMpzNvH40/fdR1p/TJ9djH14JelEd3NWS9vF/4pLmkv72m53H1q7rKzpo6QPm+c+zx44HiiuePGp89uH3/flHNw4LyhwWFdbkZLH5J2bqWDjgK3cY7wC0wWJ9moozDqeG1DA0NHb4edDrd3t4+PDw8ODjYysoqwDMgMjjY0pScEOsHykqLtTA2drF1MTU19fD0Do2C51Lz8FV/eXNHWPatsGtVhXc7iupfxObd8YrJz654RLEP9k8sCkkr94pLz6tpLLzTVN306FZ13b2mllftLyODQ+9Ulob4eyfGRD57+LCy9JaZoZmvm9/A2+E3Pa97B7snpgc/r01+OZqD+Z1xNHa01/95vH1hsPXT+4erY22HCz2MtSHG6sDBfPd8b9Xu1APGUgdj7sXBdMfOh7a5d/f6H5b3P7w1+qwGNNRaNdFx9/PAs43h9uW+1uGnee8a057djH1cGPPkRkpnSd6b0uKusrI3HeX9b+tePq28XZJRkpNWf7OipeZefdndpqKChhv5d6/nwnqv+EZzSSGLY0i0sr6RpIoG0dTC2tXdyNKCZm7q6uWmr69vaWlpbW1No9FsbGyCgoL8/f0tLCw8HD2iQkIcbekpiUFx0T7pyVH2lpZh/mEUqhFMRV7+wQmZ+aV1D5IKqtwiM3wSC8obO0vrOyIzbjpB0b1eS7L0gR1RWGqpd0xKXE5RUk5RccWd6LhkFxe38NAwGoVccC090MfDxpwOTo8OjYwKjvL3CPB09IlJjG66X7u4PHH8u8fOxMJs5/z0s9X5jvnBRx/77oNWxp4dLLxjrL6HdWPqxfSbsvXRhqNPTw8/tu1Pte9OtC/03B9qreh7UD785PbAo4q3jUUgCN633Hx9twA4dtYkPimLeVKU8Kw4vb0k93lh/vP86x2txX1v7r5pu1Nfcb2iILeuDKaZiuspubfSU0CVmWnVOZm1eTkgFn0rRwm0Op+0opoeydjaimJCo5kZu7o7aWpqgjGNjY0NDAxMTExcXFwcHR2pVCqdQvd1d7egG0RHeAb62cdGBtiam8eGxZIphnZOri6evoERcQDIPybV3jciIOFacc3jG1Ut/tHZxnZ+oYnXtal2XmFpvpGZCVk30vPL8oorHz3ryMrNO/a7v6+DvbWfp7O3m5ODtYWpoaE5zdTewt7G1NZIzwSqc0ZW/Os3jzc3PsDszziaYOwNMvbeT/c0Tr6rn+ltWh1/erDQdbQEHNvnBh6MddxYHrizO/Vwd/LJzodnW2PPwJUDj24OPq4EM4LAnr33y2DtaS59UZPbXhX3tDzmUXH0o6KEJyWZrUXXWvJzm7Kym2qyX7RWvnxS11xTWlde2lhRVZFflhaZnB8dUZQQW5GReic3Gzjezs5gQeH1BOURogoIApkKfsTraKNVEFicsoaGBkAEmmBPJk3gCBd1NXQhozVxSHcXU1BkqA+cBvsEU41Nndw83bz9/UMiopMy/MNiPIMi0/KK06+VZebddPeNJBnZ+IcmaujQnDxCrB19I6JTcvKKK27Xdff0NzXfS09PLS27ER0VGh8V4mJvbW9lHujt7efhY0o1pVNMvZ39TEz08Xi0gb5qUqzncG8TgzHJOBj4PPNo8l0d6FP/vc3pti/Lb4+WulbHW+EKoFzqr9meeLA59nBt6OFKf8uHjpquhoKuhkJwJaCEFbCOt9WCwJudVYlPS6Kb86Mac2Pv5ac238htKshvyM+/WZB8/07J44bK+lvFDbduPb7bUF9enZeUfS0itCQpHiBCdkOy11zLYpFBYwSlZSURigSSnjHdUJeohcOhNNVQgA+qJOQ4rACUTCYTCAQsFkslUulUKkpB3NmBFuTvALXSzsLC28WbZGhi6+Tm6Obl7R8Uk5AcGhYBKioujY1NTU/P8/EJodEso6KSyGS6mxtwsbakWyfFphTm3Wisb6isKCspLbhVUUQ3J9fdLvdxd6bq64L3C3Lyc9Nzg7yDHSycoyK8zUwIBA2ZAC/j7heVjC+jjMOBz9PN0721M311iyPNO5/aGGtvj5ZfLY89GO+qmnxVsjpUByjXhu8v9DROv6rtuV/0uCy56Xps++2cN/U3OqqvtVVlQ2rDQA5839ZkPi2Jr8sMuZUUfCstuiYv825xcVP5zdtFec3VFU1VFZU3rt8pKXtU19hUWVOQmpMVGgQooVZClawvyINkZ1FQURWTl5NSkNPU1qAZk63Mqc72dD8veyAIJdLJyQk6j7m5ORMlZL013RoyWlVZ1tfLOjkhsLz4mqu9vaeTp7qOAdXU2sTCxtnFLSoqKizIP9jP61pGSmxETE56doh/sJWpZXpSmq2FDcQWJuaOdNucxPTC7NybRUW52WnX8lKuXU9GY2VjI4KS46LCg/zdHR1D/YOvpV1LjEqyM3Osrcyvrcy9f/dGb+edtZnnjO1uxu5bxsaL2f460OJI0/bsU8bqq4PFDohHX98ElCuDtZvjzcv9jR/f1I4+r+iszWnMjwKUzyuzIKMfFCXW5UTA6eOy1NbytDcV6Q/zo2/F++eFe+fFhJZkplUVFdbdqrhXVf2orr7hVmVxVk7Ztet3yysrrhelRMQk+XpBjldlpUOtBKbZYcEsqpqaSliMqgbWgKxraUlzsjPxcbMK9XWCvIaGAyXM1tYWsOrq6mp+PSi6FHMaDYuW8/O2gXKZnR5nZmRkY2qjrKFLMKDpkQ3hAUSHh4SAqezMI/3dYoJDspOSA9w9TEgGKdExzlbWsSGhDuYWoY5eOdGJuUkpFUUFackx4ZE+6dkxNAs9CxNKZEhAZkpisK+vmRHd2MDYwdLRx8U/IdKzujxj4HXj/PjT2YHGD+9uzb6v+DxW92mw5mP/bVg/T97bnW/d/NgyO1A92HljpO36XE/l6lD9fE/dZOftoSflL+5k1+dGPCpN6byTBygb82NuJfvXZIbeL0w4ppkbXZcSXBjumRnskR4ReC058fq1nBvXC2pLbjfeqrt9ozw/Gap7dtWNkoK0jFBP73gv95zwkLKUROCYGRIY4+7CoqlL0CHpQmo7Otm4OVvZW1DpZC2qLkZZWVldXR3SHDoPiUTC4XAqKiqQ4AhpBEBFyos52Ru5Opn4eTnilJX1tfVVtPTwJCMdfTI0/bjIUJjbHekG3rbGEX6+qdFRLlaWeIxKuK+PrYlxTFCgo7mZC8XUy9TKz84+NyUpJMDdzMIgKjEwMMo9LjKYRtaDBA/19w/w8lNHq6soYsCVQZ4WhTmRb55WzY+0rk48/jx+b2uq6XDhGNx0XyVoYaRubap5daJpqrfifXv++8fZ0MQX39+ZfVsz8aJq+OlNcGXT9eiGvGjwIACtTA0siHQtT/RlGrMuwe9WhEdekEtGkHtaeFB6fGxaSmpKanp+Ul5ZTnFRRkF2XPqNtGu3C0vzU9ICXd3BlXlR4YASmk9qgG+4kz0LRkWNQia5OJl6eZg42+pYGKmZG2hYGRCodCM5pLIShqBPttXE09W1KXoUI209AkpdQ0ZRFq+JDvKyTY72A/pEsp4myQCJo2jpGFmamPo7WcX7OyWHeyZG+8dG+1tY03X0tIxNKLZWpp6OdjiEQnxIUKi7W6h7SKRPcKCbk4uVkas1zcfR1pFubaBGqihMjQ9zd7Emezkap8f5l+TGZycFh/vZ1xaFNFfEdDZnjXXeXOytXeqpnekoHXmY+/ZB5sCz69NvK1ZHGtfHm+f6at4/yWuvS/jQcv3jsxsLLws/vswdbE1/WZ/0uCLpQUnqzayIe+UZZWmhOaGu1anhDdmxd5LD7mXGpkc7+jnS7Iwo7jYukYFxaQk5udkFxcWloSGRcbFJSYlpiQmpyUnpKckZEeExMKkkuprfCPeszYiqy4wuifbN8LFjkZNHaWlpWFiQnR0o9lYEK5qmNVXHjmZAMCBIyMnJIbDqWkYIJQJKRYtAImnra2PwBEVlhC5elYnSy93OyJRGoptitE10Saa25pbBbnaJgS4pEV6AMi4mwNnN3siEbG1j5uxg7eFgi5AQ83N2tKcZ2dGs3a3tvR1s/FysogLcEkID/ZzcjHUM40LdgjytPB1o/m5GeGdzAAAgAElEQVTmCeEe11JCc1PDMhMCa4simm7GPL+bMfC0ePZN9fzbakA59ji/+2H26Ivihf5a4Lgy3DD55iZcAZQLHbcWO8vmO29Mv8gZeJzWfieu4UZERVpIaohDWUZIboxHqp9NZXJQQ3Z0bUrog2txhWk+4V6WTqaGbpYOwR5hUUGxsVGJKUmpEUFB8ZGRCVD+Q0JgbwKnXi4uUOKSPa1yQ1yLY3zzw9wT3S2CLUks3Hyi8ooKOkScsYmWGV3DgqZlY6zvYErTJGpIysvKo1TRWKKYlLKMIhqvT9QhE7A6uiiMEqD0cjKNCHB2dbIElBRzCxUtYx19urWpObgyxsc+NtA5Mtg9NNjdzdPJ1ILm4mrv5+0W4OGqJC3pZW9rrq9nqkezM6Z72VvGBLnlpUbmp8YHuXkY4cmO5gbutjQfJzNfZ3NQoLt1VIBLcqRvVV5ETUFk883Elw3Zw0+KJjvKJp8Xjbfm9bRkTb0u3xi7B80a0nn4ecHb5mMPAsrZ54UTrVmjT1IB5Yu6hDu5wQXRnomBVqUZgdfjPbNC7G+nBtVnRVQnBTRlRlTmhsQHwKaN6mRi4WHj5u3o5ePmFeDjG+BoE+buFOrm6O9g7WdvBacupkYmBI0AC3Kko2mipy0oxsUCxMLKISggKqGMQejooQ2pODpN28aU4mRhrmekg1JVRuM0IccFRRWkFVC6ZD24CCjROBVIcBs60dXWyMyEpGtA1CZTFFUNoAiYUAxdLYwCHemBrubQvtxdLSHByYZ6gDI0yDc2NAiPQYf7eDmb0p3NrV0szcGSSZEehdlRuSlRPo72JHVta5qek4Whuy0dVguqjom+Jqz2puTrCQE3kgJuZobeK4p9VZfe35I78vjayMOsN3eTJ9qLN4ebtkeb57oqBx/ldjel99zLGH+QP9CQ2lMX09ccCyhfNSTX5YfmR7oXpXo/qEy5WxRdnuJTfy3sblbIzRj3O8l+FTl+sd6mDhRdKxLFwcjKwdTWydLG1cHWVl/TxYgIcqQQXGl6vpZG7iYkK101J7KWF10/xM4kwsk80tkixs2a5aqAtJCkPAKD0NRVIRuq0+l6thZ0R2trAxOCigYaraYGxuQVkpBFInUpOlr6qhr6JA2Cpp4OzoyqZUkjkPU11fEakPUKGBJO08CIRHY2o/raGvk6mrg7mjo50HX1tdW1VCHBA/08Y0ICCaoqTJS+js7uNhZeDvSYEMesJH/wnZe9tam+gYuliZM5zc6EYknVMyURjHQ0yFpYfXWVGE/nOB+n9BC38hT/h8XRr+tS3jenDtxPbbsZOfggZ/ld9Vpf3ccXZUMt1/qbs2AdbMjqrol/czv8XUNkz/3EthrYmfimB9jdzPF/Vp/VUpl0OzugMS+sNiPgZqxrbYpvabJLuLOBBQFD19Sy1KPaUk3sYY9nZWGmjbEmqlvq4Ey1VCAAms6GuhYErAuN5Glm6GdNB7nTKXYGBBZROTVJlKoiTgWLV9Yl4SiGBGMaxYxmiidj5dEyMggFUSk5bgERlKoKWFJFS0HLgAx9hkaFBoU3N9SmkLS0dLVVCTrQdjQJhnSqkbuVcZCTaZCbha+7tYebFXBUUlGEtuPuYh/o6aYiJwMJbkrUdbYwAwPam+kEehrHhtpFBtgHuNn6OjmAN+ElK0NASbYzoTmYmlgbUU1Jeu4mdB8L80hXm/xIz6b88Jd3kvrupQzcT35eHNpblzLzrGih8yasow+uDTZlHqsh6/3d5N67sYCyszaiocA3J9wm3IGaEWlxtySspiCwONGpOsPrToZ3dbL7w+uht1KdIx2JFpooI6yqqaaOqY6epQHJ3phsroe3JOlARpOwyhR1jBlRm66jCbETjeRmSvWyNAZBYEvWYRGSUxeUUxaWlxVXFJNBiSOUZFAohBJSBUtQFJMTFBQXFhSTFJWSJVL0ze2NcToIJQ1NbSLeiEIAV5pSNA3JeIL+cdYjsGRmggPKYGezYHdLf09bLw8bNU0MCq1gaERycbTxd3dRlpEClGZ6RFOSLo2oZmWs4etGDvYx9nU19ne1jvL39nV0dLOysjM2tjY0PPaFhQWcgiwJBg5kapCtVW6YV3NB9Ju7qYMt6SOPUjvLIt/dThi5lz31uAAEQe+d5DcVsW+rEntrE983xAPKpxWBlRnOqQGmYfaUKB/9smyPknTXnAjzcqCZ5lGf5dNZkdBc4J/qbeSgi6Fh0IYYnIGKKgmrYqiJIREIBjo6BHV1VRRKXUUFTkFaWKyjMcWBRobVyYTqTDeElYVDGHlZQPIiD9dFHlY2ngvsXJfZr3CwXb6qoiUjJMXNL8YvIiWFUFGxdrL2CHAkGmFF5OSVsWgiAWtIVAVBguP1CJDg0igdNFaXQtR3pJP97Gj+zqberpZQK5kojWgG4MpQXy9NZVSEr7eruZkhQdNQB2tD1/BzNwA5Wem42RiH+3j4ODh52tq7WFjZGBmbG1AsKYZOZhZwxRinZ0OkBtpY50f4PCxK6LmXNfYkZ+JZ1tvKuJ7qxIG7aWPNORMtecONmW9uxTwrCHqcF9hZHg618m19ROtN/4p0p6xQqwRP8xg/g/IcT0CZFWZaGu9wO9W9Mcevqya143Z0QbiNB1ndRFWZhFLGyytoyEpqIiRV0DhVjLoSCiMvh0QrY4m6BmQDI10dkr+jnbulmTWFZKKjTdVUI6tjWa6Ii3OIibGJiLAKCV0UEDjPx3eOl/csD8/fTpz66cy5E5cus/LwwSZdEaumoW9ApJlgiVhVXVW8IZ5mSzO2MyYYEXB6ODV9NSQSicNiSLp4uqGBnSnVw840xN0u1t9FH6lhoU2la+hFuXoF2TkY4bChTnZZ4dCZKfBpV0uDKD+HhBA3aFNwxdPWECMvStbGQMWEkdPf2dnFwsaKQjfVM4Q9lbO1BQyhbuaE1ACTtsrIyefZU8/SG7Idm/NcHxd5Py8P6KgIbr8V9KzM/0mJ7/PqKJjSodtUZ3lVpHo2F0bdSvEJsyW60dXjPOmFce6VaT6NuYHPy2Ne3IptKwlrLY0uinL3MSEb4dQJSjgNZawSCiEnL4n6h5QVpTEoOTUVhBZOmaCBgUIJJdLZSN+WhDfD4yiqSBZOSUmgyS4qCigv8PMDxNNcXCevXuUQELrMy3+Bk/ssx1XQ+atcl7h54YoESkocKamAQ2gYaGmStVGayjIqcvJYRS1tgiGkpJ2Nl6ujl7Otq7Ux7HbsaHpGanhLXRIVqxZgZ+dpboJHSNuSCa50kpst1c5U19FCP9DDMtjL2tnKwJyqYUZRJ6gq6OKQBpqqdH0dKyrVimpMJ1IpmkSskhJNX9fBjOxnT86PdnhVm/jhafZgc9yDbNeWHLdHuR6t+V5PC3yeF/q1FweAmgp9WyvCmosDy5OdSxNcqtJ9b0Q7RzqQXOmaoc6U1EDLvHD7m4lu964FNl/zu5PiWpXinuROt9JSVZeSQYnKICTl5GSlpWXEpEQFpcWEZMSF5SRF5aXEFKTFFWUkQPZUoh1F18aAYEHUNNZSJWNR/+7KS4KC4EcmxxNXrrDzC4IfAeW5K5wgCIAj8L0ixMUucJVPUlBWRUEBixRVkBCQFhaRF0epYDW18FQq1czUxJJuZEUjWRrqWhkRKWpq5no6Bji0j62ZmwVFCylGJ6KNdVBaGBl1ZUmiBsLaRNfNjuZkRYHpCmRvakAjqhMwSLwKiqKlZapPAUsa4UmqSgiqLt7SUMfJWDvJh/7gRujb2oTOW6FN8baNcTYNsdYgiO8nOTxMdX6c7lqaZF0Ub1EQY349yup6pG1umE26v3mCO82Bpu5upu1jRQi2J6b4GBdG2hWEWKS465fHO8W70Ky1sVqy8hgpRYyCEloZhVZByEoAQXGErJSSgiwIKSetIC0BF8lqKtCFQBBAF9JFI1jAiSDI62+pfYabG3TqMjtTYElgyikMT0dWTAFxkZv9POdlDkFuMUVpSZScgLQor4SQkKw4VBJZhLKMrLykpKSMhKiyoiwRnGVAwCpImehpA50At+M9jJ6mrIMF3sFCS1aMR16CD4OQIOExFjSirRnZmk6yNNbzdbZ0MKPADKSjqoxHo/VwmmBJQGlqBG+gQqcioiVsiYgsP7O6NM86cFOQye1g+p0w87oIy7uRVkxBnBVCSfDCx3sSMoOMs4LMEjyocW7UVB8zWyMNG0N1K320DQnlb6md6GkY40T0oaHyQy1inQyd9LUpGCwehVVDYQAlSklemJdXXFBQTkICISODlJVVkJKSFhWFb6wsLY6WkcDISWEVZHCKsrCy/M7BAR4EJ4IfgSMABbJQNCGdIanPsF85ycoGgoCZ4+eucJxmu3yJm4tfUkJYVoZbVIRTWAhiZQ1dRRV1CVlFHgFhDg4Ozqsc4kJ8kAjSgvw0Pbw5lejvZutgYYDHyThZ67s7ULQ1lAlaKrBr0tdVoxpowyQAs6oGDgnNB+qss4WxMRGvjkCgpeW1UFigaUYzsDIxoOBV1WQFyEqiQab4NDdasgMp14l4w51c5mtcGWReFWxx059e7GVY4GaQ7Ksb5aIW5aKR7ENO9KREOOhGOZEAJZQUO2NtUz00XQcBdTPKjQrXvU0wIZY4L0OcpSZGXwmNlUHKiUoJ8PNycrGd+Om3s7+fvnzuEuflK9zsnLCyX7jMevaiGA+3BB+vtKCAnIiwgpgoiOWXy5d/ZWMDoEyaYEwmSjY+gW8JDhAhhuwGb55mY//94qUz7BxXBIW4RERZeXgvcfNAzCuuICyrLInAyCgqSYF/4RAVlhITFuET0tPW1dMmWJgY6eE15KQEDYg4kq4qDqusrYUj4NVBJH0YZslUih5cgcbi72oT4unsYmlKUldXRyjr4/CWZBNVJXkSHgso9VXkzDWQgSZ6oSZEN22Ur4F8oCEyjK4SZYEDhZtigoxQfmSFeE/tRG9CgpdOtAsh1FYr2For3J4Y5QijAsXenARF2URXydFIHepmjIdRmIO+B0XBiYgyU1MmIpXQEvIS/CJcnFfY2C+c+PHEqZ9Pnfv93KXTl1jPsMJ6/sT5s7+d5efkFuTmFeETEBMQEhcUhpUFCP5TgQ1BkN0XuYCUsICUjAQCJYvGAFmmSY/rpqAwkzVw//Ecx+krApzCMrB3EpOWB5pwKMjLivDKqqK0JYXlVRA4NEJFXFhEVVlJXFgIaoa4pIisvJScgrQqDk2m6lMMSZraahZUAmwTYcNjSSUBSh2MmqG2vjXVVBkhqaeFphKwFBwKKloQnRxkRHTAIj2Nke5Gis5kWUeStIO+lJOBjJuhggcNEeOmkRNmmBlMDbRSdaMi/M3Vgqy0PY1UaSRNE4oWRUdFV1WKoikPXSjEiRzuRPEzUXYnY6DtgCtVpREK4jLSUhIysuKifGIivKLCPCKCXEJ8V/i52Xg4WbmuXuIU4RcWFRARFxIDiQmKwikLs0RCcQR84E0w6U+XLv148eJpNg5ABsMQExwABXZcImLsfMLnr/Bc4uLnEpYAsXILXOTkuyIgepZL9ByX8FkO/pOXrp44e/HsxctXrnIJCgqK8SnJiuIunOAR5pFByeHkJBAYFPYK61WOq+zwgIREBHn4uIVFhRAoRXlFOQEhfhxCAqsooSIrjpIURUlIqMgoQILrYbXBy6ZUgqEOjoCUNkIjvMnEEBrFQ1sjNcw8xpca4KjtYanqboHxd9CK8iYnBdMjnXE3Ys3yIuleJkhrvLgPXdXfXMMGL4tRktJSVVBXlkZKcWNkuGnaxzR9rXX86WhXEpqORWnKyCFFpAElDENq6ipYpDpaXlVREiUlJCvCI85/RYiXXYCHjV9aTEpGXBoEgaSIBNBkAUOBrX67cOmXcxdgBXa/X2T99fxFEMQAlOlNcB/0dEAJ74dWDkWTORtdFRLhFZcEz17kFLrMI8rKLXKOg//3C1dPXuKCmFdMnktYBlZBKaSwjJKAJAJO4W3nwb+8Eld5xK9wi3FwicIKp9z8UryCMhxsQlfYhTivCHGDC3iFBAQEhIQEhIUFhSUEJWWE1TXk7a0IUYHGGVGm12KM8uOozwrM5ttiFtrjH2ablQSp30s1e1ni1XbdLchVMcIbfT3FqCCVFumjEuKO9HOUNdQ+H+om62sj50iVM9NSoKkijLFK5poq1mBSFIqsqkrG4bSUUQgJ8BqfpJigvIw4WoxVDy1sY4B2MdFwMMTaUTAQ+FgTMbKKCiISiqKSOAWUBhKtJCnLwkxY4AiCgDn6ADtACWQBK1PQyuE64AN7QukExACa6VmIj7s8twgHv8QVAUk2XjEgBWLnE+cRlWNe5BSSBkHA5HiGjfciG/95Vt6zF7nPXOACQXDuEg9cOX+W69IFHg42fh5uYWEhcZgH5ORkFBXlObiOzYvDoews9EK96NE+lDAXzQBbpaxIal2hZ3Wee6Q73s0EEeKID3XUdSArWhIVoUcHOZDCXKjQXvxtiRFuRk5GqiEuCr42Ck6GilYEZQstrI2OhjOZ4GGsoyImpiQsLM/PL8XPK8nPK8LPLcjHycfNgRS5pIXgN9KSMyEoGuAkCUpCRBWYhKRkBUUF2Tn5WDnEufllBEQkeARYANmPp89+f/I07G2AF7gPeMHKRAaMvhVNOIXrzHbEfABML/989jwIzHiJSxjwgSAAXheuCgJfIAsCgnARnAvXz7LzAUpwIjunyOUrQqwcgpfYBWBluyoMV7g5xfl4JIUEpMXF5GSkFRQVFZWUkCoqyjx8UiIiMnIy8urKSJI6wlBdRl+JR1P6PEaFi0JWIOnJIxQ4FWS5tDUUcCoygryXOH8+efWnE5KsV6Uuc/L+flaBk58gi1TmF9VBn1STO4EQOCnBfkL00mkJtnNyXBeQApcU+fnF2Ni4Tp/munBOmPMKoOTlYmdnPacowoaT5yeqSulhpTWRwhgZHhBckeIT4r5w+fKJM1fPXuS9xM51npUFWADKH06dARzgL+DFJAjIgCZABL5MlPAqxEzQcAoo4THAA4DPwpP4+QzbiYucgIkJCxL8l7PsP52+zITIdOLpyzwgCOANkNcADsRMcO7je5MVgFlfFCkmoigqLCcsJCUkKAYJzs/Py8fHIyCoLMCvyMUhwnP5qjQvFwEhYaImb6ouY0qScrXCOVvgDPGSVG0ZO5o6TI4kNVkNSWmsqDhREaktIyfPya0uIUVVUYXV3kTaVE+CqCKsKsmPEORSFLiKErmClmBXFhGR4+ERYWMTYL8MKIX5uAR4r/JwsimI8cBeVltFTgd2dGhZdZSUhpI0nCLEpISvcPNcZBPi4BK5ygP2ZGHOj0zTgd2Ym0VgB76DvAbKIGYNhRXibykPp4ASHgDzSfx4ihXYAU0gBYJy+f2Ji3/+6TRcgZiJlSmIfz3H8cMv50E//Xbx15OXT527euEyH7gSmPJwSXBdFb3CLnCZlev8OdbTp0+fOPHbb7/9cv682BV2KS4OUWFOIS0k0sfSJC3AOSvYua3Us/tOWOfNgIpo0ywPfK63wY0A4zwfapgLOdhRP97XNMKNak9RcjXB+lrjzXVkAz2IHnZ4a0MNQ21VfZwySQ1F1UYYExU1ZGU15eRUpaRkhQQEr7BzsV+C7BYV4pUTFUBKiarIS6kqysCqLCuhJCMOKxRKSG3Ia6iSWHkkSkKGBZoGNBMYa6CBQAArAGXOQOA7MB0gA8pgUoDORAyn8CqTO6wQA33gBQJw4DtI9lOs3AAXUDL1bz+fAX07Bf3pr7//+bsTf/n+1Pc/n/vlBCuTJqQ5tB0ONkH2y3zsbDzsbJzs7OxsbKygEyd5eXnkZCXRsKUzJmgFOZhFOpt607XL/NXuROpXBOkkW8gG6fKHG0gkmaLSrTCOxtIONKkAR1UfW2UTAq8ZUcCaLIpHndPE8Ksi+BESfLJCfHLC/MoywhpoEV0NUR0kUk9ZWRuBUIDJh/Ui67lTV9kvCgtwC/HwMCXABUMM9ARWtvPnWc+ehccOtyvGxQccdVXV8WgsC/RlZkeGlVkHIZHBbrACx+9+Pwm+g1eZlJltB94DnwL6IOZW/Zj7JS7wGqQ5rBAD1r/9fuF/fH/iX/72+59+PPWXX87CKeivv54DjnAdzMjU76fZT569Am0HGhGUTmYH57oqzAujnICoiIiIuLiohITYuQt8YmIwMqkoy8kQ0HJW+hi6hhRW9BxR9jRJ4QJR5rym6EltsfMURW4TtJCxkrAtWc7GQNbLEutKV6aq8dPxonCqq3QFg+BHyfDLi/HLCgtBp1ZDSZPwCsZkBAWLJSopYaWlpQX4+NkvX718gZPjEiQ4+0W2y+dZL529eOH0+fOnzp09cebkLyd++/FX6Dmc5y5BuYSeA1syZSk5FmaSgsB9YEPIXMjWP//8K8t337P865+P9ad/g1IIVRJehbfBq4CYOTkx6yzg/rdffgOCkNFgPaD2w8lLEP/rDydZ/vQjXAGCzNxn4oZXv/vtPHRtcCJABJRMmqfPc8JF6OAXznGxwlafjefqFR5ubm4olFAuz5y/IiQkJSkuIcbPiZHltyYpO1IQVAyXCVmVoovSUVPQUUMYETXNKHpkbU0cQtGerG5FxDgbaVvrqeIVhAxUpMzwShBoq0mpoaWV5WCulEbLy2pi5A10ESaGCDMCAVAihITEebjEeblFBXigVnJdYT1/6sLZE+fO/H4WAtZzl9kvcrBdgG50WZJXEDiynTwLqwDb1eNa+T9+//5PJ3/8y5lfvoc90qVTP7GeZur7U7/8eOa3Xy+cOsF69jT7hTMcF0EQMDs+4PvbiVPMSgrBMfp//YHlu9/++tv57347+6fvf/0ff/n+z9/98N2Pv5y8ePmXM+d/O3fxNCs7rH/5+bfvfj1x4gLrr1ABLnD87fTFn89cPHPx8kU2dlbY2l+6ICR8WViEQ1SUU0yMT1xMEHafosIiIkLC4jwyMgIyikLiGFERQ7SsF0UthKbmq69ogeKzUxVxx8v6GygFUVUCKWgfPYQHQc7bWN3TCOdGwTjqoWwJChYa0qY4CRNVMTRSHIMUxaJENJRFdTFiVA0pE7wM1FB9PFJdRUJBik9U8CrktYgAP2xgBPmFLvAI/XKejVNI/MxldlaOK5KS4hfOn+ZgvwQlVUbweHJiCmKWv53//Y8Qf7h4Eq58d+63v/7+43cnfvrh9K8/nzsBQH+7ePr3S2dA4EQw5l9+/R30199OwPov3//I8m9/BY5/+fXcz8cthe37E+f/+vPJ73459dPvp388df5vv5/56fSFU6xXTlxk/+HkuV/OXrpwlfcsrzhskM5zi7ALiPGKSgiJSwkJi/ILCkhICMDuQUZaXE5WWv5454mQl0HKy4BhdNRV9fXU9WnaRHe6Uby7baqXZawjOdxKL8aekuxGz/SxAqW4m8Y6UCOs9SPsDcLtSMFWun6mWh6GWCd9JTsdRWttOQ2MrAZGWktVioiVJmvI0PHyMIHakRBG+mgddTllBRFpcT5JUSGwv5SErIS4rLCCyhVBKSmkCgefIDe/AAKB4LzKwcfLiZQQUxQTkRcRYjI9RvnjxXM/XToPguBv507/5fSJf/39l3/59ad/++Xnv/z6y19/+/VvJ37/4dTJn86c/vksDEx/RwkQmTr241//dlwH/vLLn346/cMpVqD54+nL35+8BPFPZ6BicP56/sppNl52fgnQRS6osFIicmheeTV+eXUxlJaCmi5G2wCjqYtUwckoIBUUEIoKSkiEihK4RBmvitbDYchqqhQ9ipepZZCTc6ifd1hyVGxJZtqtrISCuOC86KCCuNDSlOjytNiS5Kj8mOD0YK9EX5dUH4tkL7N4N+NIB3KQpY4XTc2ZpGyvi9DXUtbXQhloI43wSHNdlK0B2pmKcaepWlJxZDwKh5JESIvKS0vJyyEVFbHyimpITX0JBA6tqc8jLMkvLIbBYKGWCgsJ4BTlMXIyytKSCHFRJlCWv507C/r+/DkQBH85ferPJ4Hmbz+cAi6nvz95CtYfTwPEc7+eh/p4kbmt/LbLhBUq6Z9++uXffj7146mLJ1m5wWisAtKXhRXYxZU4JJR5JdHc4kqCslgZFV2QOFJLFkPEEk3ltUyROpY4ij2R7kK2cNMzslbVMlBAqSFQmiCUso4yWl8Va6SubqalZY3H22tQ/U3sYlx90oLD0lOSrhXlXS+5ln0tKSYnLjo/Kb4oPQXgFqYlX4uPSQkLjgvwzQq0zQywAaBAM8xW38dEA1BCptNJmmYkdXN9nLUBzoGCc6Op+9I1A8y17A01AK4mUgolIwnZgESqodC6KAxZUc1ACqWpomnAKSDFwy+Gw2qKCIkKC4oQMGjYYgJQoAn2lBMWZPnh/KWfLl7+9TLHCQ7OU1e5T3PygCA4w8bJTMnfL8DszQ7xWRjpr/Aw/3+CuSXnFhUHQQCnrJz8HPxiAlJIaQxBiWiKNXLEmXqqmXkpaprKqRkjtMywJHuMni0EyjpWeGN3VUMvDRMffetgmlMY3TFE39QVrWkoqaCpiMYronUU0UQE2kAZS8NqWGngHbR1neU1nAkmIVZuCe5+iWERKanJGZmJ8YnhoSlRkZnxcXmpKYVZmaDclOT02JikiPD8cGfQtRCHdD+rOFcaGNOdqupARNoa6toaEhyo2k6GWh40LT86PsicEGpJcCRjjTUU1RXEERLictIIBaQ2StUIpW4ujSZKIQk4vAmXgAy/kDQBbyAjqSAmIqmvjtPFYjSVkOBNSHYwJsspKFvcApcERK+ISfNIK/DLIQUVlIQUla8IiLPxilziEjx/he/CVdgUCrLziV4VlGDOTDAbCcnISaGUpZXQYgoIfklpTj4hSAFReRVFLaqmqZuec4S+e7yeRyKa6Igi2MGqTvVQJbkoalnDqaaRlyotUMMsVM82ytg51tgpmmjiiVQ3FpbTRuJ0FFXx8miCvLIuAkNGq5ngtK00dR0wep7GttGeAVkh4RkJcZl5mdmFWUsZJuMAACAASURBVBl5KXFZMZHgytKs9Mr8a1XXc2/lZhdnpF5PTiiO9QQVxXhcj3ABmtFOVH8z7eOiSdN3MtJ1NiS4GeG9adoBJvhQM0K4BcFZX8UEJ6cuK6ogJi4jpSSP0kPiLJW0nWRVyAhVCpHqICKlKiWDoRlaKSNxkmLyJA21/4jyAp8oq6DEVXE5PlmUCFJVXFlNCqMJ4pdQ5BGVY/48AZs/Dn4JbhFZPnEF5iQP7CQQKHkMFiSuiBSQkmHn5GGHSVZMXhxDRFEc1ayDsXZRaJtIpK6LvLYDrKoUbzTJQ07LHqHjrE7zR1ICVIyCtCwiyPbxhg4xunQ/ZW0rCRQZrU1AaWgpYLXkVLTkMTooNTJG20RNx0LX0MfeNT40PCc+NisjMaP0WnZ1QfbtvNTc6JAbCZE3MxKrc9Nr8jIqs1NKU+PgSkGk640ot8Jod0CZ4W8d42wYYI4HlM5G+s6Guq6GBA+KtrehVoCRVoiJdpiptps+2gwnrykrpiAqKSuNUUQbAkcVPR8FyAy8hbGljyxCRwFyiu6kjFQX4pfSU8NCjqsjFVVkpaFcHif4edgj80twiMjySCEF5NDCiqqiSBxIWFqZXxzBKSjDzisBuiogzSuqICCBhIzmEZMQlJZl/hIMrgR7AlweAWEeQVE+CUUJVT0lqhPWOkTZOkLeIgKh4yqv7YQiuuMM/VUpvkhdNzTJC28WJkv0UTTwUzUOIVrHUO1jiWbBGKKTPNYUo4dX1tFW1NCQxarLYbUQGnpovCGWaILTtKab+Xp6RAR4hUT6B2RFhxUnRZYkhmSFeOZF+hXFh5SnRIIguBbukxHkDoUyO8guJ9geiib0H+jmzM7jbKjnQtFxIWu7k7W8KBr+hppBNM0wE00vA4ylmjxeThIpLi0vo4ZSpavoemIpwYBSXdfWzCZIHkVUUMSb0OzlpFQ4WAXAktpoJTWEAlpG6u8ozwgpXBBDscuocilq8CnhQbwobR6kliACxyunwiGuyCose1FQ+rKI3FVJJLeMMq+IFLeQBL8YVAxlFFZLCactjVCB01NC/GdFxNikkSIYkjLJlWAWpW+Vqm+VYWAeiFC3UCe5UCyDlbSsJZUMMTr22lQPLX0zNZK1qpG7pnWYjkO0lrkfUpMmJodFyMghZeVRcgoQyEtKK0jJQKyCQMFYRMCibPRVg03V0pyJRUFmJeF2hWF2yU5aeX6UylibhnS3+jTXqjjb4lD69QDDHE/KdT/jwiDz68HW6d6m0HlcKFhLbQUTbYSDoYabCcHJQM1FD+dnpBNqSgqmER0MVCg4GbSUoKyosJycMlqNoq7nqEHxIOnZGujb6eAtNNSM8VpmRB0rLIYqLqqKkBNVR8oaqKAMFBW0xMWUhflZLomj2KVVuBTUBJTxwhhdUayeiCoRxCeP5pRCXBaROc8vDmIVlr4qqcgjq8QrJMYtIMInLC4ph0Bh1JRU1aXkkfwiEud5jwsup7iChJIORtdS19jHwCzEwCwMT7KVVMCj1Wl6hk5Q+0RlNJCqFFUtOhpLUFIjoXTMsTQP4KhGdVBQ0RESO4YIApqK0rJ/RIlQlAeUtiRsqLlGhqt+YaBpcZgtoExx1gaUFTHWwBF0O94OUOb7U5koi4ItCkJsMnyOXelKxVnhFc11lV1M8J5mRBeKhqu+GqAMoesHGek6UVQBpYqUoIKEmLISVhNvrKlnq0Z00CGY6eqYa2uZ4LAULU1jiFUxBuL/s02zDpL6zP/83D9Xd1f3+/32NrubhAAD49ru7u7u7iPdPdLT466Mu/swDDJYgAAhBBKSJSEJhIQQwX1wDRHoe1iutlJ7S72q6+nmW0PxqvdHnppGsiUCul7Cc8nFDh5XTSTw0PC4tXDcehQxBU/LpLChDD6CLUJyxIA0LAkMojVZcDCUAPEQZAqakEmgpmVBUzLArQqGwhGpTA6NxUXjSRkQeEIKNCkNngnF4ck8vlin0jl1Jq/W6BEKtQgEhU4Xq9V2BkOCRtNpNBGLJWNRmQyGgCnWi/QBtaNQbvSyWCIMHM2i0BgkymuPAHAAKplk8DRNwWfk6PjNfjnQNF1pn6n1AZW9YdlYmX6pxbu7NwyCub0zb77eAT75o8rBMhfY2AtNAr+C5tNyCx2KqBuEVBRS8aIGaaVZUaaTgMVIz8WzMNkMHEbCl2o0DpnSxRZYxHyDVGgScnVcpgqclVIbn63BIJhqOc+mlga0So9IqCEROUho3JvJaW+nZqzJhCTAkCkobAaOmE2kQEjUdDQ6CQZbnZb2ZmLiW0lJ8ZmZqUhkNh6fmpaRnJKWnpGFRGGoNAYAjcGBt6nrs9MTs2GZCDKOIuLxNQq5Xq3Qa+RingiRDaeTaDqllsfkkrBEDp3NZXAENLD48kQyvdaeZ88psThy5CIZE4/jM9lAHJCIR6KJaCwoc6ASyOVx2SohK88g7AhqgaOpCttEpQuo7C9UAHEbG127ekL7Bot3dgeBypGoFqicKLMAldN1gaFyd3O+odgiylExvBpOgV0OUpmv5efKWAUqfkQjLJBx/Dqemo1horNYeLRKKDFqzDKJkU6TiDiqf3wpUcmlS8FBLTWDMw5BE3IpWhHHKRPZOGw5FkPLTo97c138W+vXvZOUGJ+WmgzJzkAiIODiRsBnYaEp8PTVqfF/W/82YE3aulREBgQPB0+Bm1MGuPMj4aDoaFQyBo0Eb1PiU9PWp0PToMCCkM1Wy8Q65SuEXF52egYejVFIpGw6g4wncBhMAFAp5AhkKrPJU+AJVbh8YbVMxSWTJDwBCCYBhcHAEEDl674JXiVioVrEDprE/RHLfK0b2BwtswOVg8Wq0VId0AckvjcUAdkE56GIerhY/1oleGa4wgMmeNQuzdeyQYEHLZICqyygZHuF1FwJMyRj5wpoTiVLxcKCVHIJKCWXa5Aq5Vwpm8iSc1RKnkbGVoroUnAwSM3gTEHSaSSklEWxCLlWNkuJx7Hg2XGJyeuSUtanpCWCYEHhYMlBkih4sOegybBsdFpCxpq31//lrXVvrE15Ow2WCMVmZKYmpScnZKUlY5EwBoXIpJJwKHh2ekpi/Lrk9QlZqZkENF7A5qtlGr3KAGBzeIlJKZlZEAaTTSCSQYTpDBY4g5wymWDNtWpdxba8KqM7LBKpQGaVYimHxsAhUCgIDAh93TpBmSsVMo2YE7ZIRytcS00BoGmoxPJKU4kGqJyttYHS3j9cAmp8ocEJ/P5R5Uilty1sLnPKQ3quU8HIN4vBz/ErWB4B5bXKPCHdpmBreEQRBS0iY5QsupbLVbF5UhpTL9YapXqtUK3kysHZqjSreAoGhkYno+QcGkilVywyMxkyMj4uKysJkJ2dDIenY7FQKhXL4VAEAgaZhQK7Zkr2mncS/vz2uj+tTf5rGjQeiknJTkvKSk2EZqQQ0HA2jcShk4ng9p+Rsmbd2/HrV6emp2GwJB5PpVI69dpcvTaPI1WtS4ckZsHxDC4YKgCGUMYSK/BkDpEpYyjdUneFNq9B4Sym8zVg7GjloJSYIJKILMg/VYLho9WotBIuSBPofdva8sdLzQPFpleaQC1HtdPVluWO3AMjUVDjQCWo+tcq52o9sw25o1U+cH0sdynA5HGrWCGrtMiuyNPwcqTM1wVeKOc6NDyrnKMX0tQskpJB1LJoJh7XLha5tDa3zm5TmowSLXgFZ71IzcEzOAw8KHDQK4NqlVsoAM/HQTITANCsRCQsFY/JplPQfA5ZImSweFgCJTsTujY+8c/vxP/nuqQ30rNXw1CJ8IwkaFoCIjOZjIHx6EQ+aGNYsLKn/G39G28nrkrITEPgqWCTkKvztYZSraFSbHQlgVUfQcRzZSiGEMuW8LU2od6Bp0uIPD1dmy/xN2jC7TJPJUVoykLRdQoVUImGwuGZ2UAl+PFAJWgaep1GJ+WBJQbo294eAir7Cg3gDCIJVE5VmYHKg6OloMaByr4C+VCR7p8qx6r9QGWFWwkmz+uxU+JSvx47JXpJhUleqhW79WKPQeJUC0xCpppB0jLILhEvqFXnmjx5Zq9P53AoTG61NWBwmcVaAYHFYxHBBM/Vq0MaNVCpZlDiiOj4//3n/5EIFg5/cbZUD6HRpBKSiLwOy8xEUNLSUOvWpL0FNL25/q349PUpsDRoNiQ9PT4L8haZvo4vzmJxYEhkekpScvza/5WS+mZqRiKZzTP6I3JnOcdYZioYMpgrmBx3briTq/Ch6KoUHEefFyVKDQyll67JkfprbNX9xkgzRaFPRyNTs5K5YjEcjQF/jGp1rsNukUhUNLqRw3ZrCWYZ2a2R1+aHxurrF1qiW9u8u7usM/X2gSJ5b0i42Gg7OFG+f7purivSVe3rK7IOROwjZe6JKv9ouacjX19m5OSIsC4+I2JU1XltNW5LldNU67FWu8wlYG+XMr1cgoEE1+DhehrRwmeBRcejkDukNIeUXuI2apjkPKNeQaUbhRIGHEvBUoVUpp7NMjIoMgyalgmLw8LW/J83/yObwVYWVlGtAZJEIpUxeKQkIi0dS0qGoeNTM1clpLyZkLwqNWN9JiQVDoW9agiQ1TjiOiYnk8lCEAgIJBwBSVsN0h2fmJCGILK0Pr6rWhkZLJ36WO6uYWjC5mAzWeoW28Isrcdf3qpwhRTOEpEtqivYUNC9qWxgk7Okhi2XowlIOpsDmumr39lSqDIuTy+WKpksNgIl5qHImCwCCqUTK6vz8saqw1tbXPu7rNPVpv4CaU9QNFtr2TdcClQu9pT21fp7Cy2DJQ7gca4hCBiKOhvcsoiWkacQVtgNDX4HUFnpMAKnwGa5TR9R8YJShpdPcXGpbhHXLRO+2hkl4hKXJk8viXpMChopx2hUsQU2uY6No3MofAVbZBWK7GDPpJCFGGIcKM2/vvVfEBpDFSqXBIrZOhNXxCZhUkikBDw+Ho1eA4ethkJWQ7PXQbPXgz4AgUCyIWkQWCIal0xlQNlcAvPVf5ySunoVaHAEMktoDHibxmztS+rWZe/Mp/7BLd7uja6WSYw2YClt45nzZfYwS+VUuyvE9jJ1sC3ctdQ4vSfSNqC02PAUHJ3JkMikHA4Hng3BwtEKvkTM4EET0jFkTCYSjaZwbY5gZ0v7tqG2g0PFHw94p8q1A4Wy7qBsrNK+faDivemW5cGq8aZ8kEoQydn6/C3tJVs7ojN1eZ1BQ7VNCAJY77M35bhAJMusOiAUvAXBjGoEBQo2mEI5Ek6OQuxViB1SoZnPay30FNnURXajiEAIGG06kcap87DJIglHqRUo7WKpk88DS5OMRIlLWP2nv/7tT4lwBENvF7uDHL2VyObA0FAsejUauQqFeAeNiMeiEjGIFCQ0CZqZkJSWmgHNBA9giCgmjy5WiPgSAZlOg8UnU1BkOltuyK2pWThcsvWEsv8Av+9AePlI1f7P86Z3w01Ba00fXulCcrQ4cLPQFzI1RVxbtbao11MzZAnXsGUqOBrFZDMEYOoxGEg4CgXHgfFHwtDSE6GpGDK43ZsKG3sXD+w/+vmRfcuHpxsO9/onywwjJaaeiL2/NrQ41LJv4+DuyQ1zHVHgcbI6sLG5YLmrbHt3OQhmd9hU6xCDJAKPAOCx2KB8HUwgFKQyX0L38MhODsUl5LikAjCdQSpbQi5wZw+adAICOd+Ra9F63bYIi6bXSuxGscEmlIFlSEshiPG4uGTQBNe9syY5FU7jiq1+odmL48uRNA4SsRYGfQeavRaFSCbioCQ8AoOEQDPT3klanwKFwPHgnsqRaPRGp1ukViGIOCGBRsNQE1IQULra17FYsfOUc/4z1eQxTvOYc3qPfXhbui5XXdaBlnsoSp/CFeWoC7iGMo6lhmGtphsjVIUTxxCCLslkUBAIGAyGIJHpZDI3C0JMTcfB4EwEQy52Rssn9m756tb7393ce/CDnZPde3pKJqu8E01Fg621fV2ds7Pz+3bveG/L3KbBNpDH+cbQptYiEMnNGyJAa3uersoqAGEEHhsDzqhZU6iTg2IHqQQ2y3QiUOB2Js5Exdq4DJ9SErYYiu22ep81pFUU2ewajqyisCHHXxsMdQmlBV5zsUcbcEq0VjYHqBTh0XEoaCYK5C05NQtN0HmCpvwKutZNU3ug2KwMRGoaNBWCguGpZDKDDe7aMDRxbXpyGgIFxdGJDIXOGgwUVsiN5lQEhIyAgftJUioEw1GXDm/rOfRDaP64umsPKdgurh61tG+EaEJcfx1E7OC7ShU5tWpXoy7QKfd30Uy1OHmQJHFReAoCmUEh41KS1ycnpxIpTApDkgGjQVACrtTjC1aHGkcbt306cfLu4rd3N3741fZtOw5tnp9qrZgfGZic3dK/sG96z2f7Pzlz4OCHm6YngT7gcbGlEAQTOAWTB6gEqQQqm3PdACAR2ASNEpyB3AaHJqLhg1TamETQK8MmbVWOt6kgXO+xFZt0Nbn5NoW1vqq/oLA3WrOod3QU+ZuDthKv3Gzn8kxMiopOjCOgEWw6LSMjA47C+wsrcys7uLYIx1EGp9PS8fgkJAbcu8EeQ5PoSQItmqHIxCKzsMQ0OA1BkOvt0eKqDq3DkwjNTI5/A4vKRIObn9JU3TvXOn/YWjdL82wwlE2Lc7pcdfNEQynVUgYReWTBBrwuz5rXbQkNKvy9NFM9w1AhNBdz5WYckcGkEfE4FArcdvA0Il3Klbr07spAtG94YLq+b6507v2mjy6Pnnm+8eu7uz8++8H7n00N9G9Z3rfx/W9GDl2a+fv9A9/9vP/vP85v2g3qeqmtGEgE8QSNcrzS119sA3MctMUNIX9HQQ4IJggjOHcX53cW5jY6taV6UY6Y4eHTA3JRoUVf4XfX5uU2euxlFnNdXpFRYo0UdroCnUXVWy25E2FPi19faBfqzEwOUKljU+IwCDiPxYRkZKLQ+ILyhsKGQY6tlOaoQgql6TROAp6eThXgJCaGNkBV+XFiB4ZNg5IY67MoaXCJ2lIerR8w+vLXwzIh2W+TyNnpWcnxqRk0iVHhqmDpo2Rl1Fc6z1BWWQtGgS+mpYJsjjibxtG6fFOgS+Pr5FqaSbpqvr1e66/lyW2ZEKyYxwCXd5FIAkdTCHS5p6ClaXBH6+jeyb6xsvpe+4a5wt1nBn6MbTofW/rk6uLOE1Pjc8v7P99y4v7457/MfRt7/0rsvZN3ZrZ+APojUAk8TtfmApUAMM1BAwUxBOL6ouH2cAB4BIehiuL+0oJqsxykEowdv4gFxk6+XgUKPGw2NbhtpWZTpS8oZiidtkqptsoXWdAHJj2GKrPYp6ZIlHiShozTsAhxWA4/Pj1t1eo3sSioVMjj8sQwHDsRxszMSEmHoxzRJl20S1PWCxPZ+aYAliWCwzLJRBKPI09OwiiUXhxRgKOyIRjcm+vWpGZCKESWlGdQSLw8cYAg9MP4Xh74JwNt3vwWg7VQrs9VucrlOU1sTyND5ctgGAj6qK5i2ly7YCgd5lgi8XA2h4ZSKoU6m0MTKLbXjhbPfFy6/EP+prPtdaPtfdvad37e+/XdiRuxhduxTZefL529M3js0ujXt2eu/brwJLb4LLZw6+X02YcTJ26Oj451dvTWNba3tHQP9/ZPd7YNleVu8CibvYr6yurqrqXaDRubSiq6cy2DxY7Rhkip1l2s1ebp2D49wWcgg8tlicVRYQ3bnLlRs6teKg+xqVqpSOkrtxQveQqPltbuikRninJaQtZgrtbilMrj5DYnnsmAAEEEtIDDZLL4GIoQTpHD4fD1GVCxLQiKEacLv4nkEeVWFENMJOMoVDqFIvjr3zL4AguWwGdwxQQmA0MiwODo7AwkCkZnM40ybZHc1SDxtdIczURdFMVzollGoSFsL+hU53WRDDU59RNcVx3D0yaJTisrF5zNWzz1M2J3NYWAJZPJODITw5LzrRF7zYSjabM8OuWwRQPR3sjUwYZjl/rO/zZ9M7b5+ssdl38Z+uzWyLcPJ6++mH0Qm3sYm70Zm/rx58lTD0bmtnaNLbYNLfZOLk/Pb58bnRqoKW/wmbvCnvaWwZapI20TH3S2DPaVFIJI9tVWt9j81WZjoYHj1REdOqrLqMq15Yec1d6cSJUz0ChXhjlUvUyo8UetxYv+gsO5FTsChZM+d4NbF3BKdSa+OE5qsVN4XDBIkLBMJDQLBseAVGKYGr5EkYWh8k05cJEdJnK9kc2iaf00pQNHpxHoXApdtnYdWqvP5/B1PLGSSKcT6eTMLMjqt5MS1sCxOBVPXSzxtAkC3YzSWWJOD0ITgfF9NFWxytehyR0TuocVxQNUdxuvZMbc86Gt/yPf0BF781aStVoiMZCpwoxsUko2mcjUyMwhsSlMEjltuQ3B1tm6nV91nnzQe/7l0KWXU5d+W7z0y/Dpx8Pf/zxy5eX4rRhg7Fps/Nxv49/9PPDu8e4dn3bu+Hx43+m5/admNh3oau2rChZ1FUfbu7ds2PJTx/YLPaP7uhu628oa68o7+jz+VocxauTn6Jkui8zjD+UW9xdWbS2pbm8rrOyy2KNSvtOgtoZq/OXbQtGPPPWHPGVb3YFuu6nQIjMbBYo4klACUonGIiCZKSkJ8UnJGeAijGVplUYPnCyUWoNgd6Gqc1chBAxDAVMfSseQ0HSxQOHGktWF0U6dMcATyrJgr74KmZUNzc5AY5A8BtfN11cynW0Ud7d68rhj7nP30PuyomGsLIoRlcu8E/7aQ/ScPpy3T1S72zJ60jb+tX/ypLFtL9xYn1PQqbOW0jgWFF6Mo0gYHAWdKSWQObaqwaLJfRs+ugoaZc+FWM+52PCFFzNXYwM/vug/97L/Qqz/4isGAOdjgz+97Pn0VvvHt9qOrPQcvTvywc2h5ZOt3ZvLSzsb8qpr2t+tWr7TcOB529K3bT3LVdWTRaUzPV4fUFlqkuSbJAG/N1g1EO3/qGr+SsPA0kDz8FB+pM5qzvN7AtXd4cb3IlXH88fO5/eeyKvbFshrd5uCYL7HYdg8ulDA5jIIWERmalJKKtiBqDCyjMA3rckgc1VetsorMITfhnJR4pwsvnc9loHkqAX6EJ5pCZd0KdQuGoubkpackZ0CLs4cpkQicog1JVJ3p7ps0dR2MO/AzcK9l0IbTxhqFgnaWoSgjGcfdVd94B88rG7cLW09KGg9zGs+5J46VbxwWt+0PbduyREZA82BJvMjqLJMNBWKI2OpDH5ln21kb/mhi22nf2//MdZ1PjZ8Izb3INZ+PtZxLtb+Q6zj7CvAof2n2IZzsY4zsaaTsZpPf6s9+rz5wP2WzWfr+g9U1i+UBRqK2g6Gdz0r+TjW8P79loUvqnsOF7V+2JFX0Oj2lJr1+SaD31+cUzdfMH62eNvPlZOHO7u29Za0VftCeUVlgZbp/JYjeRVfBLf/UrhppWT4i4KahYCvxqUPxGURKaDAOTwmDg1LTVy3PiE1PhW1NpMCpRn+ay2aLrJJNH6dsyQBKUZJghmCUAZbg5V52PqiZKRMbYrgSUIcnpwBEp0aD4dB8FgGDidDM9xMywZr26HotiuFuy/pet5nBAfpzhaOo5Vt66Db+1muCUf7u7rm3cbuo8quY+LWw76Jr8LTJ6SlM5ryTYqSOWnBMMffjFDnJLNV6QIl0WB1b/uo8NAPjV896/iHrDag71Ks+3qs5nys7sdYw7ex5lMvAXWnX1Z9F6v4IVb/fazydKzkeCxy5LfyvQ+qNv5Q1Xe0onG5orAz1HvU/d7vOV/GKk7Emg7eaFg6Vzl9sa20tT5YVuLw55q8Tme5tWTO3HnSPHU3MPllWdeB+tKxkmCDt6LL2bnT1vx3U/Ep+65YzvbnxXPnizbsCwQ7XIbCuFXpWdlYDAaHzExLTIxfnZqWnQ6nJCPYWEn+nxNINJ5ZqvJaPaVZZD3b3kT39GaLHVRziczblI43iDThbBgVBkdmpCelp69PTUlKWJe5Jh63NksOk1YJK3c5J8/a2g/SfX0QSRFBVSxwNHDdG8iOTryzj5/XIy6ZsnS+b+r5SNG839V/1NKyA64uFVfv4FdskTYsG/v2Gvp2SDZMyzqmTGOb26/83HU51nMl1n0x1vZjrO5srOxMLPLNs6KfYtGzsepTsYYvY3UnXlR8+aLw9Iv8My8iX8eKT8UiJ2Jln8Qq9z+tWvipvOtItGa5tnIwd+hjw/7fjF/Gcr6KVR69U/vurYpt92sbp6vLekpzq8KuqN/XbC9dMnV8pRu7ZZy9nD9wsrx+V1HlZKBji3P8uLHrR3nJT5KtMcv2l6HNK5GBj0PRcb+zOu6NBHBnBDYgQCUkI5VG5wiVNp7aR1aX/Nc6CpqsYLG1akN+Bl4jCnTLS+ZTBA6up85TPclQF1t89TAMC0ybhPWrcTgIFJKVnAiJTyQlIQ1QeS0hbyO9+gDPN0Q3NbMM1WJbDctYhlWXEB2tovIFd9OCqW6jtmGZXjSH9g3pGrf7Onfx/C263o+l7QcNo59ED11t+/ZJ05mH9d/ebjn3sOrcw4rvnlSc+rXqq1jd6Vj1t7Hot7Hw6Wd538cKv4lVgFo+8bLqs9+jJ37L+/IX96nngc9+DX4Ri56KVX8Ra/jw99pNF8o7DhdXbK6pHfQMfSje80jw95jh+M/BD25Edl0v3nq3vHVrec0kyGxZXnOkeCjUtC8wds679FS3+XH+1OWqrk/LOvaFpz7yb7lgGbsjr1lhborplmPB5YdlkydL6pcKczfE/SX+/8Snr6Py2BS2mMLUaEwRBtfLFxdoywdwCueq1GwijflqnZT7rMMf6WbO4iTuZKoh2L2TbKvBKfLWZZEIGCwNngGHkpJTUW/FI95Ko2cxnUxnqyg8wQ1Nquv2uzuOGEo3CRzdAlsPUdUOEXeQHRv1A/uErTs0fUf1vcc5pbukZdvtjXsM5RudQyed02c8u66EPn0C4lZ5LlbxXazs1Muyb2Klp18R/TpWAuJ2Mlb81SsKPo+FP3tF6Hgs+PdY/qexcug87QAADG1JREFUvE9eAvKP/Zb76e85x1/kfPJb4P0ngeXbgalLOYM/Oocue6du5W97UvDei+AHMc8HL4z7n6n3PNTM3dYNfKNvfNcQnTSWThma9hiGzugW7mp3PDIv3vOM3MztvprTdcU1dF0/t6LYcle27bFsyyPFxvvKqdvq4Ru63qtxq9e/A8ciBQo1R2bQOCNcdUhuryeKw6L8VrzSlYwg0HhCCJG1hqySNmyV9n5qKmhLphllwU6oLCz21klNuQq5hopC4FFEOJSQlklIQ/LRPA/HVi/K7xcER5j5M7KieZa1na6qUrq6xfY+srab7Z5Vdu4QNG6zjn9euP1a3vxPwcmvc3uPSAvG1a0fmUZOundeCR57UgTEAY/fxspPxYq+fEXhF7GCE7Hw57HQZy8BweMvco+9Iufj3wMf/eY/+qvvyC8A74fP/Yefg7feY795j/7iOfjEt3wnMHM1MHLBNX7dN3s7Z8uj/Hd/8b/3q33/c/3ex8rd9w1bn5tnr9n6PrO37X1F/+eWueum5V8VOx/rlx7Yx1fc/dddfdesozfVC3fEW+8JtjwSLj0UL9yXTN9RjK2oBm7ErXlnLY3K4ssMDKnVXzmQyrBaa+ZSBSGqNYqXuqBkHk9uSMMw/zODQcvrZ1Ut851Vb0CEWE1htsAn9daacqrEchMkC05BYvEI/Kvvb+KESLoRLfBjVRG8vjpJVAmRVSaTnVkki1BXLjY0kCRVNO0Gduk0MTwh6zySu+1aaPlG4abzrs4PKLYOXsV7mr4Tnl3XQ5/8HPzyd0DRVy/LTsbyPv0dkPvJbznHfg18/Iv/o+cA39Gf3R/8CnAd+sX5/nPHwZ/tB54BbPufOvc9fXU49BzgeO+pa/m+b37FP3HdPXfHs/Gee+mBc/mRdccj/c6Hqh335dvvqpdj+k2PLVMXHCNfA8BBt/gIfCjc+Vi6+YF25o5x+KZh6IZq8pZw4x3O1nv0xfvMhXvsubu8qTvC8duSkZW4VX96i0ZgkSjCbILYWz3039O5/sF9a8RhgjqEFjqgVKlI5wGvf85ik53N5EDfWpLuf6awaJYyuqmErg3yDPlgZUmGkFloHA1NpOKZZJoURdOkk3XpdCdMFF4vKkWoq7PZfijFzJUFmeIQiuEnS8o44UlMYJTdfFA/+71m6ox59KSh7SDF0csrP2AY/DrvvftFn73I+exXz7GnuZ88B+c/Js5zGBh85jr0FABiBbC997N13zPL3qfmPU9M7z5+xdaHxh2PtbufaPc81e96Ytn2yLlw3z19x7npsWMR1OwD3cZ7yo13ZIt3ZEt3JZvvchdeiGafKqZXNOOXALLJm/ypR6zZX1nb7nM33RXPrMjGb0rHbggmbzDnb9GWbhOmV4hTK+SpFfrkbebEbc7Y7bh3/vOvJAQBCiWuSsHog03/LZFSMHYQaqokKvMQHGsmUSGzFlClnmSCmueup1jrINLQOzgNw1TCNhfD2Wa2PpxJ16dRNGQEBgPFgGWIwTWQhW44xw2XhMjmekpoRle/rC0eEVoqxLoiEteNorv4umpJcJZXssU0dca3/6F26ZJ2/LSp+6ggNKNqPu6avlBw6Oei4zHfJ7/aPnjk+uBx7hGg7zfAHwP4OoOWPc8B5nd/Nu1+Ztz11LDzCUAPJC48UG16CNqZFDS1bY/VS4+M8w+tsw+NS4/1iw9V83cl07eEUzcEMzcFs7eEcyu0yWesySe8iXsgYoKxFfbobcrwPcLwA9rCXfrMbdbkCnvsJmv0Bn3sBnniBnH6JnbwOm7oBmHoBmnoJmXoFn1oJS551d/wcCgciohPhAh1vjVwfnjDRoG3kSzPRXIdEKpe463lG4oQTLPKV883R3UVk1nCQDrdCGHq3oYw+fbydJ47lZ+blgx7Z1VafBIWQdfhZUGErAijr+fkjgjbPgQ7o6N9rySng6mJQCjWdKKVrasBi7oosiOw/WbJyZjj0BPD4jl99yfsvBl73w/++ZvB/c/zj750fviL5eAT2/7H7v1PHQd++f8DCDDsfKbf8RSg2/5Eu/xYs+2ReutDgGrqkWzmkWD+EXfxMUC48Fgx90Qz80Qyf188d08wfZs7cZMzfuM14MyaeMiefMCdeMCdvMcev8MYvk0evEnsv0kZAaZuAKiD1ykD14j9Vwl9V/D9V/Ad/w9C51UAsetaXGbSX1CQBCIGlpWR+Y9vDWttrkqjrZIk9BFFPoI4xxLuYusimUS11lmpspSoy6fxhlKCIsBS+99IJrIspSmCfKSlBUUUr0kmgPEN43pJpjqUoRlp72UWbGR2faEdOS2q2YGzNKJkxalUZxLRRdHWSO1T7LzN+qkfPMdeGA49MW2/Zhr+khNccA9ddE1ds2+5Y9/z2HzgKcD63hNwNu5+bNj1CAC6m27HA+32+5rlewDl5ocAxdID+ab7ssV70o13JQt3AMqJJ5LJx9zpR/TZhwDWzEPB1CPwCWPyFnPiFezxW6x/BI05ch3AH73FHV1hjawAibTBW5S+q5SeS5Su8+SOy5TOK8TuK4TuK/iuy7iOi4S2C7iWc5TGSwBS4yViw0VC40Vc44W4jJT/yE77C4MEwcGysdlojcQsYuqM8gCWa6fJg1xDmbt0lKooWAfhK8yFJmcEZ22SBLujnRtreuaSMAKaMZouK5HXbncGm8FVD8nzclwt8sgsIzRDDi1yKvfSB78XDn1LiGzO1jfhDDUoeSlMXMJ0dOaUHRQV7OR1fy7ZuSLdd8918GFo21Vzy2HnwHnz8Hn11EXN5pv6vQ8tB1/NENu7IGv3AaotwN1dxdId+abbANniinjuDkA0e1s4syKYvsWfAj3uJm/yhnr8mXjiCXvyEXX6IWnqAW0KhO6RcOIxcfgaefQGbfwWY3yFPX6bNXKLMXSDOXid13+B3X+B2nuZ0HMJ23ke3/4TofUbUstpatN5cusF4oaLhPaL+A2vJOIbfyTUfk+vuUSruUStvkiuvkCoPo+rOhf39tpVKKaA560gu1tM9Vu1hcNZWLUZ9EGaGs+WExgsg9XIkynQDKXMswEjq4UwvBRxfjjaa3OU8IU2oSKXKgnai0cN/iqWKoco9TGMpXRrLUZfTXZ1ycs2aqeOyafPcru/JfoXcewwlqCHcvOSNM1J7gVo5F1K75fizTc0e55qdz9TbXogm1rhjlzmj10VT92Uz91RbbyvXnyg2fQQoFy4B1DM3wWfy2ZvS2dWAKDfccbugL4GAIFiDgMvN+mDNwDM/usARt81eu9VWs8VALX7MqXrEmPDDQC97Tqt9Rq15Sql+QqA3HSZUH/h31PxAwBf/j2u7Cy29DtM9Ay65Nt/SxwEhaDJ9cpwKyPQqa9Z0hQMZeCUam0ujmsicpUoEkUkF+PpTChJrPB1kLUtWTQ3kuE0u6rEUheJomQKXFiOVxPoYiq8GI4VJ/IKXfWy/F62r5sXHNXXLatGPpRPnuH1fs8o2EWTV1LZbqw8km3txZcdoDUf442flS/fVr/7RLXjsXzhrmTiJvAonLgOHAFlr/X90eBrieBvgWvR5A0A0PdPg7SB69T+awBQnv9ikNx5kdRxAQD0vTYI9L0uz1cVWn8BW/PTv6f0uz8aREW+QRafBkDDX/0LcVypQmoPWipH2MEBWdm8MjyQRdIIpE6yyE7mq7NQGAKVmAZDpKLYqkAX3diO5OZmEU0CeQ6BJEdhhCyhG8P2SJ0tRL4TyTRT5EFdqNdcPiMJjwnDk9qaZUXP++LhrwVDF0R1RyXuHr4mQrc0EfPnFH2nVWPfKxevKHfcVex8KNt6XzK7Ihq7DhwBU0AZcPfPAP7RHRAtGL8GjPNGrwD+6Y7ce4XUc5nYfQlA6LoI3L3WR2w/T9hwDt/2E671R8DrrOHrzgNwteeALEz1jwBkxdl/y2t3iKKvAfDCU7CCk6/Fpecc/xfiVBaf1FViq59jhUeZoVFpuB+sODS+Ac8zk3gqIBGOQaxNSUuCM5T+ToqulaWrhFFtdJ4DjuRhcGKJOkiThlS+DrExwlQEBeZKS2TUUr4gyB1h+kfFxZuULQeE3aeEI1fUvaf1ZQsKT7Mgp59Xuds6fdE8f1m9dE22bUW89Y5wcUU0fVM8fgOI+6NHYBC4A+JeA9yBDsAZvsQeughgDV54rQ+4A+A7L+A6zmPbzwGAu9f6sC0/YJq/RzedBaAav3stDl31A6rye2AKUf4dvOwMAFJy+t8C3L3WBwl9mR38Iiv/RGbe54AU3yf/wv8Fe4XaH0Z+k6QAAAAASUVORK5CYII="; byte[] rawInlineImageBytes = Convert.FromBase64String(InlineJpegImage); diff --git a/src/libraries/System.Runtime.Serialization.Formatters/tests/runtimeconfig.template.json b/src/libraries/System.Runtime.Serialization.Formatters/tests/runtimeconfig.template.json deleted file mode 100644 index e3ad204dd9e51..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Formatters/tests/runtimeconfig.template.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "configProperties": { - "System.Drawing.EnableUnixSupport": true - } -} \ No newline at end of file From 29acf9590029141ee3d3bfd71dd2ce9d76319184 Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Sat, 22 Jan 2022 01:46:22 +0300 Subject: [PATCH 132/308] Address-expose locals under complex local addresses in block morphing (#63100) * Handle complex local addresses in block morphing In block morphing, "addrSpill" is used when the destination or source represent indirections of "complex" addresses. Unfortunately, some trees in the form of "IND(ADDR(LCL))" fall into this category. If such an "ADDR(LCL)" is used as an "addrSpill", the underlying local *must* be marked as address-exposed. Block morphing was using a very simplistic test for when that needs to happen, essentially only recognizing "ADDR(LCL_VAR/FLD)". But it is possible to have a more complicated pattern as "PrepareDst/Src" uses "IsLocalAddrExpr" to recognize indirect stores to locals. Currently it appears impossible to get a mismatch here as morph transforms "IND(ADD(ADDR(LCL_VAR), OFFSET))" into "LCL_FLD" (including for TYP_STRUCT indirections), but this is a very fragile invariant. Transforming TYP_STRUCT GT_FIELDs into GT_OBJs instead of GT_INDs breaks it, for example. Fix this by address-exposing the local obtained via "IsLocalAddrExpr". * Add a TODO-CQ for LCL_FLD usage --- src/coreclr/jit/morphblock.cpp | 53 +++++++++++----------------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/src/coreclr/jit/morphblock.cpp b/src/coreclr/jit/morphblock.cpp index 233f72ef8f110..4dd0325c480f6 100644 --- a/src/coreclr/jit/morphblock.cpp +++ b/src/coreclr/jit/morphblock.cpp @@ -1048,9 +1048,9 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField() { GenTreeOp* asgFields = nullptr; - GenTree* addrSpill = nullptr; - unsigned addrSpillTemp = BAD_VAR_NUM; - bool addrSpillIsStackDest = false; // true if 'addrSpill' represents the address in our local stack frame + GenTree* addrSpill = nullptr; + unsigned addrSpillSrcLclNum = BAD_VAR_NUM; + unsigned addrSpillTemp = BAD_VAR_NUM; GenTree* addrSpillAsg = nullptr; @@ -1095,7 +1095,8 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField() // We will spill m_srcAddr (i.e. assign to a temp "BlockOp address local") // no need to clone a new copy as it is only used once // - addrSpill = m_srcAddr; // addrSpill represents the 'm_srcAddr' + addrSpill = m_srcAddr; // addrSpill represents the 'm_srcAddr' + addrSpillSrcLclNum = m_srcLclNum; } } } @@ -1144,28 +1145,13 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField() // We will spill m_dstAddr (i.e. assign to a temp "BlockOp address local") // no need to clone a new copy as it is only used once // - addrSpill = m_dstAddr; // addrSpill represents the 'm_dstAddr' + addrSpill = m_dstAddr; // addrSpill represents the 'm_dstAddr' + addrSpillSrcLclNum = m_dstLclNum; } } } } - // TODO-CQ: this should be based on a more general - // "BaseAddress" method, that handles fields of structs, before or after - // morphing. - if ((addrSpill != nullptr) && addrSpill->OperIs(GT_ADDR)) - { - GenTree* addrSpillOp = addrSpill->AsOp()->gtGetOp1(); - if (addrSpillOp->IsLocal()) - { - // We will *not* consider this to define the local, but rather have each individual field assign - // be a definition. - addrSpillOp->gtFlags &= ~(GTF_LIVENESS_MASK); - addrSpillIsStackDest = true; // addrSpill represents the address of LclVar[varNum] in our - // local stack frame - } - } - if (addrSpill != nullptr) { // 'addrSpill' is already morphed @@ -1178,30 +1164,26 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField() addrSpillDsc->lvType = TYP_BYREF; - if (addrSpillIsStackDest) + if (addrSpillSrcLclNum != BAD_VAR_NUM) { + // addrSpill represents the address of LclVar[varNum] in our local stack frame. addrSpillDsc->lvStackByref = true; } GenTreeLclVar* addrSpillNode = m_comp->gtNewLclvNode(addrSpillTemp, TYP_BYREF); addrSpillAsg = m_comp->gtNewAssignNode(addrSpillNode, addrSpill); - // If we are assigning the address of a LclVar here - // liveness does not account for this kind of address taken use. + // If we are assigning the address of a LclVar here liveness will not + // account for this kind of address taken use. Mark the local as + // address-exposed so that we don't do illegal optimizations with it. // - // We have to mark this local as address exposed so - // that we don't delete the definition for this LclVar - // as a dead store later on. + // TODO-CQ: usage of "addrSpill" for local addresses is a workaround + // for cases where we fail to use LCL_FLD nodes instead. Fix them and + // delete this code. // - if (addrSpill->OperGet() == GT_ADDR) + if (addrSpillSrcLclNum != BAD_VAR_NUM) { - GenTree* addrOp = addrSpill->AsOp()->gtOp1; - if (addrOp->IsLocal()) - { - unsigned lclVarNum = addrOp->AsLclVarCommon()->GetLclNum(); - m_comp->lvaGetDesc(lclVarNum)->SetAddressExposed(true DEBUGARG(AddressExposedReason::COPY_FLD_BY_FLD)); - m_comp->lvaSetVarDoNotEnregister(lclVarNum DEBUGARG(DoNotEnregisterReason::AddrExposed)); - } + m_comp->lvaSetVarAddrExposed(addrSpillSrcLclNum DEBUGARG(AddressExposedReason::COPY_FLD_BY_FLD)); } } @@ -1209,7 +1191,6 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField() // So, beyond this point we cannot rely on the old values of 'm_srcVarDsc' and 'm_dstVarDsc'. for (unsigned i = 0; i < fieldCnt; ++i) { - GenTree* dstFld; if (m_dstDoFldAsg) { From 8fa0af631713ab7e0e548121099462ccfbc8148c Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 22 Jan 2022 01:09:11 +0200 Subject: [PATCH 133/308] [Group 2] Enable nullable annotations for `Microsoft.Extensions.DependencyInjection` (#63836) * Annotate src * Update ResolverBuilder.Build * Update RunOnEmptyStackCore * ILEmitResolverBuilderContext constructor * Remove setter * Add assert --- ...icrosoft.Extensions.DependencyInjection.cs | 2 +- ...soft.Extensions.DependencyInjection.csproj | 1 + .../src/CallSiteJsonFormatter.cs | 16 ++--- .../src/DependencyInjectionEventSource.cs | 7 ++- ...soft.Extensions.DependencyInjection.csproj | 4 +- .../src/ServiceLookup/CallSiteChain.cs | 8 +-- .../src/ServiceLookup/CallSiteFactory.cs | 61 ++++++++++--------- .../ServiceLookup/CallSiteRuntimeResolver.cs | 30 ++++----- .../src/ServiceLookup/CallSiteValidator.cs | 32 +++++----- .../CompiledServiceProviderEngine.cs | 2 +- .../src/ServiceLookup/ConstantCallSite.cs | 4 +- .../src/ServiceLookup/ConstructorCallSite.cs | 2 +- .../DynamicServiceProviderEngine.cs | 2 +- .../Expressions/ExpressionResolverBuilder.cs | 26 ++++---- .../src/ServiceLookup/FactoryCallSite.cs | 2 +- .../ILEmit/ILEmitResolverBuilder.cs | 56 +++++++++-------- .../ILEmit/ILEmitResolverBuilderContext.cs | 7 ++- .../ILEmit/ILEmitServiceProviderEngine.cs | 2 +- .../src/ServiceLookup/ResultCache.cs | 2 +- .../RuntimeServiceProviderEngine.cs | 2 +- .../src/ServiceLookup/ServiceCacheKey.cs | 4 +- .../src/ServiceLookup/ServiceCallSite.cs | 4 +- .../src/ServiceLookup/ServiceLookupHelpers.cs | 16 ++--- .../ServiceLookup/ServiceProviderEngine.cs | 2 +- .../ServiceProviderEngineScope.cs | 18 +++--- .../src/ServiceLookup/StackGuard.cs | 2 +- .../src/ServiceLookup/ThrowHelper.cs | 2 + .../src/ServiceProvider.cs | 26 ++++---- 28 files changed, 178 insertions(+), 164 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.cs index d2161d8905150..0b85156d60885 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.cs @@ -24,7 +24,7 @@ public sealed partial class ServiceProvider : System.IAsyncDisposable, System.ID internal ServiceProvider() { } public void Dispose() { } public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; } - public object GetService(System.Type serviceType) { throw null; } + public object? GetService(System.Type serviceType) { throw null; } } public partial class ServiceProviderOptions { 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 71e3f9dcb84d2..bcd739c9f5f1a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/ref/Microsoft.Extensions.DependencyInjection.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.1;netstandard2.0;$(NetFrameworkMinimum) + enable diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/CallSiteJsonFormatter.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/CallSiteJsonFormatter.cs index eb26ebb7cfa7f..79a93d3052acb 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/CallSiteJsonFormatter.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/CallSiteJsonFormatter.cs @@ -7,7 +7,7 @@ namespace Microsoft.Extensions.DependencyInjection { - internal sealed class CallSiteJsonFormatter: CallSiteVisitor + internal sealed class CallSiteJsonFormatter: CallSiteVisitor { internal static CallSiteJsonFormatter Instance = new CallSiteJsonFormatter(); @@ -25,7 +25,7 @@ public string Format(ServiceCallSite callSite) return stringBuilder.ToString(); } - protected override object VisitConstructor(ConstructorCallSite constructorCallSite, CallSiteFormatterContext argument) + protected override object? VisitConstructor(ConstructorCallSite constructorCallSite, CallSiteFormatterContext argument) { argument.WriteProperty("implementationType", constructorCallSite.ImplementationType); @@ -45,7 +45,7 @@ protected override object VisitConstructor(ConstructorCallSite constructorCallSi return null; } - protected override object VisitCallSiteMain(ServiceCallSite callSite, CallSiteFormatterContext argument) + protected override object? VisitCallSiteMain(ServiceCallSite callSite, CallSiteFormatterContext argument) { if (argument.ShouldFormat(callSite)) { @@ -69,19 +69,19 @@ protected override object VisitCallSiteMain(ServiceCallSite callSite, CallSiteFo return null; } - protected override object VisitConstant(ConstantCallSite constantCallSite, CallSiteFormatterContext argument) + protected override object? VisitConstant(ConstantCallSite constantCallSite, CallSiteFormatterContext argument) { argument.WriteProperty("value", constantCallSite.DefaultValue ?? ""); return null; } - protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, CallSiteFormatterContext argument) + protected override object? VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, CallSiteFormatterContext argument) { return null; } - protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, CallSiteFormatterContext argument) + protected override object? VisitIEnumerable(IEnumerableCallSite enumerableCallSite, CallSiteFormatterContext argument) { argument.WriteProperty("itemType", enumerableCallSite.ItemType); argument.WriteProperty("size", enumerableCallSite.ServiceCallSites.Length); @@ -101,7 +101,7 @@ protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSit return null; } - protected override object VisitFactory(FactoryCallSite factoryCallSite, CallSiteFormatterContext argument) + protected override object? VisitFactory(FactoryCallSite factoryCallSite, CallSiteFormatterContext argument) { argument.WriteProperty("method", factoryCallSite.Factory.Method); @@ -174,7 +174,7 @@ public void StartArrayItem() } } - public void WriteProperty(string name, object value) + public void WriteProperty(string name, object? value) { StartProperty(name); if (value != null) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/DependencyInjectionEventSource.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/DependencyInjectionEventSource.cs index 03b245224d8bb..b77679cc4e857 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/DependencyInjectionEventSource.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/DependencyInjectionEventSource.cs @@ -158,7 +158,7 @@ public void ServiceProviderDisposed(ServiceProvider provider) { // remove the provider, along with any stale references WeakReference reference = _providers[i]; - if (!reference.TryGetTarget(out ServiceProvider target) || target == provider) + if (!reference.TryGetTarget(out ServiceProvider? target) || target == provider) { _providers.RemoveAt(i); } @@ -279,7 +279,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) { foreach (WeakReference reference in _providers) { - if (reference.TryGetTarget(out ServiceProvider provider)) + if (reference.TryGetTarget(out ServiceProvider? provider)) { WriteServiceProviderBuilt(provider); } @@ -308,7 +308,8 @@ private sealed class NodeCountingVisitor : ExpressionVisitor { public int NodeCount { get; private set; } - public override Expression Visit(Expression e) + [return: NotNullIfNotNull("e")] + public override Expression? Visit(Expression? e) { base.Visit(e); NodeCount++; 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 38174f12577d0..23c3a776251f3 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj @@ -1,10 +1,10 @@ - + $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.1;netstandard2.0;$(NetFrameworkMinimum) + enable false - Annotations $(NoWarn);CP0001 true diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteChain.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteChain.cs index ca65e64ca557b..c8279dc0879e2 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteChain.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteChain.cs @@ -31,7 +31,7 @@ public void Remove(Type serviceType) _callSiteChain.Remove(serviceType); } - public void Add(Type serviceType, Type implementationType = null) + public void Add(Type serviceType, Type? implementationType = null) { _callSiteChain[serviceType] = new ChainItemInfo(_callSiteChain.Count, implementationType); } @@ -55,7 +55,7 @@ private void AppendResolutionPath(StringBuilder builder, Type currentlyResolving foreach (KeyValuePair pair in ordered) { Type serviceType = pair.Key; - Type implementationType = pair.Value.ImplementationType; + Type? implementationType = pair.Value.ImplementationType; if (implementationType == null || serviceType == implementationType) { builder.Append(TypeNameHelper.GetTypeDisplayName(serviceType)); @@ -76,9 +76,9 @@ private void AppendResolutionPath(StringBuilder builder, Type currentlyResolving private readonly struct ChainItemInfo { public int Order { get; } - public Type ImplementationType { get; } + public Type? ImplementationType { get; } - public ChainItemInfo(int order, Type implementationType) + public ChainItemInfo(int order, Type? implementationType) { Order = order; ImplementationType = implementationType; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs index 36e0ab4473822..a4092ca70c83a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs @@ -39,7 +39,7 @@ private void Populate() Type serviceType = descriptor.ServiceType; if (serviceType.IsGenericTypeDefinition) { - Type implementationType = descriptor.ImplementationType; + Type? implementationType = descriptor.ImplementationType; if (implementationType == null || !implementationType.IsGenericTypeDefinition) { @@ -135,7 +135,7 @@ private static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypes( attributeData.ConstructorArguments.Count == 1 && attributeData.ConstructorArguments[0].ArgumentType.FullName == "System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes") { - return (DynamicallyAccessedMemberTypes)(int)attributeData.ConstructorArguments[0].Value; + return (DynamicallyAccessedMemberTypes)(int)attributeData.ConstructorArguments[0].Value!; } } @@ -160,11 +160,11 @@ private static bool AreCompatible(DynamicallyAccessedMemberTypes serviceDynamica return null; } - internal ServiceCallSite GetCallSite(Type serviceType, CallSiteChain callSiteChain) => - _callSiteCache.TryGetValue(new ServiceCacheKey(serviceType, DefaultSlot), out ServiceCallSite site) ? site : + internal ServiceCallSite? GetCallSite(Type serviceType, CallSiteChain callSiteChain) => + _callSiteCache.TryGetValue(new ServiceCacheKey(serviceType, DefaultSlot), out ServiceCallSite? site) ? site : CreateCallSite(serviceType, callSiteChain); - internal ServiceCallSite GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) + internal ServiceCallSite? GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) { if (_descriptorLookup.TryGetValue(serviceDescriptor.ServiceType, out ServiceDescriptorCacheItem descriptor)) { @@ -175,7 +175,7 @@ internal ServiceCallSite GetCallSite(ServiceDescriptor serviceDescriptor, CallSi return null; } - private ServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain) + private ServiceCallSite? CreateCallSite(Type serviceType, CallSiteChain callSiteChain) { if (!_stackGuard.TryEnterOnCurrentStack()) { @@ -198,7 +198,7 @@ private ServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteC { callSiteChain.CheckCircularDependency(serviceType); - ServiceCallSite callSite = TryCreateExact(serviceType, callSiteChain) ?? + ServiceCallSite? callSite = TryCreateExact(serviceType, callSiteChain) ?? TryCreateOpenGeneric(serviceType, callSiteChain) ?? TryCreateEnumerable(serviceType, callSiteChain); @@ -206,7 +206,7 @@ private ServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteC } } - private ServiceCallSite TryCreateExact(Type serviceType, CallSiteChain callSiteChain) + private ServiceCallSite? TryCreateExact(Type serviceType, CallSiteChain callSiteChain) { if (_descriptorLookup.TryGetValue(serviceType, out ServiceDescriptorCacheItem descriptor)) { @@ -216,7 +216,7 @@ private ServiceCallSite TryCreateExact(Type serviceType, CallSiteChain callSiteC return null; } - private ServiceCallSite TryCreateOpenGeneric(Type serviceType, CallSiteChain callSiteChain) + private ServiceCallSite? TryCreateOpenGeneric(Type serviceType, CallSiteChain callSiteChain) { if (serviceType.IsConstructedGenericType && _descriptorLookup.TryGetValue(serviceType.GetGenericTypeDefinition(), out ServiceDescriptorCacheItem descriptor)) @@ -227,10 +227,10 @@ private ServiceCallSite TryCreateOpenGeneric(Type serviceType, CallSiteChain cal return null; } - private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain) + private ServiceCallSite? TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain) { ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, DefaultSlot); - if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite serviceCallSite)) + if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite? serviceCallSite)) { return serviceCallSite; } @@ -258,7 +258,7 @@ private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain call // Last service should get slot 0 int slot = descriptors.Count - i - 1; // There may not be any open generics here - ServiceCallSite callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot); + ServiceCallSite? callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot); Debug.Assert(callSite != null); cacheLocation = GetCommonCacheLocation(cacheLocation, callSite.Cache.Location); @@ -272,7 +272,7 @@ private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain call for (int i = _descriptors.Length - 1; i >= 0; i--) { ServiceDescriptor descriptor = _descriptors[i]; - ServiceCallSite callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot) ?? + ServiceCallSite? callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot) ?? TryCreateOpenGeneric(descriptor, itemType, callSiteChain, slot, false); if (callSite != null) @@ -310,12 +310,12 @@ private CallSiteResultCacheLocation GetCommonCacheLocation(CallSiteResultCacheLo return (CallSiteResultCacheLocation)Math.Max((int)locationA, (int)locationB); } - private ServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot) + private ServiceCallSite? TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot) { if (serviceType == descriptor.ServiceType) { ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, slot); - if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite serviceCallSite)) + if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite? serviceCallSite)) { return serviceCallSite; } @@ -349,13 +349,13 @@ private ServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type servic Justification = "MakeGenericType here is used to create a closed generic implementation type given the closed service type. " + "Trimming annotations on the generic types are verified when 'Microsoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmability' is set, which is set by default when PublishTrimmed=true. " + "That check informs developers when these generic types don't have compatible trimming annotations.")] - private ServiceCallSite TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot, bool throwOnConstraintViolation) + private ServiceCallSite? TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot, bool throwOnConstraintViolation) { if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == descriptor.ServiceType) { ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, slot); - if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite serviceCallSite)) + if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite? serviceCallSite)) { return serviceCallSite; } @@ -394,7 +394,7 @@ private ServiceCallSite CreateConstructorCallSite( callSiteChain.Add(serviceType, implementationType); ConstructorInfo[] constructors = implementationType.GetConstructors(); - ServiceCallSite[] parameterCallSites = null; + ServiceCallSite[]? parameterCallSites = null; if (constructors.Length == 0) { @@ -413,7 +413,7 @@ private ServiceCallSite CreateConstructorCallSite( implementationType, callSiteChain, parameters, - throwIfCallSiteNotFound: true); + throwIfCallSiteNotFound: true)!; return new ConstructorCallSite(lifetime, serviceType, constructor, parameterCallSites); } @@ -421,13 +421,13 @@ private ServiceCallSite CreateConstructorCallSite( Array.Sort(constructors, (a, b) => b.GetParameters().Length.CompareTo(a.GetParameters().Length)); - ConstructorInfo bestConstructor = null; - HashSet bestConstructorParameterTypes = null; + ConstructorInfo? bestConstructor = null; + HashSet? bestConstructorParameterTypes = null; for (int i = 0; i < constructors.Length; i++) { ParameterInfo[] parameters = constructors[i].GetParameters(); - ServiceCallSite[] currentParameterCallSites = CreateArgumentCallSites( + ServiceCallSite[]? currentParameterCallSites = CreateArgumentCallSites( implementationType, callSiteChain, parameters, @@ -487,7 +487,8 @@ private ServiceCallSite CreateConstructorCallSite( } } - private ServiceCallSite[] CreateArgumentCallSites( + /// Not null if throwIfCallSiteNotFound is true + private ServiceCallSite[]? CreateArgumentCallSites( Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, @@ -497,9 +498,9 @@ private ServiceCallSite[] CreateArgumentCallSites( for (int index = 0; index < parameters.Length; index++) { Type parameterType = parameters[index].ParameterType; - ServiceCallSite callSite = GetCallSite(parameterType, callSiteChain); + ServiceCallSite? callSite = GetCallSite(parameterType, callSiteChain); - if (callSite == null && ParameterDefaultValue.TryGetDefaultValue(parameters[index], out object defaultValue)) + if (callSite == null && ParameterDefaultValue.TryGetDefaultValue(parameters[index], out object? defaultValue)) { callSite = new ConstantCallSite(parameterType, defaultValue); } @@ -562,9 +563,11 @@ public bool IsService(Type serviceType) private struct ServiceDescriptorCacheItem { - private ServiceDescriptor _item; + [DisallowNull] + private ServiceDescriptor? _item; - private List _items; + [DisallowNull] + private List? _items; public ServiceDescriptor Last { @@ -605,10 +608,10 @@ public ServiceDescriptor this[int index] if (index == 0) { - return _item; + return _item!; } - return _items[index - 1]; + return _items![index - 1]; } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteRuntimeResolver.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteRuntimeResolver.cs index 1e330624aeb81..96fcd070295cf 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteRuntimeResolver.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteRuntimeResolver.cs @@ -10,7 +10,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { - internal sealed class CallSiteRuntimeResolver : CallSiteVisitor + internal sealed class CallSiteRuntimeResolver : CallSiteVisitor { public static CallSiteRuntimeResolver Instance { get; } = new(); @@ -18,7 +18,7 @@ private CallSiteRuntimeResolver() { } - public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) + public object? Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) { // Fast path to avoid virtual calls if we already have the cached value in the root scope if (scope.IsRootScope && callSite.Value is object cached) @@ -32,21 +32,21 @@ public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope }); } - protected override object VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context) + protected override object? VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context) { return context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context)); } protected override object VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) { - object[] parameterValues; + object?[] parameterValues; if (constructorCallSite.ParameterCallSites.Length == 0) { parameterValues = Array.Empty(); } else { - parameterValues = new object[constructorCallSite.ParameterCallSites.Length]; + parameterValues = new object?[constructorCallSite.ParameterCallSites.Length]; for (int index = 0; index < parameterValues.Length; index++) { parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context); @@ -69,7 +69,7 @@ protected override object VisitConstructor(ConstructorCallSite constructorCallSi #endif } - protected override object VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context) + protected override object? VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context) { if (callSite.Value is object value) { @@ -83,12 +83,12 @@ protected override object VisitRootCache(ServiceCallSite callSite, RuntimeResolv lock (callSite) { // Lock the callsite and check if another thread already cached the value - if (callSite.Value is object resolved) + if (callSite.Value is object callSiteValue) { - return resolved; + return callSiteValue; } - resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext + object? resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext { Scope = serviceProviderEngine, AcquiredLocks = context.AcquiredLocks | lockType @@ -99,7 +99,7 @@ protected override object VisitRootCache(ServiceCallSite callSite, RuntimeResolv } } - protected override object VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) + protected override object? VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) { // Check if we are in the situation where scoped service was promoted to singleton // and we need to lock the root @@ -108,11 +108,11 @@ protected override object VisitScopeCache(ServiceCallSite callSite, RuntimeResol VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope); } - private object VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) + private object? VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) { bool lockTaken = false; object sync = serviceProviderEngine.Sync; - Dictionary resolvedServices = serviceProviderEngine.ResolvedServices; + Dictionary resolvedServices = serviceProviderEngine.ResolvedServices; // Taking locks only once allows us to fork resolution process // on another thread without causing the deadlock because we // always know that we are going to wait the other thread to finish before @@ -126,7 +126,7 @@ private object VisitCache(ServiceCallSite callSite, RuntimeResolverContext conte { // Note: This method has already taken lock by the caller for resolution and access synchronization. // For scoped: takes a dictionary as both a resolution lock and a dictionary access lock. - if (resolvedServices.TryGetValue(callSite.Cache.Key, out object resolved)) + if (resolvedServices.TryGetValue(callSite.Cache.Key, out object? resolved)) { return resolved; } @@ -149,7 +149,7 @@ private object VisitCache(ServiceCallSite callSite, RuntimeResolverContext conte } } - protected override object VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context) + protected override object? VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context) { return constantCallSite.DefaultValue; } @@ -167,7 +167,7 @@ protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSit for (int index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++) { - object value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context); + object? value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context); array.SetValue(value, index); } return array; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteValidator.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteValidator.cs index 29a95f507d357..9e0b4e3c5b999 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteValidator.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteValidator.cs @@ -3,17 +3,18 @@ using System; using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { - internal sealed class CallSiteValidator: CallSiteVisitor + internal sealed class CallSiteValidator: CallSiteVisitor { // Keys are services being resolved via GetService, values - first scoped service in their call site tree private readonly ConcurrentDictionary _scopedServices = new ConcurrentDictionary(); public void ValidateCallSite(ServiceCallSite callSite) { - Type scoped = VisitCallSite(callSite, default); + Type? scoped = VisitCallSite(callSite, default); if (scoped != null) { _scopedServices[callSite.ServiceType] = scoped; @@ -23,7 +24,7 @@ public void ValidateCallSite(ServiceCallSite callSite) public void ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope) { if (ReferenceEquals(scope, rootScope) - && _scopedServices.TryGetValue(serviceType, out Type scopedService)) + && _scopedServices.TryGetValue(serviceType, out Type? scopedService)) { if (serviceType == scopedService) { @@ -40,12 +41,12 @@ public void ValidateResolution(Type serviceType, IServiceScope scope, IServiceSc } } - protected override Type VisitConstructor(ConstructorCallSite constructorCallSite, CallSiteValidatorState state) + protected override Type? VisitConstructor(ConstructorCallSite constructorCallSite, CallSiteValidatorState state) { - Type result = null; + Type? result = null; foreach (ServiceCallSite parameterCallSite in constructorCallSite.ParameterCallSites) { - Type scoped = VisitCallSite(parameterCallSite, state); + Type? scoped = VisitCallSite(parameterCallSite, state); if (result == null) { result = scoped; @@ -54,13 +55,13 @@ protected override Type VisitConstructor(ConstructorCallSite constructorCallSite return result; } - protected override Type VisitIEnumerable(IEnumerableCallSite enumerableCallSite, + protected override Type? VisitIEnumerable(IEnumerableCallSite enumerableCallSite, CallSiteValidatorState state) { - Type result = null; + Type? result = null; foreach (ServiceCallSite serviceCallSite in enumerableCallSite.ServiceCallSites) { - Type scoped = VisitCallSite(serviceCallSite, state); + Type? scoped = VisitCallSite(serviceCallSite, state); if (result == null) { result = scoped; @@ -69,13 +70,13 @@ protected override Type VisitIEnumerable(IEnumerableCallSite enumerableCallSite, return result; } - protected override Type VisitRootCache(ServiceCallSite singletonCallSite, CallSiteValidatorState state) + protected override Type? VisitRootCache(ServiceCallSite singletonCallSite, CallSiteValidatorState state) { state.Singleton = singletonCallSite; return VisitCallSiteMain(singletonCallSite, state); } - protected override Type VisitScopeCache(ServiceCallSite scopedCallSite, CallSiteValidatorState state) + protected override Type? VisitScopeCache(ServiceCallSite scopedCallSite, CallSiteValidatorState state) { // We are fine with having ServiceScopeService requested by singletons if (scopedCallSite.ServiceType == typeof(IServiceScopeFactory)) @@ -96,15 +97,16 @@ protected override Type VisitScopeCache(ServiceCallSite scopedCallSite, CallSite return scopedCallSite.ServiceType; } - protected override Type VisitConstant(ConstantCallSite constantCallSite, CallSiteValidatorState state) => null; + protected override Type? VisitConstant(ConstantCallSite constantCallSite, CallSiteValidatorState state) => null; - protected override Type VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, CallSiteValidatorState state) => null; + protected override Type? VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, CallSiteValidatorState state) => null; - protected override Type VisitFactory(FactoryCallSite factoryCallSite, CallSiteValidatorState state) => null; + protected override Type? VisitFactory(FactoryCallSite factoryCallSite, CallSiteValidatorState state) => null; internal struct CallSiteValidatorState { - public ServiceCallSite Singleton { get; set; } + [DisallowNull] + public ServiceCallSite? Singleton { get; set; } } } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CompiledServiceProviderEngine.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CompiledServiceProviderEngine.cs index b51b879c54395..eef3e1fe70214 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CompiledServiceProviderEngine.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CompiledServiceProviderEngine.cs @@ -18,6 +18,6 @@ public CompiledServiceProviderEngine(ServiceProvider provider) ResolverBuilder = new(provider); } - public override Func RealizeService(ServiceCallSite callSite) => ResolverBuilder.Build(callSite); + public override Func RealizeService(ServiceCallSite callSite) => ResolverBuilder.Build(callSite); } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs index bb822437a0e36..8071c67013352 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs @@ -8,9 +8,9 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup internal sealed class ConstantCallSite : ServiceCallSite { private readonly Type _serviceType; - internal object DefaultValue => Value; + internal object? DefaultValue => Value; - public ConstantCallSite(Type serviceType, object defaultValue): base(ResultCache.None) + public ConstantCallSite(Type serviceType, object? defaultValue): base(ResultCache.None) { _serviceType = serviceType ?? throw new ArgumentNullException(nameof(serviceType)); if (defaultValue != null && !serviceType.IsInstanceOfType(defaultValue)) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstructorCallSite.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstructorCallSite.cs index b44608c0841b5..1dbd77cb45171 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstructorCallSite.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstructorCallSite.cs @@ -29,7 +29,7 @@ public ConstructorCallSite(ResultCache cache, Type serviceType, ConstructorInfo public override Type ServiceType { get; } - public override Type ImplementationType => ConstructorInfo.DeclaringType; + public override Type? ImplementationType => ConstructorInfo.DeclaringType; public override CallSiteKind Kind { get; } = CallSiteKind.Constructor; } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs index 09abe625a658c..5c52efcc4f181 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs @@ -16,7 +16,7 @@ public DynamicServiceProviderEngine(ServiceProvider serviceProvider): base(servi _serviceProvider = serviceProvider; } - public override Func RealizeService(ServiceCallSite callSite) + public override Func RealizeService(ServiceCallSite callSite) { int callCount = 0; return scope => diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs index 001a3d7e07207..3d7f40834ad3f 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs @@ -10,7 +10,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { - internal sealed class ExpressionResolverBuilder : CallSiteVisitor + internal sealed class ExpressionResolverBuilder : CallSiteVisitor { private static readonly ParameterExpression ScopeParameter = Expression.Parameter(typeof(ServiceProviderEngineScope)); @@ -20,13 +20,13 @@ internal sealed class ExpressionResolverBuilder : CallSiteVisitor> BuildExpression(Ser ScopeParameter); } - protected override Expression VisitRootCache(ServiceCallSite singletonCallSite, object context) + protected override Expression VisitRootCache(ServiceCallSite singletonCallSite, object? context) { return Expression.Constant(CallSiteRuntimeResolver.Instance.Resolve(singletonCallSite, _rootScope)); } - protected override Expression VisitConstant(ConstantCallSite constantCallSite, object context) + protected override Expression VisitConstant(ConstantCallSite constantCallSite, object? context) { return Expression.Constant(constantCallSite.DefaultValue); } - protected override Expression VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, object context) + protected override Expression VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, object? context) { return ScopeParameter; } - protected override Expression VisitFactory(FactoryCallSite factoryCallSite, object context) + protected override Expression VisitFactory(FactoryCallSite factoryCallSite, object? context) { return Expression.Invoke(Expression.Constant(factoryCallSite.Factory), ScopeParameter); } - protected override Expression VisitIEnumerable(IEnumerableCallSite callSite, object context) + protected override Expression VisitIEnumerable(IEnumerableCallSite callSite, object? context) { if (callSite.ServiceCallSites.Length == 0) { @@ -127,7 +127,7 @@ protected override Expression VisitIEnumerable(IEnumerableCallSite callSite, obj callSite.ItemType))); } - protected override Expression VisitDisposeCache(ServiceCallSite callSite, object context) + protected override Expression VisitDisposeCache(ServiceCallSite callSite, object? context) { // Elide calls to GetCaptureDisposable if the implementation type isn't disposable return TryCaptureDisposable( @@ -146,7 +146,7 @@ private Expression TryCaptureDisposable(ServiceCallSite callSite, ParameterExpre return Expression.Invoke(GetCaptureDisposable(scope), service); } - protected override Expression VisitConstructor(ConstructorCallSite callSite, object context) + protected override Expression VisitConstructor(ConstructorCallSite callSite, object? context) { ParameterInfo[] parameters = callSite.ConstructorInfo.GetParameters(); Expression[] parameterExpressions; @@ -164,7 +164,7 @@ protected override Expression VisitConstructor(ConstructorCallSite callSite, obj } Expression expression = Expression.New(callSite.ConstructorInfo, parameterExpressions); - if (callSite.ImplementationType.IsValueType) + if (callSite.ImplementationType!.IsValueType) { expression = Expression.Convert(expression, typeof(object)); } @@ -183,7 +183,7 @@ private static Expression Convert(Expression expression, Type type, bool forceVa return Expression.Convert(expression, type); } - protected override Expression VisitScopeCache(ServiceCallSite callSite, object context) + protected override Expression VisitScopeCache(ServiceCallSite callSite, object? context) { Func lambda = Build(callSite); return Expression.Invoke(Expression.Constant(lambda), ScopeParameter); @@ -260,7 +260,7 @@ private Expression BuildScopedExpression(ServiceCallSite callSite) Expression.Property( ScopeParameter, typeof(ServiceProviderEngineScope) - .GetProperty(nameof(ServiceProviderEngineScope.IsRootScope), BindingFlags.Instance | BindingFlags.Public)), + .GetProperty(nameof(ServiceProviderEngineScope.IsRootScope), BindingFlags.Instance | BindingFlags.Public)!), resolveRootScopeExpression, Expression.Block( typeof(object), diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/FactoryCallSite.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/FactoryCallSite.cs index 59e5267974ac5..3386987b077e7 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/FactoryCallSite.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/FactoryCallSite.cs @@ -16,7 +16,7 @@ public FactoryCallSite(ResultCache cache, Type serviceType, Func null; + public override Type? ImplementationType => null; public override CallSiteKind Kind { get; } = CallSiteKind.Factory; } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs index e5370ca652957..e46e459ce9d50 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs @@ -4,43 +4,44 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { - internal sealed class ILEmitResolverBuilder : CallSiteVisitor + internal sealed class ILEmitResolverBuilder : CallSiteVisitor { private static readonly MethodInfo ResolvedServicesGetter = typeof(ServiceProviderEngineScope).GetProperty( - nameof(ServiceProviderEngineScope.ResolvedServices), BindingFlags.Instance | BindingFlags.NonPublic).GetMethod; + nameof(ServiceProviderEngineScope.ResolvedServices), BindingFlags.Instance | BindingFlags.NonPublic)!.GetMethod!; private static readonly MethodInfo ScopeLockGetter = typeof(ServiceProviderEngineScope).GetProperty( - nameof(ServiceProviderEngineScope.Sync), BindingFlags.Instance | BindingFlags.NonPublic).GetMethod; + nameof(ServiceProviderEngineScope.Sync), BindingFlags.Instance | BindingFlags.NonPublic)!.GetMethod!; private static readonly MethodInfo ScopeIsRootScope = typeof(ServiceProviderEngineScope).GetProperty( - nameof(ServiceProviderEngineScope.IsRootScope), BindingFlags.Instance | BindingFlags.Public).GetMethod; + nameof(ServiceProviderEngineScope.IsRootScope), BindingFlags.Instance | BindingFlags.Public)!.GetMethod!; private static readonly MethodInfo CallSiteRuntimeResolverResolveMethod = typeof(CallSiteRuntimeResolver).GetMethod( - nameof(CallSiteRuntimeResolver.Resolve), BindingFlags.Public | BindingFlags.Instance); + nameof(CallSiteRuntimeResolver.Resolve), BindingFlags.Public | BindingFlags.Instance)!; private static readonly MethodInfo CallSiteRuntimeResolverInstanceField = typeof(CallSiteRuntimeResolver).GetProperty( - nameof(CallSiteRuntimeResolver.Instance), BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance).GetMethod; + nameof(CallSiteRuntimeResolver.Instance), BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance)!.GetMethod!; - private static readonly FieldInfo FactoriesField = typeof(ILEmitResolverBuilderRuntimeContext).GetField(nameof(ILEmitResolverBuilderRuntimeContext.Factories)); - private static readonly FieldInfo ConstantsField = typeof(ILEmitResolverBuilderRuntimeContext).GetField(nameof(ILEmitResolverBuilderRuntimeContext.Constants)); - private static readonly MethodInfo GetTypeFromHandleMethod = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)); + private static readonly FieldInfo FactoriesField = typeof(ILEmitResolverBuilderRuntimeContext).GetField(nameof(ILEmitResolverBuilderRuntimeContext.Factories))!; + private static readonly FieldInfo ConstantsField = typeof(ILEmitResolverBuilderRuntimeContext).GetField(nameof(ILEmitResolverBuilderRuntimeContext.Constants))!; + private static readonly MethodInfo GetTypeFromHandleMethod = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle))!; private static readonly ConstructorInfo CacheKeyCtor = typeof(ServiceCacheKey).GetConstructors()[0]; private sealed class ILEmitResolverBuilderRuntimeContext { - public object[] Constants; - public Func[] Factories; + public object?[]? Constants; + public Func[]? Factories; } private struct GeneratedMethod { - public Func Lambda; + public Func Lambda; public ILEmitResolverBuilderRuntimeContext Context; public DynamicMethod DynamicMethod; @@ -59,7 +60,7 @@ public ILEmitResolverBuilder(ServiceProvider serviceProvider) _buildTypeDelegate = (key, cs) => BuildTypeNoCache(cs); } - public Func Build(ServiceCallSite callSite) + public Func Build(ServiceCallSite callSite) { return BuildType(callSite).Lambda; } @@ -117,14 +118,14 @@ private GeneratedMethod BuildTypeNoCache(ServiceCallSite callSite) return new GeneratedMethod() { - Lambda = (Func)dynamicMethod.CreateDelegate(typeof(Func), runtimeContext), + Lambda = (Func)dynamicMethod.CreateDelegate(typeof(Func), runtimeContext), Context = runtimeContext, DynamicMethod = dynamicMethod }; } - protected override object VisitDisposeCache(ServiceCallSite transientCallSite, ILEmitResolverBuilderContext argument) + protected override object? VisitDisposeCache(ServiceCallSite transientCallSite, ILEmitResolverBuilderContext argument) { if (transientCallSite.CaptureDisposable) { @@ -139,7 +140,7 @@ protected override object VisitDisposeCache(ServiceCallSite transientCallSite, I return null; } - protected override object VisitConstructor(ConstructorCallSite constructorCallSite, ILEmitResolverBuilderContext argument) + protected override object? VisitConstructor(ConstructorCallSite constructorCallSite, ILEmitResolverBuilderContext argument) { // new T([create arguments]) foreach (ServiceCallSite parameterCallSite in constructorCallSite.ParameterCallSites) @@ -152,7 +153,7 @@ protected override object VisitConstructor(ConstructorCallSite constructorCallSi } argument.Generator.Emit(OpCodes.Newobj, constructorCallSite.ConstructorInfo); - if (constructorCallSite.ImplementationType.IsValueType) + if (constructorCallSite.ImplementationType!.IsValueType) { argument.Generator.Emit(OpCodes.Box, constructorCallSite.ImplementationType); } @@ -160,13 +161,13 @@ protected override object VisitConstructor(ConstructorCallSite constructorCallSi return null; } - protected override object VisitRootCache(ServiceCallSite callSite, ILEmitResolverBuilderContext argument) + protected override object? VisitRootCache(ServiceCallSite callSite, ILEmitResolverBuilderContext argument) { AddConstant(argument, CallSiteRuntimeResolver.Instance.Resolve(callSite, _rootScope)); return null; } - protected override object VisitScopeCache(ServiceCallSite scopedCallSite, ILEmitResolverBuilderContext argument) + protected override object? VisitScopeCache(ServiceCallSite scopedCallSite, ILEmitResolverBuilderContext argument) { GeneratedMethod generatedMethod = BuildType(scopedCallSite); @@ -186,20 +187,20 @@ protected override object VisitScopeCache(ServiceCallSite scopedCallSite, ILEmit return null; } - protected override object VisitConstant(ConstantCallSite constantCallSite, ILEmitResolverBuilderContext argument) + protected override object? VisitConstant(ConstantCallSite constantCallSite, ILEmitResolverBuilderContext argument) { AddConstant(argument, constantCallSite.DefaultValue); return null; } - protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, ILEmitResolverBuilderContext argument) + protected override object? VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, ILEmitResolverBuilderContext argument) { // [return] ProviderScope argument.Generator.Emit(OpCodes.Ldarg_1); return null; } - protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, ILEmitResolverBuilderContext argument) + protected override object? VisitIEnumerable(IEnumerableCallSite enumerableCallSite, ILEmitResolverBuilderContext argument) { if (enumerableCallSite.ServiceCallSites.Length == 0) { @@ -235,7 +236,7 @@ protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSit return null; } - protected override object VisitFactory(FactoryCallSite factoryCallSite, ILEmitResolverBuilderContext argument) + protected override object? VisitFactory(FactoryCallSite factoryCallSite, ILEmitResolverBuilderContext argument) { if (argument.Factories == null) { @@ -256,11 +257,11 @@ protected override object VisitFactory(FactoryCallSite factoryCallSite, ILEmitRe return null; } - private void AddConstant(ILEmitResolverBuilderContext argument, object value) + private void AddConstant(ILEmitResolverBuilderContext argument, object? value) { if (argument.Constants == null) { - argument.Constants = new List(); + argument.Constants = new List(); } // this.Constants[i] @@ -274,6 +275,8 @@ private void AddConstant(ILEmitResolverBuilderContext argument, object value) private void AddCacheKey(ILEmitResolverBuilderContext argument, ServiceCacheKey key) { + Debug.Assert(key.Type != null); + // new ServiceCacheKey(typeof(key.Type), key.Slot) argument.Generator.Emit(OpCodes.Ldtoken, key.Type); argument.Generator.Emit(OpCodes.Call, GetTypeFromHandleMethod); @@ -283,9 +286,8 @@ private void AddCacheKey(ILEmitResolverBuilderContext argument, ServiceCacheKey private ILEmitResolverBuilderRuntimeContext GenerateMethodBody(ServiceCallSite callSite, ILGenerator generator) { - var context = new ILEmitResolverBuilderContext() + var context = new ILEmitResolverBuilderContext(generator) { - Generator = generator, Constants = null, Factories = null }; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilderContext.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilderContext.cs index 33cde16bb0091..f32d60fe12f32 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilderContext.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilderContext.cs @@ -9,8 +9,9 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { internal sealed class ILEmitResolverBuilderContext { - public ILGenerator Generator { get; set; } - public List Constants { get; set; } - public List> Factories { get; set; } + public ILEmitResolverBuilderContext(ILGenerator generator) => Generator = generator; + public ILGenerator Generator { get; } + public List? Constants { get; set; } + public List>? Factories { get; set; } } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitServiceProviderEngine.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitServiceProviderEngine.cs index f0bcebf5df782..5facb1a8ab95d 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitServiceProviderEngine.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitServiceProviderEngine.cs @@ -13,7 +13,7 @@ public ILEmitServiceProviderEngine(ServiceProvider serviceProvider) _expressionResolverBuilder = new ILEmitResolverBuilder(serviceProvider); } - public override Func RealizeService(ServiceCallSite callSite) + public override Func RealizeService(ServiceCallSite callSite) { return _expressionResolverBuilder.Build(callSite); } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ResultCache.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ResultCache.cs index 4a87b7be3675f..65b1c799b6f3a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ResultCache.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ResultCache.cs @@ -16,7 +16,7 @@ internal ResultCache(CallSiteResultCacheLocation lifetime, ServiceCacheKey cache Key = cacheKey; } - public ResultCache(ServiceLifetime lifetime, Type type, int slot) + public ResultCache(ServiceLifetime lifetime, Type? type, int slot) { Debug.Assert(lifetime == ServiceLifetime.Transient || type != null); diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/RuntimeServiceProviderEngine.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/RuntimeServiceProviderEngine.cs index c656092efff96..52c1afbafcbd0 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/RuntimeServiceProviderEngine.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/RuntimeServiceProviderEngine.cs @@ -11,7 +11,7 @@ internal sealed class RuntimeServiceProviderEngine : ServiceProviderEngine private RuntimeServiceProviderEngine() { } - public override Func RealizeService(ServiceCallSite callSite) + public override Func RealizeService(ServiceCallSite callSite) { return scope => { diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCacheKey.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCacheKey.cs index e1f7cd2bae3a4..8f812ae45e6a8 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCacheKey.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCacheKey.cs @@ -12,7 +12,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup /// /// Type of service being cached /// - public Type Type { get; } + public Type? Type { get; } /// /// Reverse index of the service when resolved in IEnumerable<Type> where default instance gets slot 0. @@ -27,7 +27,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup /// public int Slot { get; } - public ServiceCacheKey(Type type, int slot) + public ServiceCacheKey(Type? type, int slot) { Type = type; Slot = slot; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCallSite.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCallSite.cs index 626ecce4f2548..1ede82e09c914 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCallSite.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCallSite.cs @@ -16,10 +16,10 @@ protected ServiceCallSite(ResultCache cache) } public abstract Type ServiceType { get; } - public abstract Type ImplementationType { get; } + public abstract Type? ImplementationType { get; } public abstract CallSiteKind Kind { get; } public ResultCache Cache { get; } - public object Value { get; set; } + public object? Value { get; set; } public bool CaptureDisposable => ImplementationType == null || diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceLookupHelpers.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceLookupHelpers.cs index c17b501ef4b78..d41f9cb7cec4f 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceLookupHelpers.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceLookupHelpers.cs @@ -12,27 +12,27 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup internal static class ServiceLookupHelpers { private const BindingFlags LookupFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - private static readonly MethodInfo ArrayEmptyMethodInfo = typeof(Array).GetMethod(nameof(Array.Empty)); + private static readonly MethodInfo ArrayEmptyMethodInfo = typeof(Array).GetMethod(nameof(Array.Empty))!; internal static readonly MethodInfo InvokeFactoryMethodInfo = typeof(Func) - .GetMethod(nameof(Func.Invoke), LookupFlags); + .GetMethod(nameof(Func.Invoke), LookupFlags)!; internal static readonly MethodInfo CaptureDisposableMethodInfo = typeof(ServiceProviderEngineScope) - .GetMethod(nameof(ServiceProviderEngineScope.CaptureDisposable), LookupFlags); + .GetMethod(nameof(ServiceProviderEngineScope.CaptureDisposable), LookupFlags)!; internal static readonly MethodInfo TryGetValueMethodInfo = typeof(IDictionary) - .GetMethod(nameof(IDictionary.TryGetValue), LookupFlags); + .GetMethod(nameof(IDictionary.TryGetValue), LookupFlags)!; internal static readonly MethodInfo ResolveCallSiteAndScopeMethodInfo = typeof(CallSiteRuntimeResolver) - .GetMethod(nameof(CallSiteRuntimeResolver.Resolve), LookupFlags); + .GetMethod(nameof(CallSiteRuntimeResolver.Resolve), LookupFlags)!; internal static readonly MethodInfo AddMethodInfo = typeof(IDictionary) - .GetMethod(nameof(IDictionary.Add), LookupFlags); + .GetMethod(nameof(IDictionary.Add), LookupFlags)!; internal static readonly MethodInfo MonitorEnterMethodInfo = typeof(Monitor) - .GetMethod(nameof(Monitor.Enter), BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(object), typeof(bool).MakeByRefType() }, null); + .GetMethod(nameof(Monitor.Enter), BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(object), typeof(bool).MakeByRefType() }, null)!; internal static readonly MethodInfo MonitorExitMethodInfo = typeof(Monitor) - .GetMethod(nameof(Monitor.Exit), BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(object) }, null); + .GetMethod(nameof(Monitor.Exit), BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(object) }, null)!; [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod", Justification = "Calling Array.Empty() is safe since the T doesn't have trimming annotations.")] diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngine.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngine.cs index 77cd2533759d9..978170fa995e2 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngine.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngine.cs @@ -7,6 +7,6 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { internal abstract class ServiceProviderEngine { - public abstract Func RealizeService(ServiceCallSite callSite); + public abstract Func RealizeService(ServiceCallSite callSite); } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs index 4ad8b1579a029..7f4598fecfc5e 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.Extensions.Internal; @@ -14,16 +15,16 @@ internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvid internal IList Disposables => _disposables ?? (IList)Array.Empty(); private bool _disposed; - private List _disposables; + private List? _disposables; public ServiceProviderEngineScope(ServiceProvider provider, bool isRootScope) { - ResolvedServices = new Dictionary(); + ResolvedServices = new Dictionary(); RootProvider = provider; IsRootScope = isRootScope; } - internal Dictionary ResolvedServices { get; } + internal Dictionary ResolvedServices { get; } // This lock protects state on the scope, in particular, for the root scope, it protects // the list of disposable entries only, since ResolvedServices are cached on CallSites @@ -34,7 +35,7 @@ public ServiceProviderEngineScope(ServiceProvider provider, bool isRootScope) internal ServiceProvider RootProvider { get; } - public object GetService(Type serviceType) + public object? GetService(Type serviceType) { if (_disposed) { @@ -48,7 +49,8 @@ public object GetService(Type serviceType) public IServiceScope CreateScope() => RootProvider.CreateScope(); - internal object CaptureDisposable(object service) + [return: NotNullIfNotNull("service")] + internal object? CaptureDisposable(object? service) { if (ReferenceEquals(this, service) || !(service is IDisposable || service is IAsyncDisposable)) { @@ -91,7 +93,7 @@ internal object CaptureDisposable(object service) public void Dispose() { - List toDispose = BeginDispose(); + List? toDispose = BeginDispose(); if (toDispose != null) { @@ -111,7 +113,7 @@ public void Dispose() public ValueTask DisposeAsync() { - List toDispose = BeginDispose(); + List? toDispose = BeginDispose(); if (toDispose != null) { @@ -168,7 +170,7 @@ static async ValueTask Await(int i, ValueTask vt, List toDispose) } } - private List BeginDispose() + private List? BeginDispose() { lock (Sync) { diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/StackGuard.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/StackGuard.cs index a11c36192529b..fe58ab651bf97 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/StackGuard.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/StackGuard.cs @@ -65,7 +65,7 @@ private R RunOnEmptyStackCore(Func action, object state) try { // Using default scheduler rather than picking up the current scheduler. - Task task = Task.Factory.StartNew(action, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + Task task = Task.Factory.StartNew((Func)action, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // Avoid AsyncWaitHandle lazy allocation of ManualResetEvent in the rare case we finish quickly. if (!task.IsCompleted) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ThrowHelper.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ThrowHelper.cs index 9ed91ff5148c4..ffacbf9bbc052 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ThrowHelper.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ThrowHelper.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { internal static class ThrowHelper { + [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] internal static void ThrowObjectDisposedException() { diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs index db1c1e72e9349..1b22c43223519 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs @@ -15,16 +15,16 @@ namespace Microsoft.Extensions.DependencyInjection /// public sealed class ServiceProvider : IServiceProvider, IDisposable, IAsyncDisposable { - private readonly CallSiteValidator _callSiteValidator; + private readonly CallSiteValidator? _callSiteValidator; - private readonly Func> _createServiceAccessor; + private readonly Func> _createServiceAccessor; // Internal for testing internal ServiceProviderEngine _engine; private bool _disposed; - private ConcurrentDictionary> _realizedServices; + private ConcurrentDictionary> _realizedServices; internal CallSiteFactory CallSiteFactory { get; } @@ -39,7 +39,7 @@ internal ServiceProvider(ICollection serviceDescriptors, Serv Root = new ServiceProviderEngineScope(this, isRootScope: true); _engine = GetEngine(); _createServiceAccessor = CreateServiceAccessor; - _realizedServices = new ConcurrentDictionary>(); + _realizedServices = new ConcurrentDictionary>(); CallSiteFactory = new CallSiteFactory(serviceDescriptors); // The list of built in services that aren't part of the list of service descriptors @@ -55,7 +55,7 @@ internal ServiceProvider(ICollection serviceDescriptors, Serv if (options.ValidateOnBuild) { - List exceptions = null; + List? exceptions = null; foreach (ServiceDescriptor serviceDescriptor in serviceDescriptors) { try @@ -83,7 +83,7 @@ internal ServiceProvider(ICollection serviceDescriptors, Serv /// /// The type of the service to get. /// The service that was produced. - public object GetService(Type serviceType) => GetService(serviceType, Root); + public object? GetService(Type serviceType) => GetService(serviceType, Root); /// public void Dispose() @@ -115,14 +115,14 @@ private void OnResolve(Type serviceType, IServiceScope scope) _callSiteValidator?.ValidateResolution(serviceType, scope, Root); } - internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) + internal object? GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) { if (_disposed) { ThrowHelper.ThrowObjectDisposedException(); } - Func realizedService = _realizedServices.GetOrAdd(serviceType, _createServiceAccessor); + Func realizedService = _realizedServices.GetOrAdd(serviceType, _createServiceAccessor); OnResolve(serviceType, serviceProviderEngineScope); DependencyInjectionEventSource.Log.ServiceResolved(this, serviceType); var result = realizedService.Invoke(serviceProviderEngineScope); @@ -139,7 +139,7 @@ private void ValidateService(ServiceDescriptor descriptor) try { - ServiceCallSite callSite = CallSiteFactory.GetCallSite(descriptor, new CallSiteChain()); + ServiceCallSite? callSite = CallSiteFactory.GetCallSite(descriptor, new CallSiteChain()); if (callSite != null) { OnCreate(callSite); @@ -151,9 +151,9 @@ private void ValidateService(ServiceDescriptor descriptor) } } - private Func CreateServiceAccessor(Type serviceType) + private Func CreateServiceAccessor(Type serviceType) { - ServiceCallSite callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain()); + ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain()); if (callSite != null) { DependencyInjectionEventSource.Log.CallSiteBuilt(this, serviceType, callSite); @@ -162,7 +162,7 @@ private Func CreateServiceAccessor(Type serv // Optimize singleton case if (callSite.Cache.Location == CallSiteResultCacheLocation.Root) { - object value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root); + object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root); return scope => value; } @@ -172,7 +172,7 @@ private Func CreateServiceAccessor(Type serv return _ => null; } - internal void ReplaceServiceAccessor(ServiceCallSite callSite, Func accessor) + internal void ReplaceServiceAccessor(ServiceCallSite callSite, Func accessor) { _realizedServices[callSite.ServiceType] = accessor; } From 9ae8fa16e099621e5d4fc6d20f3dd46542d3b225 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 22 Jan 2022 01:10:23 +0200 Subject: [PATCH 134/308] Enable nullable annotations for Microsoft.Extensions.Configuration.UserSecrets (#63700) --- .../Microsoft.Extensions.Configuration.UserSecrets.csproj | 1 + .../Microsoft.Extensions.Configuration.UserSecrets.csproj | 1 + .../src/PathHelper.cs | 4 ++-- .../src/UserSecretsConfigurationExtensions.cs | 6 +++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/ref/Microsoft.Extensions.Configuration.UserSecrets.csproj b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/ref/Microsoft.Extensions.Configuration.UserSecrets.csproj index 32f367d46a125..db24c060dc924 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/ref/Microsoft.Extensions.Configuration.UserSecrets.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/ref/Microsoft.Extensions.Configuration.UserSecrets.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) + enable diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/Microsoft.Extensions.Configuration.UserSecrets.csproj b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/Microsoft.Extensions.Configuration.UserSecrets.csproj index d3b36b403a0b7..880f1a2d35f6d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/Microsoft.Extensions.Configuration.UserSecrets.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/Microsoft.Extensions.Configuration.UserSecrets.csproj @@ -2,6 +2,7 @@ $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) + enable true false diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PathHelper.cs b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PathHelper.cs index 3bf8ab8c9cafb..e22840114fd53 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PathHelper.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PathHelper.cs @@ -43,8 +43,8 @@ public static string GetSecretsPathFromSecretsId(string userSecretsId) const string userSecretsFallbackDir = "DOTNET_USER_SECRETS_FALLBACK_DIR"; // For backwards compat, this checks env vars first before using Env.GetFolderPath - string appData = Environment.GetEnvironmentVariable("APPDATA"); - string root = appData // On Windows it goes to %APPDATA%\Microsoft\UserSecrets\ + string? appData = Environment.GetEnvironmentVariable("APPDATA"); + string? root = appData // On Windows it goes to %APPDATA%\Microsoft\UserSecrets\ ?? Environment.GetEnvironmentVariable("HOME") // On Mac/Linux it goes to ~/.microsoft/usersecrets/ ?? Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs index 963ac77a30eea..0b683da9140fa 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs @@ -128,7 +128,7 @@ public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder co throw new ArgumentNullException(nameof(assembly)); } - UserSecretsIdAttribute attribute = assembly.GetCustomAttribute(); + UserSecretsIdAttribute? attribute = assembly.GetCustomAttribute(); if (attribute != null) { return AddUserSecretsInternal(configuration, attribute.UserSecretsId, optional, reloadOnChange); @@ -188,8 +188,8 @@ private static IConfigurationBuilder AddUserSecretsInternal(IConfigurationBuilde private static IConfigurationBuilder AddSecretsFile(IConfigurationBuilder configuration, string secretPath, bool optional, bool reloadOnChange) { - string directoryPath = Path.GetDirectoryName(secretPath); - PhysicalFileProvider fileProvider = Directory.Exists(directoryPath) + string? directoryPath = Path.GetDirectoryName(secretPath); + PhysicalFileProvider? fileProvider = Directory.Exists(directoryPath) ? new PhysicalFileProvider(directoryPath) : null; return configuration.AddJsonFile(fileProvider, PathHelper.SecretsFileName, optional, reloadOnChange); From 4b8bb2d48dd362a8e5f48987f366ed01321cac14 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Fri, 21 Jan 2022 18:10:37 -0500 Subject: [PATCH 135/308] [mono] Cleanup trailing whitespace. (#64112) --- src/mono/mono/arch/amd64/amd64-codegen.h | 10 +- src/mono/mono/arch/arm/arm-codegen.h | 2 +- src/mono/mono/arch/arm/arm-wmmx.h | 2 +- src/mono/mono/arch/mips/test.c | 2 +- src/mono/mono/arch/ppc/ppc-codegen.h | 24 +- src/mono/mono/arch/s390x/s390x-codegen.h | 48 +- src/mono/mono/arch/s390x/tramp.c | 104 +-- src/mono/mono/arch/sparc/sparc-codegen.h | 10 +- src/mono/mono/arch/sparc/test.c | 4 +- src/mono/mono/arch/x86/x86-codegen.h | 42 +- src/mono/mono/component/debugger-agent.h | 16 +- src/mono/mono/component/debugger-engine.c | 8 +- src/mono/mono/component/debugger-engine.h | 8 +- .../mono/component/debugger-mono-compat.h | 2 +- src/mono/mono/component/debugger-protocol.c | 4 +- src/mono/mono/component/debugger-protocol.h | 2 +- .../mono/component/debugger-state-machine.h | 2 +- src/mono/mono/component/debugger-stub.c | 14 +- src/mono/mono/component/debugger.c | 4 +- src/mono/mono/component/hot_reload.c | 16 +- src/mono/mono/component/mini-wasm-debugger.c | 16 +- src/mono/mono/eglib/garray.c | 14 +- src/mono/mono/eglib/gdir-unix.c | 10 +- src/mono/mono/eglib/gdir-win32.c | 2 +- src/mono/mono/eglib/gerror.c | 10 +- src/mono/mono/eglib/gfile-win32.c | 4 +- src/mono/mono/eglib/gfile.c | 18 +- src/mono/mono/eglib/glist.c | 10 +- src/mono/mono/eglib/gmarkup.c | 48 +- src/mono/mono/eglib/gmem.c | 18 +- src/mono/mono/eglib/gmisc-unix.c | 6 +- src/mono/mono/eglib/gmisc-win32.c | 10 +- src/mono/mono/eglib/gmodule-unix.c | 18 +- src/mono/mono/eglib/goutput.c | 4 +- src/mono/mono/eglib/gpath.c | 46 +- src/mono/mono/eglib/gpattern.c | 2 +- src/mono/mono/eglib/gptrarray.c | 12 +- src/mono/mono/eglib/gqsort.c | 40 +- src/mono/mono/eglib/gqueue.c | 14 +- src/mono/mono/eglib/gshell.c | 20 +- src/mono/mono/eglib/gslist.c | 20 +- src/mono/mono/eglib/gspawn.c | 18 +- src/mono/mono/eglib/gstr.c | 94 +- src/mono/mono/eglib/gstring.c | 22 +- src/mono/mono/eglib/gunicode-win32.c | 2 +- src/mono/mono/eglib/gutf8.c | 74 +- src/mono/mono/eglib/sort.frag.h | 4 +- src/mono/mono/eglib/test/array.c | 4 +- src/mono/mono/eglib/test/assertf.c | 2 +- src/mono/mono/eglib/test/endian.c | 6 +- src/mono/mono/eglib/test/fake.c | 2 +- src/mono/mono/eglib/test/hashtable.c | 12 +- src/mono/mono/eglib/test/list.c | 36 +- src/mono/mono/eglib/test/markup.c | 16 +- src/mono/mono/eglib/test/path.c | 22 +- src/mono/mono/eglib/test/ptrarray.c | 48 +- src/mono/mono/eglib/test/queue.c | 4 +- src/mono/mono/eglib/test/shell.c | 8 +- src/mono/mono/eglib/test/sizes.c | 8 +- src/mono/mono/eglib/test/slist.c | 22 +- src/mono/mono/eglib/test/string-util.c | 78 +- src/mono/mono/eglib/test/string.c | 32 +- src/mono/mono/eglib/test/test.c | 36 +- src/mono/mono/eglib/test/test.h | 6 +- src/mono/mono/eglib/test/tests.h | 6 +- src/mono/mono/eventpipe/ep-rt-mono.c | 14 +- .../eventpipe/test/ep-fastserializer-tests.c | 2 +- src/mono/mono/metadata/appdomain.c | 20 +- .../mono/metadata/assembly-load-context.c | 6 +- src/mono/mono/metadata/assembly.h | 14 +- src/mono/mono/metadata/attrdefs.h | 6 +- src/mono/mono/metadata/boehm-gc.c | 24 +- src/mono/mono/metadata/cil-coff.h | 2 +- src/mono/mono/metadata/class-accessors.c | 4 +- src/mono/mono/metadata/class-getters.h | 4 +- src/mono/mono/metadata/class-init.c | 84 +- src/mono/mono/metadata/class-internals.h | 16 +- .../mono/metadata/class-private-definition.h | 18 +- src/mono/mono/metadata/class-setup-vtable.c | 76 +- src/mono/mono/metadata/class.h | 4 +- src/mono/mono/metadata/cominterop.c | 114 +-- src/mono/mono/metadata/cominterop.h | 12 +- src/mono/mono/metadata/coree.c | 2 +- src/mono/mono/metadata/debug-helpers.c | 16 +- src/mono/mono/metadata/debug-mono-ppdb.h | 4 +- src/mono/mono/metadata/debug-mono-symfile.c | 8 +- src/mono/mono/metadata/domain-internals.h | 4 +- src/mono/mono/metadata/dynamic-image.c | 18 +- src/mono/mono/metadata/dynamic-stream.c | 12 +- src/mono/mono/metadata/exception.c | 12 +- src/mono/mono/metadata/exception.h | 8 +- src/mono/mono/metadata/external-only.c | 6 +- src/mono/mono/metadata/gc-internals.h | 18 +- src/mono/mono/metadata/gc.c | 26 +- src/mono/mono/metadata/handle.c | 4 +- src/mono/mono/metadata/handle.h | 2 +- src/mono/mono/metadata/image.c | 104 +-- src/mono/mono/metadata/image.h | 4 +- src/mono/mono/metadata/jit-info.c | 2 +- src/mono/mono/metadata/jit-info.h | 4 +- src/mono/mono/metadata/loaded-images.c | 2 +- src/mono/mono/metadata/loader.c | 48 +- src/mono/mono/metadata/loader.h | 2 +- src/mono/mono/metadata/lock-tracer.c | 6 +- src/mono/mono/metadata/marshal-ilgen.c | 392 ++++---- src/mono/mono/metadata/marshal.c | 4 +- src/mono/mono/metadata/marshal.h | 18 +- src/mono/mono/metadata/mempool-internals.h | 4 +- src/mono/mono/metadata/mempool.c | 2 +- src/mono/mono/metadata/metadata-internals.h | 28 +- src/mono/mono/metadata/metadata-update.c | 2 +- src/mono/mono/metadata/metadata.c | 2 +- src/mono/mono/metadata/method-builder-ilgen.c | 4 +- src/mono/mono/metadata/method-builder.c | 6 +- src/mono/mono/metadata/method-builder.h | 2 +- src/mono/mono/metadata/monitor.c | 28 +- src/mono/mono/metadata/mono-basic-block.c | 10 +- src/mono/mono/metadata/mono-conc-hash.c | 8 +- .../mono/metadata/mono-config-internals.h | 2 +- src/mono/mono/metadata/mono-config.c | 2 +- src/mono/mono/metadata/mono-debug.c | 6 +- src/mono/mono/metadata/mono-endian.c | 6 +- src/mono/mono/metadata/mono-hash-internals.h | 2 +- .../mono/metadata/mono-private-unstable.h | 2 +- src/mono/mono/metadata/native-library.c | 12 +- src/mono/mono/metadata/null-gc-handles.c | 14 +- src/mono/mono/metadata/null-gc.c | 2 +- src/mono/mono/metadata/object-internals.h | 34 +- src/mono/mono/metadata/object.h | 8 +- src/mono/mono/metadata/property-bag.c | 2 +- src/mono/mono/metadata/reflection.c | 70 +- src/mono/mono/metadata/reflection.h | 2 +- src/mono/mono/metadata/row-indexes.h | 2 +- src/mono/mono/metadata/runtime.c | 2 +- src/mono/mono/metadata/seq-points-data.c | 2 +- src/mono/mono/metadata/seq-points-data.h | 4 +- src/mono/mono/metadata/sgen-bridge.h | 4 +- src/mono/mono/metadata/sgen-client-mono.h | 2 +- src/mono/mono/metadata/sgen-mono-ilgen.c | 4 +- src/mono/mono/metadata/sgen-old-bridge.c | 6 +- src/mono/mono/metadata/sgen-tarjan-bridge.c | 2 +- src/mono/mono/metadata/sgen-toggleref.h | 2 +- src/mono/mono/metadata/sre-encode.c | 12 +- src/mono/mono/metadata/sre-internals.h | 2 +- src/mono/mono/metadata/sre.c | 98 +- src/mono/mono/metadata/tabledefs.h | 6 +- src/mono/mono/metadata/tokentype.h | 4 +- src/mono/mono/metadata/verify.h | 2 +- src/mono/mono/metadata/w32file-unix.c | 56 +- src/mono/mono/metadata/w32handle.h | 2 +- src/mono/mono/mini/abcremoval.c | 94 +- src/mono/mono/mini/abcremoval.h | 4 +- src/mono/mono/mini/alias-analysis.c | 10 +- src/mono/mono/mini/aot-runtime.c | 94 +- src/mono/mono/mini/arch-stubs.c | 2 +- src/mono/mono/mini/branch-opts.c | 122 +-- src/mono/mono/mini/calls.c | 20 +- src/mono/mono/mini/cfold.c | 18 +- src/mono/mono/mini/debug-mini.c | 20 +- src/mono/mono/mini/debugger-agent-external.c | 2 +- src/mono/mono/mini/decompose.c | 42 +- src/mono/mono/mini/dominators.c | 34 +- src/mono/mono/mini/exceptions-arm.c | 54 +- src/mono/mono/mini/exceptions-arm64.c | 16 +- src/mono/mono/mini/exceptions-mips.c | 48 +- src/mono/mono/mini/exceptions-ppc.c | 124 +-- src/mono/mono/mini/exceptions-s390x.c | 50 +- src/mono/mono/mini/exceptions-sparc.c | 34 +- src/mono/mono/mini/exceptions-wasm.c | 4 +- src/mono/mono/mini/exceptions-x86.c | 58 +- src/mono/mono/mini/graph.c | 24 +- src/mono/mono/mini/helpers.c | 18 +- src/mono/mono/mini/interp/interp-internals.h | 4 +- src/mono/mono/mini/intrinsics.c | 38 +- src/mono/mono/mini/ir-emit.h | 20 +- src/mono/mono/mini/jit.h | 10 +- src/mono/mono/mini/liveness.c | 76 +- src/mono/mono/mini/llvm-runtime.h | 2 +- src/mono/mono/mini/llvmonly-runtime.c | 4 +- src/mono/mono/mini/local-propagation.c | 38 +- src/mono/mono/mini/main-core.c | 8 +- src/mono/mono/mini/main.c | 10 +- src/mono/mono/mini/memory-access.c | 4 +- src/mono/mono/mini/method-to-ir.c | 292 +++--- src/mono/mono/mini/mini-amd64-gsharedvt.c | 4 +- src/mono/mono/mini/mini-amd64.c | 196 ++-- src/mono/mono/mini/mini-arch.h | 2 +- src/mono/mono/mini/mini-arm.c | 152 ++-- src/mono/mono/mini/mini-arm.h | 4 +- src/mono/mono/mini/mini-arm64.c | 24 +- src/mono/mono/mini/mini-arm64.h | 2 +- src/mono/mono/mini/mini-codegen.c | 122 +-- src/mono/mono/mini/mini-cross-helpers.c | 2 +- src/mono/mono/mini/mini-exceptions.c | 50 +- src/mono/mono/mini/mini-gc.c | 42 +- src/mono/mono/mini/mini-llvm-cpp.h | 12 +- src/mono/mono/mini/mini-mips.c | 104 +-- src/mono/mono/mini/mini-mips.h | 4 +- src/mono/mono/mini/mini-ops.h | 6 +- src/mono/mono/mini/mini-posix.c | 12 +- src/mono/mono/mini/mini-ppc.c | 162 ++-- src/mono/mono/mini/mini-ppc.h | 6 +- src/mono/mono/mini/mini-profiler.c | 2 +- src/mono/mono/mini/mini-runtime.c | 26 +- src/mono/mono/mini/mini-runtime.h | 4 +- src/mono/mono/mini/mini-s390x.c | 838 +++++++++--------- src/mono/mono/mini/mini-s390x.h | 6 +- src/mono/mono/mini/mini-sparc.c | 172 ++-- src/mono/mono/mini/mini-sparc.h | 4 +- src/mono/mono/mini/mini-trampolines.c | 28 +- src/mono/mono/mini/mini-unwind.h | 6 +- src/mono/mono/mini/mini-wasm.c | 4 +- src/mono/mono/mini/mini-wasm.h | 4 +- src/mono/mono/mini/mini-x86-gsharedvt.c | 2 +- src/mono/mono/mini/mini-x86.c | 230 ++--- src/mono/mono/mini/mini.c | 94 +- src/mono/mono/mini/mini.h | 78 +- src/mono/mono/mini/mono-private-unstable.h | 4 +- src/mono/mono/mini/monovm.c | 8 +- src/mono/mono/mini/regalloc.h | 4 +- src/mono/mono/mini/seq-points.c | 6 +- src/mono/mono/mini/seq-points.h | 2 +- src/mono/mono/mini/ssa.c | 60 +- src/mono/mono/mini/trace.h | 4 +- src/mono/mono/mini/tramp-amd64-gsharedvt.c | 4 +- src/mono/mono/mini/tramp-amd64.c | 12 +- src/mono/mono/mini/tramp-arm.c | 16 +- src/mono/mono/mini/tramp-arm64.c | 4 +- src/mono/mono/mini/tramp-mips.c | 12 +- src/mono/mono/mini/tramp-ppc.c | 18 +- src/mono/mono/mini/tramp-s390x.c | 164 ++-- src/mono/mono/mini/tramp-sparc.c | 8 +- src/mono/mono/mini/tramp-x86-gsharedvt.c | 2 +- src/mono/mono/mini/tramp-x86.c | 4 +- src/mono/mono/mini/type-checking.c | 16 +- src/mono/mono/mini/unwind.c | 16 +- src/mono/mono/sgen/sgen-alloc.c | 12 +- src/mono/mono/sgen/sgen-cardtable.c | 4 +- src/mono/mono/sgen/sgen-conf.h | 2 +- src/mono/mono/sgen/sgen-descriptor.c | 4 +- src/mono/mono/sgen/sgen-descriptor.h | 2 +- src/mono/mono/sgen/sgen-fin-weak-hash.c | 6 +- src/mono/mono/sgen/sgen-gc.c | 14 +- src/mono/mono/sgen/sgen-gc.h | 6 +- src/mono/mono/sgen/sgen-gray.h | 10 +- src/mono/mono/sgen/sgen-hash-table.c | 4 +- .../sgen/sgen-marksweep-drain-gray-stack.h | 2 +- src/mono/mono/sgen/sgen-marksweep.c | 4 +- src/mono/mono/sgen/sgen-memory-governor.c | 2 +- src/mono/mono/sgen/sgen-minor-copy-object.h | 6 +- src/mono/mono/sgen/sgen-nursery-allocator.c | 10 +- src/mono/mono/sgen/sgen-pinning-stats.c | 2 +- src/mono/mono/sgen/sgen-pinning.c | 2 +- src/mono/mono/sgen/sgen-simple-nursery.c | 4 +- src/mono/mono/sgen/sgen-split-nursery.c | 2 +- .../tests/metadata-verifier/gen-md-tests.c | 38 +- src/mono/mono/utils/atomic.c | 118 +-- src/mono/mono/utils/dlmalloc.c | 14 +- src/mono/mono/utils/dlmalloc.h | 6 +- src/mono/mono/utils/dtrace.h | 4 +- src/mono/mono/utils/freebsd-elf_common.h | 4 +- src/mono/mono/utils/gc_wrapper.h | 4 +- src/mono/mono/utils/lock-free-alloc.h | 4 +- src/mono/mono/utils/lock-free-queue.c | 4 +- src/mono/mono/utils/lock-free-queue.h | 4 +- src/mono/mono/utils/mach-support-arm.c | 2 +- src/mono/mono/utils/mach-support-x86.c | 2 +- src/mono/mono/utils/memcheck.h | 20 +- src/mono/mono/utils/memfuncs.c | 2 +- src/mono/mono/utils/mono-codeman.c | 20 +- src/mono/mono/utils/mono-conc-hashtable.c | 2 +- src/mono/mono/utils/mono-context.h | 12 +- src/mono/mono/utils/mono-counters.c | 6 +- src/mono/mono/utils/mono-counters.h | 4 +- src/mono/mono/utils/mono-embed.c | 12 +- src/mono/mono/utils/mono-embed.h | 4 +- src/mono/mono/utils/mono-error-internals.h | 4 +- src/mono/mono/utils/mono-error.c | 12 +- src/mono/mono/utils/mono-error.h | 2 +- src/mono/mono/utils/mono-filemap.c | 4 +- src/mono/mono/utils/mono-flight-recorder.c | 4 +- src/mono/mono/utils/mono-hwcap-arm.c | 12 +- src/mono/mono/utils/mono-jemalloc.c | 2 +- src/mono/mono/utils/mono-jemalloc.h | 4 +- src/mono/mono/utils/mono-linked-list-set.c | 2 +- src/mono/mono/utils/mono-log-android.c | 2 +- src/mono/mono/utils/mono-log-common.c | 4 +- .../mono/utils/mono-log-flight-recorder.c | 8 +- src/mono/mono/utils/mono-log-posix.c | 6 +- src/mono/mono/utils/mono-log-windows.c | 4 +- src/mono/mono/utils/mono-logger-internals.h | 8 +- src/mono/mono/utils/mono-logger.c | 28 +- src/mono/mono/utils/mono-logger.h | 4 +- src/mono/mono/utils/mono-md5.c | 98 +- src/mono/mono/utils/mono-memory-model.h | 10 +- src/mono/mono/utils/mono-mmap-wasm.c | 2 +- src/mono/mono/utils/mono-networkinterfaces.c | 6 +- src/mono/mono/utils/mono-path.c | 10 +- src/mono/mono/utils/mono-poll.c | 2 +- src/mono/mono/utils/mono-private-unstable.h | 2 +- src/mono/mono/utils/mono-property-hash.c | 4 +- src/mono/mono/utils/mono-publib.h | 2 +- src/mono/mono/utils/mono-rand.c | 4 +- src/mono/mono/utils/mono-sha1.c | 26 +- src/mono/mono/utils/mono-stack-unwinding.h | 6 +- src/mono/mono/utils/mono-stdlib.c | 2 +- src/mono/mono/utils/mono-threads-aix.c | 2 +- src/mono/mono/utils/mono-threads-coop.c | 2 +- .../mono/utils/mono-threads-mach-helper.c | 4 +- .../mono/utils/mono-threads-state-machine.c | 4 +- src/mono/mono/utils/mono-threads.h | 6 +- src/mono/mono/utils/mono-uri.c | 2 +- src/mono/mono/utils/mono-utility-thread.c | 4 +- src/mono/mono/utils/mono-value-hash.c | 16 +- src/mono/mono/utils/mono-value-hash.h | 4 +- src/mono/mono/utils/monobitset.c | 20 +- src/mono/mono/utils/monobitset.h | 2 +- src/mono/mono/utils/networking-fallback.c | 4 +- src/mono/mono/utils/networking-missing.c | 10 +- src/mono/mono/utils/networking-posix.c | 4 +- src/mono/mono/utils/strenc.c | 36 +- src/mono/mono/utils/valgrind.h | 54 +- 322 files changed, 3927 insertions(+), 3927 deletions(-) diff --git a/src/mono/mono/arch/amd64/amd64-codegen.h b/src/mono/mono/arch/amd64/amd64-codegen.h index f0ae81aa23d0f..2b1cd7eb2d3c3 100644 --- a/src/mono/mono/arch/amd64/amd64-codegen.h +++ b/src/mono/mono/arch/amd64/amd64-codegen.h @@ -8,7 +8,7 @@ * Dietmar Maurer (dietmar@ximian.com) * Patrik Torstensson * Zalman Stern - * + * * Copyright (C) 2000 Intel Corporation. All rights reserved. * Copyright (C) 2001, 2002 Ximian, Inc. * Licensed under the MIT license. See LICENSE file in the project root for full license information. @@ -652,7 +652,7 @@ typedef union { #define amd64_call_membase_size(inst,basereg,disp,size) do { amd64_emit_rex ((inst),0,0,0,(basereg)); *(inst)++ = (unsigned char)0xff; amd64_membase_emit ((inst),2, (basereg),(disp)); } while (0) #define amd64_jump_membase_size(inst,basereg,disp,size) do { amd64_emit_rex ((inst),0,0,0,(basereg)); *(inst)++ = (unsigned char)0xff; amd64_membase_emit ((inst), 4, (basereg), (disp)); } while (0) - + #define amd64_jump_code_size(inst,target,size) do { \ if (amd64_is_imm32 ((gint64)(target) - (gint64)(inst))) { \ x86_jump_code((inst),(target)); \ @@ -777,7 +777,7 @@ typedef union { } while (0) /* specific SSE opcode defines */ - + #define amd64_sse_xorpd_reg_reg(inst,dreg,reg) emit_sse_reg_reg ((inst),(dreg),(reg), 0x66, 0x0f, 0x57) #define amd64_sse_xorpd_reg_membase(inst,dreg,basereg,disp) emit_sse_reg_membase ((inst),(dreg),(basereg), (disp), 0x66, 0x0f, 0x57) @@ -1203,7 +1203,7 @@ typedef union { //#define amd64_alu_reg_imm_size(inst,opc,reg,imm,size) do { amd64_codegen_pre(inst); amd64_emit_rex ((inst),(size),0,0,(reg)); x86_alu_reg_imm((inst),(opc),((reg)&0x7),(imm)); amd64_codegen_post(inst); } while (0) #define amd64_alu_mem_imm_size(inst,opc,mem,imm,size) do { amd64_codegen_pre(inst); amd64_emit_rex ((inst),(size),0,0,0); x86_alu_mem_imm((inst),(opc),(mem),(imm)); amd64_codegen_post(inst); } while (0) #define amd64_alu_membase_imm_size(inst,opc,basereg,disp,imm,size) do { amd64_codegen_pre(inst); amd64_emit_rex ((inst),(size),0,0,(basereg)); x86_alu_membase_imm((inst),(opc),((basereg)&0x7),(disp),(imm)); amd64_codegen_post(inst); } while (0) -#define amd64_alu_membase8_imm_size(inst,opc,basereg,disp,imm,size) do { amd64_codegen_pre(inst); amd64_emit_rex ((inst),(size),0,0,(basereg)); x86_alu_membase8_imm((inst),(opc),((basereg)&0x7),(disp),(imm)); amd64_codegen_post(inst); } while (0) +#define amd64_alu_membase8_imm_size(inst,opc,basereg,disp,imm,size) do { amd64_codegen_pre(inst); amd64_emit_rex ((inst),(size),0,0,(basereg)); x86_alu_membase8_imm((inst),(opc),((basereg)&0x7),(disp),(imm)); amd64_codegen_post(inst); } while (0) #define amd64_alu_mem_reg_size(inst,opc,mem,reg,size) do { amd64_codegen_pre(inst); amd64_emit_rex ((inst),(size),0,0,(reg)); x86_alu_mem_reg((inst),(opc),(mem),((reg)&0x7)); amd64_codegen_post(inst); } while (0) #define amd64_alu_membase_reg_size(inst,opc,basereg,disp,reg,size) do { amd64_codegen_pre(inst); amd64_emit_rex ((inst),(size),(reg),0,(basereg)); x86_alu_membase_reg((inst),(opc),((basereg)&0x7),(disp),((reg)&0x7)); amd64_codegen_post(inst); } while (0) //#define amd64_alu_reg_reg_size(inst,opc,dreg,reg,size) do { amd64_codegen_pre(inst); amd64_emit_rex ((inst),(size),(dreg),0,(reg)); x86_alu_reg_reg((inst),(opc),((dreg)&0x7),((reg)&0x7)); amd64_codegen_post(inst); } while (0) @@ -1475,7 +1475,7 @@ typedef union { #define amd64_fucomi(inst,index) amd64_fucomi_size(inst,index,8) #define amd64_fucomip(inst,index) amd64_fucomip_size(inst,index,8) #define amd64_fld(inst,mem,is_double) amd64_fld_size(inst,mem,is_double,8) -#define amd64_fld_membase(inst,basereg,disp,is_double) amd64_fld_membase_size(inst,basereg,disp,is_double,8) +#define amd64_fld_membase(inst,basereg,disp,is_double) amd64_fld_membase_size(inst,basereg,disp,is_double,8) #define amd64_fld80_mem(inst,mem) amd64_fld80_mem_size(inst,mem,8) #define amd64_fld80_membase(inst,basereg,disp) amd64_fld80_membase_size(inst,basereg,disp,8) #define amd64_fild(inst,mem,is_long) amd64_fild_size(inst,mem,is_long,8) diff --git a/src/mono/mono/arch/arm/arm-codegen.h b/src/mono/mono/arch/arm/arm-codegen.h index eb63f596fc3d0..3f0e9a17b3bb9 100644 --- a/src/mono/mono/arch/arm/arm-codegen.h +++ b/src/mono/mono/arch/arm/arm-codegen.h @@ -27,7 +27,7 @@ typedef unsigned int armword_t; #if defined(_MSC_VER) && !defined(ARM_NOIASM) # define ARM_IASM(_expr) __emit (_expr) #else -# define ARM_IASM(_expr) +# define ARM_IASM(_expr) #endif /* even_scale = rot << 1 */ diff --git a/src/mono/mono/arch/arm/arm-wmmx.h b/src/mono/mono/arch/arm/arm-wmmx.h index 6f2fc785dca9a..b9dc023ce5ab6 100644 --- a/src/mono/mono/arch/arm/arm-wmmx.h +++ b/src/mono/mono/arch/arm/arm-wmmx.h @@ -21,7 +21,7 @@ #if defined(ARM_EMIT) # define WM_EMIT(p, i) ARM_EMIT(p, i) #else -# define WM_EMIT(p, i) +# define WM_EMIT(p, i) #endif enum { diff --git a/src/mono/mono/arch/mips/test.c b/src/mono/mono/arch/mips/test.c index 4f5e1adee1f1d..c7b324f08630d 100644 --- a/src/mono/mono/arch/mips/test.c +++ b/src/mono/mono/arch/mips/test.c @@ -15,7 +15,7 @@ int main (int argc, char *argv[]) { guint32 *code, * p; code = p = (guint32 *) malloc (sizeof (guint32) * 1024); - + mips_add (p, 3, 4, 5); mips_addi (p, 3, 4, 5); mips_addu (p, 3, 4, 5); diff --git a/src/mono/mono/arch/ppc/ppc-codegen.h b/src/mono/mono/arch/ppc/ppc-codegen.h index 83d366acc83ab..a52d17ab767f0 100644 --- a/src/mono/mono/arch/ppc/ppc-codegen.h +++ b/src/mono/mono/arch/ppc/ppc-codegen.h @@ -274,7 +274,7 @@ from 18 November 2002 to 19 December 2002. Special thanks to rodo, lupus, dietmar, miguel, and duncan for patience, and motivation. -The macros found in this file are based on the assembler instructions found +The macros found in this file are based on the assembler instructions found in Motorola and Digital DNA's: "Programming Enviornments Manual For 32-bit Implementations of the PowerPC Architecture" @@ -334,7 +334,7 @@ my and Ximian's copyright to this code. ;) #define ppc_andisd(c,S,A,ui) ppc_emit32(c, (29 << 26) | ((S) << 21 ) | ((A) << 16) | ((guint16)(ui))) #define ppc_bcx(c,BO,BI,BD,AA,LK) ppc_emit32(c, (16 << 26) | ((BO) << 21 )| ((BI) << 16) | (BD << 2) | ((AA) << 1) | LK) -#define ppc_bc(c,BO,BI,BD) ppc_bcx(c,BO,BI,BD,0,0) +#define ppc_bc(c,BO,BI,BD) ppc_bcx(c,BO,BI,BD,0,0) #define ppc_bca(c,BO,BI,BD) ppc_bcx(c,BO,BI,BD,1,0) #define ppc_bcl(c,BO,BI,BD) ppc_bcx(c,BO,BI,BD,0,1) #define ppc_bcla(c,BO,BI,BD) ppc_bcx(c,BO,BI,BD,1,1) @@ -400,15 +400,15 @@ my and Ximian's copyright to this code. ;) #define ppc_eqv(c,A,S,B) ppc_eqvx(c,A,S,B,0) #define ppc_eqvd(c,A,S,B) ppc_eqvx(c,A,S,B,1) -#define ppc_extsbx(c,A,S,Rc) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (0 << 11) | (954 << 1) | Rc) +#define ppc_extsbx(c,A,S,Rc) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (0 << 11) | (954 << 1) | Rc) #define ppc_extsb(c,A,S) ppc_extsbx(c,A,S,0) #define ppc_extsbd(c,A,S) ppc_extsbx(c,A,S,1) -#define ppc_extshx(c,A,S,Rc) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (0 << 11) | (922 << 1) | Rc) +#define ppc_extshx(c,A,S,Rc) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (0 << 11) | (922 << 1) | Rc) #define ppc_extsh(c,A,S) ppc_extshx(c,A,S,0) #define ppc_extshd(c,A,S) ppc_extshx(c,A,S,1) -#define ppc_fabsx(c,D,B,Rc) ppc_emit32(c, (63 << 26) | (D << 21) | (0 << 16) | (B << 11) | (264 << 1) | Rc) +#define ppc_fabsx(c,D,B,Rc) ppc_emit32(c, (63 << 26) | (D << 21) | (0 << 16) | (B << 11) | (264 << 1) | Rc) #define ppc_fabs(c,D,B) ppc_fabsx(c,D,B,0) #define ppc_fabsd(c,D,B) ppc_fabsx(c,D,B,1) @@ -441,11 +441,11 @@ my and Ximian's copyright to this code. ;) #define ppc_fmaddx(c,D,A,B,C,Rc) ppc_emit32(c, (63 << 26) | (D << 21) | (A << 16) | (B << 11) | (C << 6) | (29 << 1) | Rc) #define ppc_fmadd(c,D,A,B,C) ppc_fmaddx(c,D,A,B,C,0) -#define ppc_fmaddd(c,D,A,B,C) ppc_fmaddx(c,D,A,B,C,1) +#define ppc_fmaddd(c,D,A,B,C) ppc_fmaddx(c,D,A,B,C,1) #define ppc_fmaddsx(c,D,A,B,C,Rc) ppc_emit32(c, (59 << 26) | (D << 21) | (A << 16) | (B << 11) | (C << 6) | (29 << 1) | Rc) #define ppc_fmadds(c,D,A,B,C) ppc_fmaddsx(c,D,A,B,C,0) -#define ppc_fmaddsd(c,D,A,B,C) ppc_fmaddsx(c,D,A,B,C,1) +#define ppc_fmaddsd(c,D,A,B,C) ppc_fmaddsx(c,D,A,B,C,1) #define ppc_fmrx(c,D,B,Rc) ppc_emit32(c, (63 << 26) | (D << 21) | (0 << 16) | (B << 11) | (72 << 1) | Rc) #define ppc_fmr(c,D,B) ppc_fmrx(c,D,B,0) @@ -459,11 +459,11 @@ my and Ximian's copyright to this code. ;) #define ppc_fmsubs(c,D,A,C,B) ppc_fmsubsx(c,D,A,C,B,0) #define ppc_fmsubsd(c,D,A,C,B) ppc_fmsubsx(c,D,A,C,B,1) -#define ppc_fmulx(c,D,A,C,Rc) ppc_emit32(c, (63 << 26) | (D << 21) | (A << 16) | (0 << 11) | (C << 6) | (25 << 1) | Rc) +#define ppc_fmulx(c,D,A,C,Rc) ppc_emit32(c, (63 << 26) | (D << 21) | (A << 16) | (0 << 11) | (C << 6) | (25 << 1) | Rc) #define ppc_fmul(c,D,A,C) ppc_fmulx(c,D,A,C,0) #define ppc_fmuld(c,D,A,C) ppc_fmulx(c,D,A,C,1) -#define ppc_fmulsx(c,D,A,C,Rc) ppc_emit32(c, (59 << 26) | (D << 21) | (A << 16) | (0 << 11) | (C << 6) | (25 << 1) | Rc) +#define ppc_fmulsx(c,D,A,C,Rc) ppc_emit32(c, (59 << 26) | (D << 21) | (A << 16) | (0 << 11) | (C << 6) | (25 << 1) | Rc) #define ppc_fmuls(c,D,A,C) ppc_fmulsx(c,D,A,C,0) #define ppc_fmulsd(c,D,A,C) ppc_fmulsx(c,D,A,C,1) @@ -689,9 +689,9 @@ my and Ximian's copyright to this code. ;) #define ppc_stfiwx(c,S,A,B) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (B << 11) | (983 << 1) | 0) #define ppc_stfsu(c,S,d,A) ppc_emit32(c, (53 << 26) | (S << 21) | (A << 16) | (guint16)(d)) -#define ppc_stfsux(c,S,A,B) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (B << 11) | (695 << 1) | 0) -#define ppc_stfsx(c,S,A,B) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (B << 11) | (663 << 1) | 0) -#define ppc_sthbrx(c,S,A,B) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (B << 11) | (918 << 1) | 0) +#define ppc_stfsux(c,S,A,B) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (B << 11) | (695 << 1) | 0) +#define ppc_stfsx(c,S,A,B) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (B << 11) | (663 << 1) | 0) +#define ppc_sthbrx(c,S,A,B) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (B << 11) | (918 << 1) | 0) #define ppc_sthu(c,S,d,A) ppc_emit32(c, (45 << 26) | (S << 21) | (A << 16) | (guint16)(d)) #define ppc_sthux(c,S,A,B) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (B << 11) | (439 << 1) | 0) #define ppc_sthx(c,S,A,B) ppc_emit32(c, (31 << 26) | (S << 21) | (A << 16) | (B << 11) | (407 << 1) | 0) diff --git a/src/mono/mono/arch/s390x/s390x-codegen.h b/src/mono/mono/arch/s390x/s390x-codegen.h index ec9562a0e0474..cd96c9f2f331f 100644 --- a/src/mono/mono/arch/s390x/s390x-codegen.h +++ b/src/mono/mono/arch/s390x/s390x-codegen.h @@ -254,7 +254,7 @@ typedef struct { short op; short m1 : 4; short ri2 : 12; - short i3; + short i3; } MII_Format; typedef struct { @@ -569,7 +569,7 @@ typedef struct { char op; char l1 : 4; char l2 : 4; - short b1 : 4; + short b1 : 4; short d1 : 12; short b2 : 4; short d2 : 12; @@ -579,21 +579,21 @@ typedef struct { char op; char r1 : 4; char r3 : 4; - short b1 : 4; + short b1 : 4; short d1 : 12; short b2 : 4; short d2 : 12; -} __attribute__ ((__packed__)) SS_Format_3; +} __attribute__ ((__packed__)) SS_Format_3; typedef struct { char op; char r1 : 4; char r3 : 4; - short b2 : 4; + short b2 : 4; short d2 : 12; short b4 : 4; short d4 : 12; -} __attribute__ ((__packed__)) SS_Format_4; +} __attribute__ ((__packed__)) SS_Format_4; typedef struct { short op; @@ -814,7 +814,7 @@ typedef struct { #define S390_RR(c,opc,g1,g2) s390_emit16(c, (opc << 8 | (g1) << 4 | g2)) -#define S390_RRE(c,opc,g1,g2) s390_emit32(c, (opc << 16 | (g1) << 4 | g2)) +#define S390_RRE(c,opc,g1,g2) s390_emit32(c, (opc << 16 | (g1) << 4 | g2)) #define S390_RRF_1(c,opc,g1,g2,g3) s390_emit32(c, (opc << 16 | (g3) << 12 | (g1) << 4 | g2)) @@ -841,7 +841,7 @@ typedef struct { (opc & 0xff))); \ } while (0) -#define S390_RS_1(c,opc,g1,g3,s2,p2) s390_emit32(c, (opc << 24 | (g1) << 20 | (g3) << 16 | (s2) << 12 | ((p2) & 0xfff))) +#define S390_RS_1(c,opc,g1,g3,s2,p2) s390_emit32(c, (opc << 24 | (g1) << 20 | (g3) << 16 | (s2) << 12 | ((p2) & 0xfff))) #define S390_RS_2(c,opc,g1,k3,s2,p2) s390_emit32(c, (opc << 24 | (g1) << 20 | (k3) << 16 | (s2) << 12 | ((p2) & 0xfff))) @@ -1450,7 +1450,7 @@ typedef struct { #define s390_msr(c, r1, r2) S390_RRE(c, 0xb252, r1, r2) #define s390_msrkc(c, r1, r2, r3) S390_RRF_1(c, 0xb9fd, r1, r2, r3) #define s390_mvc(c, l, b1, d1, b2, d2) S390_SS_1(c, 0xd2, l, b1, d1, b2, d2) -#define s390_mvghi(c, b1, d1, i2) S390_SIL(c, 0xe548, b1, d1, i2) +#define s390_mvghi(c, b1, d1, i2) S390_SIL(c, 0xe548, b1, d1, i2) #define s390_mvcl(c, r1, r2) S390_RR(c, 0x0e, r1, r2) #define s390_mvcle(c, r1, r3, d2, b2) S390_RS_1(c, 0xa8, r1, r3, d2, b2) #define s390_mvi(c, b, d, v) S390_SI(c, 0x92, b, d, v) @@ -1459,14 +1459,14 @@ typedef struct { #define s390_ng(c, r, x, b, d) S390_RXY(c, 0xe380, r, x, b, d) #define s390_ngr(c, r1, r2) S390_RRE(c, 0xb980, r1, r2) #define s390_ngrk(c, r1, r2, r3) S390_RRF_1(c, 0xb9e4, r1, r2, r3) -#define s390_ni(c, b, d, v) S390_SI(c, 0x94, b, d, v) +#define s390_ni(c, b, d, v) S390_SI(c, 0x94, b, d, v) #define s390_nihf(c, r, v) S390_RIL_1(c, 0xc0a, r, v) #define s390_nihh(c, r, v) S390_RI(c, 0xa54, r, v) #define s390_nihl(c, r, v) S390_RI(c, 0xa55, r, v) #define s390_nilf(c, r, v) S390_RIL_1(c, 0xc0b, r, v) #define s390_nilh(c, r, v) S390_RI(c, 0xa56, r, v) #define s390_nill(c, r, v) S390_RI(c, 0xa57, r, v) -#define s390_niy(c, b, d, v) S390_SIY(c, 0xeb54, b, d, v) +#define s390_niy(c, b, d, v) S390_SIY(c, 0xeb54, b, d, v) #define s390_nop(c) S390_RR(c, 0x07, 0x0, 0) #define s390_mem(c) S390_RR(c, 0x07, 0xe, 0) #define s390_nr(c, r1, r2) S390_RR(c, 0x14, r1, r2) @@ -1479,7 +1479,7 @@ typedef struct { #define s390_oilf(c, r, v) S390_RIL_1(c, 0xc0d, r, v) #define s390_oilh(c, r, v) S390_RI(c, 0xa5a, r, v) #define s390_oill(c, r, v) S390_RI(c, 0xa5b, r, v) -#define s390_oiy(c, b, d, v) S390_SIY(c, 0xeb56 b, d, v) +#define s390_oiy(c, b, d, v) S390_SIY(c, 0xeb56 b, d, v) #define s390_og(c, r, x, b, d) S390_RXY(c, 0xe381, r, x, b, d) #define s390_ogr(c, r1, r2) S390_RRE(c, 0xb981, r1, r2) #define s390_ogrk(c, r1, r2, r3) S390_RRF_1(c, 0xb9e6, r1, r2, r3) @@ -1497,13 +1497,13 @@ typedef struct { #define s390_sgr(c, r1, r2) S390_RRE(c, 0xb909, r1, r2) #define s390_sgrk(c, r1, r2, r3) S390_RRF_1(c, 0xb9e9, r1, r2, r3) #define s390_sl(c, r, x, b, d) S390_RX(c, 0x5f, r, x, b, d) -#define s390_sla(c, r, b, d) S390_RS_3(c, 0x8b, r, b, d) -#define s390_slag(c, r1, r2, b, d) S390_RSY_1(c, 0xeb0b, r1, r2, b, d) +#define s390_sla(c, r, b, d) S390_RS_3(c, 0x8b, r, b, d) +#define s390_slag(c, r1, r2, b, d) S390_RSY_1(c, 0xeb0b, r1, r2, b, d) #define s390_slbg(c, r, x, b, d) S390_RXY(c, 0xe389, r, x, b, d) #define s390_slbgr(c, r1, r2) S390_RRE(c, 0xb989, r1, r2) #define s390_slbr(c, r1, r2) S390_RRE(c, 0xb999, r1, r2) -#define s390_slda(c, r, b, d) S390_RS_3(c, 0x8f, r, b, d) -#define s390_sldl(c, r, b, d) S390_RS_3(c, 0x8d, r, b, d) +#define s390_slda(c, r, b, d) S390_RS_3(c, 0x8f, r, b, d) +#define s390_sldl(c, r, b, d) S390_RS_3(c, 0x8d, r, b, d) #define s390_slfi(c, r, v) S390_RIL_1(c, 0xc25, r, v) #define s390_slg(c, r, x, b, d) S390_RXY(c, 0xe30b, r, x, b, d) #define s390_slgf(c, r, x, b, d) S390_RXY(c, 0xe31b, r, x, b, d) @@ -1511,20 +1511,20 @@ typedef struct { #define s390_slgfi(c, r, v) S390_RIL_1(c, 0xc24, r, v) #define s390_slgr(c, r1, r2) S390_RRE(c, 0xb90b, r1, r2) #define s390_slgrk(c, r1, r2, r3) S390_RRF_1(c, 0xb9eb, r1, r2, r3) -#define s390_sll(c, r, b, d) S390_RS_3(c, 0x89, r, b, d) -#define s390_sllg(c, r1, r2, b, d) S390_RSY_1(c, 0xeb0d, r1, r2, b, d) +#define s390_sll(c, r, b, d) S390_RS_3(c, 0x89, r, b, d) +#define s390_sllg(c, r1, r2, b, d) S390_RSY_1(c, 0xeb0d, r1, r2, b, d) #define s390_slr(c, r1, r2) S390_RR(c, 0x1f, r1, r2) #define s390_slrk(c, r1, r2, r3) S390_RRF_1(c, 0xb9fb, r1, r2, r3) #define s390_sqdbr(c, r1, r2) S390_RRE(c, 0xb315, r1, r2) #define s390_sqebr(c, r1, r2) S390_RRE(c, 0xb314, r1, r2) -#define s390_sra(c, r, b, d) S390_RS_3(c, 0x8a, r, b, d) -#define s390_srag(c, r1, r2, b, d) S390_RSY_1(c, 0xeb0a, r1, r2, b, d) +#define s390_sra(c, r, b, d) S390_RS_3(c, 0x8a, r, b, d) +#define s390_srag(c, r1, r2, b, d) S390_RSY_1(c, 0xeb0a, r1, r2, b, d) #define s390_sr(c, r1, r2) S390_RR(c, 0x1b, r1, r2) -#define s390_srda(c, r, b, d) S390_RS_3(c, 0x8e, r, b, d) -#define s390_srdl(c, r, b, d) S390_RS_3(c, 0x8c, r, b, d) +#define s390_srda(c, r, b, d) S390_RS_3(c, 0x8e, r, b, d) +#define s390_srdl(c, r, b, d) S390_RS_3(c, 0x8c, r, b, d) #define s390_srk(c, r1, r2, r3) S390_RRF_1(c, 0xb9f9, r1, r2, r3) -#define s390_srl(c, r, b, d) S390_RS_3(c, 0x88, r, b, d) -#define s390_srlg(c, r1, r2, b, d) S390_RSY_1(c, 0xeb0c, r1, r2, b, d) +#define s390_srl(c, r, b, d) S390_RS_3(c, 0x88, r, b, d) +#define s390_srlg(c, r1, r2, b, d) S390_RSY_1(c, 0xeb0c, r1, r2, b, d) #define s390_st(c, r, x, b, d) S390_RX(c, 0x50, r, x, b, d) #define s390_stam(c, r1, r2, b, d) S390_RS_1(c, 0x9b, r1, r2, b, d) #define s390_stamy(c, r1, r2, b, d) S390_RSY_1(c, 0xeb9b, r1, r2, b, d) diff --git a/src/mono/mono/arch/s390x/tramp.c b/src/mono/mono/arch/s390x/tramp.c index 451511dfc53e5..9d38d9380b93e 100644 --- a/src/mono/mono/arch/s390x/tramp.c +++ b/src/mono/mono/arch/s390x/tramp.c @@ -59,7 +59,7 @@ typedef struct { local_size, code_size, retStruct; -} size_data; +} size_data; /*========================= End of Typedefs ========================*/ @@ -78,14 +78,14 @@ add_general (guint *gr, size_data *sz, gboolean simple) if (simple) { if (*gr >= GENERAL_REGS) { sz->stack_size += sizeof(long); - sz->code_size += 12; + sz->code_size += 12; } else { - sz->code_size += 8; + sz->code_size += 8; } } else { if (*gr >= GENERAL_REGS - 1) { sz->stack_size += 8 + (sz->stack_size % 8); - sz->code_size += 10; + sz->code_size += 10; } else { sz->code_size += 8; } @@ -108,7 +108,7 @@ add_general (guint *gr, size_data *sz, gboolean simple) /*------------------------------------------------------------------*/ static void inline -calculate_sizes (MonoMethodSignature *sig, size_data *sz, +calculate_sizes (MonoMethodSignature *sig, size_data *sz, gboolean string_ctor) { guint i, fr, gr, size; @@ -290,9 +290,9 @@ calculate_sizes (MonoMethodSignature *sig, size_data *sz, /* align stack size to 8 */ DEBUG (printf (" stack size: %d (%d)\n" - " code size: %d\n" + " code size: %d\n" " local size: %d\n", - (sz->stack_size + 8) & ~8, sz->stack_size, + (sz->stack_size + 8) & ~8, sz->stack_size, (sz->code_size),(sz->local_size + 8) & ~8)); sz->stack_size = (sz->stack_size + 8) & ~8; sz->local_size = (sz->local_size + 8) & ~8; @@ -342,7 +342,7 @@ emit_prolog (guint8 *p, MonoMethodSignature *sig, size_data *sz) /* */ /* Name - emit_save_parameters */ /* */ -/* Function - Create the instructions that load registers with */ +/* Function - Create the instructions that load registers with */ /* parameters, place others on the stack according */ /* to the S/390 ABI. */ /* */ @@ -355,12 +355,12 @@ emit_prolog (guint8 *p, MonoMethodSignature *sig, size_data *sz) inline static guint8* emit_save_parameters (guint8 *p, MonoMethodSignature *sig, size_data *sz) { - guint i, fr, gr, act_strs, align, + guint i, fr, gr, act_strs, align, stack_par_pos, size, local_pos; guint32 simpletype; /*----------------------------------------------------------*/ - /* If a structure on stack is being returned, reserve r2 */ + /* If a structure on stack is being returned, reserve r2 */ /* to point to an area where it can be passed. */ /*----------------------------------------------------------*/ if (sz->retStruct) @@ -423,7 +423,7 @@ emit_save_parameters (guint8 *p, MonoMethodSignature *sig, size_data *sz) simpletype = sig->params [i]->data.klass->enum_basetype->type; goto enum_calc_size; } - if (sig->pinvoke && !sig->marshalling_disabled) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size (sig->params [i]->data.klass, &align); else size = mono_class_value_size (sig->params [i]->data.klass, &align); @@ -455,7 +455,7 @@ emit_save_parameters (guint8 *p, MonoMethodSignature *sig, size_data *sz) s390_mvc (p, sizeof(long long), STK_BASE, stack_par_pos, s390_r10, 0); stack_par_pos += sizeof(long long); } - break; + break; default: if (size <= 256) { local_pos += (local_pos % align); @@ -488,12 +488,12 @@ emit_save_parameters (guint8 *p, MonoMethodSignature *sig, size_data *sz) break; case MONO_TYPE_I8: if (gr < GENERAL_REGS) { - s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG); + s390_lg (p, s390_r2 + gr, 0, ARG_BASE, STKARG); gr += 2; } else { *(guint32 *) p += 7; *(guint32 *) p &= ~7; - s390_mvc (p, sizeof(long long), STK_BASE, stack_par_pos, ARG_BASE, STKARG); + s390_mvc (p, sizeof(long long), STK_BASE, stack_par_pos, ARG_BASE, STKARG); stack_par_pos += sizeof(long long) + (stack_par_pos % sizeof(long long)); } break; @@ -523,7 +523,7 @@ emit_save_parameters (guint8 *p, MonoMethodSignature *sig, size_data *sz) } /*----------------------------------------------------------*/ - /* If we're returning a structure but not in a register */ + /* If we're returning a structure but not in a register */ /* then point the result area for the called routine */ /*----------------------------------------------------------*/ if (sz->retStruct) { @@ -574,14 +574,14 @@ alloc_code_memory (guint code_size) /*------------------------------------------------------------------*/ static guint8 * -emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, +emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, size_data *sz, gboolean string_ctor) { guint32 simpletype; guint retSize, align; /* call "callme" */ - s390_basr (p, s390_r14, s390_r9); + s390_basr (p, s390_r14, s390_r9); /* get return value */ if (m_type_is_byref (sig->ret) || string_ctor) { @@ -625,7 +625,7 @@ emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, simpletype = sig->ret->data.klass->enum_basetype->type; goto enum_retvalue; } - if (sig->pinvoke && !sig->marshalling_disabled) + if (sig->pinvoke && !sig->marshalling_disabled) retSize = mono_class_native_size (sig->ret->data.klass, &align); else retSize = mono_class_value_size (sig->ret->data.klass, &align); @@ -655,7 +655,7 @@ printf("Returning %d bytes for type %d (%d)\n",retSize,simpletype,sig->pinvoke); case MONO_TYPE_VOID: break; default: - g_error ("Can't handle as return value 0x%x", + g_error ("Can't handle as return value 0x%x", sig->ret->type); } } @@ -803,12 +803,12 @@ mono_arch_create_method_pointer (MonoMethod *method) p = code_buffer = g_malloc (sz.code_size); - DEBUG (printf ("\nDelegate [start emiting] %s at 0x%08x\n", + DEBUG (printf ("\nDelegate [start emiting] %s at 0x%08x\n", method->name,p)); - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ /* prolog */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ s390_stmg(p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET); s390_lg (p, s390_r7, 0, STK_BASE, MINV_POS); s390_lgr (p, s390_r0, STK_BASE); @@ -820,9 +820,9 @@ mono_arch_create_method_pointer (MonoMethod *method) s390_lghi(p, s390_r11, 0); s390_mvcl(p, s390_r8, s390_r10); - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ /* Let's fill MonoInvocation - first zero some fields */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ s390_lghi (p, s390_r0, 0); s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex))); s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler))); @@ -830,15 +830,15 @@ mono_arch_create_method_pointer (MonoMethod *method) s390_lghi (p, s390_r0, 1); s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, invoke_trap))); - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ /* set method pointer */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ s390_bras (p, s390_r13, 4); s390_llong(p, method); s390_lg (p, s390_r0, 0, s390_r13, 0); s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method))); - local_start = local_pos = MINV_POS + + local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval); this_flag = (sig->hasthis ? 1 : 0); @@ -848,7 +848,7 @@ mono_arch_create_method_pointer (MonoMethod *method) /* area. If necessary save this hidden parameter for later */ /*----------------------------------------------------------*/ if (MONO_TYPE_ISSTRUCT(sig->ret)) { - if (sig->pinvoke && !sig->marshalling_disabled) + if (sig->pinvoke && !sig->marshalling_disabled) retSize = mono_class_native_size (sig->ret->data.klass, &align); else retSize = mono_class_value_size (sig->ret->data.klass, &align); @@ -870,13 +870,13 @@ mono_arch_create_method_pointer (MonoMethod *method) } if (this_flag) { - s390_stg (p, s390_r2 + reg_save, 0, STK_BASE, + s390_stg (p, s390_r2 + reg_save, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj))); reg_param++; } else { s390_stg (p, s390_r2 + reg_save, 0, STK_BASE, local_pos); local_pos += sizeof(int); - s390_stg (p, s390_r0, 0, STK_BASE, + s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj))); } @@ -888,9 +888,9 @@ mono_arch_create_method_pointer (MonoMethod *method) s390_std (p, s390_f2, 0, STK_BASE, local_pos); local_pos += sizeof(double); - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ /* prepare space for valuetypes */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ vt_cur = local_pos; vtbuf = alloca (sizeof(int)*sig->param_count); cpos = 0; @@ -904,7 +904,7 @@ mono_arch_create_method_pointer (MonoMethod *method) if (klass->enumtype) continue; - if (sig->pinvoke && !sig->marshalling_disabled) + if (sig->pinvoke && !sig->marshalling_disabled) size = mono_class_native_size (sig->ret->data.klass, &align); else size = mono_class_value_size (sig->ret->data.klass, &align); @@ -919,16 +919,16 @@ mono_arch_create_method_pointer (MonoMethod *method) local_pos += cpos; - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ /* set MonoInvocation::stack_args */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ stackval_arg_pos = MINV_POS + sizeof (MonoInvocation); s390_la (p, s390_r0, 0, STK_BASE, stackval_arg_pos); s390_stg (p, s390_r0, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args))); - /*----------------------------------------------------------*/ - /* add stackval arguments */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ + /* add stackval arguments */ + /*----------------------------------------------------------*/ for (i = 0; i < sig->param_count; ++i) { if (m_type_is_byref (sig->params [i])) { ADD_ISTACK_PARM(0, 1); @@ -972,7 +972,7 @@ mono_arch_create_method_pointer (MonoMethod *method) ADD_ISTACK_PARM(0, 1); } } - + if (vtbuf [i] >= 0) { s390_la (p, s390_r3, 0, STK_BASE, vt_cur); s390_stg (p, s390_r3, 0, STK_BASE, stackval_arg_pos); @@ -1003,13 +1003,13 @@ mono_arch_create_method_pointer (MonoMethod *method) arg_pos += mono_type_native_stack_size (sig->params [i], &align); else arg_pos += mono_type_stack_size (sig->params [i], &align); - + DEBUG (printf ("%d\n", stackval_arg_pos)); } - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ /* Set return area pointer. */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ s390_la (p, s390_r10, 0, STK_BASE, stackval_arg_pos); s390_stg(p, s390_r10, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval))); if (sig->ret->type == MONO_TYPE_VALUETYPE && !m_type_is_byref (sig->ret)) { @@ -1021,18 +1021,18 @@ mono_arch_create_method_pointer (MonoMethod *method) } } - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ /* call ves_exec_method */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ s390_bras (p, s390_r13, 4); s390_llong(p, ves_exec_method); s390_lg (p, s390_r1, 0, s390_r13, 0); s390_la (p, s390_r2, 0, STK_BASE, MINV_POS); s390_basr (p, s390_r14, s390_r1); - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ /* move retval from stackval to proper place (r3/r4/...) */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ DEBUG(printf("retType: %d byRef: %d\n",sig->ret->type,m_type_is_byref (sig->ret))); if (m_type_is_byref (sig->ret)) { DEBUG (printf ("ret by ref\n")); @@ -1084,15 +1084,15 @@ mono_arch_create_method_pointer (MonoMethod *method) s390_llong(p, stackval_to_data); s390_lg (p, s390_r2, 0, s390_r13, 0); s390_lg (p, s390_r3, 0, STK_BASE, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval))); - if (sz.retStruct) { + if (sz.retStruct) { /*------------------------------------------*/ /* Get stackval_to_data to set result area */ /*------------------------------------------*/ s390_lgr (p, s390_r4, s390_r8); - } else { + } else { /*------------------------------------------*/ /* Give stackval_to_data a temp result area */ - /*------------------------------------------*/ + /*------------------------------------------*/ s390_la (p, s390_r4, 0, STK_BASE, stackval_arg_pos); } s390_lg (p, s390_r5, 0,s390_r13, 4); @@ -1121,15 +1121,15 @@ mono_arch_create_method_pointer (MonoMethod *method) } break; default: - g_error ("Type 0x%x not handled yet in thunk creation", + g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type); break; } } - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ /* epilog */ - /*----------------------------------------------------------*/ + /*----------------------------------------------------------*/ s390_lg (p, STK_BASE, 0, STK_BASE, 0); s390_lg (p, s390_r4, 0, STK_BASE, S390_RET_ADDR_OFFSET); s390_lmg (p, s390_r6, STK_BASE, STK_BASE, S390_REG_SAVE_OFFSET); diff --git a/src/mono/mono/arch/sparc/sparc-codegen.h b/src/mono/mono/arch/sparc/sparc-codegen.h index eb421bbcf9a6f..b8c478c473bbd 100644 --- a/src/mono/mono/arch/sparc/sparc-codegen.h +++ b/src/mono/mono/arch/sparc/sparc-codegen.h @@ -224,7 +224,7 @@ typedef enum { sparc_membar_store_load = 0x2, sparc_membar_load_store = 0x4, sparc_membar_store_store = 0x8, - + sparc_membar_lookaside = 0x10, sparc_membar_memissue = 0x20, sparc_membar_sync = 0x40, @@ -680,9 +680,9 @@ typedef struct { #define sparc_faddd(ins, r1, r2, dest) sparc_fop( ins, r1, sparc_faddd_val, r2, dest ) #define sparc_faddq(ins, r1, r2, dest) sparc_fop( ins, r1, sparc_faddq_val, r2, dest ) -#define sparc_fsubs(ins, r1, r2, dest) sparc_fop( ins, r1, sparc_fsubs_val, r2, dest ) -#define sparc_fsubd(ins, r1, r2, dest) sparc_fop( ins, r1, sparc_fsubd_val, r2, dest ) -#define sparc_fsubq(ins, r1, r2, dest) sparc_fop( ins, r1, sparc_fsubq_val, r2, dest ) +#define sparc_fsubs(ins, r1, r2, dest) sparc_fop( ins, r1, sparc_fsubs_val, r2, dest ) +#define sparc_fsubd(ins, r1, r2, dest) sparc_fop( ins, r1, sparc_fsubd_val, r2, dest ) +#define sparc_fsubq(ins, r1, r2, dest) sparc_fop( ins, r1, sparc_fsubq_val, r2, dest ) #define sparc_fmuls( ins, r1, r2, dest ) sparc_fop( ins, r1, sparc_fmuls_val, r2, dest ) #define sparc_fmuld( ins, r1, r2, dest ) sparc_fop( ins, r1, sparc_fmuld_val, r2, dest ) @@ -735,7 +735,7 @@ typedef struct { #define sparc_fcmpq( ins, r1, r2 ) sparc_fcmp( ins, r1, sparc_fcmpq_val, r2 ) #define sparc_fcmpes( ins, r1, r2 ) sparc_fcmpes( ins, r1, sparc_fcmpes_val, r2 ) #define sparc_fcmped( ins, r1, r2 ) sparc_fcmped( ins, r1, sparc_fcmped_val, r2 ) -#define sparc_fcmpeq( ins, r1, r2 ) sparc_fcmpeq( ins, r1, sparc_fcmpeq_val, r2 ) +#define sparc_fcmpeq( ins, r1, r2 ) sparc_fcmpeq( ins, r1, sparc_fcmpeq_val, r2 ) /* logical */ diff --git a/src/mono/mono/arch/sparc/test.c b/src/mono/mono/arch/sparc/test.c index 0d4ad1869b99e..8bfeb56544c57 100644 --- a/src/mono/mono/arch/sparc/test.c +++ b/src/mono/mono/arch/sparc/test.c @@ -35,8 +35,8 @@ main () ++cur_out_reg; sparc_ld_imm (p, sparc_i3, arg_pos+4, cur_out_reg); ++cur_out_reg; - /* - * Insert call to function + /* + * Insert call to function */ sparc_jmpl (p, sparc_i0, 0, sparc_callsite); sparc_nop (p); diff --git a/src/mono/mono/arch/x86/x86-codegen.h b/src/mono/mono/arch/x86/x86-codegen.h index 86a051cbcc939..c4edb3c1e2d62 100644 --- a/src/mono/mono/arch/x86/x86-codegen.h +++ b/src/mono/mono/arch/x86/x86-codegen.h @@ -7,7 +7,7 @@ * Sergey Chaban (serge@wildwestsoftware.com) * Dietmar Maurer (dietmar@ximian.com) * Patrik Torstensson - * + * * Copyright (C) 2000 Intel Corporation. All rights reserved. * Copyright (C) 2001, 2002 Ximian, Inc. * Licensed under the MIT license. See LICENSE file in the project root for full license information. @@ -151,7 +151,7 @@ enum { typedef enum { X86_LOCK_PREFIX = 0xF0, X86_REPNZ_PREFIX = 0xF2, - X86_REPZ_PREFIX = 0xF3, + X86_REPZ_PREFIX = 0xF3, X86_REP_PREFIX = 0xF3, X86_CS_PREFIX = 0x2E, X86_SS_PREFIX = 0x36, @@ -165,7 +165,7 @@ typedef enum { X86_ADDRESS_PREFIX = 0x67 } X86_Prefix; -static const unsigned char +static const unsigned char x86_cc_unsigned_map [X86_NCC] = { 0x74, /* eq */ 0x75, /* ne */ @@ -181,7 +181,7 @@ x86_cc_unsigned_map [X86_NCC] = { 0x71, /* no */ }; -static const unsigned char +static const unsigned char x86_cc_signed_map [X86_NCC] = { 0x74, /* eq */ 0x75, /* ne */ @@ -239,10 +239,10 @@ typedef union { // | var[n_arg] | // | var[n_arg+1] | local variables area // | . . . | -// | var[n_var-1] | +// | var[n_var-1] | // +--------------------------------+ // | | -// | | +// | | // | spill area | area for spilling mimic stack // | | // +--------------------------------| @@ -453,7 +453,7 @@ mono_x86_patch_inline (guchar* code, gpointer target) x86_byte (inst, 0xb1); \ x86_reg_emit ((inst), (reg), (dreg)); \ } while (0) - + #define x86_cmpxchg_mem_reg(inst,mem,reg) \ do { \ x86_codegen_pre(&(inst), 7); \ @@ -461,7 +461,7 @@ mono_x86_patch_inline (guchar* code, gpointer target) x86_byte (inst, 0xb1); \ x86_mem_emit ((inst), (reg), (mem)); \ } while (0) - + #define x86_cmpxchg_membase_reg(inst,basereg,disp,reg) \ do { \ x86_codegen_pre(&(inst), 2 + kMaxMembaseEmitPadding); \ @@ -659,7 +659,7 @@ mono_x86_patch_inline (guchar* code, gpointer target) x86_imm_emit32 ((inst), (imm)); \ } \ } while (0) - + #define x86_alu_membase8_imm(inst,opc,basereg,disp,imm) \ do { \ x86_codegen_pre(&(inst), 2 + kMaxMembaseEmitPadding); \ @@ -1597,7 +1597,7 @@ mono_x86_patch_inline (guchar* code, gpointer target) } while (0) #define x86_push_imm_template(inst) x86_push_imm (inst, 0xf0f0f0f0) - + #define x86_push_imm(inst,imm) \ do { \ int _imm = (int) (imm); \ @@ -1952,7 +1952,7 @@ mono_x86_patch_inline (guchar* code, gpointer target) x86_imm_emit16 ((inst), (framesize)); \ x86_byte(inst, 0); \ } while (0) - + #define x86_leave(inst) do { x86_byte (inst, 0xc9); } while (0) #define x86_sahf(inst) do { x86_byte (inst, 0x9e); } while (0) @@ -2040,16 +2040,16 @@ typedef enum { X86_SSE_MOVSHDUP = 0x16, X86_SSE_MOVSLDUP = 0x12, X86_SSE_MOVDDUP = 0x12, - + X86_SSE_PAND = 0xDB, X86_SSE_POR = 0xEB, X86_SSE_PXOR = 0xEF, - + X86_SSE_PADDB = 0xFC, X86_SSE_PADDW = 0xFD, X86_SSE_PADDD = 0xFE, X86_SSE_PADDQ = 0xD4, - + X86_SSE_PSUBB = 0xF8, X86_SSE_PSUBW = 0xF9, X86_SSE_PSUBD = 0xFA, @@ -2064,7 +2064,7 @@ typedef enum { X86_SSE_PMAXUD = 0x3F, /*sse41*/ X86_SSE_PMINSB = 0x38, /*sse41*/ - X86_SSE_PMINSW = 0xEA, + X86_SSE_PMINSW = 0xEA, X86_SSE_PMINSD = 0x39,/*sse41*/ X86_SSE_PMINUB = 0xDA, @@ -2085,9 +2085,9 @@ typedef enum { X86_SSE_PCMPGTQ = 0x37, /*sse42*/ X86_SSE_PSADBW = 0xf6, - + X86_SSE_PSHUFD = 0x70, - + X86_SSE_PUNPCKLBW = 0x60, X86_SSE_PUNPCKLWD = 0x61, X86_SSE_PUNPCKLDQ = 0x62, @@ -2121,14 +2121,14 @@ typedef enum { X86_SSE_PMULUDQ = 0xF4, X86_SSE_PMOVMSKB = 0xD7, - + X86_SSE_PSHIFTW = 0x71, X86_SSE_PSHIFTD = 0x72, X86_SSE_PSHIFTQ = 0x73, X86_SSE_SHR = 2, X86_SSE_SAR = 4, X86_SSE_SHL = 6, - + X86_SSE_PSRLW_REG = 0xD1, X86_SSE_PSRAW_REG = 0xE1, X86_SSE_PSLLW_REG = 0xF1, @@ -2136,7 +2136,7 @@ typedef enum { X86_SSE_PSRLD_REG = 0xD2, X86_SSE_PSRAD_REG = 0xE2, X86_SSE_PSLLD_REG = 0xF2, - + X86_SSE_PSRLQ_REG = 0xD3, X86_SSE_PSLLQ_REG = 0xF3, @@ -2156,7 +2156,7 @@ typedef enum { X86_SSE_PEXTRW = 0xC5, X86_SSE_PEXTRD = 0x16,/*sse41*/ - X86_SSE_SHUFP = 0xC6, + X86_SSE_SHUFP = 0xC6, X86_SSE_CVTDQ2PD = 0xE6, X86_SSE_CVTDQ2PS = 0x5B, diff --git a/src/mono/mono/component/debugger-agent.h b/src/mono/mono/component/debugger-agent.h index ad5a0cb1d0b1d..8ff34438d54da 100644 --- a/src/mono/mono/component/debugger-agent.h +++ b/src/mono/mono/component/debugger-agent.h @@ -12,7 +12,7 @@ void debugger_agent_add_function_pointers (MonoComponentDebugger* fn_table); -void +void mono_ss_calculate_framecount (void *the_tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***frames, int *nframes); void @@ -22,10 +22,10 @@ mono_ss_discard_frame_context (void *the_tls); DebuggerTlsData* mono_wasm_get_tls (void); -void +void mono_init_debugger_agent_for_wasm (int log_level, MonoProfilerHandle *prof); -void +void mono_wasm_save_thread_context (void); #endif @@ -33,10 +33,10 @@ mono_wasm_save_thread_context (void); void mini_wasm_debugger_add_function_pointers (MonoComponentDebugger* fn_table); -MdbgProtErrorCode +MdbgProtErrorCode mono_do_invoke_method (DebuggerTlsData *tls, MdbgProtBuffer *buf, InvokeData *invoke, guint8 *p, guint8 **endp); -MdbgProtErrorCode +MdbgProtErrorCode mono_process_dbg_packet (int id, MdbgProtCommandSet command_set, int command, gboolean *no_reply, guint8 *p, guint8 *end, MdbgProtBuffer *buf); void @@ -45,12 +45,12 @@ mono_dbg_process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext void* mono_dbg_create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, MdbgProtEventKind kind); -int +int mono_ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args); -void +void mono_ss_args_destroy (SingleStepArgs *ss_args); -int +int mono_de_frame_async_id (DbgEngineStackFrame *frame); #endif diff --git a/src/mono/mono/component/debugger-engine.c b/src/mono/mono/component/debugger-engine.c index 5083e3b68c819..ce0cc5eb65745 100644 --- a/src/mono/mono/component/debugger-engine.c +++ b/src/mono/mono/component/debugger-engine.c @@ -807,7 +807,7 @@ mono_de_process_single_step (void *tls, gboolean from_signal) if (method->wrapper_type && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD) goto exit; - /* + /* * FIXME: * Stopping in memset makes half-initialized vtypes visible. * Stopping in memcpy makes half-copied vtypes visible. @@ -999,7 +999,7 @@ mono_de_ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, void *tls, hit = FALSE; } } - + if (loc) { req->last_method = method; req->last_line = loc->row; @@ -1498,7 +1498,7 @@ mono_de_ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, S err = rt_callbacks.handle_multiple_ss_requests (); if (err == DE_ERR_NOT_IMPLEMENTED) { - PRINT_DEBUG_MSG (0, "Received a single step request while the previous one was still active.\n"); + PRINT_DEBUG_MSG (0, "Received a single step request while the previous one was still active.\n"); return DE_ERR_NOT_IMPLEMENTED; } } @@ -1596,7 +1596,7 @@ get_class_to_get_builder_field (DbgEngineStackFrame *frame) if (!this_obj) return NULL; - + context = mono_get_generic_context_from_stack_frame (frame->ji, mono_get_generic_info_from_stack_frame (frame->ji, &the_frame->ctx)); inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (original_class), &context, error); mono_error_assert_ok (error); /* FIXME don't swallow the error */ diff --git a/src/mono/mono/component/debugger-engine.h b/src/mono/mono/component/debugger-engine.h index a3c30d6d995cc..e6e47280e50b0 100644 --- a/src/mono/mono/component/debugger-engine.h +++ b/src/mono/mono/component/debugger-engine.h @@ -107,7 +107,7 @@ #define CMD_TYPE_GET_VALUE_SIZE MDBGPROT_CMD_TYPE_GET_VALUE_SIZE #define CMD_METHOD_GET_NAME MDBGPROT_CMD_METHOD_GET_NAME -#define CMD_METHOD_GET_DECLARING_TYPE MDBGPROT_CMD_METHOD_GET_DECLARING_TYPE +#define CMD_METHOD_GET_DECLARING_TYPE MDBGPROT_CMD_METHOD_GET_DECLARING_TYPE #define CMD_METHOD_GET_DEBUG_INFO MDBGPROT_CMD_METHOD_GET_DEBUG_INFO #define CMD_METHOD_GET_PARAM_INFO MDBGPROT_CMD_METHOD_GET_PARAM_INFO #define CMD_METHOD_GET_LOCALS_INFO MDBGPROT_CMD_METHOD_GET_LOCALS_INFO @@ -263,7 +263,7 @@ #define FRAME_FLAG_DEBUGGER_INVOKE MDBGPROT_FRAME_FLAG_DEBUGGER_INVOKE #define FRAME_FLAG_NATIVE_TRANSITION MDBGPROT_FRAME_FLAG_NATIVE_TRANSITION -/* +/* * Contains information about an inserted breakpoint. */ typedef struct { @@ -284,7 +284,7 @@ typedef struct { /* Unique id used in the wire protocol to refer to objects */ int id; /* - * A weakref gc handle pointing to the object. The gc handle is used to + * A weakref gc handle pointing to the object. The gc handle is used to * detect if the object was garbage collected. */ MonoGCHandle handle; @@ -403,5 +403,5 @@ void win32_debugger_log(FILE *stream, const gchar *format, ...); #define PRINT_MSG(...) g_print (__VA_ARGS__) #endif -void +void mono_de_init(DebuggerEngineCallbacks* cbs); diff --git a/src/mono/mono/component/debugger-mono-compat.h b/src/mono/mono/component/debugger-mono-compat.h index 0492a71f3468c..565dc81b2fb93 100644 --- a/src/mono/mono/component/debugger-mono-compat.h +++ b/src/mono/mono/component/debugger-mono-compat.h @@ -18,4 +18,4 @@ dbg_rt_atomic_inc_int32_t (volatile int32_t *value) return (int32_t)mono_atomic_inc_i32 ((volatile gint32 *)value); } -#endif \ No newline at end of file +#endif diff --git a/src/mono/mono/component/debugger-protocol.c b/src/mono/mono/component/debugger-protocol.c index 2fe3096608a51..a63b92d1ee381 100644 --- a/src/mono/mono/component/debugger-protocol.c +++ b/src/mono/mono/component/debugger-protocol.c @@ -11,7 +11,7 @@ static int32_t packet_id = 0; /* * Functions to decode protocol data */ -int +int m_dbgprot_buffer_add_command_header (MdbgProtBuffer *data, int command_set, int command, MdbgProtBuffer *out) { int id = dbg_rt_atomic_inc_int32_t ((volatile int32_t *)&packet_id); @@ -27,7 +27,7 @@ m_dbgprot_buffer_add_command_header (MdbgProtBuffer *data, int command_set, int return id; } -void +void m_dbgprot_decode_command_header (MdbgProtBuffer *recvbuf, MdbgProtHeader *header) { header->len = m_dbgprot_decode_int (recvbuf->p, &recvbuf->p, recvbuf->end); diff --git a/src/mono/mono/component/debugger-protocol.h b/src/mono/mono/component/debugger-protocol.h index 2aa52c2a857ff..af28674c42d52 100644 --- a/src/mono/mono/component/debugger-protocol.h +++ b/src/mono/mono/component/debugger-protocol.h @@ -6,7 +6,7 @@ #define HEADER_LENGTH 11 #define REPLY_PACKET 0x80 -/* +/* * Wire Protocol definitions */ diff --git a/src/mono/mono/component/debugger-state-machine.h b/src/mono/mono/component/debugger-state-machine.h index 5002467b93264..9a549401dc699 100644 --- a/src/mono/mono/component/debugger-state-machine.h +++ b/src/mono/mono/component/debugger-state-machine.h @@ -66,4 +66,4 @@ mono_debugger_state (JsonWriter *writer); char * mono_debugger_state_str (void); -#endif // __MONO_DEBUGGER_STATE_MACHINE__ +#endif // __MONO_DEBUGGER_STATE_MACHINE__ diff --git a/src/mono/mono/component/debugger-stub.c b/src/mono/mono/component/debugger-stub.c index 4235a97eb5017..c6a6a445b41d7 100644 --- a/src/mono/mono/component/debugger-stub.c +++ b/src/mono/mono/component/debugger-stub.c @@ -54,7 +54,7 @@ stub_debugger_single_step_from_context (MonoContext *ctx); static void stub_debugger_breakpoint_from_context (MonoContext *ctx); -static gboolean +static gboolean stub_debugger_transport_handshake (void); static void @@ -63,13 +63,13 @@ stub_mono_wasm_breakpoint_hit (void); static void stub_mono_wasm_single_step_hit (void); -static void +static void stub_send_enc_delta (MonoImage *image, gconstpointer dmeta_bytes, int32_t dmeta_len, gconstpointer dpdb_bytes, int32_t dpdb_len); static MonoComponentDebugger fn_table = { { MONO_COMPONENT_ITF_VERSION, &debugger_avaliable }, &stub_debugger_init, - &stub_debugger_user_break, + &stub_debugger_user_break, &stub_debugger_parse_options, &stub_debugger_breakpoint_hit, &stub_debugger_single_step_event, @@ -183,7 +183,7 @@ stub_debugger_breakpoint_from_context (MonoContext *ctx) g_assert_not_reached (); } -static gboolean +static gboolean stub_debugger_transport_handshake (void) { g_assert_not_reached(); @@ -199,7 +199,7 @@ stub_mono_wasm_single_step_hit (void) { } -static void +static void stub_send_enc_delta (MonoImage *image, gconstpointer dmeta_bytes, int32_t dmeta_len, gconstpointer dpdb_bytes, int32_t dpdb_len) { } @@ -217,13 +217,13 @@ EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command_with_parms (int id, int G_END_DECLS -EMSCRIPTEN_KEEPALIVE gboolean +EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command_with_parms (int id, int command_set, int command, guint8* data, unsigned int size, int valtype, char* newvalue) { return false; } -EMSCRIPTEN_KEEPALIVE gboolean +EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, int command_set, int command, guint8* data, unsigned int size) { return false; diff --git a/src/mono/mono/component/debugger.c b/src/mono/mono/component/debugger.c index 2ebb4f46aae91..5187d70a8954c 100644 --- a/src/mono/mono/component/debugger.c +++ b/src/mono/mono/component/debugger.c @@ -28,8 +28,8 @@ MonoComponentDebugger * mono_component_debugger_init (void) { debugger_agent_add_function_pointers (&fn_table); -#ifdef TARGET_WASM +#ifdef TARGET_WASM mini_wasm_debugger_add_function_pointers (&fn_table); -#endif +#endif return &fn_table; } diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index e44ae56e5f4af..155dcdf6f2c9a 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -87,7 +87,7 @@ hot_reload_table_bounds_check (MonoImage *base_image, int table_index, int token static gboolean hot_reload_delta_heap_lookup (MonoImage *base_image, MetadataHeapGetterFunc get_heap, uint32_t orig_index, MonoImage **image_out, uint32_t *index_out); -static gpointer +static gpointer hot_reload_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx); static gboolean @@ -188,14 +188,14 @@ static MonoNativeTlsKey exposed_generation_id; * In each delta, the physical tables contain the rows that modify existing rows of a prior generation, * followed by inserted rows. * https://github.com/dotnet/runtime/blob/6072e4d3a7a2a1493f514cdf4be75a3d56580e84/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataAggregator.cs#L324 - * + * * The total logical number of rows in a table for a particular generation is * prev_gen_rows + inserted_rows. */ typedef struct _delta_row_count { guint32 prev_gen_rows; guint32 modified_rows; - guint32 inserted_rows; + guint32 inserted_rows; } delta_row_count; /* Additional informaiton for MonoImages representing deltas */ @@ -212,7 +212,7 @@ struct _DeltaInfo { // for each table, the row in the EncMap table that has the first token for remapping it? uint32_t enc_recs [MONO_TABLE_NUM]; delta_row_count count [MONO_TABLE_NUM]; - + MonoPPDBFile *ppdb_file; MonoMemPool *pool; /* mutated tables are allocated here */ @@ -1607,7 +1607,7 @@ set_update_method (MonoImage *image_base, BaselineInfo *base_info, uint32_t gene /* FIXME: this is a race if other threads are doing a lookup. */ g_hash_table_insert (base_info->method_table_update, GUINT_TO_POINTER (token_index), GUINT_TO_POINTER (generation)); g_hash_table_insert (delta_info->method_table_update, GUINT_TO_POINTER (token_index), (gpointer) il_address); - set_delta_method_debug_info (delta_info, token_index, pdb_address); + set_delta_method_debug_info (delta_info, token_index, pdb_address); } static MonoDebugInformationEnc * @@ -1813,7 +1813,7 @@ apply_enclog_pass2 (MonoImage *image_base, BaselineInfo *base_info, uint32_t gen if (!delta_info->method_table_update) delta_info->method_table_update = g_hash_table_new (g_direct_hash, g_direct_equal); if (!delta_info->method_ppdb_table_update) - + delta_info->method_ppdb_table_update = g_hash_table_new (g_direct_hash, g_direct_equal); int mapped_token = hot_reload_relative_delta_index (image_dmeta, delta_info, mono_metadata_make_token (token_table, token_index)); @@ -2089,7 +2089,7 @@ get_method_update_rva (MonoImage *image_base, BaselineInfo *base_info, uint32_t gpointer loc = NULL; uint32_t cur = hot_reload_get_thread_generation (); int generation = -1; - + /* Go through all the updates that the current thread can see and see * if they updated the method. Keep the latest visible update */ for (GList *ptr = base_info->delta_info; ptr != NULL; ptr = ptr->next) { @@ -2117,7 +2117,7 @@ get_method_update_rva (MonoImage *image_base, BaselineInfo *base_info, uint32_t return loc; } -gpointer +gpointer hot_reload_get_updated_method_ppdb (MonoImage *base_image, uint32_t idx) { BaselineInfo *info = baseline_info_lookup (base_image); diff --git a/src/mono/mono/component/mini-wasm-debugger.c b/src/mono/mono/component/mini-wasm-debugger.c index 81a2011e1ef54..33728e8ca0609 100644 --- a/src/mono/mono/component/mini-wasm-debugger.c +++ b/src/mono/mono/component/mini-wasm-debugger.c @@ -174,7 +174,7 @@ mono_wasm_debugger_init (void) mono_profiler_set_domain_loaded_callback (prof, appdomain_load); mono_profiler_set_assembly_loaded_callback (prof, assembly_loaded); -//debugger-agent initialization +//debugger-agent initialization DebuggerTransport trans; trans.name = "buffer-wasm-communication"; trans.send = receive_debugger_agent_message; @@ -202,7 +202,7 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly) MonoDebugHandle *handle = mono_debug_get_handle (assembly_image); if (handle) { MonoPPDBFile *ppdb = handle->ppdb; - if (ppdb && !mono_ppdb_is_embedded (ppdb)) { //if it's an embedded pdb we don't need to send pdb extrated to DebuggerProxy. + if (ppdb && !mono_ppdb_is_embedded (ppdb)) { //if it's an embedded pdb we don't need to send pdb extrated to DebuggerProxy. pdb_image = mono_ppdb_get_image (ppdb); mono_wasm_asm_loaded (assembly_image->assembly_name, assembly_image->raw_data, assembly_image->raw_data_len, pdb_image->raw_data, pdb_image->raw_data_len); return; @@ -339,7 +339,7 @@ write_value_to_buffer (MdbgProtBuffer *buf, MonoTypeEnum type, const char* varia return TRUE; } -EMSCRIPTEN_KEEPALIVE void +EMSCRIPTEN_KEEPALIVE void mono_wasm_set_is_debugger_attached (gboolean is_attached) { mono_set_is_debugger_attached (is_attached); @@ -357,7 +357,7 @@ mono_wasm_set_is_debugger_attached (gboolean is_attached) extern void mono_wasm_add_dbg_command_received(mono_bool res_ok, int id, void* buffer, int buffer_len); -EMSCRIPTEN_KEEPALIVE gboolean +EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size, int valtype, char* newvalue) { if (!debugger_enabled) { @@ -378,7 +378,7 @@ mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, i return TRUE; } -EMSCRIPTEN_KEEPALIVE gboolean +EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, guint8* data, unsigned int size) { if (!debugger_enabled) { @@ -392,7 +392,7 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, buffer_init (&buf, 128); gboolean no_reply; MdbgProtErrorCode error = 0; - if (command_set == MDBGPROT_CMD_SET_VM && command == MDBGPROT_CMD_VM_INVOKE_METHOD ) + if (command_set == MDBGPROT_CMD_SET_VM && command == MDBGPROT_CMD_VM_INVOKE_METHOD ) { DebuggerTlsData* tls = mono_wasm_get_tls (); InvokeData invoke_data; @@ -409,12 +409,12 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command, return TRUE; } -static gboolean +static gboolean receive_debugger_agent_message (void *data, int len) { mono_wasm_add_dbg_command_received(1, -1, data, len); mono_wasm_save_thread_context(); - mono_wasm_fire_debugger_agent_message (); + mono_wasm_fire_debugger_agent_message (); return FALSE; } diff --git a/src/mono/mono/eglib/garray.c b/src/mono/mono/eglib/garray.c index 97df96736a14f..212179043bb03 100644 --- a/src/mono/mono/eglib/garray.c +++ b/src/mono/mono/eglib/garray.c @@ -46,20 +46,20 @@ static void ensure_capacity (GArrayPriv *priv, guint capacity) { guint new_capacity; - + if (capacity <= priv->capacity) return; - + new_capacity = (capacity + (capacity >> 1) + 63) & ~63; - + priv->array.data = g_realloc (priv->array.data, element_length (priv, new_capacity)); - + if (priv->clear_) { memset (element_offset (priv, priv->capacity), 0, element_length (priv, new_capacity - priv->capacity)); } - + priv->capacity = new_capacity; } @@ -122,7 +122,7 @@ g_array_append_vals (GArray *array, g_return_val_if_fail (array != NULL, NULL); ensure_capacity (priv, priv->array.len + len + (priv->zero_terminated ? 1 : 0)); - + memmove (element_offset (priv, priv->array.len), data, element_length (priv, len)); @@ -150,7 +150,7 @@ g_array_insert_vals (GArray *array, g_return_val_if_fail (array != NULL, NULL); ensure_capacity (priv, array->len + len + extra); - + /* first move the existing elements out of the way */ memmove (element_offset (priv, index_ + len), element_offset (priv, index_), diff --git a/src/mono/mono/eglib/gdir-unix.c b/src/mono/mono/eglib/gdir-unix.c index fe27306f6252a..10b15e7bc24e4 100644 --- a/src/mono/mono/eglib/gdir-unix.c +++ b/src/mono/mono/eglib/gdir-unix.c @@ -112,16 +112,16 @@ g_mkdir_with_parents (const gchar *pathname, int mode) { char *path, *d; int rv; - + if (!pathname || *pathname == '\0') { mono_set_errno (EINVAL); return -1; } - + d = path = g_strdup (pathname); if (*d == '/') d++; - + while (TRUE) { if (*d == '/' || *d == '\0') { char orig = *d; @@ -141,8 +141,8 @@ g_mkdir_with_parents (const gchar *pathname, int mode) d++; } } - + g_free (path); - + return 0; } diff --git a/src/mono/mono/eglib/gdir-win32.c b/src/mono/mono/eglib/gdir-win32.c index 5683c499236af..30004642361fd 100644 --- a/src/mono/mono/eglib/gdir-win32.c +++ b/src/mono/mono/eglib/gdir-win32.c @@ -127,7 +127,7 @@ void g_dir_close (GDir *dir) { g_return_if_fail (dir != NULL && dir->handle != 0); - + if (dir->current) g_free (dir->current); dir->current = NULL; diff --git a/src/mono/mono/eglib/gerror.c b/src/mono/mono/eglib/gerror.c index f767f95bc2711..b68d4ccb4121a 100644 --- a/src/mono/mono/eglib/gerror.c +++ b/src/mono/mono/eglib/gerror.c @@ -35,13 +35,13 @@ g_error_new (gpointer domain, gint code, const char *format, ...) { va_list args; GError *err = g_new (GError, 1); - + err->domain = domain; err->code = code; va_start (args, format); if (g_vasprintf (&err->message, format, args) == -1) - err->message = g_strdup_printf ("internal: invalid format string %s", format); + err->message = g_strdup_printf ("internal: invalid format string %s", format); va_end (args); return err; @@ -51,12 +51,12 @@ static GError * g_error_vnew (gpointer domain, gint code, const char *format, va_list ap) { GError *err = g_new (GError, 1); - + err->domain = domain; err->code = code; if (g_vasprintf (&err->message, format, ap) == -1) - err->message = g_strdup_printf ("internal: invalid format string %s", format); + err->message = g_strdup_printf ("internal: invalid format string %s", format); return err; } @@ -75,7 +75,7 @@ g_error_free (GError *gerror) { if (!gerror) return; - + g_free (gerror->message); g_free (gerror); } diff --git a/src/mono/mono/eglib/gfile-win32.c b/src/mono/mono/eglib/gfile-win32.c index f7195444860f5..2d86027d164fc 100644 --- a/src/mono/mono/eglib/gfile-win32.c +++ b/src/mono/mono/eglib/gfile-win32.c @@ -94,14 +94,14 @@ g_file_test (const gchar *filename, GFileTest test) { gunichar2* utf16_filename = NULL; DWORD attr; - + if (filename == NULL || test == 0) return FALSE; utf16_filename = u8to16 (filename); attr = GetFileAttributesW (utf16_filename); g_free (utf16_filename); - + if (attr == INVALID_FILE_ATTRIBUTES) return FALSE; diff --git a/src/mono/mono/eglib/gfile.c b/src/mono/mono/eglib/gfile.c index a0222ccbbd3c6..75f9ccfa47cf4 100644 --- a/src/mono/mono/eglib/gfile.c +++ b/src/mono/mono/eglib/gfile.c @@ -117,41 +117,41 @@ g_file_set_contents (const gchar *filename, const gchar *contents, gssize length const char *name; char *path; FILE *fp; - + if (!(name = strrchr (filename, G_DIR_SEPARATOR))) name = filename; else name++; - + path = g_strdup_printf (TMP_FILE_FORMAT, (int)(name - filename), filename, name); if (!(fp = fopen (path, "wb"))) { g_set_error (err, G_FILE_ERROR, g_file_error_from_errno (errno), "%s", g_strerror (errno)); g_free (path); return FALSE; } - + if (length < 0) length = strlen (contents); - + if (fwrite (contents, 1, length, fp) < length) { g_set_error (err, G_FILE_ERROR, g_file_error_from_errno (ferror (fp)), "%s", g_strerror (ferror (fp))); g_unlink (path); g_free (path); fclose (fp); - + return FALSE; } - + fclose (fp); - + if (g_rename (path, filename) != 0) { g_set_error (err, G_FILE_ERROR, g_file_error_from_errno (errno), "%s", g_strerror (errno)); g_unlink (path); g_free (path); return FALSE; } - + g_free (path); - + return TRUE; } diff --git a/src/mono/mono/eglib/glist.c b/src/mono/mono/eglib/glist.c index 9fe1748133857..6a05f96a511e3 100644 --- a/src/mono/mono/eglib/glist.c +++ b/src/mono/mono/eglib/glist.c @@ -12,10 +12,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -185,14 +185,14 @@ g_list_find_custom (GList *list, gconstpointer data, GCompareFunc func) { if (!func) return NULL; - + while (list) { if (func (list->data, data) == 0) return list; - + list = list->next; } - + return NULL; } diff --git a/src/mono/mono/eglib/gmarkup.c b/src/mono/mono/eglib/gmarkup.c index 826854a1ed346..6639ec2aa83ea 100644 --- a/src/mono/mono/eglib/gmarkup.c +++ b/src/mono/mono/eglib/gmarkup.c @@ -87,12 +87,12 @@ void g_markup_parse_context_free (GMarkupParseContext *context) { GSList *l; - + g_return_if_fail (context != NULL); if (context->user_data_dnotify != NULL) (context->user_data_dnotify) (context->user_data); - + if (context->text != NULL) g_string_free (context->text, TRUE); for (l = context->level; l; l = l->next) @@ -159,7 +159,7 @@ parse_value (const char *p, const char *end, char **value, GError **gerror) { const char *start; int l; - + if (*p != '"'){ set_error ("%s", "Expected the attribute value to start with a quote"); return end; @@ -184,7 +184,7 @@ parse_name (const char *p, const char *end, char **value) { const char *start = p; int l; - + if (p < end && my_isnamestartchar (*p)) for (; p < end && my_isnamechar (*p); p++) ; @@ -209,22 +209,22 @@ parse_attributes (const char *p, const char *end, char ***names, char ***values, p = skip_space (p, end); if (p == end) return end; - + if (*p == '>'){ *full_stop = 0; - return p; + return p; } if (state == SKIP_XML_DECLARATION && *p == '?' && ((p+1) < end) && *(p+1) == '>'){ *full_stop = 0; return p+1; } - + if (*p == '/' && ((p+1) < end && *(p+1) == '>')){ *full_stop = 1; return p+1; } else { char *name, *value; - + p = parse_name (p, end, &name); if (p == end) return p; @@ -258,9 +258,9 @@ parse_attributes (const char *p, const char *end, char ***names, char ***values, (*names) [nnames-1] = name; (*values) [nnames-1] = value; (*names) [nnames] = NULL; - (*values) [nnames] = NULL; + (*values) [nnames] = NULL; } - } + } } static void @@ -270,7 +270,7 @@ destroy_parse_state (GMarkupParseContext *context) for (p = context->level; p != NULL; p = p->next) g_free (p->data); - + g_slist_free (context->level); if (context->text != NULL) g_string_free (context->text, TRUE); @@ -284,13 +284,13 @@ g_markup_parse_context_parse (GMarkupParseContext *context, GError **gerror) { const char *p, *end; - + g_return_val_if_fail (context != NULL, FALSE); g_return_val_if_fail (text != NULL, FALSE); g_return_val_if_fail (text_len >= 0, FALSE); end = text + text_len; - + for (p = text; p < end; p++){ char c = *p; @@ -328,12 +328,12 @@ g_markup_parse_context_parse (GMarkupParseContext *context, p += 2; break; } - + if (!my_isnamestartchar (*p)){ set_error ("%s", "Expected an element name"); goto fail; } - + for (++p; p < end && my_isnamechar (*p); p++) ; if (p == end){ @@ -341,7 +341,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context, goto fail; } element_end = p; - + for (; p < end && my_isspace (*p); p++) ; if (p == end){ @@ -382,7 +382,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context, g_free (ename); goto fail; } - + if (full_stop){ if (context->parser.end_element != NULL && context->state == START_ELEMENT){ context->parser.end_element (context, ename, context->user_data, gerror); @@ -395,7 +395,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context, } else { context->level = g_slist_prepend (context->level, ename); } - + context->state = TEXT; break; } /* case START_ELEMENT */ @@ -422,7 +422,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context, break; } break; - + case FLUSH_TEXT: if (context->parser.text != NULL && context->text != NULL){ context->parser.text (context, context->text->str, context->text->len, @@ -430,7 +430,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context, if (gerror != NULL && *gerror != NULL) goto fail; } - + if (c == '/') context->state = CLOSING_ELEMENT; else { @@ -447,7 +447,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context, set_error ("%s", "Too many closing tags, not enough open tags"); goto fail; } - + text = (char*)current->data; if (context->parser.end_element != NULL){ context->parser.end_element (context, text, context->user_data, gerror); @@ -460,13 +460,13 @@ g_markup_parse_context_parse (GMarkupParseContext *context, while (p < end && *p != '>') p++; - + context->level = context->level->next; g_slist_free_1 (current); context->state = TEXT; break; } /* case CLOSING_ELEMENT */ - + } /* switch */ } @@ -475,7 +475,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context, fail: if (context->parser.error && gerror != NULL && *gerror) context->parser.error (context, *gerror, context->user_data); - + destroy_parse_state (context); return FALSE; } diff --git a/src/mono/mono/eglib/gmem.c b/src/mono/mono/eglib/gmem.c index 11d117bb60944..b50a241571504 100644 --- a/src/mono/mono/eglib/gmem.c +++ b/src/mono/mono/eglib/gmem.c @@ -111,14 +111,14 @@ gpointer g_realloc (gpointer obj, gsize size) g_error ("Could not allocate %i bytes", size); } -gpointer -g_malloc (gsize x) -{ +gpointer +g_malloc (gsize x) +{ gpointer ptr; if (!x) return 0; ptr = G_MALLOC_INTERNAL (x); - if (ptr) + if (ptr) return ptr; g_error ("Could not allocate %i bytes", x); } @@ -133,12 +133,12 @@ gpointer g_calloc (gsize n, gsize x) return ptr; g_error ("Could not allocate %i (%i * %i) bytes", x*n, n, x); } -gpointer g_malloc0 (gsize x) -{ +gpointer g_malloc0 (gsize x) +{ return g_calloc (1,x); } -gpointer g_try_malloc (gsize x) +gpointer g_try_malloc (gsize x) { if (x) return G_MALLOC_INTERNAL (x); @@ -147,10 +147,10 @@ gpointer g_try_malloc (gsize x) gpointer g_try_realloc (gpointer obj, gsize size) -{ +{ if (!size) { G_FREE_INTERNAL (obj); return 0; - } + } return G_REALLOC_INTERNAL (obj, size); } diff --git a/src/mono/mono/eglib/gmisc-unix.c b/src/mono/mono/eglib/gmisc-unix.c index 2630d515fda5f..0c8ec6bec8d47 100644 --- a/src/mono/mono/eglib/gmisc-unix.c +++ b/src/mono/mono/eglib/gmisc-unix.c @@ -43,8 +43,8 @@ static pthread_mutex_t env_lock = PTHREAD_MUTEX_INITIALIZER; /* MONO Comment - * - * As per the UNIX spec, + * + * As per the UNIX spec, * "The return value from getenv() may point to static data which may be overwritten by subsequent calls to getenv(), setenv(), or unsetenv()." * Source: Unix Manual Pages for getenv, IEEE Std 1003.1 * @@ -56,7 +56,7 @@ static pthread_mutex_t env_lock = PTHREAD_MUTEX_INITIALIZER; * g_getenv does not mimic the behavior of POSIX getenv anymore. * * The memory address returned will be unique to the invocaton, and must be freed. - * */ + * */ gchar * g_getenv (const gchar *variable) { diff --git a/src/mono/mono/eglib/gmisc-win32.c b/src/mono/mono/eglib/gmisc-win32.c index 82860a575ed12..0c2f6e12f2a4d 100644 --- a/src/mono/mono/eglib/gmisc-win32.c +++ b/src/mono/mono/eglib/gmisc-win32.c @@ -48,7 +48,7 @@ g_getenv(const gchar *variable) gchar* val = NULL; gint32 buffer_size = 1024; gint32 retval; - var = u8to16(variable); + var = u8to16(variable); // FIXME This should loop in case another thread is growing the data. buffer = g_new (gunichar2, buffer_size); retval = GetEnvironmentVariableW (var, buffer, buffer_size); @@ -68,7 +68,7 @@ g_getenv(const gchar *variable) } g_free(var); g_free(buffer); - return val; + return val; } gboolean @@ -76,7 +76,7 @@ g_setenv(const gchar *variable, const gchar *value, gboolean overwrite) { gunichar2 *var, *val; gboolean result; - var = u8to16(variable); + var = u8to16(variable); val = u8to16(value); result = (SetEnvironmentVariableW(var, val) != 0) ? TRUE : FALSE; g_free(var); @@ -88,7 +88,7 @@ void g_unsetenv(const gchar *variable) { gunichar2 *var; - var = u8to16(variable); + var = u8to16(variable); SetEnvironmentVariableW(var, L""); g_free(var); } @@ -141,7 +141,7 @@ g_path_is_absolute (const char *filename) (filename[2] == '\\' || filename[2] == '/')) return TRUE; /* UNC paths */ - else if (filename[0] == '\\' && filename[1] == '\\' && + else if (filename[0] == '\\' && filename[1] == '\\' && filename[2] != '\0') return TRUE; } diff --git a/src/mono/mono/eglib/gmodule-unix.c b/src/mono/mono/eglib/gmodule-unix.c index 24b3a3023b114..bd5cc2648d80e 100644 --- a/src/mono/mono/eglib/gmodule-unix.c +++ b/src/mono/mono/eglib/gmodule-unix.c @@ -50,7 +50,7 @@ g_module_open (const gchar *file, GModuleFlags flags) int f = 0; GModule *module; void *handle; - + flags &= G_MODULE_BIND_MASK; if ((flags & G_MODULE_BIND_LAZY) != 0) f |= RTLD_LAZY; @@ -60,10 +60,10 @@ g_module_open (const gchar *file, GModuleFlags flags) handle = dlopen (file, f); if (handle == NULL) return NULL; - + module = g_new (GModule,1); module->handle = handle; - + return module; } @@ -167,7 +167,7 @@ g_module_open (const gchar *file, GModuleFlags flags) if (file != NULL) { gunichar2 *file16; - file16 = u8to16(file); + file16 = u8to16(file); module->main_module = FALSE; module->handle = LoadLibrary (file16); g_free(file16); @@ -175,7 +175,7 @@ g_module_open (const gchar *file, GModuleFlags flags) g_free (module); return NULL; } - + } else { module->main_module = TRUE; module->handle = GetModuleHandle (NULL); @@ -257,7 +257,7 @@ g_module_error (void) TCHAR* buf = NULL; DWORD code = GetLastError (); - FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL); ret = u16to8 (buf); @@ -320,15 +320,15 @@ gchar * g_module_build_path (const gchar *directory, const gchar *module_name) { const char *lib_prefix = ""; - + if (module_name == NULL) return NULL; if (strncmp (module_name, "lib", 3) != 0) lib_prefix = LIBPREFIX; - + if (directory && *directory) return g_strdup_printf ("%s/%s%s" LIBSUFFIX, directory, lib_prefix, module_name); - return g_strdup_printf ("%s%s" LIBSUFFIX, lib_prefix, module_name); + return g_strdup_printf ("%s%s" LIBSUFFIX, lib_prefix, module_name); } diff --git a/src/mono/mono/eglib/goutput.c b/src/mono/mono/eglib/goutput.c index 82ba7c09d03d0..bee7f9446a6b3 100644 --- a/src/mono/mono/eglib/goutput.c +++ b/src/mono/mono/eglib/goutput.c @@ -124,7 +124,7 @@ g_log_set_always_fatal (GLogLevelFlags fatal_mask) GLogLevelFlags old_fatal = fatal; fatal |= fatal_mask; - + return old_fatal; } @@ -147,7 +147,7 @@ g_logstr (const gchar *log_domain, GLogLevelFlags log_level, const gchar *msg) { if (!default_log_func) default_log_func = g_log_default_handler; - + default_log_func (log_domain, log_level, msg, default_log_func_user_data); } diff --git a/src/mono/mono/eglib/gpath.c b/src/mono/mono/eglib/gpath.c index e6ec47b05f1ee..96f67f27388bb 100644 --- a/src/mono/mono/eglib/gpath.c +++ b/src/mono/mono/eglib/gpath.c @@ -32,7 +32,7 @@ #include #ifdef G_OS_WIN32 -#include +#include #endif #ifdef HAVE_UNISTD_H @@ -47,45 +47,45 @@ g_build_path (const gchar *separator, const gchar *first_element, ...) GString *path; va_list args; size_t slen; - + g_return_val_if_fail (separator != NULL, NULL); - + path = g_string_sized_new (48); slen = strlen (separator); - + va_start (args, first_element); for (elem = first_element; elem != NULL; elem = next) { /* trim any trailing separators from @elem */ endptr = elem + strlen (elem); trimmed = FALSE; - + while (endptr >= elem + slen) { if (strncmp (endptr - slen, separator, slen) != 0) break; - + endptr -= slen; trimmed = TRUE; } - + /* append elem, not including any trailing separators */ if (endptr > elem) g_string_append_len (path, elem, endptr - elem); - + /* get the next element */ do { if (!(next = va_arg (args, char *))) break; - + /* remove leading separators */ while (!strncmp (next, separator, slen)) next += slen; } while (*next == '\0'); - + if (next || trimmed) g_string_append_len (path, separator, slen); } va_end (args); - + return g_string_free (path, FALSE); } @@ -149,7 +149,7 @@ g_path_get_basename (const char *filename) r = strrchr_seperator (copy); if (r == NULL){ - g_free (copy); + g_free (copy); return g_strdup ("/"); } r = g_strdup (&r[1]); @@ -170,10 +170,10 @@ strtok_r(char *s, const char *delim, char **last) char *spanp; int c, sc; char *tok; - + if (s == NULL && (s = *last) == NULL) return NULL; - + /* * Skip (span) leading delimiters (s += strspn(s, delim), sort of). */ @@ -247,8 +247,8 @@ g_find_program_in_path (const gchar *program) #endif while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){ - char *probe_path; - + char *probe_path; + x = NULL; probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL); #ifdef HAVE_ACCESS @@ -309,7 +309,7 @@ g_ensure_directory_exists (const gchar *filename) gunichar2 *p; gunichar2 *dir_utf16 = NULL; int retval; - + if (!dir_utf8 || !dir_utf8 [0]) return FALSE; @@ -332,7 +332,7 @@ g_ensure_directory_exists (const gchar *filename) p = dir_utf16; /* get past C:\ )*/ - while (*p++ != '\\') + while (*p++ != '\\') { } @@ -349,7 +349,7 @@ g_ensure_directory_exists (const gchar *filename) break; *p++ = '\\'; } - + g_free (dir_utf16); return TRUE; #else @@ -357,17 +357,17 @@ g_ensure_directory_exists (const gchar *filename) gchar *dir = g_path_get_dirname (filename); int retval; struct stat sbuf; - + if (!dir || !dir [0]) { g_free (dir); return FALSE; } - + if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) { g_free (dir); return TRUE; } - + p = dir; while (*p == '/') p++; @@ -385,7 +385,7 @@ g_ensure_directory_exists (const gchar *filename) break; *p++ = '/'; } - + g_free (dir); return TRUE; #endif diff --git a/src/mono/mono/eglib/gpattern.c b/src/mono/mono/eglib/gpattern.c index 1bece4df7726e..1ddbdb18f6263 100644 --- a/src/mono/mono/eglib/gpattern.c +++ b/src/mono/mono/eglib/gpattern.c @@ -176,7 +176,7 @@ match_string (GSList *list, const gchar *str, size_t idx, size_t max) idx += len; list = list->next; if (list) { - /* + /* * When recursing, we need this to avoid returning FALSE * because 'list' will not be NULL */ diff --git a/src/mono/mono/eglib/gptrarray.c b/src/mono/mono/eglib/gptrarray.c index 18509bc4accf3..a22288b09895e 100644 --- a/src/mono/mono/eglib/gptrarray.c +++ b/src/mono/mono/eglib/gptrarray.c @@ -37,7 +37,7 @@ typedef struct _GPtrArrayPriv { guint size; } GPtrArrayPriv; -static void +static void g_ptr_array_grow(GPtrArrayPriv *array, guint length) { g_assert (array); @@ -93,7 +93,7 @@ g_ptr_array_free(GPtrArray *array, gboolean free_seg) } g_free(array); - + return data; } @@ -104,7 +104,7 @@ g_ptr_array_set_size(GPtrArray *array, gint length) if((size_t)length > array->len) { g_ptr_array_grow((GPtrArrayPriv *)array, length); - memset(array->pdata + array->len, 0, (length - array->len) + memset(array->pdata + array->len, 0, (length - array->len) * sizeof(gpointer)); } @@ -133,7 +133,7 @@ g_ptr_array_remove_index(GPtrArray *array, guint index) g_memmove(array->pdata + index, array->pdata + index + 1, (array->len - index - 1) * sizeof(gpointer)); } - + array->len--; array->pdata[array->len] = NULL; @@ -199,7 +199,7 @@ g_ptr_array_remove_fast(GPtrArray *array, gpointer data) return FALSE; } -void +void g_ptr_array_foreach(GPtrArray *array, GFunc func, gpointer user_data) { guint i; @@ -220,7 +220,7 @@ void g_ptr_array_sort_with_data (GPtrArray *array, GCompareDataFunc compare, gpointer user_data) { g_assert (array); - + g_qsort_with_data (array->pdata, array->len, sizeof (gpointer), compare, user_data); } diff --git a/src/mono/mono/eglib/gqsort.c b/src/mono/mono/eglib/gqsort.c index cbc9089d33175..f06a3e2efe043 100644 --- a/src/mono/mono/eglib/gqsort.c +++ b/src/mono/mono/eglib/gqsort.c @@ -73,85 +73,85 @@ g_qsort_with_data (gpointer base, size_t nmemb, size_t size, GCompareDataFunc co size_t n, n1, n2; char *lo, *hi; int swaplong; - + if (nmemb <= 1) return; - + SWAP_INIT (); - + /* initialize our stack */ sp = stack; QSORT_PUSH (sp, base, nmemb); - + do { QSORT_POP (sp, lo, n); - + hi = lo + (n - 1) * size; - + if (n < MAX_THRESHOLD) { /* switch to insertion sort */ for (i = lo + size; i <= hi; i += size) for (k = i; k > lo && compare (k - size, k, user_data) > 0; k -= size) SWAP (k - size, k); - + continue; } - + /* calculate the middle element */ mid = lo + (n / 2) * size; - + /* once we re-order the lo, mid, and hi elements to be in * ascending order, we'll use mid as our pivot. */ if (compare (mid, lo, user_data) < 0) { SWAP (mid, lo); } - + if (compare (hi, mid, user_data) < 0) { SWAP (mid, hi); if (compare (mid, lo, user_data) < 0) { SWAP (mid, lo); } } - + /* since we've already guaranteed that lo <= mid and mid <= hi, * we can skip comparing them again */ i = lo + size; k = hi - size; - + do { /* find the first element with a value > pivot value */ while (i < k && compare (i, mid, user_data) <= 0) i += size; - + /* find the last element with a value <= pivot value */ while (k >= i && compare (mid, k, user_data) < 0) k -= size; - + if (k <= i) break; - + SWAP (i, k); - + /* make sure we keep track of our pivot element */ if (mid == i) { mid = k; } else if (mid == k) { mid = i; } - + i += size; k -= size; } while (1); - + if (k != mid) { /* swap the pivot with the last element in the first partition */ SWAP (mid, k); } - + /* calculate segment sizes */ n2 = (hi - k) / size; n1 = (k - lo) / size; - + /* push our partitions onto the stack, largest first * (to make sure we don't run out of stack space) */ if (n2 > n1) { diff --git a/src/mono/mono/eglib/gqueue.c b/src/mono/mono/eglib/gqueue.c index f9bba47aee4ba..adf5700b7c5df 100644 --- a/src/mono/mono/eglib/gqueue.c +++ b/src/mono/mono/eglib/gqueue.c @@ -12,10 +12,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -58,7 +58,7 @@ g_queue_is_empty (GQueue *queue) { if (!queue) return TRUE; - + return queue->length == 0; } @@ -67,9 +67,9 @@ g_queue_push_head (GQueue *queue, gpointer head) { if (!queue) return; - + queue->head = g_list_prepend (queue->head, head); - + if (!queue->tail) queue->tail = queue->head; @@ -101,12 +101,12 @@ g_queue_free (GQueue *queue) { if (!queue) return; - + g_list_free (queue->head); g_free (queue); } -void +void g_queue_foreach (GQueue *queue, GFunc func, gpointer user_data) { g_list_foreach (queue->head, func, user_data); diff --git a/src/mono/mono/eglib/gshell.c b/src/mono/mono/eglib/gshell.c index 820ac46c2fff8..5fdf99d35c094 100644 --- a/src/mono/mono/eglib/gshell.c +++ b/src/mono/mono/eglib/gshell.c @@ -64,7 +64,7 @@ split_cmdline (const gchar *cmdline, GPtrArray *array, GError **gerror) } } else if (c == '\\' && quote_char == '\"'){ escaped = TRUE; - } else + } else g_string_append_c (str, c); } else if (g_ascii_isspace (c)) { if (str->len > 0) { @@ -150,7 +150,7 @@ g_shell_quote (const gchar *unquoted_string) { GString *result = g_string_new ("'"); const gchar *p; - + for (p = unquoted_string; *p; p++){ if (*p == '\'') g_string_append (result, "'\\'"); @@ -169,7 +169,7 @@ g_shell_unquote (const gchar *quoted_string, GError **gerror) if (quoted_string == NULL) return NULL; - + /* Quickly try to determine if we need to unquote or not */ for (p = quoted_string; *p; p++){ if (*p == '\'' || *p == '"' || *p == '\\'){ @@ -177,7 +177,7 @@ g_shell_unquote (const gchar *quoted_string, GError **gerror) break; } } - + if (!do_unquote) return g_strdup (quoted_string); @@ -217,7 +217,7 @@ g_shell_unquote (const gchar *quoted_string, GError **gerror) g_string_append_c (result, '\\'); break; } - } + } g_string_append_c (result, *p); } if (!*p){ @@ -257,8 +257,8 @@ char *args [] = { "\\\\", "'\\\\'", "\"f\\$\"\\\"\\\\", // /\\\"\\\\" - "'f\\$'\\\"\\\\", - "'f\\$\\\\'", + "'f\\$'\\\"\\\\", + "'f\\$\\\\'", NULL }; @@ -268,12 +268,12 @@ main () { char **s = args; int i; - + while (*s){ char *r1 = g_shell_unquote (*s, NULL); char *r2 = g2_shell_unquote (*s, NULL); char *ok = r1 == r2 ? "ok" : (r1 != NULL && r2 != NULL && strcmp (r1, r2) == 0) ? "ok" : "fail"; - + printf ("%s [%s] -> [%s] - [%s]\n", ok, *s, r1, r2); s++; } @@ -283,7 +283,7 @@ main () buffer [1] = '\\'; buffer [3] = '\"'; buffer [4] = 0; - + for (i = 32; i < 255; i++){ buffer [2] = i; printf ("%d [%s] -> [%s]\n", i, buffer, g_shell_unquote (buffer, NULL)); diff --git a/src/mono/mono/eglib/gslist.c b/src/mono/mono/eglib/gslist.c index 65744eaa73b72..71cd6dfd972e9 100644 --- a/src/mono/mono/eglib/gslist.c +++ b/src/mono/mono/eglib/gslist.c @@ -12,10 +12,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -60,7 +60,7 @@ g_slist_prepend (GSList *list, gpointer data) } /* - * Insert the given data in a new node after the current node. + * Insert the given data in a new node after the current node. * Return new node. */ static GSList * @@ -186,14 +186,14 @@ g_slist_find_custom (GSList *list, gconstpointer data, GCompareFunc func) { if (!func) return NULL; - + while (list) { if (func (list->data, data) == 0) return list; - + list = list->next; } - + return NULL; } @@ -299,7 +299,7 @@ GSList* g_slist_insert_sorted (GSList *list, gpointer data, GCompareFunc func) { GSList *prev = NULL; - + if (!func) return list; @@ -320,15 +320,15 @@ gint g_slist_index (GSList *list, gconstpointer data) { gint index = 0; - + while (list) { if (list->data == data) return index; - + index++; list = list->next; } - + return -1; } diff --git a/src/mono/mono/eglib/gspawn.c b/src/mono/mono/eglib/gspawn.c index 03711f9affd06..7dc6fbcd8c7ff 100644 --- a/src/mono/mono/eglib/gspawn.c +++ b/src/mono/mono/eglib/gspawn.c @@ -84,9 +84,9 @@ mono_close_pipe (int p [2]) #if defined(__APPLE__) #if defined (TARGET_OSX) -/* Apple defines this in crt_externs.h but doesn't provide that header for +/* Apple defines this in crt_externs.h but doesn't provide that header for * arm-apple-darwin9. We'll manually define the symbol on Apple as it does - * in fact exist on all implementations (so far) + * in fact exist on all implementations (so far) */ G_BEGIN_DECLS gchar ***_NSGetEnviron(void); @@ -131,12 +131,12 @@ read_pipes (int outfd, gchar **out_str, int errfd, gchar **err_str, GError **ger if (out_str) { *out_str = NULL; out = g_string_new (""); - } + } if (err_str) { *err_str = NULL; err = g_string_new (""); - } + } do { if (out_closed && err_closed) @@ -208,18 +208,18 @@ write_all (int fd, const void *vbuf, size_t n) const char *buf = (const char *) vbuf; size_t nwritten = 0; int w; - + do { do { w = write (fd, buf + nwritten, n - nwritten); } while (w == -1 && errno == EINTR); - + if (w == -1) return -1; - + nwritten += w; } while (nwritten < n); - + return nwritten; } @@ -264,7 +264,7 @@ g_spawn_command_line_sync (const gchar *command_line, int stderr_pipe [2] = { -1, -1 }; int status; int res; - + if (!g_shell_parse_argv (command_line, &argc, &argv, gerror)) return FALSE; diff --git a/src/mono/mono/eglib/gstr.c b/src/mono/mono/eglib/gstr.c index cbf63d8f02b97..8e03bf7e2e465 100644 --- a/src/mono/mono/eglib/gstr.c +++ b/src/mono/mono/eglib/gstr.c @@ -38,9 +38,9 @@ #include -/* - * g_strndup and g_vasprintf need to allocate memory with g_malloc if - * ENABLE_OVERRIDABLE_ALLOCATORS is defined so that it can be safely freed with g_free +/* + * g_strndup and g_vasprintf need to allocate memory with g_malloc if + * ENABLE_OVERRIDABLE_ALLOCATORS is defined so that it can be safely freed with g_free * rather than free. */ @@ -71,7 +71,7 @@ gint g_vasprintf (gchar **ret, const gchar *fmt, va_list ap) int len; size_t buflen; va_list ap2; - + #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) ap2 = ap; len = _vscprintf(fmt, ap2); // NOTE MS specific extension ( :-( ) @@ -139,7 +139,7 @@ g_str_has_suffix(const gchar *str, const gchar *suffix) { size_t str_length; size_t suffix_length; - + g_return_val_if_fail(str != NULL, FALSE); g_return_val_if_fail(suffix != NULL, FALSE); @@ -156,7 +156,7 @@ g_str_has_prefix(const gchar *str, const gchar *prefix) { size_t str_length; size_t prefix_length; - + g_return_val_if_fail(str != NULL, FALSE); g_return_val_if_fail(prefix != NULL, FALSE); @@ -173,7 +173,7 @@ g_strdup_vprintf (const gchar *format, va_list args) { int n; char *ret; - + n = g_vasprintf (&ret, format, args); if (n == -1) return NULL; @@ -301,7 +301,7 @@ g_strconcat (const gchar *first, ...) len += strlen (s); } va_end (args); - + ret = (char*)g_malloc (len + 1); if (ret == NULL) return NULL; @@ -323,24 +323,24 @@ g_strconcat (const gchar *first, ...) static void add_to_vector (gchar ***vector, int size, gchar *token) { - *vector = *vector == NULL ? + *vector = *vector == NULL ? (gchar **)g_malloc(2 * sizeof(*vector)) : (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector)); - + (*vector)[size - 1] = token; } -gchar ** +gchar ** g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens) { const gchar *c; gchar *token, **vector; gint size = 1; - + g_return_val_if_fail (string != NULL, NULL); g_return_val_if_fail (delimiter != NULL, NULL); g_return_val_if_fail (delimiter[0] != 0, NULL); - + if (strncmp (string, delimiter, strlen (delimiter)) == 0) { vector = (gchar **)g_malloc (2 * sizeof(vector)); vector[0] = g_strdup (""); @@ -375,7 +375,7 @@ g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens) token = g_strdup (c); } } - + add_to_vector (&vector, size, token); size++; } @@ -389,14 +389,14 @@ g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens) } size++; } - + if (vector == NULL) { vector = (gchar **) g_malloc (2 * sizeof (vector)); vector [0] = NULL; } else if (size > 0) { vector[size - 1] = NULL; } - + return vector; } @@ -409,21 +409,21 @@ charcmp (gchar testchar, const gchar *compare) } compare++; } - + return FALSE; } -gchar ** +gchar ** g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens) { const gchar *c; gchar *token, **vector; gint size = 1; - + g_return_val_if_fail (string != NULL, NULL); g_return_val_if_fail (delimiter != NULL, NULL); g_return_val_if_fail (delimiter[0] != 0, NULL); - + if (charcmp (*string, delimiter)) { vector = (gchar **)g_malloc (2 * sizeof(vector)); vector[0] = g_strdup (""); @@ -442,16 +442,16 @@ g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens) } else { token = g_strndup (c, toklen); } - + c = string + 1; - + add_to_vector (&vector, size, token); size++; } string++; } - + if (max_tokens > 0 && size >= max_tokens) { if (*string) { /* Add the rest of the string as the last element */ @@ -471,14 +471,14 @@ g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens) size++; } } - + if (vector == NULL) { vector = (gchar **) g_malloc (2 * sizeof (vector)); vector [0] = NULL; } else if (size > 0) { vector[size - 1] = NULL; } - + return vector; } @@ -514,7 +514,7 @@ g_strjoin (const gchar *separator, ...) slen = strlen (separator); else slen = 0; - + len = 0; va_start (args, separator); for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){ @@ -525,7 +525,7 @@ g_strjoin (const gchar *separator, ...) if (len == 0) return g_strdup (""); - + /* Remove the last separator */ if (slen > 0 && len > 0) len -= slen; @@ -549,12 +549,12 @@ g_strjoinv (const gchar *separator, gchar **str_array) { char *res, *r; size_t slen, len, i; - + if (separator != NULL) slen = strlen (separator); else slen = 0; - + len = 0; for (i = 0; str_array [i] != NULL; i++){ len += strlen (str_array [i]); @@ -641,7 +641,7 @@ g_snprintf(gchar *string, gulong n, gchar const *format, ...) { va_list args; gint ret; - + va_start(args, format); ret = vsnprintf(string, n, format, args); va_end(args); @@ -657,7 +657,7 @@ char_needs_encoding (char c) { if (((unsigned char)c) >= 0x80) return TRUE; - + if ((c >= '@' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '&' && c < 0x3b) || @@ -677,7 +677,7 @@ g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **gerror #else const char *uriPrefix = "file://"; #endif - + g_return_val_if_fail (filename != NULL, NULL); if (hostname != NULL) @@ -686,10 +686,10 @@ g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **gerror if (!g_path_is_absolute (filename)){ if (gerror != NULL) *gerror = g_error_new (NULL, 2, "Not an absolute filename"); - + return NULL; } - + n = strlen (uriPrefix) + 1; for (p = filename; *p; p++){ #ifdef G_OS_WIN32 @@ -742,7 +742,7 @@ g_filename_from_uri (const gchar *uri, gchar **hostname, GError **gerror) const char *p; char *r, *result; int flen = 0; - + g_return_val_if_fail (uri != NULL, NULL); if (hostname != NULL) @@ -763,7 +763,7 @@ g_filename_from_uri (const gchar *uri, gchar **hostname, GError **gerror) *gerror = g_error_new (NULL, 2, "URI contains an invalid escape sequence"); return NULL; } - } + } flen++; } #ifndef G_OS_WIN32 @@ -822,16 +822,16 @@ gchar * g_ascii_strdown (const gchar *str, gssize len) { char *ret; - + g_return_val_if_fail (str != NULL, NULL); if (len == -1) len = strlen (str); - + ret = g_malloc (len + 1); g_ascii_strdown_no_alloc (ret, str, len); ret [len] = 0; - + return ret; } @@ -846,17 +846,17 @@ g_ascii_strup (const gchar *str, gssize len) { char *ret; int i; - + g_return_val_if_fail (str != NULL, NULL); if (len == -1) len = strlen (str); - + ret = g_malloc (len + 1); for (i = 0; i < len; i++) ret [i] = g_ascii_toupper (str [i]); ret [i] = 0; - + return ret; } @@ -899,7 +899,7 @@ g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n) if (j) return j; } - + return 0; } @@ -965,7 +965,7 @@ g_strdelimit (gchar *string, gchar delimiter, gchar new_delimiter) } } -gsize +gsize g_strlcpy (gchar *dest, const gchar *src, gsize dest_size) { g_assert (src); @@ -1011,9 +1011,9 @@ g_stpcpy (gchar *dest, const char *src) #else while (*src) *dest++ = *src++; - + *dest = '\0'; - + return dest; #endif } @@ -1128,7 +1128,7 @@ g_str_from_file_region (int fd, guint64 offset, gsize size) char *buffer; off_t loc; int status; - + do { loc = lseek (fd, offset, SEEK_SET); } while (loc == -1 && errno == EINTR); diff --git a/src/mono/mono/eglib/gstring.c b/src/mono/mono/eglib/gstring.c index 403b3ec416736..de3f0658de4c6 100644 --- a/src/mono/mono/eglib/gstring.c +++ b/src/mono/mono/eglib/gstring.c @@ -78,12 +78,12 @@ gchar * g_string_free (GString *string, gboolean free_segment) { gchar *data; - + g_return_val_if_fail (string != NULL, NULL); data = string->str; g_free(string); - + if(!free_segment) { return data; } @@ -125,7 +125,7 @@ g_string_append_c (GString *string, gchar c) g_return_val_if_fail(string != NULL, NULL); GROW_IF_NECESSARY(string, 1); - + string->str[string->len] = c; string->str[string->len + 1] = 0; string->len++; @@ -138,12 +138,12 @@ g_string_append_unichar (GString *string, gunichar c) { gchar utf8[6]; gint len; - + g_return_val_if_fail (string != NULL, NULL); - + if ((len = g_unichar_to_utf8 (c, utf8)) <= 0) return string; - + return g_string_append_len (string, utf8, len); } @@ -152,7 +152,7 @@ g_string_append_printf (GString *string, const gchar *format, ...) { char *ret; va_list args; - + g_return_if_fail (string != NULL); g_return_if_fail (format != NULL); @@ -181,12 +181,12 @@ void g_string_printf (GString *string, const gchar *format, ...) { va_list args; - + g_return_if_fail (string != NULL); g_return_if_fail (format != NULL); g_free (string->str); - + va_start (args, format); string->str = g_strdup_vprintf (format, args); va_end (args); @@ -203,7 +203,7 @@ g_string_truncate (GString *string, gsize len) /* Silent return */ if (len >= string->len) return string; - + string->len = len; string->str[len] = 0; return string; @@ -215,7 +215,7 @@ g_string_set_size (GString *string, gsize len) g_return_val_if_fail (string != NULL, string); GROW_IF_NECESSARY(string, len); - + string->len = len; string->str[len] = 0; return string; diff --git a/src/mono/mono/eglib/gunicode-win32.c b/src/mono/mono/eglib/gunicode-win32.c index bbae5972f318d..c402b6301c4e5 100644 --- a/src/mono/mono/eglib/gunicode-win32.c +++ b/src/mono/mono/eglib/gunicode-win32.c @@ -30,7 +30,7 @@ g_get_charset (G_CONST_RETURN char **charset) eg_my_charset = buf; is_utf8 = FALSE; } - + if (charset != NULL) *charset = eg_my_charset; diff --git a/src/mono/mono/eglib/gutf8.c b/src/mono/mono/eglib/gutf8.c index ab6e190b91dfe..8be331aaae774 100644 --- a/src/mono/mono/eglib/gutf8.c +++ b/src/mono/mono/eglib/gutf8.c @@ -36,13 +36,13 @@ utf8_case_conv (const gchar *str, gssize len, gboolean upper) gunichar *ustr; glong i, ulen; gchar *utf8; - + ustr = g_utf8_to_ucs4_fast (str, (glong) len, &ulen); for (i = 0; i < ulen; i++) ustr[i] = upper ? g_unichar_toupper (ustr[i]) : g_unichar_tolower (ustr[i]); utf8 = g_ucs4_to_utf8 (ustr, ulen, NULL, NULL, NULL); g_free (ustr); - + return utf8; } @@ -63,7 +63,7 @@ utf8_validate (const unsigned char *inptr, size_t len) { const unsigned char *ptr = inptr + len; unsigned char c; - + /* Everything falls through when TRUE... */ switch (len) { default: @@ -71,7 +71,7 @@ utf8_validate (const unsigned char *inptr, size_t len) case 4: if ((c = (*--ptr)) < 0x80 || c > 0xBF) return FALSE; - + if ((c == 0xBF || c == 0xBE) && ptr[-1] == 0xBF) { if (ptr[-2] == 0x8F || ptr[-2] == 0x9F || ptr[-2] == 0xAF || ptr[-2] == 0xBF) @@ -83,7 +83,7 @@ utf8_validate (const unsigned char *inptr, size_t len) case 2: if ((c = (*--ptr)) < 0x80 || c > 0xBF) return FALSE; - + /* no fall-through in this inner switch */ switch (*inptr) { case 0xE0: if (c < 0xA0) return FALSE; break; @@ -97,10 +97,10 @@ utf8_validate (const unsigned char *inptr, size_t len) } case 1: if (*inptr >= 0x80 && *inptr < 0xC2) return FALSE; } - + if (*inptr > 0xF4) return FALSE; - + return TRUE; } @@ -126,10 +126,10 @@ g_utf8_validate (const gchar *str, gssize max_len, const gchar **end) gboolean valid = TRUE; guint length, min; gssize n = 0; - + if (max_len == 0) return FALSE; - + if (max_len < 0) { while (*inptr != 0) { length = g_utf8_jump_table[*inptr]; @@ -137,7 +137,7 @@ g_utf8_validate (const gchar *str, gssize max_len, const gchar **end) valid = FALSE; break; } - + inptr += length; } } else { @@ -148,28 +148,28 @@ g_utf8_validate (const gchar *str, gssize max_len, const gchar **end) valid = FALSE; break; } - + length = g_utf8_jump_table[*inptr]; min = MIN (length, max_len - n); - + if (!utf8_validate (inptr, min)) { valid = FALSE; break; } - + if (min < length) { valid = FALSE; break; } - + inptr += length; n += length; } } - + if (end != NULL) *end = (gchar *) inptr; - + return valid; } @@ -179,10 +179,10 @@ g_utf8_get_char_validated (const gchar *str, gssize max_len) unsigned char *inptr = (unsigned char *) str; gunichar u = *inptr; int n, i; - + if (max_len == 0) return -2; - + if (u < 0x80) { /* simple ascii case */ return u; @@ -206,21 +206,21 @@ g_utf8_get_char_validated (const gchar *str, gssize max_len) } else { return -1; } - + if (max_len > 0) { if (!utf8_validate (inptr, MIN (max_len, n))) return -1; - + if (max_len < n) return -2; } else { if (!utf8_validate (inptr, n)) return -1; } - + for (i = 1; i < n; i++) u = (u << 6) | (*++inptr ^ 0x80); - + return u; } @@ -229,10 +229,10 @@ g_utf8_strlen (const gchar *str, gssize max_len) { const guchar *inptr = (const guchar *) str; glong clen = 0, len = 0, n; - + if (max_len == 0) return 0; - + if (max_len < 0) { while (*inptr) { inptr += g_utf8_jump_table[*inptr]; @@ -243,13 +243,13 @@ g_utf8_strlen (const gchar *str, gssize max_len) n = g_utf8_jump_table[*inptr]; if ((clen + n) > max_len) break; - + inptr += n; clen += n; len++; } } - + return len; } @@ -259,7 +259,7 @@ g_utf8_get_char (const gchar *src) unsigned char *inptr = (unsigned char *) src; gunichar u = *inptr; int n, i; - + if (u < 0x80) { /* simple ascii case */ return u; @@ -279,10 +279,10 @@ g_utf8_get_char (const gchar *src) u &= 0x01; n = 6; } - + for (i = 1; i < n; i++) u = (u << 6) | (*++inptr ^ 0x80); - + return u; } @@ -303,12 +303,12 @@ g_utf8_offset_to_pointer (const gchar *str, glong offset) // since the minimum size of a character is 1 // we know we can step back at least offset bytes jump = jump + offset; - + // if we land in the middle of a character // walk to the beginning while ((*jump & 0xc0) == 0x80) jump --; - + // count how many characters we've actually walked // by going forward p = jump; @@ -316,10 +316,10 @@ g_utf8_offset_to_pointer (const gchar *str, glong offset) p = g_utf8_next_char (p); offset ++; } while (p < jump); - + } while (offset < 0); } - + return (gchar *)p; } @@ -329,10 +329,10 @@ g_utf8_pointer_to_offset (const gchar *str, const gchar *pos) const gchar *inptr, *inend; glong offset = 0; glong sign = 1; - + if (pos == str) return 0; - + if (str < pos) { inptr = str; inend = pos; @@ -341,11 +341,11 @@ g_utf8_pointer_to_offset (const gchar *str, const gchar *pos) inend = str; sign = -1; } - + do { inptr = g_utf8_next_char (inptr); offset++; } while (inptr < inend); - + return offset * sign; } diff --git a/src/mono/mono/eglib/sort.frag.h b/src/mono/mono/eglib/sort.frag.h index 6dc1950ae4e9a..10ff451d4e6e8 100644 --- a/src/mono/mono/eglib/sort.frag.h +++ b/src/mono/mono/eglib/sort.frag.h @@ -11,10 +11,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/src/mono/mono/eglib/test/array.c b/src/mono/mono/eglib/test/array.c index 20865dadbe8cb..305c2f317396b 100644 --- a/src/mono/mono/eglib/test/array.c +++ b/src/mono/mono/eglib/test/array.c @@ -19,7 +19,7 @@ test_array_big (void) for (i = 0; i < 10000; i++) if (g_array_index (garray, gint, i) != i) return FAILED ("array value didn't match"); - + g_array_free (garray, TRUE); return NULL; @@ -101,7 +101,7 @@ test_array_insert_val (void) g_array_insert_val (array, 2, array); if (array != g_array_index (array, gpointer, 2)) return FAILED ("3 The value in the array is incorrect"); - + g_array_free (array, TRUE); array = g_array_new (FALSE, FALSE, sizeof (gpointer)); ptr0 = array; diff --git a/src/mono/mono/eglib/test/assertf.c b/src/mono/mono/eglib/test/assertf.c index 05484adb91d8b..3a844d75e1776 100644 --- a/src/mono/mono/eglib/test/assertf.c +++ b/src/mono/mono/eglib/test/assertf.c @@ -5,7 +5,7 @@ f is for format, like printf Previously one would say like: if (!expr) g_error(...) - + now: g_assertf(expr, ...); */ diff --git a/src/mono/mono/eglib/test/endian.c b/src/mono/mono/eglib/test/endian.c index d70c7c68c906f..ff40b7d2fce52 100644 --- a/src/mono/mono/eglib/test/endian.c +++ b/src/mono/mono/eglib/test/endian.c @@ -7,7 +7,7 @@ test_swap (void) guint64 b = (((guint64)a) << 32) | a, res64; guint64 b_expect = (((guint64)0x1efcdab) << 32) | 0x01efcdab; guint16 c = 0xabcd, res16; - + res32 = GUINT32_SWAP_LE_BE (a); if (res32 != 0x01efcdab) return FAILED ("GUINT32_SWAP_LE_BE returned 0x%x", res32); @@ -20,8 +20,8 @@ test_swap (void) return FAILED ("GUINT64_SWAP_LE_BE returned 0x%" PRIx64 " (had=0x%" PRIx64 ")", (guint64)res64, (guint64)b); res16 = GUINT16_SWAP_LE_BE(c); if (res16 != 0xcdab) - return FAILED ("GUINT16_SWAP_LE_BE returned 0x%x", (guint32) res16); - + return FAILED ("GUINT16_SWAP_LE_BE returned 0x%x", (guint32) res16); + return OK; } diff --git a/src/mono/mono/eglib/test/fake.c b/src/mono/mono/eglib/test/fake.c index 96e85541182ab..07f511f966216 100644 --- a/src/mono/mono/eglib/test/fake.c +++ b/src/mono/mono/eglib/test/fake.c @@ -1,7 +1,7 @@ /* * Fake test allows debugging of the driver itself */ - + #include "test.h" static RESULT diff --git a/src/mono/mono/eglib/test/hashtable.c b/src/mono/mono/eglib/test/hashtable.c index 94878f3fa8e1c..7ec13baefb995 100644 --- a/src/mono/mono/eglib/test/hashtable.c +++ b/src/mono/mono/eglib/test/hashtable.c @@ -29,7 +29,7 @@ hash_t1 (void) return FAILED ("did not find all keys, got %d expected 2", foreach_count); if (foreach_fail) return FAILED("failed to pass the user-data to foreach"); - + if (!g_hash_table_remove (t, (char*)"my")) return FAILED ("did not find known key"); if (g_hash_table_size (t) != 1) @@ -37,7 +37,7 @@ hash_t1 (void) g_hash_table_insert(t, (char*)"hello", (char*)"moon"); if (strcmp (g_hash_table_lookup (t, (char*)"hello"), (char*)"moon") != 0) return FAILED ("did not replace world with moon"); - + if (!g_hash_table_remove (t, (char*)"hello")) return FAILED ("did not find known key"); if (g_hash_table_size (t) != 0) @@ -70,7 +70,7 @@ hash_null_lookup (void) { GHashTable *hash = g_hash_table_new (NULL, NULL); gpointer ok, ov; - + g_hash_table_insert (hash, NULL, GINT_TO_POINTER (1)); g_hash_table_insert (hash, GINT_TO_POINTER(1), GINT_TO_POINTER(2)); @@ -87,7 +87,7 @@ hash_null_lookup (void) return FAILED ("Incorrect key found"); if (ov != GINT_TO_POINTER (2)) return FAILED ("Got wrong value %p\n", ov); - + g_hash_table_destroy (hash); return NULL; @@ -106,14 +106,14 @@ hash_grow (void) { GHashTable *hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); int i, count = 0; - + for (i = 0; i < 1000; i++) g_hash_table_insert (hash, g_strdup_printf ("%d", i), g_strdup_printf ("x-%d", i)); for (i = 0; i < 1000; i++){ char buffer [30]; gpointer value; - + sprintf (buffer, "%d", i); value = g_hash_table_lookup (hash, buffer); diff --git a/src/mono/mono/eglib/test/list.c b/src/mono/mono/eglib/test/list.c index b428e2d8dd422..98b2182924cd0 100644 --- a/src/mono/mono/eglib/test/list.c +++ b/src/mono/mono/eglib/test/list.c @@ -41,7 +41,7 @@ test_list_nth (void) nth = g_list_nth (list, 1); if (nth->data != bar) return FAILED ("nth failed. #1"); - + nth = g_list_nth (list, 2); if (nth->data != baz) return FAILED ("nth failed. #2"); @@ -73,7 +73,7 @@ test_list_index (void) i = g_list_index (list, bar); if (i != 1) return FAILED ("index failed. #1: %d", i); - + i = g_list_index (list, baz); if (i != 2) return FAILED ("index failed. #2: %d", i); @@ -104,7 +104,7 @@ test_list_last (void) GList *foo = g_list_prepend (NULL, (char*)"foo"); GList *bar = g_list_prepend (NULL, (char*)"bar"); GList *last; - + foo = g_list_concat (foo, bar); last = g_list_last (foo); @@ -114,7 +114,7 @@ test_list_last (void) foo = g_list_concat (foo, g_list_prepend (NULL, (char*)"baz")); foo = g_list_concat (foo, g_list_prepend (NULL, (char*)"quux")); - last = g_list_last (foo); + last = g_list_last (foo); if (strcmp ("quux", last->data)) return FAILED ("last failed. #2"); @@ -141,7 +141,7 @@ test_list_concat (void) if (g_list_first (list) != foo) return FAILED ("Concat failed. #4"); - + if (g_list_last (list) != bar) return FAILED ("Concat failed. #5"); @@ -176,7 +176,7 @@ test_list_insert_sorted (void) /* insert at the beginning */ list = g_list_insert_sorted (list, (char*)"", compare); if (strcmp ("", list->data)) - return FAILED ("insert_sorted failed. #2"); + return FAILED ("insert_sorted failed. #2"); /* insert at the end */ list = g_list_insert_sorted (list, (char*)"aaaa", compare); @@ -206,7 +206,7 @@ test_list_copy (void) return FAILED ("copy failed."); g_list_free (list); - g_list_free (copy); + g_list_free (copy); return OK; } @@ -234,7 +234,7 @@ test_list_reverse (void) } g_list_free (list); - g_list_free (reverse); + g_list_free (reverse); return OK; } @@ -267,7 +267,7 @@ test_list_remove_link (void) GList *list = foo; foo = g_list_concat (foo, bar); - foo = g_list_concat (foo, baz); + foo = g_list_concat (foo, baz); list = g_list_remove_link (list, bar); @@ -277,7 +277,7 @@ test_list_remove_link (void) if (bar->next != NULL) return FAILED ("remove_link failed #2"); - g_list_free (list); + g_list_free (list); g_list_free (bar); return OK; } @@ -299,7 +299,7 @@ test_list_insert_before (void) return FAILED ("2"); if (strcmp (g_list_nth_data (foo, 1), (char*)"baz")) - return FAILED ("3: %s", g_list_nth_data (foo, 1)); + return FAILED ("3: %s", g_list_nth_data (foo, 1)); g_list_free (foo); return OK; @@ -400,26 +400,26 @@ test_list_find_custom (void) char *foo = (char*)"foo"; char *bar = (char*)"bar"; char *baz = (char*)"baz"; - + list = g_list_prepend (list, baz); list = g_list_prepend (list, bar); list = g_list_prepend (list, foo); - + found = g_list_find_custom (list, baz, find_custom); - + if (found == NULL) return FAILED ("Find failed"); - + g_list_free (list); - + return OK; } static Test list_tests [] = { { "length", test_list_length}, { "nth", test_list_nth}, - { "index", test_list_index}, - { "last", test_list_last}, + { "index", test_list_index}, + { "last", test_list_last}, { "append", test_list_append}, { "concat", test_list_concat}, {"insert_sorted", test_list_insert_sorted}, diff --git a/src/mono/mono/eglib/test/markup.c b/src/mono/mono/eglib/test/markup.c index b7700615a710c..7dd3ca3ea1546 100644 --- a/src/mono/mono/eglib/test/markup.c +++ b/src/mono/mono/eglib/test/markup.c @@ -12,7 +12,7 @@ markup_test (const char *s) GMarkupParser *parser = g_new0 (GMarkupParser, 1); GMarkupParseContext *context; GError *gerror = NULL; - + context = g_markup_parse_context_new (parser, 0, 0, 0); g_markup_parse_context_parse (context, s, strlen (s), &gerror); @@ -39,7 +39,7 @@ invalid_documents (void) do_bad_test (""); do_bad_test (""); do_bad_test (""); - + return OK; } @@ -49,7 +49,7 @@ valid_documents (void) /* These should fail */ do_ok_test (""); do_ok_test (""); - + return OK; } @@ -114,7 +114,7 @@ end_element (GMarkupParseContext *context, GError **gerror) { AppConfigInfo* app_config = (AppConfigInfo*) user_data; - + if (strcmp (element_name, "configuration") == 0) { app_config->configuration_count--; } else if (strcmp (element_name, "startup") == 0) { @@ -136,7 +136,7 @@ domain_test (const char *text) { AppConfigInfo *app_config = g_new0 (AppConfigInfo, 1); GMarkupParseContext *context; - + context = g_markup_parse_context_new (&mono_parser, 0, app_config, NULL); if (g_markup_parse_context_parse (context, text, strlen (text), NULL)) { g_markup_parse_context_end_parse (context, NULL); @@ -164,7 +164,7 @@ mono_domain (void) { AppConfigInfo *info; - info = domain_test (""); + info = domain_test (""); if (info->required_runtime == NULL) return FAILED ("No required runtime section"); if (strcmp (info->required_runtime, "v1") != 0) @@ -182,7 +182,7 @@ mono_domain (void) if ((strcmp ((char*)info->supported_runtimes->data, "v1") == 0)){ if (info->supported_runtimes->next == NULL) return FAILED ("Expected 2 supported runtimes"); - + if ((strcmp ((char*)info->supported_runtimes->next->data, "v2") != 0)) return FAILED ("Expected v1, v2, got %s", info->supported_runtimes->next->data); if (info->supported_runtimes->next->next != NULL) @@ -212,7 +212,7 @@ machine_config (void) { char *data; gsize size; - + if (g_file_get_contents ("../../data/net_1_1/machine.config", &data, &size, NULL)){ return markup_test (data); } diff --git a/src/mono/mono/eglib/test/path.c b/src/mono/mono/eglib/test/path.c index 3af25b13b9f6c..a0c2f272289dd 100644 --- a/src/mono/mono/eglib/test/path.c +++ b/src/mono/mono/eglib/test/path.c @@ -22,7 +22,7 @@ test_buildpath (void) char *s; const char *buffer = "var/private"; const char *dir = "/"; - + s = g_build_path ("/", "hola///", "//mundo", (const char*)NULL); if (strcmp (s, "hola/mundo") != 0) return FAILED ("1 Got wrong result, got: %s", s); @@ -47,7 +47,7 @@ test_buildpath (void) if (strcmp (s, "/hello/world/") != 0) return FAILED ("5 Got wrong result, got: %s", s); g_free (s); - + /* Now test multi-char-separators */ s = g_build_path ("**", "hello", "world", (const char*)NULL); if (strcmp (s, "hello**world") != 0) @@ -63,7 +63,7 @@ test_buildpath (void) if (strcmp (s, "hello**world") != 0) return FAILED ("8 Got wrong result, got: %s", s); g_free (s); - + s = g_build_path ("**", "hello**", "**world", (const char*)NULL); if (strcmp (s, "hello**world") != 0) return FAILED ("9 Got wrong result, got: %s", s); @@ -119,7 +119,7 @@ static RESULT test_buildfname (void) { char *s; - + s = g_build_filename ("a", "b", "c", "d", (const char*)NULL); #ifdef G_OS_WIN32 if (strcmp (s, "a\\b\\c\\d") != 0) @@ -143,7 +143,7 @@ test_buildfname (void) if (strcmp (s, "/foo/bar/tolo/meo/") != 0) return FAILED ("1 Got wrong result, got: %s", s); #endif - + return OK; } @@ -195,7 +195,7 @@ test_dirname (void) s = g_path_get_dirname ("/index.html"); if (strcmp (s, "/") != 0) return FAILED ("Expected [/], got [%s]", s); -#endif +#endif return OK; } @@ -274,7 +274,7 @@ test_ppath2 (void) #else const gchar *searchfor = "test-eglib"; #endif - + g_setenv ("PATH", "", TRUE); s = g_find_program_in_path ("ls"); if (s != NULL) { @@ -310,15 +310,15 @@ test_cwd (void) if (dir == NULL) return FAILED ("No current directory?"); g_free (dir); - + if (chdir (newdir) == -1) return FAILED ("No %s?", newdir); - + dir = g_get_current_dir (); if (strcmp (dir, newdir) != 0) return FAILED("Did not go to %s? Instead in %s", newdir, dir); g_free (dir); - + return OK; } #else @@ -334,7 +334,7 @@ test_misc (void) { const char *home = g_get_home_dir (); const char *tmp = g_get_tmp_dir (); - + if (home == NULL) return FAILED ("Where did my home go?"); diff --git a/src/mono/mono/eglib/test/ptrarray.c b/src/mono/mono/eglib/test/ptrarray.c index 51a1396f4c861..f90899814a596 100644 --- a/src/mono/mono/eglib/test/ptrarray.c +++ b/src/mono/mono/eglib/test/ptrarray.c @@ -11,7 +11,7 @@ typedef struct _GPtrArrayPriv { /* Don't add more than 32 items to this please */ static const char *items [] = { - "Apples", "Oranges", "Plumbs", "Goats", "Snorps", "Grapes", + "Apples", "Oranges", "Plumbs", "Goats", "Snorps", "Grapes", "Tickle", "Place", "Coffee", "Cookies", "Cake", "Cheese", "Tseng", "Holiday", "Avenue", "Smashing", "Water", "Toilet", NULL @@ -21,7 +21,7 @@ static GPtrArray *ptrarray_alloc_and_fill(guint *item_count) { GPtrArray *array = g_ptr_array_new(); gint i; - + for(i = 0; items[i] != NULL; i++) { g_ptr_array_add(array, (gpointer)items[i]); } @@ -29,7 +29,7 @@ static GPtrArray *ptrarray_alloc_and_fill(guint *item_count) if (item_count != NULL) { *item_count = i; } - + return array; } @@ -49,18 +49,18 @@ ptrarray_alloc (void) { GPtrArrayPriv *array; guint i; - + array = (GPtrArrayPriv *)ptrarray_alloc_and_fill(&i); - + if (array->size != guess_size(array->len)) { - return FAILED("Size should be %d, but it is %d", + return FAILED("Size should be %d, but it is %d", guess_size(array->len), array->size); } - + if (array->len != i) { return FAILED("Expected %d node(s) in the array", i); } - + g_ptr_array_free((GPtrArray *)array, TRUE); return OK; @@ -76,7 +76,7 @@ RESULT ptrarray_for_iterate (void) char *item = (char *)g_ptr_array_index(array, i); if (item != items[i]) { return FAILED( - "Expected item at %d to be %s, but it was %s", + "Expected item at %d to be %s, but it was %s", i, items[i], item); } } @@ -101,7 +101,7 @@ foreach_callback (gpointer data, gpointer user_data) if (item != item_cmp) { foreach_iterate_error = FAILED( - "Expected item at %d to be %s, but it was %s", + "Expected item at %d to be %s, but it was %s", foreach_iterate_index - 1, item_cmp, item); } } @@ -110,12 +110,12 @@ static RESULT ptrarray_foreach_iterate (void) { GPtrArray *array = ptrarray_alloc_and_fill(NULL); - + foreach_iterate_index = 0; foreach_iterate_error = NULL; - + g_ptr_array_foreach(array, foreach_callback, array); - + g_ptr_array_free(array, TRUE); return foreach_iterate_error; @@ -126,7 +126,7 @@ ptrarray_set_size (void) { GPtrArray *array = g_ptr_array_new(); guint i, grow_length = 50; - + g_ptr_array_add(array, (gpointer)items[0]); g_ptr_array_add(array, (gpointer)items[1]); g_ptr_array_set_size(array, grow_length); @@ -155,9 +155,9 @@ ptrarray_remove_index (void) { GPtrArray *array; guint i; - + array = ptrarray_alloc_and_fill(&i); - + g_ptr_array_remove_index(array, 0); if (array->pdata[0] != items[1]) { return FAILED("First item is not %s, it is %s", items[1], @@ -165,9 +165,9 @@ ptrarray_remove_index (void) } g_ptr_array_remove_index(array, array->len - 1); - + if (array->pdata[array->len - 1] != items[array->len]) { - return FAILED("Last item is not %s, it is %s", + return FAILED("Last item is not %s, it is %s", items[array->len - 2], array->pdata[array->len - 1]); } @@ -206,7 +206,7 @@ ptrarray_remove (void) { GPtrArray *array; guint i; - + array = ptrarray_alloc_and_fill(&i); g_ptr_array_remove(array, (gpointer)items[7]); @@ -242,13 +242,13 @@ ptrarray_sort (void) GPtrArray *array = g_ptr_array_new(); guint i; static gchar * const letters [] = { (char*)"A", (char*)"B", (char*)"C", (char*)"D", (char*)"E" }; - + g_ptr_array_add(array, letters[0]); g_ptr_array_add(array, letters[1]); g_ptr_array_add(array, letters[2]); g_ptr_array_add(array, letters[3]); g_ptr_array_add(array, letters[4]); - + g_ptr_array_sort(array, ptrarray_sort_compare); for (i = 0; i < array->len; i++) { @@ -259,7 +259,7 @@ ptrarray_sort (void) } g_ptr_array_free(array, TRUE); - + return OK; } @@ -307,7 +307,7 @@ ptrarray_remove_fast (void) { GPtrArray *array = g_ptr_array_new(); static gchar * const letters [] = { (char*)"A", (char*)"B", (char*)"C", (char*)"D", (char*)"E" }; - + if (g_ptr_array_remove_fast (array, NULL)) return FAILED ("Removing NULL succeeded"); @@ -339,7 +339,7 @@ ptrarray_remove_fast (void) if (array->pdata [0] != letters [4] || array->pdata [1] != letters [2]) return FAILED ("Last two elements are wrong"); g_ptr_array_free(array, TRUE); - + return OK; } diff --git a/src/mono/mono/eglib/test/queue.c b/src/mono/mono/eglib/test/queue.c index 200952199a8de..f267cb86c8236 100644 --- a/src/mono/mono/eglib/test/queue.c +++ b/src/mono/mono/eglib/test/queue.c @@ -95,12 +95,12 @@ test_queue_pop (void) data = g_queue_pop_head (queue); if (strcmp ("bar", data)) - return FAILED ("expect bar."); + return FAILED ("expect bar."); data = g_queue_pop_head (queue); if (strcmp ("foo", data)) return FAILED ("expect foo."); - + if (g_queue_is_empty (queue) == FALSE) return FAILED ("expect is_empty."); diff --git a/src/mono/mono/eglib/test/shell.c b/src/mono/mono/eglib/test/shell.c index d464f98aed067..4b32f08672571 100644 --- a/src/mono/mono/eglib/test/shell.c +++ b/src/mono/mono/eglib/test/shell.c @@ -11,7 +11,7 @@ test_shell_argv1 (void) gchar **argv; gboolean ret; - /* The next line prints a critical error and returns FALSE + /* The next line prints a critical error and returns FALSE ret = g_shell_parse_argv (NULL, NULL, NULL, NULL); */ ret = g_shell_parse_argv ("", NULL, NULL, NULL); @@ -97,7 +97,7 @@ test_shell_argv1 (void) return FAILED ("24. argv[2] was %s", argv [1]); if (gerror != NULL) return FAILED ("25. error is not null"); - + return OK; } @@ -268,7 +268,7 @@ test_shell_argv4 (void) return FAILED ("6. Expected -e, got: %s", argv [1]); if (strcmp (argv [2], "bash -c 'read -p \"Press any key to continue...\" -n1;'")) return FAILED ("7. Got unexpected result: %s\n", argv [2]); - + return OK; } @@ -299,7 +299,7 @@ test_shell_argv5 (void) return FAILED ("5. Expected echo got %s", argv [0]); if (strcmp (argv [1], "foo,bar")) return FAILED ("6. Expected foo,bar, got: %s", argv [1]); - + return OK; } diff --git a/src/mono/mono/eglib/test/sizes.c b/src/mono/mono/eglib/test/sizes.c index 1f3861fc99a40..cdfab0e95190a 100644 --- a/src/mono/mono/eglib/test/sizes.c +++ b/src/mono/mono/eglib/test/sizes.c @@ -16,7 +16,7 @@ test_formats (void) { char buffer [1024]; gsize a = 1; - + sprintf (buffer, "%" G_GSIZE_FORMAT, a); return NULL; @@ -64,7 +64,7 @@ test_ptrconv (void) uv2 = GPOINTER_TO_UINT (ptr); if (uv != uv2) return FAILED ("uint to pointer and back conversions fail %u != %d", uv, uv2); - + uv = 1; ptr = GUINT_TO_POINTER (uv); uv2 = GPOINTER_TO_UINT (ptr); @@ -78,7 +78,7 @@ test_ptrconv (void) return FAILED ("uint to pointer and back conversions fail %u != %d", uv, uv2); return NULL; - + } typedef struct { @@ -91,7 +91,7 @@ test_offset (void) { if (G_STRUCT_OFFSET (my_struct, a) != 0) return FAILED ("offset of a is not zero"); - + if (G_STRUCT_OFFSET (my_struct, b) != 4 && G_STRUCT_OFFSET (my_struct, b) != 8) return FAILED ("offset of b is 4 or 8, macro might be busted"); diff --git a/src/mono/mono/eglib/test/slist.c b/src/mono/mono/eglib/test/slist.c index b36a9a9c7b525..b678b5427d365 100644 --- a/src/mono/mono/eglib/test/slist.c +++ b/src/mono/mono/eglib/test/slist.c @@ -21,7 +21,7 @@ test_slist_nth (void) nth = g_slist_nth (list, 1); if (nth->data != bar) return FAILED ("nth failed. #1"); - + nth = g_slist_nth (list, 2); if (nth->data != baz) return FAILED ("nth failed. #2"); @@ -53,7 +53,7 @@ test_slist_index (void) i = g_slist_index (list, bar); if (i != 1) return FAILED ("index failed. #1: %d", i); - + i = g_slist_index (list, baz); if (i != 2) return FAILED ("index failed. #2: %d", i); @@ -102,7 +102,7 @@ test_slist_find (void) GSList *list = g_slist_prepend (NULL, (char*)"three"); GSList *found; char *data; - + list = g_slist_prepend (list, (char*)"two"); list = g_slist_prepend (list, (char*)"one"); @@ -131,18 +131,18 @@ test_slist_find_custom (void) char *foo = (char*)"foo"; char *bar = (char*)"bar"; char *baz = (char*)"baz"; - + list = g_slist_prepend (list, baz); list = g_slist_prepend (list, bar); list = g_slist_prepend (list, foo); - + found = g_slist_find_custom (list, baz, find_custom); - + if (found == NULL) return FAILED ("Find failed"); - + g_slist_free (list); - + return OK; } @@ -175,7 +175,7 @@ test_slist_remove_link (void) GSList *list = foo; foo = g_slist_concat (foo, bar); - foo = g_slist_concat (foo, baz); + foo = g_slist_concat (foo, baz); list = g_slist_remove_link (list, bar); @@ -185,7 +185,7 @@ test_slist_remove_link (void) if (bar->next != NULL) return FAILED ("remove_link failed #2"); - g_slist_free (list); + g_slist_free (list); g_slist_free (bar); return OK; @@ -224,7 +224,7 @@ test_slist_insert_sorted (void) if (strcmp ("aaaa", g_slist_last (list)->data)) return FAILED ("insert_sorted failed #3"); - g_slist_free (list); + g_slist_free (list); return OK; } diff --git a/src/mono/mono/eglib/test/string-util.c b/src/mono/mono/eglib/test/string-util.c index fb447229ef404..5c5c445b16c50 100644 --- a/src/mono/mono/eglib/test/string-util.c +++ b/src/mono/mono/eglib/test/string-util.c @@ -12,7 +12,7 @@ test_strfreev (void) array [1] = g_strdup ("two"); array [2] = g_strdup ("three"); array [3] = NULL; - + g_strfreev (array); g_strfreev (NULL); @@ -35,18 +35,18 @@ test_split (void) const gchar *to_split = "Hello world, how are we doing today?"; gint i; gchar **v; - + v= g_strsplit(to_split, " ", 0); - + if(v == NULL) { return FAILED("split failed, got NULL vector (1)"); } - + for(i = 0; v[i] != NULL; i++); if(i != 7) { return FAILED("split failed, expected 7 tokens, got %d", i); } - + g_strfreev(v); v = g_strsplit(to_split, ":", -1); @@ -78,22 +78,22 @@ test_split (void) v = g_strsplit ("appdomain1, Version=0.0.0.0, Culture=neutral", ",", 4); if (strcmp (v [0], "appdomain1") != 0) return FAILED ("Invalid value"); - + if (strcmp (v [1], " Version=0.0.0.0") != 0) return FAILED ("Invalid value"); - + if (strcmp (v [2], " Culture=neutral") != 0) return FAILED ("Invalid value"); if (v [3] != NULL) return FAILED ("Expected only 3 elements"); - + g_strfreev (v); v = g_strsplit ("abcXYdefXghiXYjklYmno", "XY", 4); if (strcmp (v [0], "abc") != 0) return FAILED ("Invalid value 0"); - + if (strcmp (v [1], "defXghi") != 0) return FAILED ("Invalid value 1"); @@ -102,25 +102,25 @@ test_split (void) if (v [3] != NULL) return FAILED ("Expected only 3 elements (1)"); - + g_strfreev (v); v = g_strsplit ("abcXYdefXghiXYjklYmno", "XY", 2); if (strcmp (v [0], "abc") != 0) return FAILED ("Invalid value 3"); - + if (strcmp (v [1], "defXghiXYjklYmno") != 0) return FAILED ("Invalid value 4"); if (v [2] != NULL) return FAILED ("Expected only 2 elements (2)"); - + g_strfreev (v); v = g_strsplit ("abcXYdefXghiXYjklYmnoXY", "XY", 3); if (strcmp (v [0], "abc") != 0) return FAILED ("Invalid value 5"); - + if (strcmp (v [1], "defXghi") != 0) return FAILED ("Invalid value 6"); @@ -129,7 +129,7 @@ test_split (void) if (v [3] != NULL) return FAILED ("Expected only 3 elements (3)"); - + g_strfreev (v); v = g_strsplit ("abcXYXYXYdefXY", "XY", -1); @@ -141,7 +141,7 @@ test_split (void) if (strcmp (v [2], "") != 0) return FAILED ("Invalid value 10"); - + if (strcmp (v [3], "def") != 0) return FAILED ("Invalid value 11"); @@ -150,28 +150,28 @@ test_split (void) if (v [5] != NULL) return FAILED ("Expected only 5 elements (4)"); - + g_strfreev (v); v = g_strsplit ("XYXYXYabcXYdef", "XY", -1); if (strcmp (v [0], "") != 0) return FAILED ("Invalid value 13"); - + if (strcmp (v [1], "") != 0) return FAILED ("Invalid value 14"); - + if (strcmp (v [2], "") != 0) return FAILED ("Invalid value 15"); - + if (strcmp (v [3], "abc") != 0) return FAILED ("Invalid value 16"); - + if (strcmp (v [4], "def") != 0) return FAILED ("Invalid value 17"); if (v [5] != NULL) return FAILED ("Expected only 5 elements (5)"); - + g_strfreev (v); v = g_strsplit ("value=", "=", 2); @@ -191,14 +191,14 @@ static RESULT test_split_set (void) { gchar **v; - + v = g_strsplit_set ("abcXYdefXghiXYjklYmno", "XY", 6); if (strcmp (v [0], "abc") != 0) return FAILED ("Invalid value 0"); if (strcmp (v [1], "") != 0) return FAILED ("Invalid value 1"); - + if (strcmp (v [2], "def") != 0) return FAILED ("Invalid value 2"); @@ -222,19 +222,19 @@ test_split_set (void) if (strcmp (v [1], "") != 0) return FAILED ("Invalid value 7"); - + if (strcmp (v [2], "defXghiXYjklYmno") != 0) return FAILED ("Invalid value 8"); if (v [3] != NULL) return FAILED ("Expected only 3 elements (2)"); - + g_strfreev (v); v = g_strsplit_set ("abcXdefYghiXjklYmnoX", "XY", 5); if (strcmp (v [0], "abc") != 0) return FAILED ("Invalid value 9"); - + if (strcmp (v [1], "def") != 0) return FAILED ("Invalid value 10"); @@ -249,7 +249,7 @@ test_split_set (void) if (v [5] != NULL) return FAILED ("Expected only 5 elements (5)"); - + g_strfreev (v); v = g_strsplit_set ("abcXYXdefXY", "XY", -1); @@ -261,7 +261,7 @@ test_split_set (void) if (strcmp (v [2], "") != 0) return FAILED ("Invalid value 16"); - + if (strcmp (v [3], "def") != 0) return FAILED ("Invalid value 17"); @@ -273,31 +273,31 @@ test_split_set (void) if (v [6] != NULL) return FAILED ("Expected only 6 elements (4)"); - + g_strfreev (v); v = g_strsplit_set ("XYXabcXYdef", "XY", -1); if (strcmp (v [0], "") != 0) return FAILED ("Invalid value 20"); - + if (strcmp (v [1], "") != 0) return FAILED ("Invalid value 21"); - + if (strcmp (v [2], "") != 0) return FAILED ("Invalid value 22"); - + if (strcmp (v [3], "abc") != 0) return FAILED ("Invalid value 23"); if (strcmp (v [4], "") != 0) return FAILED ("Invalid value 24"); - + if (strcmp (v [5], "def") != 0) return FAILED ("Invalid value 25"); if (v [6] != NULL) return FAILED ("Expected only 6 elements (5)"); - + g_strfreev (v); return OK; @@ -343,7 +343,7 @@ static RESULT test_strjoin (void) { char *s; - + s = g_strjoin (NULL, "a", "b", (const char*)NULL); if (strcmp (s, "ab") != 0) return FAILED ("Join of two strings with no separator fails"); @@ -445,7 +445,7 @@ test_filename_to_uri (void) errit ("a"); errit ("./hola"); #endif - + return OK; } @@ -473,7 +473,7 @@ test_filename_from_uri (void) ferrit ("file:///%0"); ferrit ("file:///%jj"); #endif - + return OK; } @@ -590,7 +590,7 @@ test_strlcpy (void) if (0 != strcmp (dest, NUMBERS)) return FAILED ("problem [%s] and [%s]", dest, NUMBERS); g_free (dest); - + return OK; } @@ -622,7 +622,7 @@ test_ascii_strncasecmp (void) n = g_ascii_strncasecmp ("123", "123", 1); if (n != 0) return FAILED ("Should have been 0"); - + n = g_ascii_strncasecmp ("423", "123", 1); if (n <= 0) return FAILED ("Should have been > 0, got %d", n); diff --git a/src/mono/mono/eglib/test/string.c b/src/mono/mono/eglib/test/string.c index c2cc5f37317e2..8b2281b538530 100644 --- a/src/mono/mono/eglib/test/string.c +++ b/src/mono/mono/eglib/test/string.c @@ -10,16 +10,16 @@ test_append_speed (void) { GString *s = g_string_new(""); gint i; - + for(i = 0; i < 1024; i++) { g_string_append(s, "x"); } - + if(strlen (s->str) != 1024) { - return FAILED("Incorrect string size, got: %s %d", + return FAILED("Incorrect string size, got: %s %d", s->str, strlen(s->str)); } - + g_string_free (s, TRUE); return OK; @@ -30,16 +30,16 @@ test_append_c_speed (void) { GString *s = g_string_new(""); gint i; - + for(i = 0; i < 1024; i++) { g_string_append_c(s, 'x'); } - + if(strlen(s->str) != 1024) { - return FAILED("Incorrect string size, got: %s %d", s->str, + return FAILED("Incorrect string size, got: %s %d", s->str, strlen(s->str)); } - + g_string_free(s, TRUE); return OK; @@ -90,7 +90,7 @@ test_gstring (void) s = g_string_new ("Hola"); g_string_printf (s, "Dingus"); - + /* Test that it does not release it */ ret = g_string_free (s, FALSE); g_free (ret); @@ -104,7 +104,7 @@ test_gstring (void) sfail ( 0, 4); sfail ('2', 5); g_string_free (s, TRUE); - + return OK; } @@ -119,7 +119,7 @@ test_sized (void) return FAILED ("Expected an empty len"); g_string_free (s, TRUE); - + return NULL; } @@ -132,7 +132,7 @@ test_truncate (void) if (strlen (s->str) != 3) return FAILED ("size of string should have been 3, instead it is [%s]\n", s->str); g_string_free (s, TRUE); - + s = g_string_new ("a"); s = g_string_truncate (s, 10); if (strlen (s->str) != 1) @@ -143,7 +143,7 @@ test_truncate (void) g_string_truncate (s, 0); if (strlen (s->str) != 0) return FAILED ("The size is not 0"); - + g_string_free (s, TRUE); return NULL; @@ -163,7 +163,7 @@ test_appendlen (void) g_string_append_len (s, "ha", -1); if (s->len != 7) return FAILED ("The length is not seven %d", s->len); - + g_string_free (s, TRUE); return NULL; @@ -175,7 +175,7 @@ test_macros (void) char *s = g_strdup (G_STRLOC); char *p = strchr (s + 2, ':'); int n; - + if (p == NULL) return FAILED ("Did not find a separator"); n = atoi (p+1); @@ -185,7 +185,7 @@ test_macros (void) *p = 0; if (strcmp (s + strlen(s) - 8 , "string.c") != 0) return FAILED ("This did not store the filename on G_STRLOC"); - + g_free (s); return NULL; } diff --git a/src/mono/mono/eglib/test/test.c b/src/mono/mono/eglib/test/test.c index 426812df62c8c..d614e4e3e965b 100644 --- a/src/mono/mono/eglib/test/test.c +++ b/src/mono/mono/eglib/test/test.c @@ -48,16 +48,16 @@ extern gint global_passed, global_tests; static gchar *last_result = NULL; -static gboolean +static gboolean run_test(const Test *test, char **result_out) { - gchar *result; + gchar *result; if((result = test->handler()) == NULL) { *result_out = NULL; return TRUE; } else { - *result_out = result; + *result_out = result; return FALSE; } } @@ -88,7 +88,7 @@ run_group(const Group *group, gint iterations, gboolean quiet, for(i = 0; tests[i].name != NULL; i++) { gchar *result = (char*)""; gboolean iter_pass, run; - + iter_pass = FALSE; if(tests_to_run != NULL) { gint j; @@ -106,15 +106,15 @@ run_group(const Group *group, gint iterations, gboolean quiet, if(!run) { continue; } - + total++; - + if(!quiet) { printf(" %s: ", tests[i].name); } start_time_test = get_timestamp(); - + for(j = 0; j < iterations; j++) { iter_pass = run_test(&(tests[i]), &result); if(!iter_pass) { @@ -131,11 +131,11 @@ run_group(const Group *group, gint iterations, gboolean quiet, printf("OK\n"); } } - } else { + } else { if(!quiet) { printf("FAILED (%s)\n", result); } - + if(last_result == result) { last_result = NULL; g_free(result); @@ -198,12 +198,12 @@ get_timestamp (void) return res.tv_sec + (1.e-6) * res.tv_usec; } -/* +/* * Duplicating code here from EGlib to avoid g_strsplit skew between * EGLib and GLib */ - -gchar ** + +gchar ** eg_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens) { gchar *string_c; @@ -215,12 +215,12 @@ eg_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens) g_return_val_if_fail(string != NULL, NULL); g_return_val_if_fail(delimiter != NULL, NULL); g_return_val_if_fail(delimiter[0] != 0, NULL); - + token_length = strlen(string); string_c = (gchar *)g_malloc(token_length + 1); memcpy(string_c, string, token_length); string_c[token_length] = 0; - + vector = NULL; token = (gchar *)strtok_r(string_c, delimiter, &strtok_save); @@ -230,11 +230,11 @@ eg_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens) memcpy(token_c, token, token_length); token_c[token_length] = 0; - vector = vector == NULL ? + vector = vector == NULL ? (gchar **)g_malloc(2 * sizeof(vector)) : (gchar **)g_realloc(vector, (size + 1) * sizeof(vector)); - - vector[size - 1] = token_c; + + vector[size - 1] = token_c; size++; if(max_tokens > 0 && size >= max_tokens) { @@ -251,7 +251,7 @@ eg_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens) if(vector != NULL && size > 0) { vector[size - 1] = NULL; } - + g_free(string_c); string_c = NULL; diff --git a/src/mono/mono/eglib/test/test.h b/src/mono/mono/eglib/test/test.h index a2003211ee574..d807e6c0839ce 100644 --- a/src/mono/mono/eglib/test/test.h +++ b/src/mono/mono/eglib/test/test.h @@ -25,7 +25,7 @@ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - + #ifndef _TEST_H #define _TEST_H @@ -36,8 +36,8 @@ #include #ifdef _MSC_VER -/* disable the following warnings - * C4100: The formal parameter is not referenced in the body of the function. The unreferenced parameter is ignored. +/* disable the following warnings + * C4100: The formal parameter is not referenced in the body of the function. The unreferenced parameter is ignored. * C4127: conditional expression is constant (test macros produce a lot of these) */ #pragma warning(disable:4100 4127) diff --git a/src/mono/mono/eglib/test/tests.h b/src/mono/mono/eglib/test/tests.h index 885d87a7caf4f..445552c9dc43b 100644 --- a/src/mono/mono/eglib/test/tests.h +++ b/src/mono/mono/eglib/test/tests.h @@ -26,8 +26,8 @@ DEFINE_TEST_GROUP_INIT_H(memory_tests_init); DEFINE_TEST_GROUP_INIT_H(enum_tests_init); const -static Group test_groups [] = { - {"string", string_tests_init}, +static Group test_groups [] = { + {"string", string_tests_init}, {"strutil", strutil_tests_init}, {"ptrarray", ptrarray_tests_init}, {"slist", slist_tests_init}, @@ -40,7 +40,7 @@ static Group test_groups [] = { {"path", path_tests_init}, {"shell", shell_tests_init}, {"markup", markup_tests_init}, -#if !DISABLE_PROCESS_TESTS +#if !DISABLE_PROCESS_TESTS {"spawn", spawn_tests_init}, {"module", module_tests_init}, #endif diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index c78ab44b56dfd..b50c78617ea8b 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -5245,7 +5245,7 @@ mono_profiler_class_loading ( uint64_t class_id; uint64_t module_id; - + mono_profiler_get_class_data (klass, &class_id, &module_id, NULL, NULL, NULL); mono_profiler_fire_event_enter (); @@ -5428,7 +5428,7 @@ mono_profiler_module_loading ( { if (!EventEnabledMonoProfilerModuleLoading ()) return; - + mono_profiler_fire_event_enter (); FireEtwMonoProfilerModuleLoading ( @@ -5466,7 +5466,7 @@ mono_profiler_module_loaded ( { if (!EventEnabledMonoProfilerModuleLoaded ()) return; - + uint64_t module_id = (uint64_t)image; const ep_char8_t *module_path = NULL; const ep_char8_t *module_guid = NULL; @@ -5517,7 +5517,7 @@ mono_profiler_module_unloaded ( { if (!EventEnabledMonoProfilerModuleUnloaded ()) return; - + uint64_t module_id = (uint64_t)image; const ep_char8_t *module_path = NULL; const ep_char8_t *module_guid = NULL; @@ -5570,7 +5570,7 @@ mono_profiler_assembly_loading ( { if (!EventEnabledMonoProfilerAssemblyLoading ()) return; - + uint64_t assembly_id; uint64_t module_id; @@ -5624,7 +5624,7 @@ mono_profiler_assembly_unloading ( { if (!EventEnabledMonoProfilerAssemblyUnloading ()) return; - + uint64_t assembly_id; uint64_t module_id; @@ -6039,7 +6039,7 @@ mono_profiler_gc_allocation ( if (object) { vtable_id = (uint64_t)mono_object_get_vtable_internal (object); object_size = (uint64_t)mono_object_get_size_internal (object); - + /* account for object alignment */ object_size += 7; object_size &= ~7; diff --git a/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c b/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c index 6df68f607785d..9a00736612a56 100644 --- a/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c +++ b/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c @@ -80,7 +80,7 @@ test_fast_serializer_object_fast_serialize (void) ep_raise_error_if_nok (provider != NULL); test_location = 3; - + ep_event = ep_event_alloc (provider, 1, 1, 1, EP_EVENT_LEVEL_VERBOSE, false, NULL, 0); ep_raise_error_if_nok (ep_event != NULL); diff --git a/src/mono/mono/metadata/appdomain.c b/src/mono/mono/metadata/appdomain.c index eed7c2012e126..a717c205f7910 100644 --- a/src/mono/mono/metadata/appdomain.c +++ b/src/mono/mono/metadata/appdomain.c @@ -195,7 +195,7 @@ create_domain_objects (MonoDomain *domain) domain->out_of_memory_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL_HANDLE_STRING, error)); mono_error_assert_ok (error); - /* + /* * These two are needed because the signal handlers might be executing on * an alternate stack, and Boehm GC can't handle that. */ @@ -212,7 +212,7 @@ create_domain_objects (MonoDomain *domain) domain->ephemeron_tombstone = MONO_HANDLE_RAW (mono_object_new_handle (mono_defaults.object_class, error)); mono_error_assert_ok (error); - /* + /* * This class is used during exception handling, so initialize it here, to prevent * stack overflows while handling stack overflows. */ @@ -225,7 +225,7 @@ create_domain_objects (MonoDomain *domain) * \param domain domain returned by \c mono_init * * Initialize the core AppDomain: this function will run also some - * IL initialization code, so it needs the execution engine to be fully + * IL initialization code, so it needs the execution engine to be fully * operational. * * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where @@ -377,7 +377,7 @@ mono_runtime_quit (void) (void) mono_threads_enter_gc_unsafe_region_unbalanced_internal (&dummy); // after quit_function (in particular, mini_cleanup) everything is // cleaned up so MONO_EXIT_GC_UNSAFE can't work and doesn't make sense. - + mono_runtime_quit_internal (); } @@ -390,7 +390,7 @@ mono_runtime_quit_internal (void) MONO_REQ_GC_UNSAFE_MODE; // but note that when we return, we're not in GC Unsafe mode anymore. // After clean up threads don't _have_ a thread state anymore. - + if (quit_function != NULL) quit_function (mono_get_root_domain (), NULL); } @@ -613,12 +613,12 @@ try_load_from (MonoAssembly **assembly, { gchar *fullpath; gboolean found = FALSE; - + *assembly = NULL; fullpath = g_build_filename (path1, path2, path3, path4, (const char*)NULL); found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR); - + if (found) { *assembly = mono_assembly_request_open (fullpath, req, NULL); } @@ -698,7 +698,7 @@ get_app_context_base_directory (MonoError *error) } /* - * Try loading the assembly from ApplicationBase and PrivateBinPath + * Try loading the assembly from ApplicationBase and PrivateBinPath * and then from assemblies_path if any. * LOCKING: This is called from the assembly loading code, which means the caller * might hold the loader lock. Thus, this function must not acquire the domain lock. @@ -778,7 +778,7 @@ ves_icall_System_Reflection_Assembly_InternalLoad (MonoStringHandle name_handle, alc = mono_assembly_get_alc (requesting_assembly); if (!alc) g_assert_not_reached (); - + g_assert (alc); mono_assembly_request_prepare_byname (&req, alc); req.basedir = NULL; @@ -948,7 +948,7 @@ runtimeconfig_json_get_buffer (MonovmRuntimeConfigArguments *arg, MonoFileMap ** *file_map = NULL; *buf_handle = NULL; - return NULL; + return NULL; } static void diff --git a/src/mono/mono/metadata/assembly-load-context.c b/src/mono/mono/metadata/assembly-load-context.c index 627086e3f5dfd..f3ce63deb4314 100644 --- a/src/mono/mono/metadata/assembly-load-context.c +++ b/src/mono/mono/metadata/assembly-load-context.c @@ -95,7 +95,7 @@ mono_alc_create_individual (MonoGCHandle this_gchandle, gboolean collectible, Mo static void mono_alc_cleanup_assemblies (MonoAssemblyLoadContext *alc) { - // The minimum refcount on assemblies is 2: one for the domain and one for the ALC. + // The minimum refcount on assemblies is 2: one for the domain and one for the ALC. // The domain refcount might be less than optimal on netcore, but its removal is too likely to cause issues for now. GSList *tmp; @@ -425,7 +425,7 @@ mono_alc_from_gchandle (MonoGCHandle alc_gchandle) return default_alc; MONO_STATIC_POINTER_INIT (MonoClassField, resolve) - + MonoClass *alc_class = mono_class_get_assembly_load_context_class (); g_assert (alc_class); resolve = mono_class_get_field_from_name_full (alc_class, "_nativeAssemblyLoadContext", NULL); @@ -436,7 +436,7 @@ mono_alc_from_gchandle (MonoGCHandle alc_gchandle) MonoAssemblyLoadContext *alc = NULL; mono_field_get_value_internal (mono_gchandle_get_target_internal (alc_gchandle), resolve, &alc); - return alc; + return alc; } MonoGCHandle diff --git a/src/mono/mono/metadata/assembly.h b/src/mono/mono/metadata/assembly.h index bffe668a05333..9f55a3db8114c 100644 --- a/src/mono/mono/metadata/assembly.h +++ b/src/mono/mono/metadata/assembly.h @@ -2,7 +2,7 @@ * \file */ -#ifndef _MONONET_METADATA_ASSEMBLY_H_ +#ifndef _MONONET_METADATA_ASSEMBLY_H_ #define _MONONET_METADATA_ASSEMBLY_H_ #include @@ -21,12 +21,12 @@ MonoAssembly *mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, mono_bool refonly); MONO_API MONO_RT_EXTERNAL_ONLY -MonoAssembly* mono_assembly_load (MonoAssemblyName *aname, - const char *basedir, +MonoAssembly* mono_assembly_load (MonoAssemblyName *aname, + const char *basedir, MonoImageOpenStatus *status); MONO_API MONO_RT_EXTERNAL_ONLY MonoAssembly* mono_assembly_load_full (MonoAssemblyName *aname, - const char *basedir, + const char *basedir, MonoImageOpenStatus *status, mono_bool refonly); MONO_API MONO_RT_EXTERNAL_ONLY @@ -68,8 +68,8 @@ typedef void (*MonoAssemblyLoadFunc) (MonoAssembly *assembly, void* use MONO_API MONO_RT_EXTERNAL_ONLY void mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, void* user_data); -/* - * Installs a new function which is used to search the list of loaded +/* + * Installs a new function which is used to search the list of loaded * assemblies for a given assembly name. */ typedef MonoAssembly *(*MonoAssemblySearchFunc) (MonoAssemblyName *aname, void* user_data); @@ -82,7 +82,7 @@ MONO_API MONO_RT_EXTERNAL_ONLY MonoAssembly* mono_assembly_invoke_search_hook (MonoAssemblyName *aname); /* - * Installs a new search function which is used as a last resort when loading + * Installs a new search function which is used as a last resort when loading * an assembly fails. This could invoke AssemblyResolve events. */ MONO_API MONO_RT_EXTERNAL_ONLY diff --git a/src/mono/mono/metadata/attrdefs.h b/src/mono/mono/metadata/attrdefs.h index 504c6c65fc6d2..a3a47493e2a5a 100644 --- a/src/mono/mono/metadata/attrdefs.h +++ b/src/mono/mono/metadata/attrdefs.h @@ -12,12 +12,12 @@ * * From the ECMA documentation */ - + #ifndef _MONO_METADATA_ATTRDEFS_H_ #define _MONO_METADATA_ATTRDEFS_H_ /* - * 23.1.1 Values for AssemblyHashAlgorithm + * 23.1.1 Values for AssemblyHashAlgorithm */ enum { MONO_ASSEMBLY_HASH_NONE, @@ -186,7 +186,7 @@ enum { MONO_METHOD_IMPL_ATTR_INTERNAL_CALL = 0x1000, MONO_METHOD_IMPL_ATTR_SYNCHRONIZED = 0x0020, MONO_METHOD_IMPL_ATTR_NOINLINING = 0x0008, - MONO_METHOD_IMPL_ATTR_NOOPTIMIZATION = 0x0040, + MONO_METHOD_IMPL_ATTR_NOOPTIMIZATION = 0x0040, MONO_METHOD_IMPL_ATTR_MAX_METHOD_IMPL_VAL = 0xffff }; diff --git a/src/mono/mono/metadata/boehm-gc.c b/src/mono/mono/metadata/boehm-gc.c index bdda3e69b8b02..34c85e2a84ec0 100644 --- a/src/mono/mono/metadata/boehm-gc.c +++ b/src/mono/mono/metadata/boehm-gc.c @@ -89,7 +89,7 @@ typedef struct { #define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0, NULL} -/* weak and weak-track arrays will be allocated in malloc memory +/* weak and weak-track arrays will be allocated in malloc memory */ static HandleData gc_handles [] = { EMPTY_HANDLE_DATA (HANDLE_WEAK), @@ -254,7 +254,7 @@ mono_gc_max_generation (void) } guint64 -mono_gc_get_allocated_bytes_for_current_thread (void) +mono_gc_get_allocated_bytes_for_current_thread (void) { return 0; } @@ -1226,10 +1226,10 @@ void mono_gc_set_string_length (MonoString *str, gint32 new_length) { mono_unichar2 *new_end = str->chars + new_length; - - /* zero the discarded string. This null-delimits the string and allows + + /* zero the discarded string. This null-delimits the string and allows * the space to be reclaimed by SGen. */ - + memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2)); str->length = new_length; } @@ -1468,12 +1468,12 @@ alloc_handle (HandleData *handles, MonoObject *obj, gboolean track) * This returns a handle that wraps the object, this is used to keep a * reference to a managed object from the unmanaged world and preventing the * object from being disposed. - * + * * If \p pinned is false the address of the object can not be obtained, if it is * true the address of the object can be obtained. This will also pin the * object so it will not be possible by a moving garbage collector to move the - * object. - * + * object. + * * \returns a handle that can be used to access the object from * unmanaged code. */ @@ -1493,14 +1493,14 @@ mono_gchandle_new_internal (MonoObject *obj, gboolean pinned) * Unlike the \c mono_gchandle_new_internal the object can be reclaimed by the * garbage collector. In this case the value of the GCHandle will be * set to zero. - * + * * If \p track_resurrection is TRUE the object will be tracked through * finalization and if the object is resurrected during the execution * of the finalizer, then the returned weakref will continue to hold * a reference to the object. If \p track_resurrection is FALSE, then * the weak reference's target will become NULL as soon as the object * is passed on to the finalizer. - * + * * \returns a handle that can be used to access the object from * unmanaged code. */ @@ -1589,7 +1589,7 @@ mono_gc_is_null (void) * * Frees the \p gchandle handle. If there are no outstanding * references, the garbage collector can reclaim the memory of the - * object wrapped. + * object wrapped. */ void mono_gchandle_free_internal (MonoGCHandle gch) @@ -1625,7 +1625,7 @@ mono_gchandle_free_internal (MonoGCHandle gch) } guint64 -mono_gc_get_total_allocated_bytes (MonoBoolean precise) +mono_gc_get_total_allocated_bytes (MonoBoolean precise) { return 0; } diff --git a/src/mono/mono/metadata/cil-coff.h b/src/mono/mono/metadata/cil-coff.h index d6e966ee83c70..8751f8daa5614 100644 --- a/src/mono/mono/metadata/cil-coff.h +++ b/src/mono/mono/metadata/cil-coff.h @@ -186,7 +186,7 @@ typedef struct { #define MONO_PE_RES_DIR_ENTRY_DIR_OFFSET(d) (GUINT32_FROM_LE((d).dir) & 0x7fffffff) #define MONO_PE_RES_DIR_ENTRY_SET_DIR(d,i,o) ((d).dir = GUINT32_TO_LE(((guint32)((i)?1:0) << 31) | ((o) & 0x7fffffff))) -typedef struct +typedef struct { guint32 res_characteristics; guint32 res_date_stamp; diff --git a/src/mono/mono/metadata/class-accessors.c b/src/mono/mono/metadata/class-accessors.c index a9d950d9e0fa0..9042a0ebe5b8d 100644 --- a/src/mono/mono/metadata/class-accessors.c +++ b/src/mono/mono/metadata/class-accessors.c @@ -26,8 +26,8 @@ typedef enum { PROP_DECLSEC_FLAGS = 8, /* guint32 */ PROP_WEAK_BITMAP = 9, PROP_DIM_CONFLICTS = 10, /* GSList of MonoMethod* */ - PROP_FIELD_DEF_VALUES_2BYTESWIZZLE = 11, /* MonoFieldDefaultValue* with default values swizzled at 2 byte boundaries*/ - PROP_FIELD_DEF_VALUES_4BYTESWIZZLE = 12, /* MonoFieldDefaultValue* with default values swizzled at 4 byte boundaries*/ + PROP_FIELD_DEF_VALUES_2BYTESWIZZLE = 11, /* MonoFieldDefaultValue* with default values swizzled at 2 byte boundaries*/ + PROP_FIELD_DEF_VALUES_4BYTESWIZZLE = 12, /* MonoFieldDefaultValue* with default values swizzled at 4 byte boundaries*/ PROP_FIELD_DEF_VALUES_8BYTESWIZZLE = 13, /* MonoFieldDefaultValue* with default values swizzled at 8 byte boundaries*/ PROP_METADATA_UPDATE_INFO = 14, /* MonoClassMetadataUpdateInfo* */ } InfrequentDataKind; diff --git a/src/mono/mono/metadata/class-getters.h b/src/mono/mono/metadata/class-getters.h index 7f88b78780142..98363a33952aa 100644 --- a/src/mono/mono/metadata/class-getters.h +++ b/src/mono/mono/metadata/class-getters.h @@ -1,4 +1,4 @@ -/* +/* * \file Definitions of getters for the fields of struct _MonoClass * * Copyright 2018 Microsoft @@ -8,7 +8,7 @@ /* No include guards - this file is meant to be included multiple times. * Before including the file define the following macros: * MONO_CLASS_GETTER(funcname, rettype, optref, argtype, fieldname) - * + * * MONO_CLASS_OFFSET(funcname, argtype, fieldname) */ diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 58b95248ba828..2ae4f39dab855 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -96,7 +96,7 @@ To load TextBoxBase<> to do so it must resolve the parent which is TextInput it must resolve TextInput<> and TextBox. To load TextBox it must resolve the parent which is TextBoxBase. -At this point the runtime must instantiate TextBoxBase. Both types are partially loaded +At this point the runtime must instantiate TextBoxBase. Both types are partially loaded at this point, iow, both are registered in the type map and both and a NULL parent. This means that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage. @@ -108,7 +108,7 @@ static int record_gclass_instantiation; static GSList *gclass_recorded_list; typedef gboolean (*gclass_record_func) (MonoClass*, void*); -/* +/* * LOCKING: loader lock must be held until pairing disable_gclass_recording is called. */ static void @@ -117,7 +117,7 @@ enable_gclass_recording (void) ++record_gclass_instantiation; } -/* +/* * LOCKING: loader lock must be held since pairing enable_gclass_recording was called. */ static void @@ -426,7 +426,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError guint tidx = mono_metadata_token_index (type_token); MonoGenericContext *context = NULL; const char *name, *nspace; - guint icount = 0; + guint icount = 0; MonoClass **interfaces; guint32 field_last, method_last; guint32 nesting_tokeen; @@ -447,7 +447,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError } mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE); - + name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); @@ -528,7 +528,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError if (mono_class_is_gtd (klass)) disable_gclass_recording (fix_gclass_incomplete_instantiation, klass); - /* + /* * This might access klass->_byval_arg for recursion generated by generic constraints, * so it has to come after setup_mono_type (). */ @@ -686,8 +686,8 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError // compute is_byreflike if (m_class_is_valuetype (klass)) if (class_has_isbyreflike_attribute (klass)) - klass->is_byreflike = 1; - + klass->is_byreflike = 1; + mono_loader_unlock (); MONO_PROFILER_RAISE (class_loaded, (klass)); @@ -841,7 +841,7 @@ mono_class_create_generic_inst (MonoGenericClass *gclass) klass->name = gklass->name; klass->name_space = gklass->name_space; - + klass->image = gklass->image; klass->type_token = gklass->type_token; @@ -889,7 +889,7 @@ mono_class_create_generic_inst (MonoGenericClass *gclass) if (klass->enumtype) { /* - * For enums, gklass->fields might not been set, but instance_size etc. is + * For enums, gklass->fields might not been set, but instance_size etc. is * already set in mono_reflection_create_internal_class (). For non-enums, * these will be computed normally in mono_class_layout_fields (). */ @@ -936,7 +936,7 @@ mono_class_create_generic_inst (MonoGenericClass *gclass) ++class_ginst_count; inflated_classes_size += sizeof (MonoClassGenericInst); - + mono_loader_unlock (); return klass; @@ -994,10 +994,10 @@ class_kind_may_contain_generic_instances (MonoTypeKind kind) /** * mono_class_create_bounded_array: - * \param element_class element class + * \param element_class element class * \param rank the dimension of the array class * \param bounded whenever the array has non-zero bounds - * \returns A class object describing the array with element type \p element_type and + * \returns A class object describing the array with element type \p element_type and * dimension \p rank. */ MonoClass * @@ -1243,9 +1243,9 @@ mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bound /** * mono_class_create_array: - * \param element_class element class + * \param element_class element class * \param rank the dimension of the array class - * \returns A class object describing the array with element type \p element_type and + * \returns A class object describing the array with element type \p element_type and * dimension \p rank. */ MonoClass * @@ -1440,7 +1440,7 @@ mono_class_create_ptr (MonoType *type) } mono_image_unlock (image); } - + result = mm ? (MonoClass *)mono_mem_manager_alloc0 (mm, sizeof (MonoClassPointer)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer)); UnlockedAdd (&classes_size, sizeof (MonoClassPointer)); @@ -1565,7 +1565,7 @@ mono_class_create_fnptr (MonoMethodSignature *sig) } -static gboolean +static gboolean method_is_reabstracted (guint16 flags) { if ((flags & METHOD_ATTRIBUTE_ABSTRACT && flags & METHOD_ATTRIBUTE_FINAL)) @@ -1880,7 +1880,7 @@ mono_class_is_gparam_with_nonblittable_parent (MonoClass *klass) * \param field_offsets Offsets of the klass' fields relative to the start of layout_check * \param field_count Count of klass fields * \param invalid_field_offset When the layout is invalid it will be set to the offset of the field which is invalid - * + * * \return True if the layout of the struct is valid, otherwise false. */ static gboolean @@ -2033,7 +2033,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ /* * Enable GC aware auto layout: in this mode, reference - * fields are grouped together inside objects, increasing collector + * fields are grouped together inside objects, increasing collector * performance. * Requires that all classes whose layout is known to native code be annotated * with [StructLayout (LayoutKind.Sequential)] @@ -2099,7 +2099,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ blittable = FALSE; /* Compute klass->has_references */ - /* + /* * Process non-static fields first, since static fields might recursively * refer to the class itself. */ @@ -2175,7 +2175,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ } size = mono_type_size (field->type, &align); - + /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */ align = packing_size ? MIN (packing_size, align): align; /* if the field has managed references, we need to force-align it @@ -2196,7 +2196,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ } instance_size = MAX (real_size, instance_size); - + if (instance_size & (min_align - 1)) { instance_size += min_align - 1; instance_size &= ~(min_align - 1); @@ -2276,7 +2276,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ * enable it when a MONO_DEBUG property is set. * * For small structs, set min_align to at least the struct size to improve - * performance, and since the JIT memset/memcpy code assumes this and generates + * performance, and since the JIT memset/memcpy code assumes this and generates * unaligned accesses otherwise. See #78990 for a testcase. */ if (mono_align_small_structs && top) { @@ -2343,7 +2343,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ guint32 size; field = &klass->fields [i]; - + if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL) continue; if (mono_field_is_deleted (field)) @@ -2630,7 +2630,7 @@ generic_array_methods (MonoClass *klass) if (!iface || !check_method_exists (iface, mname)) continue; - + generic_array_method_info [i].array_method = m; name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1); @@ -2736,7 +2736,7 @@ static guint32 mono_get_unique_iid (MonoClass *klass) { int iid; - + g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)); classes_lock (); @@ -2797,8 +2797,8 @@ mono_get_unique_iid (MonoClass *klass) * mono_class_init_internal: * \param klass the class to initialize * - * Compute the \c instance_size, \c class_size and other infos that cannot be - * computed at \c mono_class_get time. Also compute vtable_size if possible. + * Compute the \c instance_size, \c class_size and other infos that cannot be + * computed at \c mono_class_get time. Also compute vtable_size if possible. * Initializes the following fields in \p klass: * - all the fields initialized by \c mono_class_init_sizes * - has_cctor @@ -2820,7 +2820,7 @@ mono_class_init_internal (MonoClass *klass) gboolean ghcimpl = FALSE; gboolean has_cctor = FALSE; int first_iface_slot = 0; - + g_assert (klass); /* Double-checking locking pattern */ @@ -2851,7 +2851,7 @@ mono_class_init_internal (MonoClass *klass) MonoClass *element_class = klass->element_class; MonoClass *cast_class = klass->cast_class; - if (!element_class->inited) + if (!element_class->inited) mono_class_init_internal (element_class); if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class")) goto leave; @@ -2888,7 +2888,7 @@ mono_class_init_internal (MonoClass *klass) initialize_object_slots (klass); - /* + /* * Initialize the rest of the data without creating a generic vtable if possible. * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can * also avoid computing a generic vtable. @@ -2959,7 +2959,7 @@ mono_class_init_internal (MonoClass *klass) int mcount = mono_class_get_method_count (klass); for (i = 0; i < mcount; ++i) { MonoMethod *method = klass->methods [i]; - if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && + if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".cctor", method->name) == 0)) { has_cctor = 1; break; @@ -3059,7 +3059,7 @@ mono_class_init_checked (MonoClass *klass, MonoError *error) /* * COM initialization is delayed until needed. * However when a [ComImport] attribute is present on a type it will trigger - * the initialization. This is not a problem unless the BCL being executed + * the initialization. This is not a problem unless the BCL being executed * lacks the types that COM depends on (e.g. Variant on Silverlight). */ static void @@ -3123,13 +3123,13 @@ mono_class_setup_parent (MonoClass *klass, MonoClass *parent) if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent)) mono_class_set_is_com_object (klass); - + if (system_namespace) { - if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate")) + if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate")) klass->delegate = 1; } - if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) && + if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) klass->valuetype = 1; if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) { @@ -3223,7 +3223,7 @@ mono_class_setup_mono_type (MonoClass *klass) t = MONO_TYPE_BOOLEAN; } else if (!strcmp(name, "Byte")) { t = MONO_TYPE_U1; - klass->blittable = TRUE; + klass->blittable = TRUE; } break; case 'C': @@ -3234,7 +3234,7 @@ mono_class_setup_mono_type (MonoClass *klass) case 'D': if (!strcmp (name, "Double")) { t = MONO_TYPE_R8; - klass->blittable = TRUE; + klass->blittable = TRUE; } break; case 'I': @@ -3255,7 +3255,7 @@ mono_class_setup_mono_type (MonoClass *klass) case 'S': if (!strcmp (name, "Single")) { t = MONO_TYPE_R4; - klass->blittable = TRUE; + klass->blittable = TRUE; } else if (!strcmp(name, "SByte")) { t = MONO_TYPE_I1; klass->blittable = TRUE; @@ -3324,7 +3324,7 @@ create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *si * @class: a class * * Initializes the 'methods' array in CLASS. - * Calling this method should be avoided if possible since it allocates a lot + * Calling this method should be avoided if possible since it allocates a lot * of long-living MonoMethod structures. * Methods belonging to an interface are assigned a sequential slot starting * from 0. @@ -3363,7 +3363,7 @@ mono_class_setup_methods (MonoClass *klass) g_free (method); mono_error_cleanup (error); - return; + return; } } } else if (klass->rank) { @@ -3936,7 +3936,7 @@ mono_class_setup_has_finalizer (MonoClass *klass) * hierarchy + 1 * - supertypes: array of classes: each element has a class in the hierarchy * starting from @class up to System.Object - * + * * LOCKING: Acquires the loader lock. */ void diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 4a7992875bf68..c45c242393e2d 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -35,7 +35,7 @@ typedef struct _MonoDynamicMethod MonoDynamicMethod; /* Properties that applies to a group of structs should better use a higher number * to avoid colision with type specific properties. - * + * * This prop applies to class, method, property, event, assembly and image. */ #define MONO_PROP_DYNAMIC_CATTR 0x1000 @@ -87,7 +87,7 @@ struct _MonoMethod { signed int slot : 16; /* - * If is_generic is TRUE, the generic_container is stored in image->property_hash, + * If is_generic is TRUE, the generic_container is stored in image->property_hash, * using the key MONO_METHOD_PROP_GENERIC_CONTAINER. */ }; @@ -115,9 +115,9 @@ struct _MonoMethodPInvoke { guint32 implmap_idx; /* index into IMPLMAP */ }; -/* +/* * Stores the default value / RVA of fields. - * This information is rarely needed, so it is stored separately from + * This information is rarely needed, so it is stored separately from * MonoClassField. */ typedef struct MonoFieldDefaultValue { @@ -358,7 +358,7 @@ struct MonoVTable { /* do not add any fields after vtable, the structure is dynamically extended */ /* vtable contains function pointers to methods or their trampolines, at the end there may be a slot containing the pointer to the static fields */ - gpointer vtable [MONO_ZERO_LEN_ARRAY]; + gpointer vtable [MONO_ZERO_LEN_ARRAY]; }; #define MONO_SIZEOF_VTABLE (sizeof (MonoVTable) - MONO_ZERO_LEN_ARRAY * SIZEOF_VOID_P) @@ -647,7 +647,7 @@ typedef struct { gboolean enabled; } MonoStats; -/* +/* * new structure to hold performace counters values that are exported * to managed code. * Note: never remove fields from this structure and only add them to the end. @@ -802,7 +802,7 @@ mono_class_has_special_static_fields (MonoClass *klass); const char* mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type); -MONO_COMPONENT_API MonoProperty* +MONO_COMPONENT_API MonoProperty* mono_class_get_property_from_name_internal (MonoClass *klass, const char *name); const char* @@ -1260,7 +1260,7 @@ mono_class_has_variant_generic_params (MonoClass *klass); gboolean mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv); -gboolean +gboolean mono_class_is_subclass_of_internal (MonoClass *klass, MonoClass *klassc, gboolean check_interfaces); MONO_COMPONENT_API mono_bool diff --git a/src/mono/mono/metadata/class-private-definition.h b/src/mono/mono/metadata/class-private-definition.h index a1b8432d690ce..949c71d71f6e2 100644 --- a/src/mono/mono/metadata/class-private-definition.h +++ b/src/mono/mono/metadata/class-private-definition.h @@ -13,9 +13,9 @@ struct _MonoClass { /* element class for arrays and enum basetype for enums */ - MonoClass *element_class; + MonoClass *element_class; /* used for subtype checks */ - MonoClass *cast_class; + MonoClass *cast_class; /* for fast subtype checks */ MonoClass **supertypes; @@ -33,10 +33,10 @@ struct _MonoClass { /* A class contains static and non static data. Static data can be * of the same type as the class itselfs, but it does not influence - * the instance size of the class. To avoid cyclic calls to + * the instance size of the class. To avoid cyclic calls to * mono_class_init_internal (from mono_class_instance_size ()) we first - * initialise all non static fields. After that we set size_inited - * to 1, because we know the instance size now. After that we + * initialise all non static fields. After that we set size_inited + * to 1, because we know the instance size now. After that we * initialise all static fields. */ @@ -55,8 +55,8 @@ struct _MonoClass { /* next byte */ guint packing_size : 4; - guint ghcimpl : 1; /* class has its own GetHashCode impl */ - guint has_finalize : 1; /* class has its own Finalize impl */ + guint ghcimpl : 1; /* class has its own GetHashCode impl */ + guint has_finalize : 1; /* class has its own Finalize impl */ /* next byte */ guint delegate : 1; /* class is a Delegate */ guint gc_descr_inited : 1; /* gc_descr is initialized */ @@ -69,7 +69,7 @@ struct _MonoClass { * for COM Interop. set this flag on loading so all we need is a quick check * during object creation rather than having to traverse supertypes */ - guint is_com_object : 1; + guint is_com_object : 1; guint nested_classes_inited : 1; /* Whenever nested_class is initialized */ /* next byte*/ @@ -95,7 +95,7 @@ struct _MonoClass { guint16 interface_count; guint32 interface_id; /* unique inderface id (for interfaces) */ guint32 max_interface_id; - + guint16 interface_offsets_count; MonoClass **interfaces_packed; guint16 *interface_offsets_packed; diff --git a/src/mono/mono/metadata/class-setup-vtable.c b/src/mono/mono/metadata/class-setup-vtable.c index e1d66fe05eb1e..a0b7128ce0705 100644 --- a/src/mono/mono/metadata/class-setup-vtable.c +++ b/src/mono/mono/metadata/class-setup-vtable.c @@ -242,7 +242,7 @@ mono_class_setup_interface_offsets_internal (MonoClass *klass, int cur_slot, gbo for (i = 0; i < ifaces->len; ++i) { int io; ic = (MonoClass *)g_ptr_array_index (ifaces, i); - + /*Force the sharing of interface offsets between parent and subtypes.*/ io = mono_class_interface_offset (k, ic); g_assertf (io >= 0, "class %s parent %s has no offset for iface %s", @@ -337,7 +337,7 @@ mono_class_setup_interface_offsets_internal (MonoClass *klass, int cur_slot, gbo } g_free (ifaces_array); } - + //printf ("JUST DONE: "); //print_implemented_interfaces (klass); @@ -345,7 +345,7 @@ mono_class_setup_interface_offsets_internal (MonoClass *klass, int cur_slot, gbo } /* - * Setup interface offsets for interfaces. + * Setup interface offsets for interfaces. * Initializes: * - klass->max_interface_id * - klass->interface_offsets_count @@ -409,7 +409,7 @@ mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespa int i; char *result; GString *res = g_string_new (""); - + g_string_append_c (res, '('); for (i = 0; i < sig->param_count; ++i) { if (i > 0) @@ -433,7 +433,7 @@ print_method_signatures (MonoMethod *im, MonoMethod *cm) { printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig); g_free (im_sig); g_free (cm_sig); - + } #endif @@ -545,7 +545,7 @@ check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *c const char *ic_name_space = ic->name_space; const char *ic_name = ic->name; char *subname; - + if (! require_newslot) { TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]")); return FALSE; @@ -579,7 +579,7 @@ check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *c TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]")); return FALSE; } - + subname = (char*)strstr (cm->name, ic_name_space); if (subname != cm->name) { TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]")); @@ -615,7 +615,7 @@ check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *c g_free (decl_name); return FALSE; } - + return TRUE; } } @@ -652,14 +652,14 @@ print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_no char *full_name = mono_type_full_name (m_class_get_byval_arg (klass)); int i; int parent_size; - + printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size); - + if (print_interfaces) { print_implemented_interfaces (klass); printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size); } - + if (klass->parent) { parent_size = klass->parent->vtable_size; } else { @@ -699,7 +699,7 @@ mono_class_verify_vtable (MonoClass *klass) printf ("*** Verifying VTable of class '%s' \n", full_name); g_free (full_name); full_name = NULL; - + if (!klass->methods) return; @@ -840,7 +840,7 @@ mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup) } return TRUE; } - + /* * mono_class_setup_vtable: * @@ -959,10 +959,10 @@ apply_override (MonoClass *klass, MonoClass *override_class, MonoMethod **vtable dslot += mono_class_interface_offset (klass, decl->klass); - //check if the override comes from an interface and the overrided method is from a class, if this is the case it shouldn't be changed + //check if the override comes from an interface and the overrided method is from a class, if this is the case it shouldn't be changed if (vtable [dslot] && vtable [dslot]->klass && MONO_CLASS_IS_INTERFACE_INTERNAL (override->klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (vtable [dslot]->klass)) return TRUE; - + vtable [dslot] = override; if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override->klass)) { /* @@ -1110,7 +1110,7 @@ print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, Mono int index, mcount; char *method_signature; char *type_name; - + for (index = 0; index < onum; ++index) { mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)", im_slot, overrides [index*2+1]->name, overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot); @@ -1266,15 +1266,15 @@ print_vtable_layout_result (MonoClass *klass, MonoMethod **vtable, int cur_slot) for (i = 0; i < klass->interface_count; i++) { MonoClass *ic = klass->interfaces [i]; - printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n", + printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n", mono_class_interface_offset (klass, ic), mono_class_setup_count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic))); } for (MonoClass *k = klass->parent; k ; k = k->parent) { for (i = 0; i < k->interface_count; i++) { - MonoClass *ic = k->interfaces [i]; - printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n", + MonoClass *ic = k->interfaces [i]; + printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n", mono_class_interface_offset (klass, ic), mono_class_setup_count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic))); } @@ -1285,10 +1285,10 @@ print_vtable_layout_result (MonoClass *klass, MonoMethod **vtable, int cur_slot) /* * LOCKING: this is supposed to be called with the loader lock held. */ -static int +static int setup_class_vtsize (MonoClass *klass, GList *in_setup, int *cur_slot, int *stelemref_slot, MonoError *error) { - GPtrArray *ifaces = NULL; + GPtrArray *ifaces = NULL; int i, max_vtsize = 0; ifaces = mono_class_get_implemented_interfaces (klass, error); if (!is_ok (error)) { @@ -1305,7 +1305,7 @@ setup_class_vtsize (MonoClass *klass, GList *in_setup, int *cur_slot, int *stele g_ptr_array_free (ifaces, TRUE); ifaces = NULL; } - + if (klass->parent) { mono_class_init_internal (klass->parent); mono_class_setup_vtable_full (klass->parent, in_setup); @@ -1381,14 +1381,14 @@ mono_class_setup_vtable_ginst (MonoClass *klass, GList *in_setup) #ifdef FEATURE_COVARIANT_RETURNS /* * vtable_slot_has_preserve_base_overrides_attribute: - * + * * Needs to walk up the class hierarchy looking for the methods in this slot to * see if any are tagged with PreserveBaseOverrideAtrribute. */ static gboolean vtable_slot_has_preserve_base_overrides_attribute (MonoClass *klass, int slot, MonoClass **out_klass) { - /* + /* * FIXME: it's slow to do this loop every time. A faster way would be * to hang a boolean in the image of the parent class if it or any of * its ancestors have the attribute. @@ -1695,7 +1695,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o max_vtsize = setup_class_vtsize (klass, in_setup, &cur_slot, &stelemref_slot, error); if (max_vtsize == -1) return; - + cur_slot = mono_class_setup_interface_offsets_internal (klass, cur_slot, TRUE); if (cur_slot == -1) /*setup_interface_offsets fails the type.*/ return; @@ -1768,7 +1768,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE)); /* - * Create a list of virtual methods to avoid calling + * Create a list of virtual methods to avoid calling * mono_class_get_virtual_methods () which is slow because of the metadata * optimization. */ @@ -1823,14 +1823,14 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o } else { interface_is_explicitly_implemented_by_class = TRUE; } - + // Loop on all interface methods... int mcount = mono_class_get_method_count (ic); for (im_index = 0; im_index < mcount; im_index++) { MonoMethod *im = ic->methods [im_index]; int im_slot = ic_offset + im->slot; MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL; - + if (!m_method_is_virtual (im)) continue; @@ -1867,14 +1867,14 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/ goto fail; } - + // If the slot is still empty, look in all the inherited virtual methods... if ((vtable [im_slot] == NULL) && klass->parent != NULL) { MonoClass *parent = klass->parent; // Reverse order, so that last added methods are preferred for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) { MonoMethod *cm = parent->vtable [cm_index]; - + TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name)); if ((cm != NULL) && check_interface_method_override (klass, im, cm, MONO_ITF_OVERRIDE_SLOT_EMPTY)) { TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING\n")); @@ -1902,7 +1902,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o } } } - + // If the class is not abstract, check that all its interface slots are full. // The check is done here and not directly at the end of the loop above because // it can happen (for injected generic array interfaces) that the same slot is @@ -1913,15 +1913,15 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o for (i = 0; i < klass->interface_offsets_count; i++) { int ic_offset; int im_index; - + ic = klass->interfaces_packed [i]; ic_offset = mono_class_interface_offset (klass, ic); - + int mcount = mono_class_get_method_count (ic); for (im_index = 0; im_index < mcount; im_index++) { MonoMethod *im = ic->methods [im_index]; int im_slot = ic_offset + im->slot; - + if (!m_method_is_virtual (im)) continue; if (mono_method_get_is_reabstracted (im)) @@ -1960,7 +1960,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o if (!cmsig || !m1sig) /* FIXME proper error message, use signature_checked? */ goto fail; - if (!strcmp(cm->name, m1->name) && + if (!strcmp(cm->name, m1->name) && mono_metadata_signature_equal (cmsig, m1sig)) { slot = mono_method_get_vtable_slot (m1); @@ -1996,8 +1996,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o } if (mono_class_has_failure (k)) goto fail; - - if (slot >= 0) + + if (slot >= 0) break; } if (slot >= 0) @@ -2033,7 +2033,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o #endif if (!override_map) override_map = g_hash_table_new (mono_aligned_addr_hash, NULL); - TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n", + TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n", mono_method_full_name (decl, 1), decl, mono_method_full_name (impl, 1), impl)); g_hash_table_insert (override_map, decl, impl); diff --git a/src/mono/mono/metadata/class.h b/src/mono/mono/metadata/class.h index 8966e029b7c6c..a9fada0d31a3c 100644 --- a/src/mono/mono/metadata/class.h +++ b/src/mono/mono/metadata/class.h @@ -127,7 +127,7 @@ MONO_API MONO_RT_EXTERNAL_ONLY MonoClass * mono_class_from_mono_type (MonoType *type); MONO_API MONO_RT_EXTERNAL_ONLY mono_bool -mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc, +mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc, mono_bool check_interfaces); MONO_API MONO_RT_EXTERNAL_ONLY mono_bool @@ -140,7 +140,7 @@ mono_ldtoken (MonoImage *image, uint32_t token, MonoClass **retcla MONO_API char * mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format); -MONO_API char* +MONO_API char* mono_type_get_name (MonoType *type); MONO_API MonoType* diff --git a/src/mono/mono/metadata/cominterop.c b/src/mono/mono/metadata/cominterop.c index 7084b5feb81fb..ff2de267ddfd6 100644 --- a/src/mono/mono/metadata/cominterop.c +++ b/src/mono/mono/metadata/cominterop.c @@ -1,7 +1,7 @@ /** * \file * COM Interop Support - * + * * * (C) 2002 Ximian, Inc. http://www.ximian.com * @@ -267,7 +267,7 @@ mono_class_try_get_com_object_class (void) * cominterop_method_signature: * @method: a method * - * Returns: the corresponding unmanaged method signature for a managed COM + * Returns: the corresponding unmanaged method signature for a managed COM * method. */ static MonoMethodSignature* @@ -380,7 +380,7 @@ cominterop_get_com_slot_begin (MonoClass* klass) { ERROR_DECL (error); MonoCustomAttrInfo *cinfo = NULL; - MonoInterfaceTypeAttribute* itf_attr = NULL; + MonoInterfaceTypeAttribute* itf_attr = NULL; cinfo = mono_custom_attrs_from_class_checked (klass, error); mono_error_assert_ok (error); @@ -760,7 +760,7 @@ mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: { guint32 pos_null = 0, pos_ccw = 0, pos_end = 0; - MonoClass *klass = NULL; + MonoClass *klass = NULL; klass = mono_class_from_mono_type_internal (type); @@ -845,13 +845,13 @@ mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, mono_mb_emit_byte (mb, CEE_CONV_U); mono_mb_emit_byte (mb, CEE_STIND_I); - mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_REF); // if null just break, dst was already inited to 0 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_icall (mb, cominterop_object_is_rcw); pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); @@ -860,7 +860,7 @@ mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, mono_mb_emit_ldloc (mb, 1); // load src - mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp)); mono_mb_emit_byte (mb, CEE_LDIND_REF); @@ -894,15 +894,15 @@ mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, } mono_mb_emit_byte (mb, CEE_STIND_I); pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S); - + // if not rcw mono_mb_patch_short_branch (mb, pos_rcw); /* load dst to store later */ mono_mb_emit_ldloc (mb, 1); /* load src */ - mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_REF); - + if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) mono_mb_emit_ptr (mb, mono_type_get_class_internal (type)); else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) @@ -991,7 +991,7 @@ cominterop_get_native_wrapper_adjusted (MonoMethod *method) if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) { // move return spec to last param - if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) { + if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) { // default object to VARIANT if (sig->ret->type == MONO_TYPE_OBJECT) { mspecs[0] = g_new0 (MonoMarshalSpec, 1); @@ -1014,7 +1014,7 @@ cominterop_get_native_wrapper_adjusted (MonoMethod *method) mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS | EMIT_NATIVE_WRAPPER_RUNTIME_MARSHALLING_ENABLED); - res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16); + res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16); mono_mb_free (mb_native); @@ -1048,7 +1048,7 @@ mono_cominterop_get_native_wrapper (MonoMethod *method) if (!m_class_get_vtable (method->klass)) mono_class_setup_vtable (method->klass); - + if (!m_class_get_methods (method->klass)) mono_class_setup_methods (method->klass); g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/ @@ -1119,7 +1119,7 @@ mono_cominterop_get_native_wrapper (MonoMethod *method) // push managed return value as byref last argument if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig) mono_mb_emit_ldloc_addr (mb, retval); - + adjusted_method = cominterop_get_native_wrapper_adjusted (method); mono_mb_emit_managed_call (mb, adjusted_method, NULL); @@ -1142,8 +1142,8 @@ mono_cominterop_get_native_wrapper (MonoMethod *method) mono_mb_emit_byte (mb, CEE_RET); } - - + + } /* Does this case ever get hit? */ else { @@ -1175,7 +1175,7 @@ mono_cominterop_get_invoke (MonoMethod *method) MonoMethod *res; int i; GHashTable* cache; - + cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL); g_assert (method); @@ -1243,14 +1243,14 @@ mono_cominterop_get_invoke (MonoMethod *method) return res; } -/* Maps a managed object to its unmanaged representation - * i.e. it's COM Callable Wrapper (CCW). +/* Maps a managed object to its unmanaged representation + * i.e. it's COM Callable Wrapper (CCW). * Key: MonoObject* * Value: MonoCCW* */ static GHashTable* ccw_hash = NULL; -/* Maps a CCW interface to it's containing CCW. +/* Maps a CCW interface to it's containing CCW. * Note that a CCW support many interfaces. * Key: MonoCCW* * Value: MonoCCWInterface* @@ -1277,10 +1277,10 @@ mono_get_addref (void) } int -mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, +mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -1334,13 +1334,13 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, conv_arg = mono_mb_add_local (mb, int_type); mono_mb_emit_ptr (mb, NULL); - mono_mb_emit_stloc (mb, conv_arg); + mono_mb_emit_stloc (mb, conv_arg); /* we dont need any conversions for out parameters */ if (m_type_is_byref (t) && t->attrs & PARAM_ATTRIBUTE_OUT) break; - mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldarg (mb, argnum); if (m_type_is_byref (t)) mono_mb_emit_byte (mb, CEE_LDIND_REF); /* if null just break, conv arg was already inited to 0 */ @@ -1472,7 +1472,7 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, /* case if null */ mono_mb_patch_short_branch (mb, pos_null); break; - } + } case MARSHAL_ACTION_MANAGED_CONV_IN: { int ccw_obj; @@ -1534,11 +1534,11 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, mono_mb_emit_byte (mb, CEE_LDC_I4_0); mono_mb_emit_byte (mb, CEE_STIND_I); - mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldloc (mb, conv_arg); pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); /* to store later */ - mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); if (klass && klass != mono_defaults.object_class) { mono_mb_emit_ptr (mb, t); @@ -1595,7 +1595,7 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, g_assert_not_reached (); mono_mb_emit_stloc (mb, 3); mono_mb_emit_ldloc (mb, 3); - + mono_mb_emit_managed_call (mb, mono_get_addref (), NULL); mono_mb_emit_byte (mb, CEE_POP); @@ -1794,7 +1794,7 @@ ves_icall_System_ComObject_CreateRCW (MonoReflectionTypeHandle ref_type, MonoErr return mono_object_new_alloc_by_vtable (vtable, error); } -static gboolean +static gboolean cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data) { mono_IUnknown_Release ((MonoIUnknown*)value); @@ -1928,7 +1928,7 @@ cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method) /* FIXME: which to use? */ csig = mono_metadata_signature_dup_full (method_klass_image, sig); /* csig = mono_metadata_signature_dup (sig); */ - + /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */ #ifdef HOST_WIN32 csig->call_convention = MONO_CALL_STDCALL; @@ -2554,10 +2554,10 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method) main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE; main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset; main_clause->data.catch_class = mono_defaults.object_class; - + /* handler code */ main_clause->handler_offset = mono_mb_get_label (mb); - + if (!preserve_sig || (sig->ret && !m_type_is_byref (sig->ret) && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) { mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL); mono_mb_emit_stloc (mb, hr); @@ -2584,7 +2584,7 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method) #endif /* DISABLE_JIT */ mono_cominterop_lock (); - res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16); + res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16); mono_cominterop_unlock (); mono_mb_free (mb); @@ -2605,10 +2605,10 @@ cominterop_class_guid_equal (const guint8* guid, MonoClass* klass) return FALSE; } -static int STDCALL +static int STDCALL cominterop_ccw_addref_impl (MonoCCWInterface* ccwe); -static int STDCALL +static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe) { int result; @@ -2621,7 +2621,7 @@ cominterop_ccw_addref (MonoCCWInterface* ccwe) return result; } -static int STDCALL +static int STDCALL cominterop_ccw_addref_impl (MonoCCWInterface* ccwe) { MONO_REQ_GC_UNSAFE_MODE; @@ -2639,10 +2639,10 @@ cominterop_ccw_addref_impl (MonoCCWInterface* ccwe) return ref_count; } -static int STDCALL +static int STDCALL cominterop_ccw_release_impl (MonoCCWInterface* ccwe); -static int STDCALL +static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe) { int result; @@ -2655,7 +2655,7 @@ cominterop_ccw_release (MonoCCWInterface* ccwe) return result; } -static int STDCALL +static int STDCALL cominterop_ccw_release_impl (MonoCCWInterface* ccwe) { MONO_REQ_GC_UNSAFE_MODE; @@ -2691,10 +2691,10 @@ cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObjectHandle object, } #endif -static int STDCALL +static int STDCALL cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv); -static int STDCALL +static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv) { int result; @@ -2707,7 +2707,7 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpoin return result; } -static int STDCALL +static int STDCALL cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv) { MONO_REQ_GC_UNSAFE_MODE; @@ -2718,7 +2718,7 @@ cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, MonoCCW* ccw = ccwe->ccw; MonoClass* klass_iter = NULL; MonoObjectHandle object = mono_gchandle_get_target_handle (ccw->gc_handle); - + g_assert (!MONO_HANDLE_IS_NULL (object)); MonoClass* const klass = mono_handle_class (object); @@ -2741,7 +2741,7 @@ cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) { if (!cominterop_can_support_dispatch (klass)) return MONO_E_NOINTERFACE; - + *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error); mono_error_assert_ok (error); /* remember to addref on QI */ @@ -2792,7 +2792,7 @@ cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, return MONO_E_NOINTERFACE; } -static int STDCALL +static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo) { if(!pctinfo) @@ -2803,19 +2803,19 @@ cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo) return MONO_S_OK; } -static int STDCALL +static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo) { return MONO_E_NOTIMPL; } -static int STDCALL +static int STDCALL cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid, gunichar2** rgszNames, guint32 cNames, guint32 lcid, gint32 *rgDispId); -static int STDCALL +static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid, gunichar2** rgszNames, guint32 cNames, guint32 lcid, gint32 *rgDispId) @@ -2830,7 +2830,7 @@ cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid, return result; } -static int STDCALL +static int STDCALL cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid, gunichar2** rgszNames, guint32 cNames, guint32 lcid, gint32 *rgDispId) @@ -2891,7 +2891,7 @@ cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid, return ret; } -static int STDCALL +static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember, gpointer riid, guint32 lcid, guint16 wFlags, gpointer pDispParams, @@ -3165,7 +3165,7 @@ mono_string_from_bstr_icall_impl (mono_bstr_const bstr, MonoError *error) return mono_string_from_bstr_checked (bstr, error); } -MONO_API void +MONO_API void mono_free_bstr (/*mono_bstr_const*/gpointer bstr) { if (!bstr) @@ -3397,7 +3397,7 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT result.SetValueImpl(elem, index); } ++index; - } + } while (mono_marshal_safearray_next(safearray, indices)); } // label2 mono_marshal_safearray_end(safearray, indices); @@ -3707,7 +3707,7 @@ mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer * gboolean bounded = FALSE; #ifndef HOST_WIN32 - // If not on windows, check that the MS provider is used as it is + // If not on windows, check that the MS provider is used as it is // required for SAFEARRAY support. // If SAFEARRAYs are not supported, returning FALSE from this // function will prevent the other mono_marshal_safearray_xxx functions @@ -3832,7 +3832,7 @@ mono_marshal_safearray_get_value (gpointer safearray, gpointer indices) #endif /* HOST_WIN32 */ /* This is an icall */ -static +static gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices) { ERROR_DECL (error); @@ -3950,7 +3950,7 @@ static gboolean mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty) { #ifndef HOST_WIN32 - // If not on windows, check that the MS provider is used as it is + // If not on windows, check that the MS provider is used as it is // required for SAFEARRAY support. // If SAFEARRAYs are not supported, returning FALSE from this // function will prevent the other mono_marshal_safearray_xxx functions @@ -4023,7 +4023,7 @@ mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer } } -static +static void mono_marshal_safearray_free_indices (gpointer indices) { g_free (indices); diff --git a/src/mono/mono/metadata/cominterop.h b/src/mono/mono/metadata/cominterop.h index ea6118b7e362d..2bd129ca7d7cd 100644 --- a/src/mono/mono/metadata/cominterop.h +++ b/src/mono/mono/metadata/cominterop.h @@ -1,7 +1,7 @@ /** * \file * COM Interop Support - * + * * * (C) 2002 Ximian, Inc. http://www.ximian.com * @@ -39,16 +39,16 @@ MonoMethod * mono_cominterop_get_invoke (MonoMethod *method); int -mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, +mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action); int mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, + MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); @@ -58,7 +58,7 @@ mono_string_from_bstr (/*mono_bstr*/gpointer bstr); MonoStringHandle mono_string_from_bstr_checked (mono_bstr_const bstr, MonoError *error); -MONO_API void +MONO_API void mono_free_bstr (/*mono_bstr_const*/gpointer bstr); MonoClass* diff --git a/src/mono/mono/metadata/coree.c b/src/mono/mono/metadata/coree.c index 0d2be4aab223f..be6ce1434544c 100644 --- a/src/mono/mono/metadata/coree.c +++ b/src/mono/mono/metadata/coree.c @@ -432,7 +432,7 @@ HMODULE WINAPI MonoLoadImage(LPCWSTR FileName) if (FileHandle == INVALID_HANDLE_VALUE) return NULL; - FileSize = GetFileSize(FileHandle, NULL); + FileSize = GetFileSize(FileHandle, NULL); if (FileSize == INVALID_FILE_SIZE) goto CloseFile; diff --git a/src/mono/mono/metadata/debug-helpers.c b/src/mono/mono/metadata/debug-helpers.c index b2743a89b0326..c3c706b754c6d 100644 --- a/src/mono/mono/metadata/debug-helpers.c +++ b/src/mono/mono/metadata/debug-helpers.c @@ -88,7 +88,7 @@ append_class_name (GString *res, MonoClass *klass, gboolean include_namespace) static MonoClass* find_system_class (const char *name) { - if (!strcmp (name, "void")) + if (!strcmp (name, "void")) return mono_defaults.void_class; else if (!strcmp (name, "char")) return mono_defaults.char_class; else if (!strcmp (name, "bool")) return mono_defaults.boolean_class; @@ -335,7 +335,7 @@ mono_context_get_desc (MonoGenericContext *context) res = g_strdup (str->str); g_string_free (str, TRUE); return res; -} +} /** * mono_method_desc_new: @@ -360,7 +360,7 @@ mono_method_desc_new (const char *name, gboolean include_namespace) char *class_name, *class_nspace, *method_name, *use_args, *end; int use_namespace; int generic_delim_stack; - + class_nspace = g_strdup (name); use_args = strchr (class_nspace, '('); if (use_args) { @@ -429,7 +429,7 @@ MonoMethodDesc* mono_method_desc_from_method (MonoMethod *method) { MonoMethodDesc *result; - + result = g_new0 (MonoMethodDesc, 1); result->include_namespace = TRUE; result->name = g_strdup (method->name); @@ -583,7 +583,7 @@ mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass) { MonoMethod* m; gpointer iter = NULL; - + while ((m = mono_class_get_methods (klass, &iter))) if (mono_method_desc_match (desc, m)) return m; @@ -663,7 +663,7 @@ dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned cha } if (dh->label_format) g_string_append_printf (str, dh->label_format, label); - + i = mono_opcode_value (&ip, end); ip++; opcode = &mono_opcodes [i]; @@ -833,7 +833,7 @@ mono_disasm_code_one (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, c ip = dis_one (res, dh, method, ip, ip + 2); if (endp) *endp = ip; - + result = res->str; g_string_free (res, FALSE); return result; @@ -853,7 +853,7 @@ mono_disasm_code (MonoDisHelper *dh, MonoMethod *method, const guchar *ip, const while (ip < end) { ip = dis_one (res, dh, method, ip, end); } - + result = res->str; g_string_free (res, FALSE); return result; diff --git a/src/mono/mono/metadata/debug-mono-ppdb.h b/src/mono/mono/metadata/debug-mono-ppdb.h index d26c16446a49a..1a011a1030778 100644 --- a/src/mono/mono/metadata/debug-mono-ppdb.h +++ b/src/mono/mono/metadata/debug-mono-ppdb.h @@ -50,7 +50,7 @@ mono_ppdb_lookup_location_enc (MonoPPDBFile *ppdb_file, int idx, uint32_t offset void mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points); -gboolean +gboolean mono_ppdb_get_seq_points_enc (MonoDebugMethodInfo *minfo, MonoPPDBFile *ppdb_file, int idx, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points); MonoDebugLocalsInfo* @@ -68,7 +68,7 @@ mono_ppdb_get_image (MonoPPDBFile *ppdb); char * mono_ppdb_get_sourcelink (MonoDebugHandle *handle); -gboolean +gboolean mono_ppdb_is_embedded (MonoPPDBFile *ppdb); MONO_COMPONENT_API MonoPPDBFile* diff --git a/src/mono/mono/metadata/debug-mono-symfile.c b/src/mono/mono/metadata/debug-mono-symfile.c index d8eed685da2b5..72925b73a68fe 100644 --- a/src/mono/mono/metadata/debug-mono-symfile.c +++ b/src/mono/mono/metadata/debug-mono-symfile.c @@ -176,7 +176,7 @@ mono_debug_open_mono_symbols (MonoDebugHandle *handle, const uint8_t *raw_conten mono_file_map_close (f); } } - + if (load_symfile (handle, symfile, in_the_debugger)) { mono_debugger_unlock (); return symfile; @@ -233,7 +233,7 @@ read_leb128 (const uint8_t *ptr, const uint8_t **rptr) do { b = *ptr++; - + ret = ret | ((b & 0x7f) << shift); shift += 7; } while ((b & 0x80) == 0x80); @@ -290,7 +290,7 @@ check_line (StatementMachine *stm, int offset, MonoDebugSourceLocation **locatio } if (stm->last_line == 0) { - /* + /* * The IL offset is less than the first IL offset which has a corresponding * source line. */ @@ -658,7 +658,7 @@ mono_debug_symfile_get_seq_points (MonoDebugMethodInfo *minfo, char **source_fil if (source_files) (*source_files) [i] = (*source_file_list)->len - 1; } - } + } if (n_seq_points) { g_assert (seq_points); diff --git a/src/mono/mono/metadata/domain-internals.h b/src/mono/mono/metadata/domain-internals.h index 398898c6e609a..65a44da3a28b4 100644 --- a/src/mono/mono/metadata/domain-internals.h +++ b/src/mono/mono/metadata/domain-internals.h @@ -29,7 +29,7 @@ G_BEGIN_DECLS * unloaded, and assemblies loaded by the appdomain are not unloaded either. This * allows us to use typed gc in non-default appdomains too, leading to increased * performance. - */ + */ extern gboolean mono_dont_free_domains; struct _MonoAppContext { @@ -136,7 +136,7 @@ mono_runtime_register_runtimeconfig_json_properties (MonovmRuntimeConfigArgument void mono_runtime_install_appctx_properties (void); -MONO_COMPONENT_API void +MONO_COMPONENT_API void mono_domain_set_fast (MonoDomain *domain); G_END_DECLS diff --git a/src/mono/mono/metadata/dynamic-image.c b/src/mono/mono/metadata/dynamic-image.c index 0eef174335576..706d4ed209a9f 100644 --- a/src/mono/mono/metadata/dynamic-image.c +++ b/src/mono/mono/metadata/dynamic-image.c @@ -1,8 +1,8 @@ /** * \file * Images created at runtime. - * - * + * + * * Author: * Paolo Molaro (lupus@ximian.com) * @@ -213,11 +213,11 @@ mono_dynamic_image_get_registered_token (MonoDynamicImage *dynimage, guint32 tok #endif /** - * + * * mono_dynamic_image_is_valid_token: - * + * * Returns TRUE if token is valid in the given image. - * + * */ gboolean mono_dynamic_image_is_valid_token (MonoDynamicImage *image, guint32 token) @@ -234,7 +234,7 @@ mono_dynamic_image_is_valid_token (MonoDynamicImage *image, guint32 token) * mono_reflection_lookup_dynamic_token: * * Finish the Builder object pointed to by TOKEN and return the corresponding - * runtime structure. If HANDLE_CLASS is not NULL, it is set to the class required by + * runtime structure. If HANDLE_CLASS is not NULL, it is set to the class required by * mono_ldtoken. If valid_token is TRUE, assert if it is not found in the token->object * mapping table. * @@ -250,7 +250,7 @@ mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean MonoClass *klass; error_init (error); - + lookup_dyn_token (assembly, token, &obj); if (MONO_HANDLE_IS_NULL (obj)) { if (valid_token) @@ -343,7 +343,7 @@ mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, c image = g_new0 (MonoDynamicImage, 1); MONO_PROFILER_RAISE (image_loading, (&image->image)); - + /*g_print ("created image %p\n", image);*/ /* keep in sync with image.c */ image->image.name = assembly_name; @@ -392,7 +392,7 @@ mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, c image->image.assembly = (MonoAssembly*)assembly; image->pe_kind = 0x1; /* ILOnly */ image->machine = 0x14c; /* I386 */ - + MONO_PROFILER_RAISE (image_loaded, (&image->image)); dynamic_images_lock (); diff --git a/src/mono/mono/metadata/dynamic-stream.c b/src/mono/mono/metadata/dynamic-stream.c index e33bec79d3fa1..940532bdd96c8 100644 --- a/src/mono/mono/metadata/dynamic-stream.c +++ b/src/mono/mono/metadata/dynamic-stream.c @@ -34,14 +34,14 @@ make_room_in_stream (MonoDynamicStream *stream, int size) if (size <= stream->alloc_size) return; - + while (stream->alloc_size <= size) { if (stream->alloc_size < 4096) stream->alloc_size = 4096; else stream->alloc_size *= 2; } - + stream->data = (char *)g_realloc (stream->data, stream->alloc_size); } @@ -59,7 +59,7 @@ mono_dynstream_insert_string (MonoDynamicStream *sh, const char *str) len = strlen (str) + 1; idx = sh->index; - + make_room_in_stream (sh, idx + len); /* @@ -93,12 +93,12 @@ mono_dynstream_add_data (MonoDynamicStream *stream, gconstpointer data, guint32 MONO_REQ_GC_NEUTRAL_MODE; guint32 idx; - + make_room_in_stream (stream, stream->index + len); memcpy (stream->data + stream->index, data, len); idx = stream->index; stream->index += len; - /* + /* * align index? Not without adding an additional param that controls it since * we may store a blob value in pieces. */ @@ -111,7 +111,7 @@ mono_dynstream_add_zero (MonoDynamicStream *stream, guint32 len) MONO_REQ_GC_NEUTRAL_MODE; guint32 idx; - + make_room_in_stream (stream, stream->index + len); memset (stream->data + stream->index, 0, len); idx = stream->index; diff --git a/src/mono/mono/metadata/exception.c b/src/mono/mono/metadata/exception.c index f1aaba68de069..340ab7d466452 100644 --- a/src/mono/mono/metadata/exception.c +++ b/src/mono/mono/metadata/exception.c @@ -101,7 +101,7 @@ mono_exception_from_name (MonoImage *image, const char *name_space, * \returns the initialized exception instance. */ MonoException * -mono_exception_from_name_domain (MonoDomain *domain, MonoImage *image, +mono_exception_from_name_domain (MonoDomain *domain, MonoImage *image, const char* name_space, const char *name) { HANDLE_FUNCTION_ENTER (); @@ -148,14 +148,14 @@ create_exception_two_strings (MonoClass *klass, MonoStringHandle a1, MonoStringH int const count = 1 + !MONO_HANDLE_IS_NULL (a2); gpointer iter; MonoMethod *m; - + MonoObjectHandle o = mono_object_new_handle (klass, error); mono_error_assert_ok (error); iter = NULL; while ((m = mono_class_get_methods (klass, &iter))) { MonoMethodSignature *sig; - + if (strcmp (".ctor", mono_method_get_name (m))) continue; sig = mono_method_signature_internal (m); @@ -862,7 +862,7 @@ MonoException * mono_get_exception_bad_image_format (const char *msg) { return mono_exception_from_name_msg (mono_get_corlib (), "System", "BadImageFormatException", msg); -} +} /** * mono_get_exception_bad_image_format2: @@ -896,7 +896,7 @@ mono_get_exception_bad_image_format2 (const char *msg, MonoString *fname_raw) MonoException * mono_get_exception_stack_overflow (void) { - return mono_exception_from_name (mono_get_corlib (), "System", "StackOverflowException"); + return mono_exception_from_name (mono_get_corlib (), "System", "StackOverflowException"); } /** @@ -1222,7 +1222,7 @@ mono_invoke_unhandled_exception_hook (MonoObject *exc) MonoObject *other = NULL; MonoString *str = mono_object_try_to_string (exc, &other, inner_error); char *msg = NULL; - + if (str && is_ok (inner_error)) { msg = mono_string_to_utf8_checked_internal (str, inner_error); if (!is_ok (inner_error)) { diff --git a/src/mono/mono/metadata/exception.h b/src/mono/mono/metadata/exception.h index 155c23c7e7747..0876657ac2e60 100644 --- a/src/mono/mono/metadata/exception.h +++ b/src/mono/mono/metadata/exception.h @@ -12,8 +12,8 @@ MONO_BEGIN_DECLS MONO_API MonoException * -mono_exception_from_name (MonoImage *image, - const char* name_space, +mono_exception_from_name (MonoImage *image, + const char* name_space, const char *name); MONO_API MonoException * @@ -34,8 +34,8 @@ mono_exception_from_token_two_strings (MonoImage *image, uint32_t token, MonoString *a1, MonoString *a2); MONO_API MonoException * -mono_exception_from_name_domain (MonoDomain *domain, MonoImage *image, - const char* name_space, +mono_exception_from_name_domain (MonoDomain *domain, MonoImage *image, + const char* name_space, const char *name); MONO_API MonoException * diff --git a/src/mono/mono/metadata/external-only.c b/src/mono/mono/metadata/external-only.c index 19999e384c776..2b65cf280fb4f 100644 --- a/src/mono/mono/metadata/external-only.c +++ b/src/mono/mono/metadata/external-only.c @@ -275,7 +275,7 @@ mono_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, Mono /** * mono_config_for_assembly: */ -void +void mono_config_for_assembly (MonoImage *assembly) { } @@ -618,8 +618,8 @@ mono_context_init (MonoDomain *domain) * * Used to set the system configuration for an appdomain * - * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException: - * Error Initializing the configuration system. ---> System.ArgumentException: + * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException: + * Error Initializing the configuration system. ---> System.ArgumentException: * The 'ExeConfigFilename' argument cannot be null.' for some managed calls. */ void diff --git a/src/mono/mono/metadata/gc-internals.h b/src/mono/mono/metadata/gc-internals.h index 60e2d79d0ff3c..466c3be715dc0 100644 --- a/src/mono/mono/metadata/gc-internals.h +++ b/src/mono/mono/metadata/gc-internals.h @@ -182,7 +182,7 @@ void mono_gc_clear_domain (MonoDomain * domain); void mono_gc_suspend_finalizers (void); -/* +/* * Register a root which can only be written using a write barrier. * Writes to the root must be done using a write barrier (MONO_ROOT_SETREF). * If the root uses an user defined mark routine, the writes are not required to be @@ -235,30 +235,30 @@ typedef void (*MonoRangeCopyFunction)(gpointer, gconstpointer, int size); MonoRangeCopyFunction mono_gc_get_range_copy_func (void); -/* +/* * Functions supplied by the runtime and called by the GC. Currently only used * by SGEN. */ typedef struct { - /* - * Function called during thread startup/attach to allocate thread-local data + /* + * Function called during thread startup/attach to allocate thread-local data * needed by the other functions. */ gpointer (*thread_attach_func) (void); - /* + /* * Function called during thread deatch to free the data allocated by * thread_attach_func. */ void (*thread_detach_func) (gpointer user_data); - /* + /* * Function called from every thread when suspending for GC. It can save - * data needed for marking from thread stacks. user_data is the data returned + * data needed for marking from thread stacks. user_data is the data returned * by attach_func. This might called with GC locks held and the word stopped, * so it shouldn't do any synchronization etc. */ void (*thread_suspend_func) (gpointer user_data, void *sigcontext, MonoContext *ctx); - /* - * Function called to mark from thread stacks. user_data is the data returned + /* + * Function called to mark from thread stacks. user_data is the data returned * by attach_func. This is called twice, with the word stopped: * - in the first pass, it should mark areas of the stack using * conservative marking by calling mono_gc_conservatively_scan_area (). diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c index ad8f0c2b9e337..5144e40eeec43 100644 --- a/src/mono/mono/metadata/gc.c +++ b/src/mono/mono/metadata/gc.c @@ -175,7 +175,7 @@ coop_cond_timedwait_alertable (MonoCoopCond *cond, MonoCoopMutex *mutex, guint32 return res; } -/* +/* * actually, we might want to queue the finalize requests in a separate thread, * but we need to be careful about the execution domain of the thread... */ @@ -253,7 +253,7 @@ mono_gc_run_finalize (void *obj, void *data) * These can't be finalized during unloading/shutdown, since that would * free the native code which can still be referenced by other * finalizers. - * FIXME: This is not perfect, objects dying at the same time as + * FIXME: This is not perfect, objects dying at the same time as * dynamic methods can still reference them even when !shutdown. */ return; @@ -293,7 +293,7 @@ mono_gc_run_finalize (void *obj, void *data) return; } - /* + /* * To avoid the locking plus the other overhead of mono_runtime_invoke_checked (), * create and precompile a wrapper which calls the finalize method using * a CALLVIRT. @@ -356,7 +356,7 @@ mono_gc_run_finalize (void *obj, void *data) * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer. * This also means that in the callback we need to adjust the pointer to get back the real * MonoObject*. - * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, + * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, * since that, too, can cause the underlying pointer to be offset. */ static void @@ -386,7 +386,7 @@ object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*)) * * Records that object \p obj has a finalizer, this will call the * Finalize method when the garbage collector disposes the object. - * + * */ void mono_object_register_finalizer_handle (MonoObjectHandle obj) @@ -420,7 +420,7 @@ mono_object_register_finalizer (MonoObject *obj) * \returns TRUE if succeeded, FALSE if there was a timeout */ gboolean -mono_domain_finalize (MonoDomain *domain, guint32 timeout) +mono_domain_finalize (MonoDomain *domain, guint32 timeout) { DomainFinalizationReq *req; MonoInternalThread *thread = mono_thread_internal_current (); @@ -432,11 +432,11 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout) /* We are called from inside a finalizer, not much we can do here */ return FALSE; - /* + /* * No need to create another thread 'cause the finalizer thread * is still working and will take care of running the finalizers - */ - + */ + if (gc_disabled) return TRUE; @@ -453,7 +453,7 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout) if (domain == mono_get_root_domain ()) finalizing_root_domain = TRUE; - + mono_finalizer_lock (); domains_to_finalize = g_slist_append (domains_to_finalize, req); @@ -789,7 +789,7 @@ finalize_domain_objects (void) while (g_hash_table_size (finalizable_objects_hash) > 0) { int i; GPtrArray *objs; - /* + /* * Since the domain is unloading, nobody is allowed to put * new entries into the hash table. But finalize_object might * remove entries from the hash table, so we make a copy. @@ -813,7 +813,7 @@ finalize_domain_objects (void) /* cleanup the reference queue */ reference_queue_clear_for_domain (domain); - + /* printf ("DONE.\n"); */ mono_coop_sem_post (&req->done); @@ -1002,7 +1002,7 @@ mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread) * In Mono objects are finalized asynchronously on a separate thread. * This routine tests whether the \p thread argument represents the * finalization thread. - * + * * \returns TRUE if \p thread is the finalization thread. */ gboolean diff --git a/src/mono/mono/metadata/handle.c b/src/mono/mono/metadata/handle.c index d6af32f73b291..8474c385007b2 100644 --- a/src/mono/mono/metadata/handle.c +++ b/src/mono/mono/metadata/handle.c @@ -49,7 +49,7 @@ Combine: MonoDefaults, GENERATE_GET_CLASS_WITH_CACHE, TYPED_HANDLE_DECL and frie /* * NOTE: Async suspend - * + * * If we are running with cooperative GC, all the handle stack * manipulation will complete before a GC thread scans the handle * stack. If we are using async suspend, however, a thread may be @@ -362,7 +362,7 @@ mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, c /* * Pop the stack until @stackmark and make @value the top value. * - * @return the new handle for what @value points to + * @return the new handle for what @value points to */ MonoRawHandle mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value) diff --git a/src/mono/mono/metadata/handle.h b/src/mono/mono/metadata/handle.h index 5628d3b179276..46f69c5124bbf 100644 --- a/src/mono/mono/metadata/handle.h +++ b/src/mono/mono/metadata/handle.h @@ -32,7 +32,7 @@ The handle stack is designed so it's efficient to pop a large amount of entries The stack is made out of a series of fixed size segments. To do bulk operations you use a stack mark. - + */ /* diff --git a/src/mono/mono/metadata/image.c b/src/mono/mono/metadata/image.c index ee77f79966982..4b2efe2b37659 100644 --- a/src/mono/mono/metadata/image.c +++ b/src/mono/mono/metadata/image.c @@ -2,7 +2,7 @@ * \file * Routines for manipulating an image stored in an * extended PE/COFF file. - * + * * Authors: * Miguel de Icaza (miguel@ximian.com) * Paolo Molaro (lupus@ximian.com) @@ -127,7 +127,7 @@ void mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data) { ImageUnloadHook *hook; - + g_return_if_fail (func != NULL); hook = g_new0 (ImageUnloadHook, 1); @@ -206,10 +206,10 @@ mono_cli_rva_image_map (MonoImage *image, guint32 addr) * \param addr relative virtual address (RVA) * * This is a low-level routine used by the runtime to map relative - * virtual address (RVA) into their location in memory. + * virtual address (RVA) into their location in memory. * * \returns the address in memory for the given RVA, or NULL if the - * RVA is not valid for this image. + * RVA is not valid for this image. */ char * mono_image_rva_map (MonoImage *image, guint32 addr) @@ -288,14 +288,14 @@ mono_image_ensure_section_idx (MonoImage *image, int section) { MonoCLIImageInfo *iinfo = image->image_info; MonoSectionTable *sect; - + g_return_val_if_fail (section < iinfo->cli_section_count, FALSE); if (iinfo->cli_sections [section] != NULL) return TRUE; sect = &iinfo->cli_section_tables [section]; - + if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len) return FALSE; #ifdef HOST_WIN32 @@ -323,11 +323,11 @@ mono_image_ensure_section (MonoImage *image, const char *section) { MonoCLIImageInfo *ii = image->image_info; int i; - + for (i = 0; i < ii->cli_section_count; i++){ if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0) continue; - + return mono_image_ensure_section_idx (image, i); } return FALSE; @@ -342,7 +342,7 @@ load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset) iinfo->cli_section_count = top; iinfo->cli_section_tables = g_new0 (MonoSectionTable, top); iinfo->cli_sections = g_new0 (void *, top); - + for (i = 0; i < top; i++){ MonoSectionTable *t = &iinfo->cli_section_tables [i]; @@ -372,7 +372,7 @@ gboolean mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo) { guint32 offset; - + offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva); if (offset == INVALID_ADDRESS) return FALSE; @@ -428,7 +428,7 @@ mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo) /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */ } - + return TRUE; } @@ -455,7 +455,7 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo) int i; guint32 pad; char *ptr; - + offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva); if (offset == INVALID_ADDRESS) return FALSE; @@ -490,7 +490,7 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo) /* skip over flags */ ptr += 2; - + streams = read16 (ptr); ptr += 2; @@ -591,7 +591,7 @@ load_tables (MonoImage *image) guint64 valid_mask; int valid = 0, table; int heap_sizes; - + heap_sizes = heap_tables [6]; image->idx_string_wide = ((heap_sizes & 0x01) == 1); image->idx_guid_wide = ((heap_sizes & 0x02) == 2); @@ -603,10 +603,10 @@ load_tables (MonoImage *image) g_assert (image->idx_guid_wide); g_assert (image->idx_blob_wide); } - + valid_mask = read64 (heap_tables + 8); rows = (const guint32 *) (heap_tables + 24); - + for (table = 0; table < 64; table++){ if ((valid_mask & ((guint64) 1 << table)) == 0){ if (table > MONO_TABLE_LAST) @@ -677,7 +677,7 @@ mono_image_check_for_module_cctor (MonoImage *image) guint32 last_method; if (table_info_get_rows (t) > 1) last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1; - else + else last_method = table_info_get_rows (mt); for (; first_method < last_method; first_method++) { nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME); @@ -777,7 +777,7 @@ mono_image_init (MonoImage *image) #define SWAPPDE(x) #endif -static int +static int do_load_header_internal (const char *raw_data, guint32 raw_data_len, MonoDotNetHeader *header, int offset, gboolean image_is_module_handle) { MonoDotNetHeader64 header64; @@ -910,12 +910,12 @@ do_load_header_internal (const char *raw_data, guint32 raw_data_len, MonoDotNetH static int do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset) { - offset = do_load_header_internal (image->raw_data, image->raw_data_len, header, offset, + offset = do_load_header_internal (image->raw_data, image->raw_data_len, header, offset, #ifdef HOST_WIN32 m_image_is_module_handle (image)); #else FALSE); -#endif +#endif #ifdef HOST_WIN32 if (m_image_is_module_handle (image)) @@ -924,7 +924,7 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset) return offset; } -mono_bool +mono_bool mono_has_pdb_checksum (char *raw_data, uint32_t raw_data_len) { MonoDotNetHeader cli_header; @@ -934,11 +934,11 @@ mono_has_pdb_checksum (char *raw_data, uint32_t raw_data_len) int offset = 0; memcpy (&msdos, raw_data + offset, sizeof (msdos)); - + if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z')) { return FALSE; } - + msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset); offset = msdos.pe_offset; @@ -959,7 +959,7 @@ mono_has_pdb_checksum (char *raw_data, uint32_t raw_data_len) if (ret + sizeof (MonoSectionTable) > raw_data_len) { return FALSE; } - + memcpy (&t, raw_data + ret, sizeof (MonoSectionTable)); ret += sizeof (MonoSectionTable); @@ -1014,10 +1014,10 @@ pe_image_load_pe_data (MonoImage *image) goto invalid_image; memcpy (&msdos, image->raw_data + offset, sizeof (msdos)); - + if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z')) goto invalid_image; - + msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset); offset = msdos.pe_offset; @@ -1052,7 +1052,7 @@ pe_image_load_pe_data (MonoImage *image) /* * FIXME: byte swap all addresses here for header. */ - + if (!load_section_tables (image, iinfo, offset)) goto invalid_image; @@ -1104,7 +1104,7 @@ mono_image_load_names (MonoImage *image) { /* modules don't have an assembly table row */ if (table_info_get_rows (&image->tables [MONO_TABLE_ASSEMBLY])) { - image->assembly_name = mono_metadata_string_heap (image, + image->assembly_name = mono_metadata_string_heap (image, mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_NAME)); } @@ -1314,7 +1314,7 @@ mono_image_storage_dtor (gpointer self) MonoImageStorage *storage = (MonoImageStorage *)self; mono_image_storage_unpublish (storage); - + #ifdef HOST_WIN32 if (storage->is_module_handle && !storage->has_entry_point) { mono_images_lock (); @@ -1369,7 +1369,7 @@ mono_image_storage_open (const char *fname) g_free (key); return published_storage; } - + MonoFileMap *filed; if ((filed = mono_file_map_open (fname)) == NULL){ g_free (key); @@ -1390,7 +1390,7 @@ mono_image_storage_open (const char *fname) mono_file_map_close (filed); storage->key = key; - + MonoImageStorage *other_storage = NULL; if (!mono_image_storage_trypublish (storage, &other_storage)) { mono_image_storage_close (storage); @@ -1789,7 +1789,7 @@ mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadConte char *absfname; g_return_val_if_fail (fname != NULL, NULL); - + #ifdef HOST_WIN32 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll), // then assemblies need to be loaded with LoadLibrary: @@ -1901,8 +1901,8 @@ mono_image_open_a_lot (MonoAssemblyLoadContext *alc, const char *fname, MonoImag * mono_image_open: * \param fname filename that points to the module we want to open * \param status An error condition is returned in this field - * \returns An open image of type \c MonoImage or NULL on error. - * The caller holds a temporary reference to the returned image which should be cleared + * \returns An open image of type \c MonoImage or NULL on error. + * The caller holds a temporary reference to the returned image which should be cleared * when no longer needed by calling \c mono_image_close. * if NULL, then check the value of \p status for details on the error */ @@ -1926,7 +1926,7 @@ MonoImage * mono_pe_file_open (const char *fname, MonoImageOpenStatus *status) { g_return_val_if_fail (fname != NULL, NULL); - + return do_mono_image_open (mono_alc_get_default (), fname, status, FALSE, TRUE, FALSE); } @@ -1935,13 +1935,13 @@ mono_pe_file_open (const char *fname, MonoImageOpenStatus *status) * \param fname filename that points to the module we want to open * \param status An error condition is returned in this field * \returns an image without loading neither pe or cli data. - * Use mono_image_load_pe_data and mono_image_load_cli_data to load them. + * Use mono_image_load_pe_data and mono_image_load_cli_data to load them. */ MonoImage * mono_image_open_raw (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status) { g_return_val_if_fail (fname != NULL, NULL); - + return do_mono_image_open (alc, fname, status, FALSE, FALSE, FALSE); } @@ -1980,7 +1980,7 @@ mono_image_fixup_vtable (MonoImage *image) vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva); if (!vtfixup) return; - + count = de->size / sizeof (MonoVTableFixup); while (count--) { if (!vtfixup->rva || !vtfixup->count) @@ -2039,7 +2039,7 @@ void mono_image_addref (MonoImage *image) { mono_atomic_inc_i32 (&image->ref_count); -} +} void mono_dynamic_stream_reset (MonoDynamicStream* stream) @@ -2068,7 +2068,7 @@ mono_wrapper_caches_free (MonoWrapperCaches *cache) free_hash (cache->delegate_end_invoke_cache); free_hash (cache->delegate_bound_static_invoke_cache); free_hash (cache->runtime_invoke_signature_cache); - + free_hash (cache->delegate_abstract_invoke_cache); free_hash (cache->runtime_invoke_method_cache); @@ -2139,7 +2139,7 @@ mono_image_close_except_pools (MonoImage *image) mono_metadata_update_cleanup_on_close (image); /* - * The caches inside a MonoImage might refer to metadata which is stored in referenced + * The caches inside a MonoImage might refer to metadata which is stored in referenced * assemblies, so we can't release these references in mono_assembly_close () since the * MonoImage might outlive its associated MonoAssembly. */ @@ -2340,7 +2340,7 @@ mono_image_close (MonoImage *image) mono_image_close_finish (image); } -/** +/** * mono_image_strerror: * \param status an code indicating the result from a recent operation * \returns a string describing the error @@ -2415,7 +2415,7 @@ mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id, for(i=0; ires_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries); res_entries=(MonoPEResourceDirEntry *)(resource_dir+1); - + for(i=0; ich_resources.rva || offset + 4 > ch->ch_resources.size) return NULL; - + data = mono_image_rva_map (image, ch->ch_resources.rva); if (!data) return NULL; @@ -2698,10 +2698,10 @@ mono_image_strong_name_position (MonoImage *image, guint32 *size) * \param size a \c guint32 pointer, or NULL. * * This is used to obtain the public key in the \p image. - * + * * If the image has a public key, and \p size is not NULL, the value * pointed to by size will have the size of the public key. - * + * * \returns NULL if the image does not have a public key, or a pointer * to the public key. */ @@ -2797,7 +2797,7 @@ mono_table_info_get_rows (const MonoTableInfo *table) * Use this routine to get the assembly that owns this image. * \returns the assembly that holds this image. */ -MonoAssembly* +MonoAssembly* mono_image_get_assembly (MonoImage *image) { return image->assembly; @@ -2911,7 +2911,7 @@ GList* mono_g_list_prepend_image (MonoImage *image, GList *list, gpointer data) { GList *new_list; - + new_list = (GList *)mono_image_alloc (image, sizeof (GList)); new_list->data = data; new_list->prev = list ? list->prev : NULL; @@ -2956,7 +2956,7 @@ mono_image_unlock (MonoImage *image) * * LOCKING: Takes the image lock */ -gpointer +gpointer mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property) { gpointer res; diff --git a/src/mono/mono/metadata/image.h b/src/mono/mono/metadata/image.h index 3049bcc973f32..4b43eefaf05e9 100644 --- a/src/mono/mono/metadata/image.h +++ b/src/mono/mono/metadata/image.h @@ -2,7 +2,7 @@ * \file */ -#ifndef _MONONET_METADATA_IMAGE_H_ +#ifndef _MONONET_METADATA_IMAGE_H_ #define _MONONET_METADATA_IMAGE_H_ #include @@ -88,7 +88,7 @@ MONO_API void* mono_image_lookup_resource (MonoImage *image, uint32_t res_i MONO_API const char* mono_image_get_public_key (MonoImage *image, uint32_t *size); MONO_API const char* mono_image_get_strong_name (MonoImage *image, uint32_t *size); MONO_API uint32_t mono_image_strong_name_position (MonoImage *image, uint32_t *size); -MONO_API void mono_image_add_to_name_cache (MonoImage *image, +MONO_API void mono_image_add_to_name_cache (MonoImage *image, const char *nspace, const char *name, uint32_t idx); MONO_API mono_bool mono_image_has_authenticode_entry (MonoImage *image); diff --git a/src/mono/mono/metadata/jit-info.c b/src/mono/mono/metadata/jit-info.c index 4dd455987afc3..a36af20affb79 100644 --- a/src/mono/mono/metadata/jit-info.c +++ b/src/mono/mono/metadata/jit-info.c @@ -335,7 +335,7 @@ mono_jit_info_table_find_internal (gpointer addr, gboolean try_aot, gboolean all if (ji && ji->is_trampoline && !allow_trampolines) return NULL; - + return ji; } diff --git a/src/mono/mono/metadata/jit-info.h b/src/mono/mono/metadata/jit-info.h index c380a23216c65..bdf6572de173c 100644 --- a/src/mono/mono/metadata/jit-info.h +++ b/src/mono/mono/metadata/jit-info.h @@ -222,7 +222,7 @@ struct _MonoJitInfo { gpointer gc_info; /* Currently only used by SGen */ gpointer seq_points; - + MonoJitExceptionInfo clauses [MONO_ZERO_LEN_ARRAY]; /* There is an optional MonoGenericJitInfo after the clauses */ /* There is an optional MonoTryBlockHoleTableJitInfo after MonoGenericJitInfo clauses*/ @@ -278,7 +278,7 @@ mono_jit_info_get_thunk_info (MonoJitInfo *ji); MonoUnwindJitInfo* mono_jit_info_get_unwind_info (MonoJitInfo *ji); -/* +/* * Installs a new function which is used to return a MonoJitInfo for a method inside * an AOT module. */ diff --git a/src/mono/mono/metadata/loaded-images.c b/src/mono/mono/metadata/loaded-images.c index 821e8f391f08d..9108a297d21f3 100644 --- a/src/mono/mono/metadata/loaded-images.c +++ b/src/mono/mono/metadata/loaded-images.c @@ -117,7 +117,7 @@ mono_loaded_images_remove_image (MonoImage *image) mono_images_unlock (); return proceed; - + } MonoLoadedImages* diff --git a/src/mono/mono/metadata/loader.c b/src/mono/mono/metadata/loader.c index e0ce3f575ae06..df93bf6864844 100644 --- a/src/mono/mono/metadata/loader.c +++ b/src/mono/mono/metadata/loader.c @@ -53,7 +53,7 @@ #include /* - * This lock protects the hash tables inside MonoImage used by the metadata + * This lock protects the hash tables inside MonoImage used by the metadata * loading functions in class.c and loader.c. * * See domain-internals.h for locking policy in combination with the @@ -65,7 +65,7 @@ static gboolean loader_lock_inited; static gboolean loader_lock_track_ownership; /* - * This TLS variable holds how many times the current thread has acquired the loader + * This TLS variable holds how many times the current thread has acquired the loader * lock. */ static MonoNativeTlsKey loader_lock_nest_id; @@ -156,7 +156,7 @@ mono_loader_unlock (void) * * Set whenever the runtime should track ownership of the loader lock. If set to TRUE, * the mono_loader_lock_is_owned_by_self () can be called to query whenever the current - * thread owns the loader lock. + * thread owns the loader lock. */ void mono_loader_lock_track_ownership (gboolean track) @@ -203,9 +203,9 @@ mono_loader_unlock_if_inited (void) * * Return a cached copy of the memberref signature identified by SIG_IDX. * We use a gpointer since the cache stores both MonoTypes and MonoMethodSignatures. - * A cache is needed since the type/signature parsing routines allocate everything - * from a mempool, so without a cache, multiple requests for the same signature would - * lead to unbounded memory growth. For normal methods/fields this is not a problem + * A cache is needed since the type/signature parsing routines allocate everything + * from a mempool, so without a cache, multiple requests for the same signature would + * lead to unbounded memory growth. For normal methods/fields this is not a problem * since the resulting methods/fields are cached, but inflated methods/fields cannot * be cached. * LOCKING: Acquires the loader lock. @@ -412,7 +412,7 @@ mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSigna sig1->sentinelpos != sig2->sentinelpos) return FALSE; - for (i = 0; i < sig1->sentinelpos; i++) { + for (i = 0; i < sig1->sentinelpos; i++) { MonoType *p1 = sig1->params[i]; MonoType *p2 = sig2->params[i]; @@ -465,7 +465,7 @@ find_method_in_class (MonoClass *klass, const char *name, const char *qname, con if (method) { other_sig = mono_method_signature_checked (method, error); if (!is_ok (error)) //bail out if we hit a loader error - return NULL; + return NULL; if (other_sig && (sig->call_convention != MONO_CALL_VARARG) && mono_metadata_signature_equal (sig, other_sig)) return method; } @@ -500,7 +500,7 @@ find_method_in_class (MonoClass *klass, const char *name, const char *qname, con (name && !strcmp (m->name, name)))) continue; msig = mono_method_signature_checked (m, error); - if (!is_ok (error)) //bail out if we hit a loader error + if (!is_ok (error)) //bail out if we hit a loader error return NULL; if (!msig) @@ -570,7 +570,7 @@ find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSig MonoClass *in_ic = in_class_interfaces_packed [i]; MonoClass *from_ic = from_class_interfaces_packed [i]; char *ic_qname, *ic_fqname, *ic_class_name; - + ic_class_name = mono_type_get_name_full (m_class_get_byval_arg (in_ic), MONO_TYPE_NAME_FORMAT_IL); ic_qname = g_strconcat (ic_class_name, ".", name, (const char*)NULL); const char *in_ic_name_space = m_class_get_name_space (in_ic); @@ -598,7 +598,7 @@ find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSig //we did not find the method if (!result && is_ok (error)) mono_error_set_method_missing (error, initial_class, name, sig, NULL); - + out: g_free (class_name); g_free (fqname); @@ -677,7 +677,7 @@ inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context, M { size_t locals_size = sizeof (gpointer) * header->num_locals; size_t clauses_size = header->num_clauses * sizeof (MonoExceptionClause); - size_t header_size = MONO_SIZEOF_METHOD_HEADER + locals_size + clauses_size; + size_t header_size = MONO_SIZEOF_METHOD_HEADER + locals_size + clauses_size; MonoMethodHeader *res = (MonoMethodHeader *)g_malloc0 (header_size); res->num_locals = header->num_locals; res->clauses = (MonoExceptionClause *) &res->locals [res->num_locals] ; @@ -1097,8 +1097,8 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass, container = mono_class_try_get_generic_container (klass); - /* - * load_generic_params does a binary search so only call it if the method + /* + * load_generic_params does a binary search so only call it if the method * is generic. */ if (*sig & 0x10) { @@ -1293,7 +1293,7 @@ get_method_constrained (MonoImage *image, MonoMethod *method, MonoClass *constra mono_error_set_for_class_failure (error, constrained_class); return NULL; } - + /* Get the slot of the method in the interface. Then get the * interface base in constrained_class */ int itf_slot = mono_method_get_vtable_index (method); @@ -1366,20 +1366,20 @@ mono_free_method (MonoMethod *method) return; MONO_PROFILER_RAISE (method_free, (method)); - + /* FIXME: This hack will go away when the profiler will support freeing methods */ if (G_UNLIKELY (mono_profiler_installed ())) return; - + if (method->signature) { - /* + /* * FIXME: This causes crashes because the types inside signatures and * locals are shared. */ /* mono_metadata_free_method_signature (method->signature); */ /* g_free (method->signature); */ } - + if (method_is_dynamic (method)) { MonoMethodWrapper *mw = (MonoMethodWrapper*)method; int i; @@ -1438,7 +1438,7 @@ mono_method_get_param_names (MonoMethod *method, const char **names) MonoImage *klass_image = m_class_get_image (klass); if (image_is_dynamic (klass_image)) { - MonoReflectionMethodAux *method_aux = + MonoReflectionMethodAux *method_aux = (MonoReflectionMethodAux *)g_hash_table_lookup ( ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method); if (method_aux && method_aux->param_names) { @@ -1535,7 +1535,7 @@ mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs) mspecs [i] = NULL; if (image_is_dynamic (m_class_get_image (method->klass))) { - MonoReflectionMethodAux *method_aux = + MonoReflectionMethodAux *method_aux = (MonoReflectionMethodAux *)g_hash_table_lookup ( ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method); if (method_aux && method_aux->param_marshall) { @@ -1601,7 +1601,7 @@ mono_method_has_marshal_info (MonoMethod *method) guint32 idx; if (image_is_dynamic (m_class_get_image (method->klass))) { - MonoReflectionMethodAux *method_aux = + MonoReflectionMethodAux *method_aux = (MonoReflectionMethodAux *)g_hash_table_lookup ( ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method); MonoMarshalSpec **dyn_specs = method_aux->param_marshall; @@ -1785,7 +1785,7 @@ mono_method_signature_checked_slow (MonoMethod *m, MonoError *error) MonoMethodSignature *signature = NULL, *sig2; guint32 sig_offset; - /* We need memory barriers below because of the double-checked locking pattern */ + /* We need memory barriers below because of the double-checked locking pattern */ error_init (error); @@ -2041,7 +2041,7 @@ mono_method_get_header_internal (MonoMethod *method, MonoError *error) return mw->header; } - /* + /* * We don't need locks here: the new header is allocated from malloc memory * and is not stored anywhere in the runtime, the user needs to free it. */ diff --git a/src/mono/mono/metadata/loader.h b/src/mono/mono/metadata/loader.h index 42c89288fcc6e..c1468257867a7 100644 --- a/src/mono/mono/metadata/loader.h +++ b/src/mono/mono/metadata/loader.h @@ -25,7 +25,7 @@ MONO_API MONO_RT_EXTERNAL_ONLY MonoMethod * mono_get_method_constrained (MonoImage *image, uint32_t token, MonoClass *constrained_class, MonoGenericContext *context, MonoMethod **cil_method); -MONO_API void +MONO_API void mono_free_method (MonoMethod *method); MONO_API MONO_RT_EXTERNAL_ONLY MonoMethodSignature* diff --git a/src/mono/mono/metadata/lock-tracer.c b/src/mono/mono/metadata/lock-tracer.c index 302c29f2c9aa8..13283f13de5d0 100644 --- a/src/mono/mono/metadata/lock-tracer.c +++ b/src/mono/mono/metadata/lock-tracer.c @@ -4,7 +4,7 @@ * * Authors: * Rodrigo Kumpera (rkumpera@novell.com) - * + * */ #include @@ -29,7 +29,7 @@ /* * This is a very simple lock trace implementation. It can be used to verify that the runtime is * correctly following all locking rules. - * + * * To log more kind of locks just do the following: * - add an entry into the RuntimeLocks enum * - change mono_os_mutex_lock(mutex) to mono_locks_os_acquire (mutex, LockName) @@ -44,7 +44,7 @@ * - Enable tracing of more runtime locks * - Add lock check assertions (must_not_hold_any_lock_but, must_hold_lock, etc) * This should be used to verify methods that expect that a given lock is held at entrypoint, for example. - * + * * To use the trace, define LOCK_TRACER in lock-trace.h and when running mono define MONO_ENABLE_LOCK_TRACER. * This will produce a locks.ZZZ where ZZZ is the pid of the mono process. * Use the decoder to verify the result. diff --git a/src/mono/mono/metadata/marshal-ilgen.c b/src/mono/mono/metadata/marshal-ilgen.c index 2290c438125c9..8061e75fc778e 100644 --- a/src/mono/mono/metadata/marshal-ilgen.c +++ b/src/mono/mono/metadata/marshal-ilgen.c @@ -348,7 +348,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv /* create a new array */ mono_mb_emit_ldloc (mb, 1); mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_op (mb, CEE_NEWARR, eklass); + mono_mb_emit_op (mb, CEE_NEWARR, eklass); mono_mb_emit_byte (mb, CEE_STIND_REF); if (m_class_is_blittable (eklass)) { @@ -360,7 +360,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_ldloc (mb, 0); mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); + mono_mb_emit_byte (mb, CEE_CPBLK); } else { int array_var, src_var, dst_var, index_var; @@ -375,7 +375,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_ldloc (mb, 1); mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_stloc (mb, array_var); - + /* save the old src pointer */ mono_mb_emit_ldloc (mb, 0); mono_mb_emit_stloc (mb, src_var); @@ -412,7 +412,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_branch_label (mb, CEE_BR, label2); mono_mb_patch_branch (mb, label3); - + /* restore the old src pointer */ mono_mb_emit_ldloc (mb, src_var); mono_mb_emit_stloc (mb, 0); @@ -428,7 +428,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv /* create a new array */ mono_mb_emit_ldloc (mb, 1); mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_op (mb, CEE_NEWARR, eclass); + mono_mb_emit_op (mb, CEE_NEWARR, eclass); mono_mb_emit_byte (mb, CEE_STIND_REF); mono_mb_emit_ldloc (mb, 1); @@ -438,7 +438,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_icall (mb, mono_byvalarray_to_byte_array); break; } - case MONO_MARSHAL_CONV_STR_BYVALSTR: + case MONO_MARSHAL_CONV_STR_BYVALSTR: if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) { mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); @@ -449,7 +449,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_ldloc (mb, 0); mono_mb_emit_icall (mb, ves_icall_string_new_wrapper); } - mono_mb_emit_byte (mb, CEE_STIND_REF); + mono_mb_emit_byte (mb, CEE_STIND_REF); break; case MONO_MARSHAL_CONV_STR_BYVALWSTR: if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) { @@ -462,8 +462,8 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_ldloc (mb, 0); mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16); } - mono_mb_emit_byte (mb, CEE_STIND_REF); - break; + mono_mb_emit_byte (mb, CEE_STIND_REF); + break; case MONO_MARSHAL_CONV_STR_ANSIBSTR: case MONO_MARSHAL_CONV_STR_TBSTR: @@ -487,13 +487,13 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv MonoType *int_type = mono_get_int_type (); src_var = mono_mb_add_local (mb, int_type); dst_var = mono_mb_add_local (mb, int_type); - + /* *dst = new object */ mono_mb_emit_ldloc (mb, 1); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); mono_mb_emit_byte (mb, CEE_STIND_REF); - + /* save the old src pointer */ mono_mb_emit_ldloc (mb, 0); mono_mb_emit_stloc (mb, src_var); @@ -506,10 +506,10 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_stloc (mb, 1); + mono_mb_emit_stloc (mb, 1); emit_struct_conv (mb, klass, TRUE); - + /* restore the old src pointer */ mono_mb_emit_ldloc (mb, src_var); mono_mb_emit_stloc (mb, 0); @@ -550,7 +550,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv * to change the SafeHandle value. If the value is changed, * we should issue a diagnostic exception (NotSupportedException) * that informs the user that changes to handles in unmanaged code - * is not supported. + * is not supported. * * Since we currently have no access to the original * SafeHandle that was used during the marshalling, @@ -559,15 +559,15 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv */ break; } - + case MONO_MARSHAL_CONV_HANDLEREF: { /* - * Passing HandleRefs in a struct that is ref()ed does not + * Passing HandleRefs in a struct that is ref()ed does not * copy the values back to the HandleRef */ break; } - + case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY: default: { char *msg = g_strdup_printf ("marshaling conversion %d not implemented", conv); @@ -837,12 +837,12 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op)); mono_mb_emit_byte (mb, stind_op); break; - case MONO_MARSHAL_CONV_STR_BYVALSTR: + case MONO_MARSHAL_CONV_STR_BYVALSTR: case MONO_MARSHAL_CONV_STR_BYVALWSTR: { g_assert (mspec); mono_mb_emit_ldloc (mb, 1); /* dst */ - mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */ mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); @@ -872,12 +872,12 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv if (m_class_is_blittable (eklass)) { mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); + mono_mb_emit_byte (mb, CEE_CPBLK); } else { int array_var, src_var, dst_var, index_var; guint32 label2, label3; @@ -889,7 +889,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv dst_var = mono_mb_add_local (mb, int_type); /* set array_var */ - mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_stloc (mb, array_var); @@ -929,7 +929,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_branch_label (mb, CEE_BR, label2); mono_mb_patch_branch (mb, label3); - + /* restore the old src pointer */ mono_mb_emit_ldloc (mb, src_var); mono_mb_emit_stloc (mb, 0); @@ -947,7 +947,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); mono_mb_emit_icall (mb, mono_array_to_byte_byvalarray); @@ -960,11 +960,11 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv MonoType *int_type = mono_get_int_type (); src_var = mono_mb_add_local (mb, int_type); dst_var = mono_mb_add_local (mb, int_type); - + mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_I); pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - + /* save the old src pointer */ mono_mb_emit_ldloc (mb, 0); mono_mb_emit_stloc (mb, src_var); @@ -974,13 +974,13 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv /* src = pointer to object data */ mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_stloc (mb, 0); + mono_mb_emit_stloc (mb, 0); emit_struct_conv (mb, mono_class_from_mono_type_internal (type), FALSE); - + /* restore the old src pointer */ mono_mb_emit_ldloc (mb, src_var); mono_mb_emit_stloc (mb, 0); @@ -1002,13 +1002,13 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv case MONO_MARSHAL_CONV_SAFEHANDLE: { int pos; - + mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_I); pos = mono_mb_emit_branch (mb, CEE_BRTRUE); mono_mb_emit_exception (mb, "ArgumentNullException", NULL); mono_mb_patch_branch (mb, pos); - + /* Pull the handle field from SafeHandle */ mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); @@ -1028,7 +1028,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_byte (mb, CEE_STIND_I); break; } - + default: { g_error ("marshalling conversion %d not implemented", conv); } @@ -1143,11 +1143,11 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje } if (klass != mono_class_try_get_safehandle_class ()){ - /* - * FIXME: Should really check for usize==0 and msize>0, but we apply + /* + * FIXME: Should really check for usize==0 and msize>0, but we apply * the layout to the managed structure as well. */ - + if (mono_class_is_explicit_layout (klass) && (usize == 0)) { if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type)))) @@ -1156,7 +1156,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje mono_type_full_name (m_class_get_byval_arg (klass))); } } - + switch (conv) { case MONO_MARSHAL_CONV_NONE: { int t; @@ -1223,7 +1223,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje MonoType *int_type = mono_get_int_type (); src_var = mono_mb_add_local (mb, int_type); dst_var = mono_mb_add_local (mb, int_type); - + /* save the old src pointer */ mono_mb_emit_ldloc (mb, 0); mono_mb_emit_stloc (mb, src_var); @@ -1269,7 +1269,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje break; } - default: + default: g_warning ("marshaling type %02x not implemented", ftype->type); g_assert_not_reached (); } @@ -1289,7 +1289,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje mono_mb_emit_ldloc (mb, 1); mono_mb_emit_stloc (mb, dst_var); - if (to_object) + if (to_object) emit_ptr_to_object_conv (mb, ftype, conv, info->fields [i].mspec); else emit_object_to_ptr_conv (mb, ftype, conv, info->fields [i].mspec); @@ -1309,7 +1309,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje } else { mono_mb_emit_add_to_local (mb, 0, msize); mono_mb_emit_add_to_local (mb, 1, usize); - } + } } } @@ -1360,7 +1360,7 @@ emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, MonoJitICallId che mono_mb_patch_branch (mb, pos_noex); mono_mb_emit_byte (mb, CEE_POP); - + mono_mb_patch_branch (mb, pos_noabort); } @@ -1370,7 +1370,7 @@ emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb) // FIXME Put a boolean in MonoMethodBuilder instead. if (strstr (mb->name, "mono_thread_interruption_checkpoint")) return; - + emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_interruption_checkpoint); } @@ -1452,10 +1452,10 @@ mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type) case MONO_TYPE_PTR: case MONO_TYPE_FNPTR: case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: /* nothing to do */ break; case MONO_TYPE_U1: @@ -1580,7 +1580,7 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i])); break; case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: + case MONO_TYPE_CLASS: case MONO_TYPE_ARRAY: case MONO_TYPE_PTR: case MONO_TYPE_FNPTR: @@ -1618,7 +1618,7 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, g_assert_not_reached (); } } - + if (virtual_) { mono_mb_emit_op (mb, CEE_CALLVIRT, method); } else if (need_direct_wrapper) { @@ -1676,7 +1676,7 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (sig->ret)); break; case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: + case MONO_TYPE_CLASS: case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: case MONO_TYPE_OBJECT: @@ -1697,12 +1697,12 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, for (i = 0; i < sig->param_count; i++) { MonoType *t = sig->params [i]; - /* + /* * Box the result and put it back into the array, the caller will have * to obtain it from there. */ if (m_type_is_byref (t) && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { - mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_ldarg (mb, 1); mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P * i); mono_mb_emit_byte (mb, CEE_ADD); @@ -1771,7 +1771,7 @@ emit_runtime_invoke_body_ilgen (MonoMethodBuilder *mb, const char **param_names, clause->handler_offset = mono_mb_get_label (mb); /* handler code */ - mono_mb_emit_stloc (mb, loc_exc); + mono_mb_emit_stloc (mb, loc_exc); mono_mb_emit_byte (mb, CEE_LDARG_2); mono_mb_emit_ldloc (mb, loc_exc); mono_mb_emit_byte (mb, CEE_STIND_REF); @@ -1812,7 +1812,7 @@ emit_runtime_invoke_dynamic_ilgen (MonoMethodBuilder *mb) /* cond set *exc to null */ mono_mb_emit_byte (mb, CEE_LDARG_1); mono_mb_emit_byte (mb, CEE_BRFALSE_S); - mono_mb_emit_byte (mb, 3); + mono_mb_emit_byte (mb, 3); mono_mb_emit_byte (mb, CEE_LDARG_1); mono_mb_emit_byte (mb, CEE_LDNULL); mono_mb_emit_byte (mb, CEE_STIND_REF); @@ -1832,7 +1832,7 @@ emit_runtime_invoke_dynamic_ilgen (MonoMethodBuilder *mb) /* filter code */ clause->data.filter_offset = mono_mb_get_label (mb); - + mono_mb_emit_byte (mb, CEE_POP); mono_mb_emit_byte (mb, CEE_LDARG_1); mono_mb_emit_byte (mb, CEE_LDC_I4_0); @@ -1846,7 +1846,7 @@ emit_runtime_invoke_dynamic_ilgen (MonoMethodBuilder *mb) /* handler code */ /* store exception */ mono_mb_emit_stloc (mb, 1); - + mono_mb_emit_byte (mb, CEE_LDARG_1); mono_mb_emit_ldloc (mb, 1); mono_mb_emit_byte (mb, CEE_STIND_REF); @@ -2129,7 +2129,7 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi for (i = 0; i < sig->param_count; i++) { mono_emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH); - } + } /* call the native method */ if (func_param) { @@ -2237,7 +2237,7 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi break; case MONO_TYPE_TYPEDBYREF: default: - g_warning ("return type 0x%02x unknown", sig->ret->type); + g_warning ("return type 0x%02x unknown", sig->ret->type); g_assert_not_reached (); } } @@ -2245,8 +2245,8 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi mono_mb_emit_stloc (mb, 3); } - /* - * Need to call this after converting the result since MONO_VTADDR needs + /* + * Need to call this after converting the result since MONO_VTADDR needs * to be adjacent to the call instruction. */ if (check_exceptions) @@ -2354,7 +2354,7 @@ emit_castclass_ilgen (MonoMethodBuilder *mb) const int class_arg_position = TYPECHECK_CLASS_ARG_POS; const int cache_arg_position = TYPECHECK_CACHE_ARG_POS; - generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position, + generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position, &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb); invalid_cast_pos = mono_mb_emit_branch (mb, CEE_BRFALSE); @@ -2382,7 +2382,7 @@ emit_isinst_ilgen (MonoMethodBuilder *mb) const int class_arg_position = TYPECHECK_CLASS_ARG_POS; const int cache_arg_position = TYPECHECK_CACHE_ARG_POS; - generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position, + generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position, &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb); // Return the object gotten via the slow path. mono_mb_emit_byte (mb, CEE_RET); @@ -2433,8 +2433,8 @@ load_value_class (MonoMethodBuilder *mb, int vklass) static int emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -2525,7 +2525,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, dest_ptr); /* Emit marshalling loop */ - index_var = mono_mb_add_local (mb, int_type); + index_var = mono_mb_add_local (mb, int_type); mono_mb_emit_byte (mb, CEE_LDC_I4_0); mono_mb_emit_stloc (mb, index_var); label2 = mono_mb_get_label (mb); @@ -2561,7 +2561,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_add_to_local (mb, index_var, 1); mono_mb_emit_add_to_local (mb, dest_ptr, esize); - + mono_mb_emit_branch_label (mb, CEE_BR, label2); mono_mb_patch_branch (mb, label3); @@ -2637,7 +2637,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, src_ptr); /* Emit marshalling loop */ - index_var = mono_mb_add_local (mb, int_type); + index_var = mono_mb_add_local (mb, int_type); mono_mb_emit_byte (mb, CEE_LDC_I4_0); mono_mb_emit_stloc (mb, index_var); label2 = mono_mb_get_label (mb); @@ -2721,7 +2721,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_patch_branch (mb, label3); } #endif - + if (m_class_is_blittable (eklass)) { /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */ @@ -2754,7 +2754,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, int index_var, src_ptr, esize, param_num, num_elem; MonoMarshalConv conv; gboolean is_string = FALSE; - + conv_arg = mono_mb_add_local (mb, object_type); *conv_arg_type = int_type; @@ -2868,8 +2868,8 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, src_ptr); /* Create managed array */ - /* - * The LPArray marshalling spec says that sometimes param_num starts + /* + * The LPArray marshalling spec says that sometimes param_num starts * from 1, sometimes it starts from 0. But MS seems to allways start * from 0. */ @@ -2946,7 +2946,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_patch_branch (mb, label1); mono_mb_patch_branch (mb, label3); #endif - + break; } case MARSHAL_ACTION_MANAGED_CONV_OUT: { @@ -2958,7 +2958,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (!spec) /* Already handled in CONV_IN */ break; - + /* These are already checked in CONV_IN */ g_assert (!m_type_is_byref (t)); g_assert (spec->native == MONO_NATIVE_LPARRAY); @@ -3022,7 +3022,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_icon (mb, esize); mono_mb_emit_byte (mb, CEE_MUL); mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); + mono_mb_emit_byte (mb, CEE_CPBLK); mono_mb_patch_branch (mb, label1); break; } @@ -3078,7 +3078,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, int index_var, src, dest, esize; MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID; gboolean is_string = FALSE; - + g_assert (!m_type_is_byref (t)); mono_marshal_load_type_info (eklass); @@ -3100,7 +3100,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, src = mono_mb_add_local (mb, object_type); dest = mono_mb_add_local (mb, int_type); - + mono_mb_emit_stloc (mb, src); mono_mb_emit_ldloc (mb, src); mono_mb_emit_stloc (mb, 3); @@ -3175,8 +3175,8 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, } static int -emit_marshal_ptr_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, +emit_marshal_ptr_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -3208,8 +3208,8 @@ emit_marshal_ptr_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, } static int -emit_marshal_scalar_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, +emit_marshal_scalar_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -3232,8 +3232,8 @@ emit_marshal_scalar_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, static int emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -3252,7 +3252,7 @@ emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, else *conv_arg_type = local_type; conv_arg = mono_mb_add_local (mb, local_type); - + mono_mb_emit_ldarg (mb, argnum); if (m_type_is_byref (t)) mono_mb_emit_byte (mb, CEE_LDIND_I1); @@ -3272,7 +3272,7 @@ emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); - + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); mono_mb_emit_byte (mb, CEE_LDC_I4_1); @@ -3314,7 +3314,7 @@ emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldarg (mb, argnum); - + /* Check null */ if (m_type_is_byref (t)) { label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); @@ -3328,7 +3328,7 @@ emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, conv_arg); mono_mb_patch_branch (mb, label_false); - if (m_type_is_byref (t)) + if (m_type_is_byref (t)) mono_mb_patch_branch (mb, label_null); break; } @@ -3354,7 +3354,7 @@ emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, break; } } - + /* Check null */ mono_mb_emit_ldarg (mb, argnum); label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); @@ -3382,8 +3382,8 @@ emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, } static int -emit_marshal_char_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, +emit_marshal_char_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -3823,50 +3823,50 @@ emit_stelemref_ilgen (MonoMethodBuilder *mb) guint32 copy_pos; int aklass, vklass; int array_slot_addr; - + MonoType *int_type = mono_get_int_type (); MonoType *object_type_byref = mono_class_get_byref_type (mono_defaults.object_class); aklass = mono_mb_add_local (mb, int_type); vklass = mono_mb_add_local (mb, int_type); array_slot_addr = mono_mb_add_local (mb, object_type_byref); - + /* the method: if (!value) goto store; - + aklass = array->vtable->m_class_get_element_class (klass); vklass = value->vtable->klass; - + if (vklass->idepth < aklass->idepth) goto long; - + if (vklass->supertypes [aklass->idepth - 1] != aklass) goto long; - + store: *array_slot_addr = value; return; - + long: if (mono_object_isinst (value, aklass)) goto store; - + throw new ArrayTypeMismatchException (); */ - + /* ldelema (implicit bound check) */ mono_mb_emit_ldarg (mb, 0); mono_mb_emit_ldarg (mb, 1); mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class); mono_mb_emit_stloc (mb, array_slot_addr); - + /* if (!value) goto do_store */ mono_mb_emit_ldarg (mb, 2); b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - + /* aklass = array->vtable->klass->element_class */ mono_mb_emit_ldarg (mb, 0); mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); @@ -3876,7 +3876,7 @@ emit_stelemref_ilgen (MonoMethodBuilder *mb) mono_mb_emit_ldflda (mb, m_class_offsetof_element_class ()); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_stloc (mb, aklass); - + /* vklass = value->vtable->klass */ mono_mb_emit_ldarg (mb, 2); mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); @@ -3884,23 +3884,23 @@ emit_stelemref_ilgen (MonoMethodBuilder *mb) mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass)); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_stloc (mb, vklass); - + /* if (vklass->idepth < aklass->idepth) goto failue */ mono_mb_emit_ldloc (mb, vklass); mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); mono_mb_emit_byte (mb, CEE_LDIND_U2); - + mono_mb_emit_ldloc (mb, aklass); mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); mono_mb_emit_byte (mb, CEE_LDIND_U2); - + b2 = mono_mb_emit_branch (mb, CEE_BLT_UN); - + /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */ mono_mb_emit_ldloc (mb, vklass); mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ()); mono_mb_emit_byte (mb, CEE_LDIND_I); - + mono_mb_emit_ldloc (mb, aklass); mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); mono_mb_emit_byte (mb, CEE_LDIND_U2); @@ -3910,32 +3910,32 @@ emit_stelemref_ilgen (MonoMethodBuilder *mb) mono_mb_emit_byte (mb, CEE_MUL); mono_mb_emit_byte (mb, CEE_ADD); mono_mb_emit_byte (mb, CEE_LDIND_I); - + mono_mb_emit_ldloc (mb, aklass); - + b3 = mono_mb_emit_branch (mb, CEE_BNE_UN); - + copy_pos = mono_mb_get_label (mb); /* do_store */ mono_mb_patch_branch (mb, b1); mono_mb_emit_ldloc (mb, array_slot_addr); mono_mb_emit_ldarg (mb, 2); mono_mb_emit_byte (mb, CEE_STIND_REF); - + mono_mb_emit_byte (mb, CEE_RET); - + /* the hard way */ mono_mb_patch_branch (mb, b2); mono_mb_patch_branch (mb, b3); - + mono_mb_emit_ldarg (mb, 2); mono_mb_emit_ldloc (mb, aklass); mono_mb_emit_icall (mb, mono_object_isinst_icall); - + b4 = mono_mb_emit_branch (mb, CEE_BRTRUE); mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4)); mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); - + mono_mb_emit_byte (mb, CEE_RET); } @@ -4165,7 +4165,7 @@ emit_delegate_invoke_internal_ilgen (MonoMethodBuilder *mb, MonoMethodSignature mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, sig); mono_mb_emit_byte (mb, CEE_RET); } - + /* else [target == null] call this->method_ptr static */ mono_mb_patch_branch (mb, pos0); } @@ -4372,7 +4372,7 @@ emit_unbox_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method) { MonoMethodSignature *sig = mono_method_signature_internal (method); - mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldarg (mb, 0); mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); mono_mb_emit_byte (mb, CEE_ADD); for (int i = 0; i < sig->param_count; ++i) @@ -4552,8 +4552,8 @@ emit_marshal_custom_get_instance (MonoMethodBuilder *mb, MonoClass *klass, MonoM static int emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action) { ERROR_DECL (error); @@ -4656,7 +4656,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); emit_marshal_custom_get_instance (mb, mklass, spec); - + mono_mb_emit_ldarg (mb, argnum); if (m_type_is_byref (t)) mono_mb_emit_byte (mb, CEE_LDIND_REF); @@ -4718,7 +4718,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, case MARSHAL_ACTION_CONV_RESULT: loc1 = mono_mb_add_local (mb, int_type); - + mono_mb_emit_stloc (mb, 3); mono_mb_emit_ldloc (mb, 3); @@ -4757,11 +4757,11 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); emit_marshal_custom_get_instance (mb, mklass, spec); - + mono_mb_emit_ldarg (mb, argnum); if (m_type_is_byref (t)) mono_mb_emit_byte (mb, CEE_LDIND_I); - + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); mono_mb_emit_stloc (mb, conv_arg); @@ -4772,9 +4772,9 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, g_assert (!m_type_is_byref (t)); loc1 = mono_mb_add_local (mb, object_type); - + mono_mb_emit_stloc (mb, 3); - + mono_mb_emit_ldloc (mb, 3); mono_mb_emit_stloc (mb, loc1); @@ -4813,7 +4813,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, /* Call CleanUpManagedData */ emit_marshal_custom_get_instance (mb, mklass, spec); - + mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); @@ -4828,8 +4828,8 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, static int emit_marshal_asany_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -4874,8 +4874,8 @@ emit_marshal_asany_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, static int emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -4924,15 +4924,15 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, break; conv_arg = mono_mb_add_local (mb, int_type); - + /* store the address of the source into local variable 0 */ if (m_type_is_byref (t)) mono_mb_emit_ldarg (mb, argnum); else mono_mb_emit_ldarg_addr (mb, argnum); - + mono_mb_emit_stloc (mb, 0); - + /* allocate space for the native struct and * store the address into local variable 1 (dest) */ mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); @@ -4984,7 +4984,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { mono_mb_emit_ldarg (mb, argnum); break; - } + } mono_mb_emit_ldloc (mb, conv_arg); if (!m_type_is_byref (t)) { mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); @@ -5037,7 +5037,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, } emit_struct_free (mb, klass, conv_arg); - + if (m_type_is_byref (t)) mono_mb_patch_branch (mb, pos); break; @@ -5056,7 +5056,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, /* set dst_ptr */ mono_mb_emit_ldloc_addr (mb, 3); mono_mb_emit_stloc (mb, 1); - + /* emit valuetype conversion code */ emit_struct_conv (mb, klass, TRUE); break; @@ -5072,7 +5072,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (t->attrs & PARAM_ATTRIBUTE_OUT) break; - if (m_type_is_byref (t)) + if (m_type_is_byref (t)) mono_mb_emit_ldarg (mb, argnum); else mono_mb_emit_ldarg_addr (mb, argnum); @@ -5081,7 +5081,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t)) { mono_mb_emit_ldloc (mb, 0); pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - } + } mono_mb_emit_ldloc_addr (mb, conv_arg); mono_mb_emit_stloc (mb, 1); @@ -5123,11 +5123,11 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, m->retobj_var = 0; break; } - + /* load pointer to returned value type */ g_assert (m->vtaddr_var); mono_mb_emit_ldloc (mb, m->vtaddr_var); - + /* store the address of the source into local variable 0 */ mono_mb_emit_stloc (mb, 0); /* allocate space for the native struct and @@ -5163,8 +5163,8 @@ emit_string_free_icall (MonoMethodBuilder *mb, MonoMarshalConv conv) static int emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -5184,7 +5184,7 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, break; mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_LDIND_I); } else { mono_mb_emit_ldarg (mb, argnum); } @@ -5221,7 +5221,7 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, MONO_STATIC_POINTER_INIT_END (MonoMethod, m) - /* + /* * Have to allocate a new string with the same length as the original, and * copy the contents of the buffer pointed to by CONV_ARG into it. */ @@ -5229,7 +5229,7 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_managed_call (mb, m, NULL); mono_mb_emit_icall (mb, mono_string_new_len_wrapper); mono_mb_emit_byte (mb, CEE_STIND_REF); @@ -5257,7 +5257,7 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, case MARSHAL_ACTION_CONV_RESULT: mono_mb_emit_stloc (mb, 0); - + conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); if (conv == MONO_MARSHAL_CONV_INVALID) { char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); @@ -5327,8 +5327,8 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, static int -emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, +emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -5348,7 +5348,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldarg (mb, argnum); pos = mono_mb_emit_branch (mb, CEE_BRTRUE); mono_mb_emit_exception (mb, "ArgumentNullException", NULL); - + mono_mb_patch_branch (mb, pos); /* Create local to hold the ref parameter to DangerousAddRef */ @@ -5399,7 +5399,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, case MARSHAL_ACTION_PUSH: if (m_type_is_byref (t)) mono_mb_emit_ldloc_addr (mb, conv_arg); - else + else mono_mb_emit_ldloc (mb, conv_arg); break; @@ -5425,7 +5425,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (is_out (t)) { ERROR_DECL (local_error); MonoMethod *ctor; - + /* * If the SafeHandle was marshalled on input we can skip the marshalling on * output if the handle value is identical. @@ -5439,7 +5439,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, /* * Create an empty SafeHandle (of correct derived type). - * + * * FIXME: If an out-of-memory situation or exception happens here we will * leak the handle. We should move the allocation of the SafeHandle to the * input marshalling code to prevent that. @@ -5476,12 +5476,12 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, } break; } - + case MARSHAL_ACTION_CONV_RESULT: { ERROR_DECL (error); MonoMethod *ctor = NULL; int intptr_handle_slot; - + if (mono_class_is_abstract (t->data.klass)) { mono_mb_emit_byte (mb, CEE_POP); mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract")); @@ -5510,11 +5510,11 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_STIND_I); break; } - + case MARSHAL_ACTION_MANAGED_CONV_IN: fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); break; - + case MARSHAL_ACTION_MANAGED_CONV_OUT: fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); break; @@ -5530,8 +5530,8 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, static int -emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, +emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -5546,7 +5546,7 @@ emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); mono_mb_emit_exception_marshal_directive (mb, msg); break; - } + } mono_mb_emit_ldarg_addr (mb, argnum); mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoHandleRef, handle)); mono_mb_emit_byte (mb, CEE_ADD); @@ -5563,17 +5563,17 @@ emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, /* no resource release required */ break; } - + case MARSHAL_ACTION_CONV_RESULT: { char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); mono_mb_emit_exception_marshal_directive (mb, msg); break; } - + case MARSHAL_ACTION_MANAGED_CONV_IN: fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); break; - + case MARSHAL_ACTION_MANAGED_CONV_OUT: fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); break; @@ -5590,8 +5590,8 @@ emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, static int emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; @@ -5629,7 +5629,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec); MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); -#if 0 +#if 0 if (m_type_is_byref (t)) { if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { char *msg = g_strdup_printf ("Byref marshalling of stringbuilders is not implemented."); @@ -5676,7 +5676,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (t->attrs & PARAM_ATTRIBUTE_OUT) break; - mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_byte (mb, CEE_LDIND_I); } else { @@ -5684,7 +5684,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); } - + /* store the address of the source into local variable 0 */ mono_mb_emit_stloc (mb, 0); mono_mb_emit_ldloc (mb, 0); @@ -5803,7 +5803,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); mono_mb_emit_byte (mb, CEE_ADD); mono_mb_emit_stloc (mb, 1); - + /* src = tmp_locals [i] */ mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_stloc (mb, 0); @@ -5815,7 +5815,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, emit_struct_free (mb, klass, conv_arg); if (m->orig_conv_args [argnum]) { - /* + /* * If the native function changed the pointer, then free * the original structure plus the new pointer. */ @@ -5865,35 +5865,35 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, } else { /* set src */ mono_mb_emit_stloc (mb, 0); - + /* Make a copy since emit_conv modifies local 0 */ loc = mono_mb_add_local (mb, int_type); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_stloc (mb, loc); - + mono_mb_emit_byte (mb, CEE_LDNULL); mono_mb_emit_stloc (mb, 3); - + mono_mb_emit_ldloc (mb, 0); pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - + /* allocate result object */ - + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); mono_mb_emit_stloc (mb, 3); - + /* set dst */ - + mono_mb_emit_ldloc (mb, 3); mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); mono_mb_emit_stloc (mb, 1); - + /* emit conversion code */ emit_struct_conv (mb, klass, TRUE); - + emit_struct_free (mb, klass, loc); - + /* Free the pointer allocated by unmanaged code */ mono_mb_emit_ldloc (mb, loc); mono_mb_emit_icall (mb, mono_marshal_free); @@ -5957,7 +5957,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_patch_branch (mb, pos2); mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_byte (mb, CEE_LDIND_I); - } + } mono_mb_emit_stloc (mb, 0); @@ -5969,11 +5969,11 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, /* Create and set dst */ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); mono_mb_emit_stloc (mb, conv_arg); mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_stloc (mb, 1); + mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ emit_struct_conv (mb, klass, TRUE); @@ -6002,8 +6002,8 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_STIND_I); pos2 = mono_mb_emit_branch (mb, CEE_BR); - mono_mb_patch_branch (mb, pos); - + mono_mb_patch_branch (mb, pos); + /* Set src */ mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); @@ -6014,12 +6014,12 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_CONV_I); mono_mb_emit_icall (mb, ves_icall_marshal_alloc); mono_mb_emit_stloc (mb, 1); - + /* Update argument pointer */ mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, 1); mono_mb_emit_byte (mb, CEE_STIND_I); - + /* emit valuetype conversion code */ emit_struct_conv (mb, klass, FALSE); @@ -6039,10 +6039,10 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, /* Set dest */ mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_stloc (mb, 1); - + /* emit valuetype conversion code */ emit_struct_conv (mb, klass, FALSE); - } + } break; case MARSHAL_ACTION_MANAGED_CONV_RESULT: @@ -6094,8 +6094,8 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, static int emit_marshal_variant_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, MarshalAction action) { #ifndef DISABLE_COM @@ -6107,7 +6107,7 @@ emit_marshal_variant_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, switch (action) { case MARSHAL_ACTION_CONV_IN: { conv_arg = mono_mb_add_local (mb, variant_type); - + if (m_type_is_byref (t)) *conv_arg_type = variant_type_byref; else @@ -6330,7 +6330,7 @@ emit_managed_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_s if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) { mono_emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT); - } else if (!m_type_is_byref (sig->ret)) { + } else if (!m_type_is_byref (sig->ret)) { switch (sig->ret->type) { case MONO_TYPE_VOID: break; @@ -6362,7 +6362,7 @@ emit_managed_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_s mono_emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT); break; default: - g_warning ("return type 0x%02x unknown", sig->ret->type); + g_warning ("return type 0x%02x unknown", sig->ret->type); g_assert_not_reached (); } } else { @@ -6481,7 +6481,7 @@ emit_ptr_to_struct_ilgen (MonoMethodBuilder *mb, MonoClass *klass) mono_mb_add_local (mb, int_type); /* allocate local 1 (pointer) dst_ptr */ mono_mb_add_local (mb, m_class_get_this_arg (klass)); - + /* initialize src_ptr to point to the start of object data */ mono_mb_emit_byte (mb, CEE_LDARG_0); mono_mb_emit_stloc (mb, 0); @@ -6776,7 +6776,7 @@ emit_marshal_directive_exception_ilgen (EmitMarshalContext *m, int argnum, const char* fullmsg = NULL; if (argnum == 0) fullmsg = g_strdup_printf("Error marshalling return value: %s", msg); - else + else fullmsg = g_strdup_printf("Error marshalling parameter #%d: %s", argnum, msg); mono_mb_emit_exception_marshal_directive (m->mb, fullmsg); diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 4f57d238e16a8..491fdcc2b9fc0 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -3088,7 +3088,7 @@ mono_emit_disabled_marshal (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref(t)) { if (emit_exception) - get_marshal_cb ()->emit_marshal_directive_exception (m, argnum, "Cannot marshal managed references when the runtime marshalling system is disabled."); + get_marshal_cb ()->emit_marshal_directive_exception (m, argnum, "Cannot marshal managed references when the runtime marshalling system is disabled."); else get_marshal_cb ()->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); return conv_arg; @@ -3140,7 +3140,7 @@ mono_emit_disabled_marshal (EmitMarshalContext *m, int argnum, MonoType *t, } if (emit_exception) - get_marshal_cb ()->emit_marshal_directive_exception (m, argnum, "Cannot marshal managed types when the runtime marshalling system is disabled."); + get_marshal_cb ()->emit_marshal_directive_exception (m, argnum, "Cannot marshal managed types when the runtime marshalling system is disabled."); else get_marshal_cb ()->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); return conv_arg; diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index 1779131e45093..3d35ee3abf75d 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -1,7 +1,7 @@ /** * \file * Routines for marshaling complex types in P/Invoke methods. - * + * * Author: * Paolo Molaro (lupus@ximian.com) * @@ -78,7 +78,7 @@ typedef enum { /* * The result from the unmanaged call is at the top of the stack when * this action is invoked. The result should be stored in the - * third local variable slot. + * third local variable slot. */ MARSHAL_ACTION_CONV_RESULT, @@ -378,7 +378,7 @@ gint32 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align, gboolean as_field, gboolean unicode); -int +int mono_type_native_stack_size (MonoType *type, guint32 *alignment); mono_bstr @@ -542,18 +542,18 @@ mono_marshal_unlock_internal (void); /* marshaling internal calls */ -void * +void * mono_marshal_alloc (gsize size, MonoError *error); ICALL_EXPORT -void +void mono_marshal_free (gpointer ptr); ICALL_EXPORT void mono_marshal_free_array (gpointer *ptr, int size); -gboolean +gboolean mono_marshal_free_ccw (MonoObject* obj); MONO_API void * @@ -564,12 +564,12 @@ void mono_marshal_set_last_error_windows (int error); ICALL_EXPORT -void +void mono_struct_delete_old (MonoClass *klass, char *ptr); int -mono_emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, +mono_emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); ICALL_EXPORT diff --git a/src/mono/mono/metadata/mempool-internals.h b/src/mono/mono/metadata/mempool-internals.h index c16e83438e443..fb09d2ecda04b 100644 --- a/src/mono/mono/metadata/mempool-internals.h +++ b/src/mono/mono/metadata/mempool-internals.h @@ -14,7 +14,7 @@ static inline GList* g_list_prepend_mempool (MonoMemPool *mp, GList *list, gpointer data) { GList *new_list; - + new_list = (GList *) mono_mempool_alloc (mp, sizeof (GList)); new_list->data = data; new_list->prev = list ? list->prev : NULL; @@ -32,7 +32,7 @@ static inline GSList* g_slist_prepend_mempool (MonoMemPool *mp, GSList *list, gpointer data) { GSList *new_list; - + new_list = (GSList *) mono_mempool_alloc (mp, sizeof (GSList)); new_list->data = data; new_list->next = list; diff --git a/src/mono/mono/metadata/mempool.c b/src/mono/mono/metadata/mempool.c index ab9fc28bccc35..6a2698a5385f9 100644 --- a/src/mono/mono/metadata/mempool.c +++ b/src/mono/mono/metadata/mempool.c @@ -113,7 +113,7 @@ mono_mempool_new_size (int initial_size) pool->next = NULL; pool->pos = (guint8*)pool + SIZEOF_MEM_POOL; // Start after header - pool->end = (guint8*)pool + initial_size; // End at end of allocated space + pool->end = (guint8*)pool + initial_size; // End at end of allocated space pool->d.allocated = pool->size = initial_size; UnlockedAdd64 (&total_bytes_allocated, initial_size); return pool; diff --git a/src/mono/mono/metadata/metadata-internals.h b/src/mono/mono/metadata/metadata-internals.h index ba8f957aaf2d0..ed4627d4bab07 100644 --- a/src/mono/mono/metadata/metadata-internals.h +++ b/src/mono/mono/metadata/metadata-internals.h @@ -32,7 +32,7 @@ struct _MonoType { } data; unsigned int attrs : 16; /* param attributes or field flags */ MonoTypeEnum type : 8; - unsigned int has_cmods : 1; + unsigned int has_cmods : 1; unsigned int byref__ : 1; /* don't access directly, use m_type_is_byref */ unsigned int pinned : 1; /* valid when included in a local var signature */ }; @@ -130,14 +130,14 @@ mono_type_get_custom_modifier (const MonoType *ty, uint8_t idx, gboolean *requir // memory unsafety on the stack and/or heap, when we try to traverse // this array. // -// Use mono_sizeof_monotype +// Use mono_sizeof_monotype // to get the size of the memory to copy. #define MONO_SIZEOF_TYPE sizeof (MonoType) -size_t +size_t mono_sizeof_type_with_mods (uint8_t num_mods, gboolean aggregate); -size_t +size_t mono_sizeof_type (const MonoType *ty); size_t @@ -192,8 +192,8 @@ typedef struct _MonoAssemblyContext { } MonoAssemblyContext; struct _MonoAssembly { - /* - * The number of appdomains which have this assembly loaded plus the number of + /* + * The number of appdomains which have this assembly loaded plus the number of * assemblies referencing this assembly through an entry in their image->references * arrays. The latter is needed because entries in the image->references array * might point to assemblies which are only loaded in some appdomains, and without @@ -238,7 +238,7 @@ struct _MonoTableInfo { * A 32 bit value can encode the resulting size * * The top eight bits encode the number of columns in the table. - * we only need 4, but 8 is aligned no shift required. + * we only need 4, but 8 is aligned no shift required. */ guint32 size_bitfield; }; @@ -350,14 +350,14 @@ struct _MonoImage { MonoMemPool *mempool; /*protected by the image lock*/ char *raw_metadata; - + MonoStreamHeader heap_strings; MonoStreamHeader heap_us; MonoStreamHeader heap_blob; MonoStreamHeader heap_guid; MonoStreamHeader heap_tables; MonoStreamHeader heap_pdb; - + const char *tables_base; /* For PPDB files */ @@ -447,7 +447,7 @@ struct _MonoImage { GHashTable *native_func_wrapper_cache; /* - * indexed by MonoMethod pointers + * indexed by MonoMethod pointers */ GHashTable *wrapper_param_names; GHashTable *array_accessor_cache; @@ -899,7 +899,7 @@ mono_metadata_parse_mh_full (MonoImage *image, const char *ptr, MonoError *error); -MonoMethodSignature *mono_metadata_parse_signature_checked (MonoImage *image, +MonoMethodSignature *mono_metadata_parse_signature_checked (MonoImage *image, uint32_t token, MonoError *error); @@ -948,7 +948,7 @@ void mono_dynamic_stream_reset (MonoDynamicStream* stream); void mono_assembly_load_friends (MonoAssembly* ass); gboolean mono_assembly_has_skip_verification (MonoAssembly* ass); -MONO_API gint32 +MONO_API gint32 mono_assembly_addref (MonoAssembly *assembly); gint32 mono_assembly_decref (MonoAssembly *assembly); @@ -1010,7 +1010,7 @@ mono_metadata_signature_equal_no_ret (MonoMethodSignature *sig1, MonoMethodSigna MONO_API void mono_metadata_field_info_with_mempool ( - MonoImage *meta, + MonoImage *meta, guint32 table_index, guint32 *offset, guint32 *rva, @@ -1059,7 +1059,7 @@ mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, Mon MonoMethodSignature* mono_method_get_signature_checked (MonoMethod *method, MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error); - + MONO_COMPONENT_API MonoMethod * mono_get_method_checked (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error); diff --git a/src/mono/mono/metadata/metadata-update.c b/src/mono/mono/metadata/metadata-update.c index e24823ead81f3..ac31818c5e499 100644 --- a/src/mono/mono/metadata/metadata-update.c +++ b/src/mono/mono/metadata/metadata-update.c @@ -155,7 +155,7 @@ mono_metadata_update_metadata_linear_search (MonoImage *base_image, MonoTableInf return mono_component_hot_reload()->metadata_linear_search (base_image, base_table, key, comparer); } -/* +/* * Returns the (1-based) table row index of the fielddef of the given field * (which must have m_field_is_from_update set). */ diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 8aa7a921ab48c..f249e816b76f5 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -4994,7 +4994,7 @@ mono_metadata_nested_in_typedef (MonoImage *meta, guint32 index) if (!found && !mono_metadata_update_metadata_linear_search (meta, tdef, &loc, table_locator)) return 0; } - + /* loc_result is 0..1, needs to be mapped to table index (that is +1) */ return mono_metadata_decode_row_col (tdef, loc.result, MONO_NESTED_CLASS_ENCLOSING) | MONO_TOKEN_TYPE_DEF; } diff --git a/src/mono/mono/metadata/method-builder-ilgen.c b/src/mono/mono/metadata/method-builder-ilgen.c index 68ddbaae60e80..5f48ac8b038aa 100644 --- a/src/mono/mono/metadata/method-builder-ilgen.c +++ b/src/mono/mono/metadata/method-builder-ilgen.c @@ -616,10 +616,10 @@ mono_mb_emit_exception_for_error (MonoMethodBuilder *mb, MonoError *error) void mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr) { - mono_mb_emit_ldloc (mb, local); + mono_mb_emit_ldloc (mb, local); mono_mb_emit_icon (mb, incr); mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_stloc (mb, local); + mono_mb_emit_stloc (mb, local); } void diff --git a/src/mono/mono/metadata/method-builder.c b/src/mono/mono/metadata/method-builder.c index b907d82add622..3f6452ec89a6b 100644 --- a/src/mono/mono/metadata/method-builder.c +++ b/src/mono/mono/metadata/method-builder.c @@ -1,7 +1,7 @@ /** * \file * Functions for creating IL methods at runtime. - * + * * Author: * Paolo Molaro (lupus@ximian.com) * @@ -47,11 +47,11 @@ static MonoDisHelper marshal_dh = { "\n", "IL_%04x: ", "IL_%04x", - indenter, + indenter, NULL, NULL }; -#endif +#endif static MonoMethodBuilderCallbacks mb_cb; static gboolean cb_inited = FALSE; diff --git a/src/mono/mono/metadata/method-builder.h b/src/mono/mono/metadata/method-builder.h index fd3903c866445..673dcec32b858 100644 --- a/src/mono/mono/metadata/method-builder.h +++ b/src/mono/mono/metadata/method-builder.h @@ -1,7 +1,7 @@ /** * \file * Functions for creating IL methods at runtime. - * + * * Author: * Paolo Molaro (lupus@ximian.com) * diff --git a/src/mono/mono/metadata/monitor.c b/src/mono/mono/metadata/monitor.c index da5662677b866..042f73b866c86 100644 --- a/src/mono/mono/metadata/monitor.c +++ b/src/mono/mono/metadata/monitor.c @@ -315,7 +315,7 @@ mono_locks_dump (gboolean include_untaken) } /* LOCKING: this is called with monitor_mutex held */ -static void +static void mon_finalize (MonoThreadsSync *mon) { LOCK_DEBUG (g_message ("%s: Finalizing sync %p", __func__, mon)); @@ -411,7 +411,7 @@ mon_new (gsize id) new_->status = mon_status_init_entry_count (new_->status); new_->nest = 1; new_->data = NULL; - + #ifndef DISABLE_PERFCOUNTERS mono_atomic_inc_i32 (&mono_perfcounters->gc_sync_blocks); #endif @@ -566,7 +566,7 @@ mono_object_hash_internal (MonoObject* obj) /* Done by somebody else */ return hash; } - + mono_monitor_inflate (obj); lw.sync = obj->synchronisation; } else if (lock_word_is_flat (lw)) { @@ -666,7 +666,7 @@ mono_monitor_exit_inflated (MonoObject *obj) old_status = tmp_status; } LOCK_DEBUG (g_message ("%s: (%d) Object %p is now unlocked", __func__, mono_thread_info_get_small_id (), obj)); - + /* object is now unlocked, leave nest==1 so we don't * need to set it when the lock is reacquired */ @@ -758,7 +758,7 @@ static gint64 thread_contentions; /* for Monitor.LockContentionCount, otherwise /* If allow_interruption==TRUE, the method will be interrupted if abort or suspend * is requested. In this case it returns -1. - */ + */ static gint32 mono_monitor_try_enter_inflated (MonoObject *obj, guint32 ms, gboolean allow_interruption, guint32 id) { @@ -874,7 +874,7 @@ mono_monitor_try_enter_inflated (MonoObject *obj, guint32 ms, gboolean allow_int then = mono_msec_ticks (); } waitms = ms; - + #ifndef DISABLE_PERFCOUNTERS mono_atomic_inc_i32 (&mono_perfcounters->thread_queue_len); mono_atomic_inc_i32 (&mono_perfcounters->thread_queue_max); @@ -905,8 +905,8 @@ mono_monitor_try_enter_inflated (MonoObject *obj, guint32 ms, gboolean allow_int if (timedout || (interrupted && allow_interruption)) { /* we're done */ } else { - /* - * We have to obey a stop/suspend request even if + /* + * We have to obey a stop/suspend request even if * allow_interruption is FALSE to avoid hangs at shutdown. * FIXME Handle abort protected blocks */ @@ -1051,7 +1051,7 @@ void mono_monitor_exit_internal (MonoObject *obj) { LockWord lw; - + LOCK_DEBUG (g_message ("%s: (%d) Unlocking %p", __func__, mono_thread_info_get_small_id (), obj)); if (G_UNLIKELY (!obj)) { @@ -1242,7 +1242,7 @@ ves_icall_System_Threading_Monitor_Monitor_test_owner (MonoObjectHandle obj_hand } else if (lock_word_is_inflated (lw)) { return mon_status_get_owner (lock_word_get_inflated_lock (lw)->status) == mono_thread_info_get_small_id (); } - + return FALSE; } @@ -1279,7 +1279,7 @@ mono_monitor_pulse (MonoObject *obj, const char *func, gboolean all) MonoThreadsSync *mon; LOCK_DEBUG (g_message ("%s: (%d) Pulsing %p", func, id, obj)); - + lw.sync = obj->synchronisation; if (!mono_monitor_ensure_owned (lw, id)) @@ -1365,7 +1365,7 @@ mono_monitor_wait (MonoObjectHandle obj_handle, guint32 ms, MonoBoolean allow_in mono_thread_set_state (thread, ThreadState_WaitSleepJoin); mon->wait_list = g_slist_append (mon->wait_list, event); - + /* Save the nest count, and release the lock */ nest = mon->nest; mon->nest = 1; @@ -1414,7 +1414,7 @@ mono_monitor_wait (MonoObjectHandle obj_handle, guint32 ms, MonoBoolean allow_in * be signalled more than once, thereby starving another * thread. */ - + if (ret == MONO_W32HANDLE_WAIT_RET_SUCCESS_0) { LOCK_DEBUG (g_message ("%s: (%d) Success", __func__, id)); success = TRUE; @@ -1426,7 +1426,7 @@ mono_monitor_wait (MonoObjectHandle obj_handle, guint32 ms, MonoBoolean allow_in mon->wait_list = g_slist_remove (mon->wait_list, event); } mono_w32event_close (event); - + return success; } diff --git a/src/mono/mono/metadata/mono-basic-block.c b/src/mono/mono/metadata/mono-basic-block.c index 6dd0a679fe541..4fef3f8b9a442 100644 --- a/src/mono/mono/metadata/mono-basic-block.c +++ b/src/mono/mono/metadata/mono-basic-block.c @@ -410,7 +410,7 @@ bb_formation_il_pass (const unsigned char *start, const unsigned char *end, Mono offset = cli_addr + 5 + (gint32)read32 (ip + 1); ip += 5; } - + branch = bb_split (bb, current, root, offset, TRUE, method, error); if (!branch) return; @@ -442,7 +442,7 @@ bb_formation_il_pass (const unsigned char *start, const unsigned char *end, Mono return; bb_link (current, next); - tmp = next; + tmp = next; for (j = 0; j < n; ++j) { if (ip >= end) { @@ -545,7 +545,7 @@ mono_basic_block_split (MonoMethod *method, MonoError *error, MonoMethodHeader * bb_formation_il_pass (start, end, bb, &root, method, error); if (!is_ok (error)) goto fail; - + bb_formation_eh_pass (header, bb, &root, method, error); if (!is_ok (error)) goto fail; @@ -567,14 +567,14 @@ mono_basic_block_split (MonoMethod *method, MonoError *error, MonoMethodHeader * * mono_opcode_value_and_size: * * Returns the size of the opcode starting at *@ip, or -1 on error. - * Value is the opcode number. + * Value is the opcode number. */ int mono_opcode_value_and_size (const unsigned char **ip, const unsigned char *end, MonoOpcodeEnum *value) { const unsigned char *start = *ip, *p; int i = *value = mono_opcode_value (ip, end); - int size = 0; + int size = 0; if (i < 0 || i >= MONO_CEE_LAST) return -1; p = *ip; diff --git a/src/mono/mono/metadata/mono-conc-hash.c b/src/mono/mono/metadata/mono-conc-hash.c index f0bdcc4002482..c79e7210ce20a 100644 --- a/src/mono/mono/metadata/mono-conc-hash.c +++ b/src/mono/mono/metadata/mono-conc-hash.c @@ -169,7 +169,7 @@ rehash_table (MonoConcGHashTable *hash_table, int multiplier) hash_table->overflow_count = (int)(new_table->table_size * LOAD_FACTOR); hash_table->element_count -= hash_table->tombstone_count; hash_table->tombstone_count = 0; - conc_table_lf_free (old_table); + conc_table_lf_free (old_table); } @@ -305,7 +305,7 @@ mono_conc_g_hash_table_foreach (MonoConcGHashTable *hash_table, GHFunc func, gpo if (table->keys [i] && !key_is_tombstone (hash_table, table->keys [i])) { func (table->keys [i], table->values [i], user_data); } - } + } } void @@ -359,7 +359,7 @@ mono_conc_g_hash_table_insert (MonoConcGHashTable *hash_table, gpointer key, gpo if (is_tombstone) --hash_table->tombstone_count; else - ++hash_table->element_count; + ++hash_table->element_count; return NULL; } @@ -382,7 +382,7 @@ mono_conc_g_hash_table_insert (MonoConcGHashTable *hash_table, gpointer key, gpo if (is_tombstone) --hash_table->tombstone_count; else - ++hash_table->element_count; + ++hash_table->element_count; return NULL; } diff --git a/src/mono/mono/metadata/mono-config-internals.h b/src/mono/mono/metadata/mono-config-internals.h index ce26f5dd52ca6..dabccc0e8a4f0 100644 --- a/src/mono/mono/metadata/mono-config-internals.h +++ b/src/mono/mono/metadata/mono-config-internals.h @@ -7,7 +7,7 @@ #include "mono/metadata/mono-config.h" -void +void mono_config_for_assembly_internal (MonoImage *assembly); #endif /* __MONO_METADATA_CONFIG_INTERNALS_H__ */ diff --git a/src/mono/mono/metadata/mono-config.c b/src/mono/mono/metadata/mono-config.c index 89c5be8ff5e7f..f38b8f5303dd5 100644 --- a/src/mono/mono/metadata/mono-config.c +++ b/src/mono/mono/metadata/mono-config.c @@ -63,7 +63,7 @@ #define CONFIG_WORDSIZE "32" #elif defined(__ppc64__) || defined(__powerpc64__) || defined(_ARCH_64) || defined(TARGET_POWERPC) #define CONFIG_WORDSIZE "64" -#ifdef __mono_ppc_ilp32__ +#ifdef __mono_ppc_ilp32__ # define CONFIG_CPU "ppc64ilp32" #else # define CONFIG_CPU "ppc64" diff --git a/src/mono/mono/metadata/mono-debug.c b/src/mono/mono/metadata/mono-debug.c index 03626981f441d..78b1e07a42183 100644 --- a/src/mono/mono/metadata/mono-debug.c +++ b/src/mono/mono/metadata/mono-debug.c @@ -847,7 +847,7 @@ mono_debug_method_lookup_location (MonoDebugMethodInfo *minfo, int il_offset) if (ret) return ret; } - } + } MonoDebugSourceLocation *location; @@ -871,7 +871,7 @@ mono_debug_lookup_locals (MonoMethod *method) { MonoDebugMethodInfo *minfo; MonoDebugLocalsInfo *res; - + MonoImage* img = m_class_get_image (method->klass); if (img->has_updates) { int idx = mono_metadata_token_index (method->token); @@ -1144,7 +1144,7 @@ mono_debug_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrA if (mono_ppdb_get_seq_points_enc (minfo, mdie->ppdb_file, mdie->idx, source_file, source_file_list, source_files, seq_points, n_seq_points)) return; } - } + } if (minfo->handle->ppdb) mono_ppdb_get_seq_points (minfo, source_file, source_file_list, source_files, seq_points, n_seq_points); else diff --git a/src/mono/mono/metadata/mono-endian.c b/src/mono/mono/metadata/mono-endian.c index d7822c72ff630..170498377f605 100644 --- a/src/mono/mono/metadata/mono-endian.c +++ b/src/mono/mono/metadata/mono-endian.c @@ -29,7 +29,7 @@ typedef union { guint64 i; } mono_rint64; -guint16 +guint16 mono_read16 (const unsigned char *x) { mono_rint16 r; @@ -43,7 +43,7 @@ mono_read16 (const unsigned char *x) return r.i; } -guint32 +guint32 mono_read32 (const unsigned char *x) { mono_rint32 r; @@ -61,7 +61,7 @@ mono_read32 (const unsigned char *x) return r.i; } -guint64 +guint64 mono_read64 (const unsigned char *x) { mono_rint64 r; diff --git a/src/mono/mono/metadata/mono-hash-internals.h b/src/mono/mono/metadata/mono-hash-internals.h index 84b8894f9e00e..bf2f4ea9fd7be 100644 --- a/src/mono/mono/metadata/mono-hash-internals.h +++ b/src/mono/mono/metadata/mono-hash-internals.h @@ -12,7 +12,7 @@ MONO_COMPONENT_API MonoGHashTable * mono_g_hash_table_new_type_internal (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, void *key, const char *msg); -MONO_COMPONENT_API void +MONO_COMPONENT_API void mono_g_hash_table_insert_internal (MonoGHashTable *h, gpointer k, gpointer v); #endif /* __MONO_G_HASH_INTERNALS_H__ */ diff --git a/src/mono/mono/metadata/mono-private-unstable.h b/src/mono/mono/metadata/mono-private-unstable.h index 4618c8fe08bc9..203ef008ad486 100644 --- a/src/mono/mono/metadata/mono-private-unstable.h +++ b/src/mono/mono/metadata/mono-private-unstable.h @@ -1,6 +1,6 @@ /** * \file - * + * * Private unstable APIs. * * WARNING: The declarations and behavior of functions in this header are NOT STABLE and can be modified or removed at diff --git a/src/mono/mono/metadata/native-library.c b/src/mono/mono/metadata/native-library.c index e32515ae8dcd1..a1fc8b47b702d 100644 --- a/src/mono/mono/metadata/native-library.c +++ b/src/mono/mono/metadata/native-library.c @@ -92,7 +92,7 @@ mono_dllmap_lookup_list (MonoDllMap *dll_map, const char *dll, const char* func, if (!dll_map) goto exit; - /* + /* * we use the first entry we find that matches, since entries from * the config file are prepended to the list and we document that the * later entries win. @@ -254,7 +254,7 @@ mono_global_dllmap_cleanup (void) * This function is used to programatically add \c DllImport remapping in either * a specific assembly, or as a global remapping. This is done by remapping * references in a \c DllImport attribute from the \p dll library name into the \p tdll - * name. If the \p dll name contains the prefix i:, the comparison of the + * name. If the \p dll name contains the prefix i:, the comparison of the * library name is done without case sensitivity. * * If you pass \p func, this is the name of the \c EntryPoint in a \c DllImport if specified @@ -526,7 +526,7 @@ netcore_probe_for_module (MonoImage *image, const char *file_name, int flags) module = netcore_probe_for_module_variations (pinvoke_search_directories[i], file_name, lflags); // Check the assembly directory if the search flag is set and the image exists - if ((flags & DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY) != 0 && image != NULL && + if ((flags & DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY) != 0 && image != NULL && module == NULL && (image->filename != NULL)) { char *mdirname = g_path_get_dirname (image->filename); if (mdirname) @@ -1145,7 +1145,7 @@ pinvoke_probe_for_symbol (MonoDl *module, MonoMethodPInvoke *piinfo, const char #if HOST_WIN32 && HOST_X86 /* Try the stdcall mangled name */ - /* + /* * gcc under windows creates mangled names without the underscore, but MS.NET * doesn't support it, so we doesn't support it either. */ @@ -1385,7 +1385,7 @@ mono_loader_save_bundled_library (int fd, uint64_t offset, uint64_t size, const char *file, *buffer, *err, *internal_path; if (!bundle_save_library_initialized) bundle_save_library_initialize (); - + file = g_build_filename (bundled_dylibrary_directory, destfname, (const char*)NULL); buffer = g_str_from_file_region (fd, offset, size); g_file_set_contents (file, buffer, size, NULL); @@ -1400,7 +1400,7 @@ mono_loader_save_bundled_library (int fd, uint64_t offset, uint64_t size, const mono_loader_register_module (internal_path, lib); g_free (internal_path); bundle_library_paths = g_slist_append (bundle_library_paths, file); - + g_free (buffer); } diff --git a/src/mono/mono/metadata/null-gc-handles.c b/src/mono/mono/metadata/null-gc-handles.c index 6ba1c0fe7f99d..8d946fe890b1c 100644 --- a/src/mono/mono/metadata/null-gc-handles.c +++ b/src/mono/mono/metadata/null-gc-handles.c @@ -36,7 +36,7 @@ typedef struct { #define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0, NULL} -/* weak and weak-track arrays will be allocated in malloc memory +/* weak and weak-track arrays will be allocated in malloc memory */ static HandleData gc_handles [] = { EMPTY_HANDLE_DATA (HANDLE_WEAK), @@ -236,12 +236,12 @@ alloc_handle (HandleData *handles, MonoObject *obj, gboolean track) * This returns a handle that wraps the object, this is used to keep a * reference to a managed object from the unmanaged world and preventing the * object from being disposed. - * + * * If \p pinned is false the address of the object can not be obtained, if it is * true the address of the object can be obtained. This will also pin the * object so it will not be possible by a moving garbage collector to move the - * object. - * + * object. + * * \returns a handle that can be used to access the object from * unmanaged code. */ @@ -261,14 +261,14 @@ mono_gchandle_new_internal (MonoObject *obj, gboolean pinned) * Unlike the \c mono_gchandle_new_internal the object can be reclaimed by the * garbage collector. In this case the value of the GCHandle will be * set to zero. - * + * * If \p track_resurrection is TRUE the object will be tracked through * finalization and if the object is resurrected during the execution * of the finalizer, then the returned weakref will continue to hold * a reference to the object. If \p track_resurrection is FALSE, then * the weak reference's target will become NULL as soon as the object * is passed on to the finalizer. - * + * * \returns a handle that can be used to access the object from * unmanaged code. */ @@ -388,7 +388,7 @@ mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain) * * Frees the \p gchandle handle. If there are no outstanding * references, the garbage collector can reclaim the memory of the - * object wrapped. + * object wrapped. */ void mono_gchandle_free_internal (guint32 gchandle) diff --git a/src/mono/mono/metadata/null-gc.c b/src/mono/mono/metadata/null-gc.c index 343756d2c67da..039e3c2ad7056 100644 --- a/src/mono/mono/metadata/null-gc.c +++ b/src/mono/mono/metadata/null-gc.c @@ -635,7 +635,7 @@ mono_gc_ephemeron_array_add (MonoObject *obj) return TRUE; } -guint64 mono_gc_get_total_allocated_bytes (MonoBoolean precise) +guint64 mono_gc_get_total_allocated_bytes (MonoBoolean precise) { return 0; } diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index c1c4d939df2a1..2be830e375b15 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -93,7 +93,7 @@ mono_array_new_specific_handle (MonoVTable *vtable, uintptr_t n, MonoError *erro MonoArray* mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error); -/* +/* * Macros which cache. * These should be used instead of the original versions. */ @@ -170,7 +170,7 @@ struct _MonoArray { /* bounds is NULL for szarrays */ MonoArrayBounds *bounds; /* total number of elements of the array */ - mono_array_size_t max_length; + mono_array_size_t max_length; /* we use mono_64bitaligned_t to ensure proper alignment on platforms that need it */ mono_64bitaligned_t vector [MONO_ZERO_LEN_ARRAY]; }; @@ -469,7 +469,7 @@ typedef struct _MonoQCallAssemblyHandle MonoQCallAssemblyHandle; typedef struct { MonoObject object; - MonoReflectionType *class_to_proxy; + MonoReflectionType *class_to_proxy; MonoObject *context; MonoObject *unwrapped_server; gint32 target_domain_id; @@ -523,7 +523,7 @@ TYPED_HANDLE_DECL (MonoComInteropProxy); typedef struct { MonoObject object; - MonoRealProxy *rp; + MonoRealProxy *rp; MonoRemoteClass *remote_class; MonoBoolean custom_type_info; } MonoTransparentProxy; @@ -534,9 +534,9 @@ TYPED_HANDLE_DECL (MonoTransparentProxy); typedef struct { MonoObject obj; MonoReflectionMethod *method; - MonoArray *args; - MonoArray *names; - MonoArray *arg_types; + MonoArray *args; + MonoArray *names; + MonoArray *arg_types; MonoObject *ctx; MonoObject *rval; MonoObject *exc; @@ -664,7 +664,7 @@ TYPED_HANDLE_DECL (MonoDelegate); typedef void (*InterpJitInfoFunc) (MonoJitInfo *ji, gpointer user_data); -/* +/* * Callbacks supplied by the runtime and called by the modules in metadata/ * This interface is easier to extend than adding a new function type + * a new 'install' function for every callback. @@ -780,9 +780,9 @@ mono_domain_get_tls_offset (void); /* * Handling System.Type objects: * - * Fields defined as System.Type in managed code should be defined as MonoObject* - * in unmanaged structures, and the monotype_cast () function should be used for - * casting them to MonoReflectionType* to avoid crashes/security issues when + * Fields defined as System.Type in managed code should be defined as MonoObject* + * in unmanaged structures, and the monotype_cast () function should be used for + * casting them to MonoReflectionType* to avoid crashes/security issues when * encountering instances of user defined subclasses of System.Type. */ @@ -830,8 +830,8 @@ struct _MonoDelegate { gpointer delegate_trampoline; /* Extra argument passed to the target method in llvmonly mode */ gpointer extra_arg; - /* - * If non-NULL, this points to a memory location which stores the address of + /* + * If non-NULL, this points to a memory location which stores the address of * the compiled code of the method, or NULL if it is not yet compiled. */ guint8 **method_code; @@ -1138,7 +1138,7 @@ typedef struct { MonoArray *modopt; } MonoReflectionFieldBuilder; -/* Safely access System.Reflection.Emit.FieldBuilder from native code */ +/* Safely access System.Reflection.Emit.FieldBuilder from native code */ TYPED_HANDLE_DECL (MonoReflectionFieldBuilder); typedef struct { @@ -1344,7 +1344,7 @@ typedef struct { MonoArray *refs; GSList *referenced_by; MonoReflectionType *owner; -} MonoReflectionDynamicMethod; +} MonoReflectionDynamicMethod; /* Safely access System.Reflection.Emit.DynamicMethod from native code */ TYPED_HANDLE_DECL (MonoReflectionDynamicMethod); @@ -1678,7 +1678,7 @@ mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error); ICALL_EXPORT MonoObject * ves_icall_object_new (MonoClass *klass); - + ICALL_EXPORT MonoObject * ves_icall_object_new_specific (MonoVTable *vtable); @@ -1886,7 +1886,7 @@ MonoObject* mono_runtime_invoke_span_checked (MonoMethod *method, void *obj, MonoSpanOfObjects *params, MonoError *error); -void* +void* mono_compile_method_checked (MonoMethod *method, MonoError *error); MonoObject* diff --git a/src/mono/mono/metadata/object.h b/src/mono/mono/metadata/object.h index fa9d84121bc1b..2186fa802c448 100644 --- a/src/mono/mono/metadata/object.h +++ b/src/mono/mono/metadata/object.h @@ -48,7 +48,7 @@ typedef void (*MonoMainThreadFunc) (void* user_data); } while (0) #define mono_array_addr(array,type,index) ((type*)mono_array_addr_with_size ((array), sizeof (type), (index))) -#define mono_array_get(array,type,index) ( *(type*)mono_array_addr ((array), type, (index)) ) +#define mono_array_get(array,type,index) ( *(type*)mono_array_addr ((array), type, (index)) ) #define mono_array_set(array,type,index,value) \ do { \ type *__p = (type *) mono_array_addr ((array), type, (index)); \ @@ -291,7 +291,7 @@ mono_runtime_exec_managed_code (MonoDomain *domain, void* main_args); MONO_API MONO_RT_EXTERNAL_ONLY int -mono_runtime_run_main (MonoMethod *method, int argc, char* argv[], +mono_runtime_run_main (MonoMethod *method, int argc, char* argv[], MonoObject **exc); MONO_API MONO_RT_EXTERNAL_ONLY int @@ -348,11 +348,11 @@ mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObjec /* GC handles support * * A handle can be created to refer to a managed object and either prevent it - * from being garbage collected or moved or to be able to know if it has been + * from being garbage collected or moved or to be able to know if it has been * collected or not (weak references). * mono_gchandle_new () is used to prevent an object from being garbage collected * until mono_gchandle_free() is called. Use a TRUE value for the pinned argument to - * prevent the object from being moved (this should be avoided as much as possible + * prevent the object from being moved (this should be avoided as much as possible * and this should be used only for shorts periods of time or performance will suffer). * To create a weakref use mono_gchandle_new_weakref (): track_resurrection should * usually be false (see the GC docs for more details). diff --git a/src/mono/mono/metadata/property-bag.c b/src/mono/mono/metadata/property-bag.c index 9dc0634ec0087..42c083f038115 100644 --- a/src/mono/mono/metadata/property-bag.c +++ b/src/mono/mono/metadata/property-bag.c @@ -21,7 +21,7 @@ void* mono_property_bag_get (MonoPropertyBag *bag, int tag) { MonoPropertyBagItem *item; - + for (item = bag->head; item && item->tag <= tag; item = item->next) { if (item->tag == tag) return item; diff --git a/src/mono/mono/metadata/reflection.c b/src/mono/mono/metadata/reflection.c index 9c39731d698b2..47683f1e68ab9 100644 --- a/src/mono/mono/metadata/reflection.c +++ b/src/mono/mono/metadata/reflection.c @@ -1,7 +1,7 @@ /** * \file * System.Type icalls and related reflection queries. - * + * * Author: * Paolo Molaro (lupus@ximian.com) * @@ -238,7 +238,7 @@ mono_assembly_get_object_handle (MonoAssembly *assembly, MonoError *error) /** * mono_module_get_object: */ -MonoReflectionModule* +MonoReflectionModule* mono_module_get_object (MonoDomain *domain, MonoImage *image) { MonoReflectionModuleHandle result; @@ -255,7 +255,7 @@ static MonoReflectionModuleHandle module_object_construct (MonoClass *unused_klass, MonoImage *image, gpointer user_data, MonoError *error) { char* basename; - + error_init (error); MonoReflectionModuleHandle res = MONO_HANDLE_CAST (MonoReflectionModule, mono_object_new_handle (mono_class_get_mono_module_class (), error)); goto_if_nok (error, fail); @@ -328,7 +328,7 @@ mono_module_file_get_object_handle (MonoImage *image, int table_index, MonoError const char *name; guint32 i, name_idx; const char *val; - + error_init (error); MonoReflectionModuleHandle res = MONO_HANDLE_CAST (MonoReflectionModule, mono_object_new_handle (mono_class_get_mono_module_class (), error)); @@ -448,7 +448,7 @@ mono_type_get_object_checked (MonoType *type, MonoError *error) /*we must avoid using @type as it might have come * from a mono_metadata_type_dup and the caller * expects that is can be freed. - * Using the right type from + * Using the right type from */ type = m_type_is_byref (m_class_get_byval_arg (klass)) == m_type_is_byref (type) ? m_class_get_byval_arg (klass) : m_class_get_this_arg (klass); @@ -469,9 +469,9 @@ mono_type_get_object_checked (MonoType *type, MonoError *error) /* * If the vtable of the given class was already created, we can use * the MonoType from there and avoid all locking and hash table lookups. - * + * * We cannot do this for TypeBuilders as mono_reflection_create_runtime_class expects - * that the resulting object is different. + * that the resulting object is different. */ if (type == m_class_get_byval_arg (klass) && !image_is_dynamic (m_class_get_image (klass))) { MonoVTable *vtable = mono_class_try_get_vtable (klass); @@ -594,7 +594,7 @@ method_object_construct (MonoClass *refclass, MonoMethod *method, gpointer user_ error_init (error); g_assert (refclass != NULL); /* - * We use the same C representation for methods and constructors, but the type + * We use the same C representation for methods and constructors, but the type * name in C# is different. */ MonoClass *klass; @@ -1053,7 +1053,7 @@ param_objects_construct (MonoClass *refclass, MonoMethodSignature **addr_of_sig, int i; error_init (error); - + MonoReflectionMethodHandle member = mono_method_get_object_handle (method, refclass, error); goto_if_nok (error, leave); names = g_new (char *, sig->param_count); @@ -1107,7 +1107,7 @@ param_objects_construct (MonoClass *refclass, MonoMethodSignature **addr_of_sig, if (!is_ok (error)) return NULL_HANDLE_ARRAY; - + return res; } @@ -1444,7 +1444,7 @@ get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types) if (!crow) { continue; } - + mono_metadata_decode_row (constt, crow - 1, const_cols, MONO_CONSTANT_SIZE); blobs [paramseq - 1] = (char *)mono_metadata_blob_heap (image, const_cols [MONO_CONSTANT_VALUE]); types [paramseq - 1] = const_cols [MONO_CONSTANT_TYPE]; @@ -1479,7 +1479,7 @@ mono_get_object_from_blob (MonoType *type, const char *blob, MonoStringHandleOut if (m_class_is_enumtype (klass)) basetype = mono_class_enum_basetype_internal (klass); } - + if (mono_get_constant_value_from_blob (basetype->type, blob, retval, string_handle, error)) MONO_HANDLE_ASSIGN_RAW (object_handle, object); else @@ -1685,7 +1685,7 @@ _mono_reflection_parse_type (char *name, char **endptr, gboolean is_recursed, // *w++ = *p++; p++; } - + if (!info->name) { if (last_point) { info->name_space = start; @@ -1936,7 +1936,7 @@ mono_reflection_parse_type (char *name, MonoTypeNameParse *info) * \param name the string to parse * \param info the parsed name components * \param error set on error - * + * * Parse the given \p name and write the results to \p info, setting \p error * on error. The string \p name is modified in place and \p info points into * its memory and into allocated memory. @@ -1969,7 +1969,7 @@ _mono_reflection_get_type_from_info (MonoAssemblyLoadContext *alc, MonoTypeNameP if (info->assembly.name) { MonoAssembly *assembly = mono_assembly_loaded_internal (alc, &info->assembly); if (!assembly && image && image->assembly && mono_assembly_check_name_match (&info->assembly, &image->assembly->aname)) - /* + /* * This could happen in the AOT compiler case when the search hook is not * installed. */ @@ -2015,7 +2015,7 @@ mono_reflection_get_type_internal (MonoAssemblyLoadContext *alc, MonoImage *root int modval; gboolean bounded = FALSE; MonoType* type = NULL; - + error_init (error); if (!image) image = mono_defaults.corlib; @@ -2151,7 +2151,7 @@ mono_reflection_get_type_internal (MonoAssemblyLoadContext *alc, MonoImage *root * \param type_resolve whenever type resolve was already tried * * Build a MonoType from the type description in \p info. - * + * */ MonoType* mono_reflection_get_type (MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase, gboolean *type_resolve) @@ -2253,7 +2253,7 @@ mono_reflection_get_type_internal_dynamic (MonoAssemblyLoadContext *alc, MonoIma leave: HANDLE_FUNCTION_RETURN_VAL (type); } - + MonoType* mono_reflection_get_type_with_rootimage (MonoAssemblyLoadContext *alc, MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase, gboolean search_mscorlib, gboolean *type_resolve, MonoError *error) { @@ -2279,11 +2279,11 @@ mono_reflection_get_type_with_rootimage (MonoAssemblyLoadContext *alc, MonoImage goto return_null; if (type_resolve) { - if (*type_resolve) + if (*type_resolve) goto return_null; *type_resolve = TRUE; } - + /* Reconstruct the type name */ fullName = g_string_new (""); if (info->name_space && (info->name_space [0] != '\0')) @@ -2354,7 +2354,7 @@ mono_reflection_free_type_info (MonoTypeNameParse *info) * Retrieves a \c MonoType from its \p name. If the name is not fully qualified, * it defaults to get the type from \p image or, if \p image is NULL or loading * from it fails, uses corlib. - * + * */ MonoType* mono_reflection_type_from_name (char *name, MonoImage *image) @@ -2392,7 +2392,7 @@ mono_reflection_type_from_name_checked (char *name, MonoAssemblyLoadContext *alc error_init (error); /* Make a copy since parse_type modifies its argument */ tmp = g_strdup (name); - + /*g_print ("requested type %s\n", str);*/ ERROR_DECL (parse_error); if (!mono_reflection_parse_type_checked (tmp, &info, parse_error)) { @@ -2421,7 +2421,7 @@ mono_reflection_get_token (MonoObject *obj_raw) ERROR_DECL (error); result = mono_reflection_get_token_checked (obj, error); mono_error_assert_ok (error); - + MONO_EXIT_GC_UNSAFE; HANDLE_FUNCTION_RETURN_VAL (result); } @@ -2570,7 +2570,7 @@ mono_reflection_bind_generic_parameters (MonoReflectionTypeHandle reftype, int t MonoClass *geninst; error_init (error); - + mono_loader_lock (); MonoClass *klass = mono_handle_class (reftype); @@ -2803,7 +2803,7 @@ mono_declsec_flags_from_method (MonoMethod *method) * mono_declsec_flags_from_class: * \param klass The class for which we want the declarative security flags. * Get the security actions (in the form of flags) associated with the specified class. - * We cache the flags inside the \c MonoClass structure as this will get + * We cache the flags inside the \c MonoClass structure as this will get * called very often (at least for each method). * \returns the declarative security flags for the class. */ @@ -2900,7 +2900,7 @@ fill_actions_from_index (MonoImage *image, guint32 token, MonoDeclSecurityAction } static MonoBoolean -mono_declsec_get_class_demands_params (MonoClass *klass, MonoDeclSecurityActions* demands, +mono_declsec_get_class_demands_params (MonoClass *klass, MonoDeclSecurityActions* demands, guint32 id_std, guint32 id_noncas, guint32 id_choice) { guint32 idx = mono_metadata_token_index (m_class_get_type_token (klass)); @@ -2910,7 +2910,7 @@ mono_declsec_get_class_demands_params (MonoClass *klass, MonoDeclSecurityActions } static MonoBoolean -mono_declsec_get_method_demands_params (MonoMethod *method, MonoDeclSecurityActions* demands, +mono_declsec_get_method_demands_params (MonoMethod *method, MonoDeclSecurityActions* demands, guint32 id_std, guint32 id_noncas, guint32 id_choice) { guint32 idx = mono_method_get_index (method); @@ -2928,7 +2928,7 @@ mono_declsec_get_method_demands_params (MonoMethod *method, MonoDeclSecurityActi MonoBoolean mono_declsec_get_demands (MonoMethod *method, MonoDeclSecurityActions* demands) { - guint32 mask = MONO_DECLSEC_FLAG_DEMAND | MONO_DECLSEC_FLAG_NONCAS_DEMAND | + guint32 mask = MONO_DECLSEC_FLAG_DEMAND | MONO_DECLSEC_FLAG_NONCAS_DEMAND | MONO_DECLSEC_FLAG_DEMAND_CHOICE; MonoBoolean result = FALSE; guint32 flags; @@ -2949,7 +2949,7 @@ mono_declsec_get_demands (MonoMethod *method, MonoDeclSecurityActions* demands) mono_class_init_internal (method->klass); memset (demands, 0, sizeof (MonoDeclSecurityActions)); - result = mono_declsec_get_method_demands_params (method, demands, + result = mono_declsec_get_method_demands_params (method, demands, SECURITY_ACTION_DEMAND, SECURITY_ACTION_NONCASDEMAND, SECURITY_ACTION_DEMANDCHOICE); } @@ -2960,7 +2960,7 @@ mono_declsec_get_demands (MonoMethod *method, MonoDeclSecurityActions* demands) mono_class_init_internal (method->klass); memset (demands, 0, sizeof (MonoDeclSecurityActions)); } - result |= mono_declsec_get_class_demands_params (method->klass, demands, + result |= mono_declsec_get_class_demands_params (method->klass, demands, SECURITY_ACTION_DEMAND, SECURITY_ACTION_NONCASDEMAND, SECURITY_ACTION_DEMANDCHOICE); } @@ -3000,7 +3000,7 @@ mono_declsec_get_linkdemands (MonoMethod *method, MonoDeclSecurityActions* klass if (method->flags & METHOD_ATTRIBUTE_HAS_SECURITY) { mono_class_init_internal (method->klass); - result = mono_declsec_get_method_demands_params (method, cmethod, + result = mono_declsec_get_method_demands_params (method, cmethod, SECURITY_ACTION_LINKDEMAND, SECURITY_ACTION_NONCASLINKDEMAND, SECURITY_ACTION_LINKDEMANDCHOICE); } @@ -3009,7 +3009,7 @@ mono_declsec_get_linkdemands (MonoMethod *method, MonoDeclSecurityActions* klass if (flags & (MONO_DECLSEC_FLAG_LINKDEMAND | MONO_DECLSEC_FLAG_NONCAS_LINKDEMAND | MONO_DECLSEC_FLAG_LINKDEMAND_CHOICE)) { mono_class_init_internal (method->klass); - result |= mono_declsec_get_class_demands_params (method->klass, klass, + result |= mono_declsec_get_class_demands_params (method->klass, klass, SECURITY_ACTION_LINKDEMAND, SECURITY_ACTION_NONCASLINKDEMAND, SECURITY_ACTION_LINKDEMANDCHOICE); } @@ -3040,7 +3040,7 @@ mono_declsec_get_inheritdemands_class (MonoClass *klass, MonoDeclSecurityActions mono_class_init_internal (klass); memset (demands, 0, sizeof (MonoDeclSecurityActions)); - result |= mono_declsec_get_class_demands_params (klass, demands, + result |= mono_declsec_get_class_demands_params (klass, demands, SECURITY_ACTION_INHERITDEMAND, SECURITY_ACTION_NONCASINHERITANCE, SECURITY_ACTION_INHERITDEMANDCHOICE); } @@ -3070,7 +3070,7 @@ mono_declsec_get_inheritdemands_method (MonoMethod *method, MonoDeclSecurityActi mono_class_init_internal (method->klass); memset (demands, 0, sizeof (MonoDeclSecurityActions)); - return mono_declsec_get_method_demands_params (method, demands, + return mono_declsec_get_method_demands_params (method, demands, SECURITY_ACTION_INHERITDEMAND, SECURITY_ACTION_NONCASINHERITANCE, SECURITY_ACTION_INHERITDEMANDCHOICE); } return FALSE; @@ -3164,7 +3164,7 @@ mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass, Mono g_assert (method); } - /* + /* * The result of mono_type_get_object_checked () might be a System.MonoType but we * need a TypeBuilder so use mono_class_get_ref_info (klass). */ diff --git a/src/mono/mono/metadata/reflection.h b/src/mono/mono/metadata/reflection.h index 83bcfccd657bf..bab5586a8d7f5 100644 --- a/src/mono/mono/metadata/reflection.h +++ b/src/mono/mono/metadata/reflection.h @@ -27,7 +27,7 @@ typedef struct { #define MONO_SIZEOF_CUSTOM_ATTR_INFO (offsetof (MonoCustomAttrInfo, attrs)) -/* +/* * Information which isn't in the MonoMethod structure is stored here for * dynamic methods. */ diff --git a/src/mono/mono/metadata/row-indexes.h b/src/mono/mono/metadata/row-indexes.h index b0f5dc072d681..64534db11373e 100644 --- a/src/mono/mono/metadata/row-indexes.h +++ b/src/mono/mono/metadata/row-indexes.h @@ -306,7 +306,7 @@ enum { MONO_GENERICPARAM_FLAGS, MONO_GENERICPARAM_OWNER, MONO_GENERICPARAM_NAME, - + MONO_GENERICPARAM_SIZE }; diff --git a/src/mono/mono/metadata/runtime.c b/src/mono/mono/metadata/runtime.c index a71933874505e..81e74c4be8d66 100644 --- a/src/mono/mono/metadata/runtime.c +++ b/src/mono/mono/metadata/runtime.c @@ -66,7 +66,7 @@ mono_runtime_fire_process_exit_event (void) MONO_STATIC_POINTER_INIT_END (MonoMethod, procexit_method) g_assert (procexit_method); - + mono_runtime_try_invoke (procexit_method, NULL, NULL, &exc, error); #endif } diff --git a/src/mono/mono/metadata/seq-points-data.c b/src/mono/mono/metadata/seq-points-data.c index 308435993793c..fa80737f1e2b3 100644 --- a/src/mono/mono/metadata/seq-points-data.c +++ b/src/mono/mono/metadata/seq-points-data.c @@ -405,7 +405,7 @@ mono_seq_point_data_read (SeqPointData *data, char *path) fclose (f); return FALSE; } - + fseek(f, 0, SEEK_SET); buffer_orig = buffer = (guint8 *)g_malloc (fsize + 1); diff --git a/src/mono/mono/metadata/seq-points-data.h b/src/mono/mono/metadata/seq-points-data.h index 4b9c1d0d479f8..575e0f815fdc9 100644 --- a/src/mono/mono/metadata/seq-points-data.h +++ b/src/mono/mono/metadata/seq-points-data.h @@ -3,7 +3,7 @@ * Copyright 2015 Xamarin Inc * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ - + #ifndef __MONO_SEQ_POINTS_DATA_H__ #define __MONO_SEQ_POINTS_DATA_H__ @@ -21,7 +21,7 @@ #define SEQ_POINT_AOT_EXT ".msym" /* Native offset used to mark seq points in dead code */ -#define SEQ_POINT_NATIVE_OFFSET_DEAD_CODE -1 +#define SEQ_POINT_NATIVE_OFFSET_DEAD_CODE -1 typedef struct { int il_offset, native_offset, flags; diff --git a/src/mono/mono/metadata/sgen-bridge.h b/src/mono/mono/metadata/sgen-bridge.h index 3f11c11bcb09f..0b91359064d97 100644 --- a/src/mono/mono/metadata/sgen-bridge.h +++ b/src/mono/mono/metadata/sgen-bridge.h @@ -1,7 +1,7 @@ /** * \file * Copyright 2011 Novell, Inc. - * + * * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ @@ -57,7 +57,7 @@ MONO_BEGIN_DECLS enum { SGEN_BRIDGE_VERSION = 5 }; - + typedef enum { /* Instances of this class should be scanned when computing the transitive dependency among bridges. E.g. List*/ GC_BRIDGE_TRANSPARENT_CLASS, diff --git a/src/mono/mono/metadata/sgen-client-mono.h b/src/mono/mono/metadata/sgen-client-mono.h index f69e05904f6df..bb54b33d0a248 100644 --- a/src/mono/mono/metadata/sgen-client-mono.h +++ b/src/mono/mono/metadata/sgen-client-mono.h @@ -697,7 +697,7 @@ sgen_client_binary_protocol_ephemeron_ref (gpointer list, gpointer key, gpointer /* Enter must be visible before anything is done in the critical region. */ #define ENTER_CRITICAL_REGION do { mono_atomic_store_acquire (&IN_CRITICAL_REGION, 1); } while (0) -/* Exit must make sure all critical regions stores are visible before it signal the end of the region. +/* Exit must make sure all critical regions stores are visible before it signal the end of the region. * We don't need to emit a full barrier since we */ #define EXIT_CRITICAL_REGION do { mono_atomic_store_release (&IN_CRITICAL_REGION, 0); } while (0) diff --git a/src/mono/mono/metadata/sgen-mono-ilgen.c b/src/mono/mono/metadata/sgen-mono-ilgen.c index aa5e034dbc6f9..734e2a4f9f5da 100644 --- a/src/mono/mono/metadata/sgen-mono-ilgen.c +++ b/src/mono/mono/metadata/sgen-mono-ilgen.c @@ -295,7 +295,7 @@ emit_managed_allocator_ilgen (MonoMethodBuilder *mb, gboolean slowpath, gboolean * * offsetof (MonoString, chars) + ((len + 1) * 2) <= INT32_MAX - (SGEN_ALLOC_ALIGN - 1) * len <= (SIZE_MAX - (SGEN_ALLOC_ALIGN - 1) - offsetof (MonoString, chars)) / 2 - 1 - * + * * On 64-bit platforms SIZE_MAX is so big that the 32-bit string length can * never reach the maximum size. */ @@ -372,7 +372,7 @@ emit_managed_allocator_ilgen (MonoMethodBuilder *mb, gboolean slowpath, gboolean mono_mb_emit_no_nullcheck (mb); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_stloc (mb, p_var); - + /* new_next = (char*)p + size; */ new_next_var = mono_mb_add_local (mb, int_type); mono_mb_emit_ldloc (mb, p_var); diff --git a/src/mono/mono/metadata/sgen-old-bridge.c b/src/mono/mono/metadata/sgen-old-bridge.c index b9ef527dd42fe..c3650a769343d 100644 --- a/src/mono/mono/metadata/sgen-old-bridge.c +++ b/src/mono/mono/metadata/sgen-old-bridge.c @@ -313,15 +313,15 @@ dyn_array_int_merge (DynIntArray *dst, DynIntArray *src) for (i = j = 0; i < dyn_array_int_size (dst) || j < dyn_array_int_size (src); ) { if (i < dyn_array_int_size (dst) && j < dyn_array_int_size (src)) { - int a = dyn_array_int_get (dst, i); - int b = dyn_array_int_get (src, j); + int a = dyn_array_int_get (dst, i); + int b = dyn_array_int_get (src, j); if (a < b) { dyn_array_int_add (&merge_array, a); ++i; } else if (a == b) { dyn_array_int_add (&merge_array, a); ++i; - ++j; + ++j; } else { dyn_array_int_add (&merge_array, b); ++j; diff --git a/src/mono/mono/metadata/sgen-tarjan-bridge.c b/src/mono/mono/metadata/sgen-tarjan-bridge.c index c5a7f876502d0..f956277b0efb2 100644 --- a/src/mono/mono/metadata/sgen-tarjan-bridge.c +++ b/src/mono/mono/metadata/sgen-tarjan-bridge.c @@ -978,7 +978,7 @@ step_timer (gint64 *timer) { gint64 curtime, diff; - SGEN_TV_GETTIME (curtime); + SGEN_TV_GETTIME (curtime); diff = SGEN_TV_ELAPSED (*timer, curtime); *timer = curtime; return diff; diff --git a/src/mono/mono/metadata/sgen-toggleref.h b/src/mono/mono/metadata/sgen-toggleref.h index a2d5ce2aa7902..77b622bed79a8 100644 --- a/src/mono/mono/metadata/sgen-toggleref.h +++ b/src/mono/mono/metadata/sgen-toggleref.h @@ -6,7 +6,7 @@ * * Author: * Rodrigo Kumpera (kumpera@gmail.com) - * + * * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ diff --git a/src/mono/mono/metadata/sre-encode.c b/src/mono/mono/metadata/sre-encode.c index 450b6f37d72d3..4bcbbf7683c4b 100644 --- a/src/mono/mono/metadata/sre-encode.c +++ b/src/mono/mono/metadata/sre-encode.c @@ -2,8 +2,8 @@ * \file * Routines for encoding SRE builders into a * MonoDynamicImage and generating tokens. - * - * + * + * * Author: * Paolo Molaro (lupus@ximian.com) * @@ -161,7 +161,7 @@ encode_type (MonoDynamicImage *assembly, MonoType *type, SigBuffer *buf) g_assert_not_reached (); return; } - + if (m_type_is_byref (type)) sigbuffer_add_value (buf, MONO_TYPE_BYREF); @@ -343,13 +343,13 @@ mono_dynimage_encode_constant (MonoDynamicImage *assembly, MonoObject *val, Mono break; case MONO_TYPE_VALUETYPE: { MonoClass *klass = val->vtable->klass; - + if (m_class_is_enumtype (klass)) { *ret_type = mono_class_enum_basetype_internal (klass)->type; goto handle_enum; } else if (mono_is_corlib_image (m_class_get_image (klass)) && strcmp (m_class_get_name_space (klass), "System") == 0 && strcmp (m_class_get_name (klass), "DateTime") == 0) { len = 8; - } else + } else g_error ("we can't encode valuetypes, we should have never reached this line"); break; } @@ -438,7 +438,7 @@ mono_dynimage_encode_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType * /* * If it's in the same module and not a generic type parameter: */ - if ((m_class_get_image (klass) == &assembly->image) && (type->type != MONO_TYPE_VAR) && + if ((m_class_get_image (klass) == &assembly->image) && (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR)) { token = MONO_TYPEDEFORREF_TYPEDEF | (MONO_HANDLE_GETVAL (tb, table_idx) << MONO_TYPEDEFORREF_BITS); /* This function is called multiple times from sre and sre-save, so same object is okay */ diff --git a/src/mono/mono/metadata/sre-internals.h b/src/mono/mono/metadata/sre-internals.h index b602748833cf6..356e0c43fb764 100644 --- a/src/mono/mono/metadata/sre-internals.h +++ b/src/mono/mono/metadata/sre-internals.h @@ -100,7 +100,7 @@ mono_reflection_methodbuilder_from_method_builder (ReflectionMethodBuilder *rmb, gboolean mono_reflection_methodbuilder_from_ctor_builder (ReflectionMethodBuilder *rmb, MonoReflectionCtorBuilder *mb, MonoError *error); - + guint32 mono_reflection_resolution_scope_from_image (MonoDynamicImage *assembly, MonoImage *image); diff --git a/src/mono/mono/metadata/sre.c b/src/mono/mono/metadata/sre.c index 912c4a9e94578..5a9e16eb81b8f 100644 --- a/src/mono/mono/metadata/sre.c +++ b/src/mono/mono/metadata/sre.c @@ -2,8 +2,8 @@ * \file * Routines for creating an image at runtime * and related System.Reflection.Emit icalls - * - * + * + * * Author: * Paolo Molaro (lupus@ximian.com) * @@ -139,7 +139,7 @@ type_get_qualified_name (MonoType *type, MonoAssembly *ass) MonoAssembly *ta; klass = mono_class_from_mono_type_internal (type); - if (!klass) + if (!klass) return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_REFLECTION); ta = klass->image->assembly; if (assembly_is_dynamic (ta) || (ta == ass)) { @@ -381,7 +381,7 @@ method_encode_clauses (MonoImage *image, MonoDynamicImage *assembly, MonoReflect #ifndef DISABLE_REFLECTION_EMIT /* - * LOCKING: Acquires the loader lock. + * LOCKING: Acquires the loader lock. */ static void mono_save_custom_attrs (MonoImage *image, void *obj, MonoArray *cattrs) @@ -440,7 +440,7 @@ mono_reflection_resolution_scope_from_image (MonoDynamicImage *assembly, MonoIma return token; } - + if (assembly_is_dynamic (image->assembly)) /* FIXME: */ memset (cols, 0, sizeof (cols)); @@ -624,7 +624,7 @@ reflection_methodbuilder_from_dynamic_method (ReflectionMethodBuilder *rmb, Mono rmb->mhandle = mb->mhandle; rmb->nrefs = 0; rmb->refs = NULL; -} +} #else /* DISABLE_REFLECTION_EMIT */ gboolean mono_reflection_methodbuilder_from_method_builder (ReflectionMethodBuilder *rmb, MonoReflectionMethodBuilder *mb, MonoError *error) { @@ -678,14 +678,14 @@ mono_image_get_methodref_token (MonoDynamicImage *assembly, MonoMethod *method, guint32 token; MonoMethodSignature *sig; - + create_typespec = create_typespec && method->is_generic && method->klass->image != &assembly->image; if (create_typespec) { token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, GUINT_TO_POINTER (GPOINTER_TO_UINT (method) + 1))); if (token) return token; - } + } token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, method)); if (token && !create_typespec) @@ -723,7 +723,7 @@ mono_image_get_varargs_method_token (MonoDynamicImage *assembly, guint32 origina { MonoDynamicTable *table; guint32 token; - + table = &assembly->tables [MONO_TABLE_MEMBERREF]; token = MONO_TOKEN_MEMBER_REF | table->next_idx; table->next_idx ++; @@ -801,7 +801,7 @@ mono_image_get_methodspec_token (MonoDynamicImage *assembly, MonoMethod *method) { MonoMethodInflated *imethod; guint32 token; - + token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, method)); if (token) return token; @@ -825,7 +825,7 @@ mono_image_get_inflated_method_token (MonoDynamicImage *assembly, MonoMethod *m) return mono_image_get_memberref_token (assembly, m_class_get_byval_arg (m->klass)); } -static guint32 +static guint32 mono_image_get_sighelper_token (MonoDynamicImage *assembly, MonoReflectionSigHelperHandle helper, MonoError *error) { guint32 idx; @@ -911,7 +911,7 @@ mono_image_get_array_token (MonoDynamicImage *assembly, MonoReflectionArrayMetho am = NULL; for (GList *tmp = assembly->array_methods; tmp; tmp = tmp->next) { am = (ArrayMethod *)tmp->data; - if (strcmp (name, am->name) == 0 && + if (strcmp (name, am->name) == 0 && mono_metadata_type_equal (am->parent, mtype) && mono_metadata_signature_equal (am->sig, sig)) { g_free (name); @@ -1040,15 +1040,15 @@ mono_image_create_method_token (MonoDynamicImage *assembly, MonoObjectHandle obj * mono_image_create_token: * @assembly: a dynamic assembly * @obj: - * @register_token: Whenever to register the token in the assembly->tokens hash. + * @register_token: Whenever to register the token in the assembly->tokens hash. * * Get a token to insert in the IL code stream for the given MemberInfo. - * The metadata emission routines need to pass FALSE as REGISTER_TOKEN, since by that time, - * the table_idx-es were recomputed, so registering the token would overwrite an existing + * The metadata emission routines need to pass FALSE as REGISTER_TOKEN, since by that time, + * the table_idx-es were recomputed, so registering the token would overwrite an existing * entry. */ guint32 -mono_image_create_token (MonoDynamicImage *assembly, MonoObjectHandle obj, +mono_image_create_token (MonoDynamicImage *assembly, MonoObjectHandle obj, gboolean create_open_instance, gboolean register_token, MonoError *error) { @@ -1215,14 +1215,14 @@ mono_reflection_dynimage_basic_init (MonoReflectionAssemblyBuilder *assemblyb, M MonoDynamicAssembly *assembly; MonoDynamicImage *image; MonoAssemblyLoadContext *alc = mono_alc_get_default (); - + if (assemblyb->dynamic_assembly) return; assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1); MONO_PROFILER_RAISE (assembly_loading, (&assembly->assembly)); - + assembly->assembly.ref_count = 1; assembly->assembly.dynamic = TRUE; assemblyb->assembly.assembly = (MonoAssembly*)assembly; @@ -1271,9 +1271,9 @@ mono_reflection_dynimage_basic_init (MonoReflectionAssemblyBuilder *assemblyb, M mono_alc_add_assembly (alc, (MonoAssembly*)assembly); register_assembly (&assemblyb->assembly, &assembly->assembly); - + MONO_PROFILER_RAISE (assembly_loaded, (&assembly->assembly)); - + mono_assembly_invoke_load_hook_internal (alc, (MonoAssembly*)assembly); } @@ -1287,7 +1287,7 @@ image_module_basic_init (MonoReflectionModuleBuilderHandle moduleb, MonoError *e if (!image) { /* * FIXME: we already created an image in mono_reflection_dynimage_basic_init (), but - * we don't know which module it belongs to, since that is only + * we don't know which module it belongs to, since that is only * determined at assembly save time. */ /*image = (MonoDynamicImage*)ab->dynamic_assembly->assembly.image; */ @@ -1993,7 +1993,7 @@ encode_cattr_value (MonoAssembly *assembly, char *buffer, char *p, char **retbuf { const char *argval = (const char*)void_argval; MonoTypeEnum simple_type; - + error_init (error); if ((p-buffer) + 10 >= *buflen) { char *newbuf; @@ -2163,7 +2163,7 @@ MONO_DISABLE_WARNING(4309) // truncation of constant MONO_RESTORE_WARNING break; } - + klass = mono_object_class (arg); if (mono_object_isinst_checked (arg, mono_defaults.systemtype_class, error)) { @@ -2537,7 +2537,7 @@ reflection_setup_internal_class_internal (MonoReflectionTypeBuilderHandle ref_tb guint32 table_idx; table_idx = MONO_HANDLE_GETVAL (ref_tb, table_idx); /* - * The size calculation here warrants some explaining. + * The size calculation here warrants some explaining. * reflection_setup_internal_class is called too early, well before we know whether the type will be a GTD or DEF, * meaning we need to alloc enough space to morth a def into a gtd. */ @@ -2554,7 +2554,7 @@ reflection_setup_internal_class_internal (MonoReflectionTypeBuilderHandle ref_tb goto_if_nok (error, leave); klass->type_token = MONO_TOKEN_TYPE_DEF | table_idx; mono_class_set_flags (klass, MONO_HANDLE_GETVAL (ref_tb, attrs)); - + MONO_PROFILER_RAISE (class_loading, (klass)); klass->element_class = klass; @@ -2649,7 +2649,7 @@ reflection_setup_internal_class_internal (MonoReflectionTypeBuilderHandle ref_tb /*g_print ("setup %s as %s (%p)\n", klass->name, ((MonoObject*)tb)->vtable->klass->name, tb);*/ MONO_PROFILER_RAISE (class_loaded, (klass)); - + leave: mono_loader_unlock (); HANDLE_FUNCTION_RETURN_VAL (is_ok (error)); @@ -2790,7 +2790,7 @@ mono_reflection_marshal_as_attribute_from_marshal_spec (MonoClass *klass, MonoMarshalSpec *spec, MonoError *error) { error_init (error); - + MonoAssemblyLoadContext *alc = mono_alc_get_ambient (); MonoReflectionMarshalAsAttributeHandle minfo = MONO_HANDLE_CAST (MonoReflectionMarshalAsAttribute, mono_object_new_handle (mono_class_get_marshal_as_attribute_class (), error)); goto_if_nok (error, fail); @@ -2909,7 +2909,7 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass, mono_error_assert_ok (error); method_aux->dll = string_to_utf8_image_raw (image, rmb->dll, error); mono_error_assert_ok (error); - + ((MonoMethodPInvoke*)m)->piflags = (rmb->native_cc << 8) | (rmb->charset ? (rmb->charset - 1) * 2 : 0) | rmb->extra_flags; if (image_is_dynamic (klass->image)) @@ -2938,7 +2938,7 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass, code = mono_array_addr_internal (rmb->code, guint8, 0); code_size = mono_array_length_internal (rmb->code); /* we probably need to run a verifier on the code... */ - max_stack = 8; + max_stack = 8; } else { code = NULL; @@ -2956,7 +2956,7 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass, header->num_locals = num_locals; for (i = 0; i < num_locals; ++i) { - MonoReflectionLocalBuilder *lb = + MonoReflectionLocalBuilder *lb = mono_array_get_internal (rmb->ilgen->locals, MonoReflectionLocalBuilder*, i); header->locals [i] = image_g_new0 (image, MonoType, 1); @@ -3095,14 +3095,14 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass, } /* Parameter marshalling */ - if (rmb->pinfo) + if (rmb->pinfo) for (i = 0; i < mono_array_length_internal (rmb->pinfo); ++i) { MonoReflectionParamBuilder *pb; if ((pb = mono_array_get_internal (rmb->pinfo, MonoReflectionParamBuilder*, i))) { if (pb->marshal_info) { if (specs == NULL) specs = image_g_new0 (image, MonoMarshalSpec*, sig->param_count + 1); - specs [pb->position] = + specs [pb->position] = mono_marshal_spec_from_builder (image, klass->image->assembly, pb->marshal_info, error); goto_if_nok (error, fail); } @@ -3126,7 +3126,7 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass, fail: m = NULL; goto leave; -} +} static MonoMethod* ctorbuilder_to_mono_method (MonoClass *klass, MonoReflectionCtorBuilder* mb, MonoError *error) @@ -3374,7 +3374,7 @@ ensure_runtime_vtable (MonoClass *klass, MonoError *error) return FALSE; klass->methods [j++] = meth; } - + if (tb->interfaces) { klass->interface_count = mono_array_length_internal (tb->interfaces); klass->interfaces = (MonoClass **)mono_image_alloc (klass->image, sizeof (MonoClass*) * klass->interface_count); @@ -3402,7 +3402,7 @@ ensure_runtime_vtable (MonoClass *klass, MonoError *error) if (!(im->flags & METHOD_ATTRIBUTE_STATIC)) im->slot = slot_num++; } - + klass->interfaces_packed = NULL; /*make setup_interface_offsets happy*/ mono_class_setup_interface_offsets (klass); mono_class_setup_interface_id (klass); @@ -3410,12 +3410,12 @@ ensure_runtime_vtable (MonoClass *klass, MonoError *error) /* * The generic vtable is needed even if image->run is not set since some - * runtime code like ves_icall_Type_GetMethodsByName depends on + * runtime code like ves_icall_Type_GetMethodsByName depends on * method->slot being defined. */ - /* - * tb->methods could not be freed since it is used for determining + /* + * tb->methods could not be freed since it is used for determining * overrides during dynamic vtable construction. */ @@ -3470,7 +3470,7 @@ mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides onum = 0; if (tb->methods) { for (i = 0; i < tb->num_methods; ++i) { - MonoReflectionMethodBuilder *mb = + MonoReflectionMethodBuilder *mb = mono_array_get_internal (tb->methods, MonoReflectionMethodBuilder*, i); if (mb->override_methods) onum += mono_array_length_internal (mb->override_methods); @@ -3482,7 +3482,7 @@ mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides onum = 0; for (i = 0; i < tb->num_methods; ++i) { - MonoReflectionMethodBuilder *mb = + MonoReflectionMethodBuilder *mb = mono_array_get_internal (tb->methods, MonoReflectionMethodBuilder*, i); if (mb->override_methods) { for (j = 0; j < mono_array_length_internal (mb->override_methods); ++j) { @@ -3622,7 +3622,7 @@ typebuilder_setup_fields (MonoClass *klass, MonoError *error) packing_size = tb->packing_size; instance_size += tb->class_size; } - + klass->fields = image_g_new0 (image, MonoClassField, fcount); def_values = image_g_new0 (image, MonoFieldDefaultValue, fcount); mono_class_set_field_def_values (klass, def_values); @@ -3738,7 +3738,7 @@ typebuilder_setup_events (MonoClass *klass, MonoError *error) int j; events [i].other = image_g_new0 (image, MonoMethod*, mono_array_length_internal (eb->other_methods) + 1); for (j = 0; j < mono_array_length_internal (eb->other_methods); ++j) { - MonoReflectionMethodBuilder *mb = + MonoReflectionMethodBuilder *mb = mono_array_get_internal (eb->other_methods, MonoReflectionMethodBuilder*, j); events [i].other [j] = mb->mhandle; @@ -3910,9 +3910,9 @@ ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilderHandle ref_ } } - /* + /* * If we are a generic TypeBuilder, there might be instantiations in the type cache - * which have type System.Reflection.MonoGenericClass, but after the type is created, + * which have type System.Reflection.MonoGenericClass, but after the type is created, * we want to return normal System.MonoType objects, so clear these out from the cache. * * Together with this we must ensure the contents of all instances to match the created type. @@ -3957,7 +3957,7 @@ typedef struct { /* * The runtime automatically clean up those after finalization. -*/ +*/ static MonoReferenceQueue *dynamic_method_queue; static void @@ -4013,7 +4013,7 @@ reflection_create_dynamic_method (MonoReflectionDynamicMethodHandle ref_mb, Mono /* * Resolve references. */ - /* + /* * Every second entry in the refs array is reserved for storing handle_class, * which is needed by the ldtoken implementation in the JIT. */ @@ -4030,7 +4030,7 @@ reflection_create_dynamic_method (MonoReflectionDynamicMethodHandle ref_mb, Mono /* * The referenced DynamicMethod should already be created by the managed * code, except in the case of circular references. In that case, we store - * method in the refs array, and fix it up later when the referenced + * method in the refs array, and fix it up later when the referenced * DynamicMethod is created. */ if (method->mhandle) { @@ -4060,7 +4060,7 @@ reflection_create_dynamic_method (MonoReflectionDynamicMethodHandle ref_mb, Mono rmb.refs [i] = ref; rmb.refs [i + 1] = handle_class; - } + } if (mb->owner) { MonoType *owner_type = mono_reflection_type_get_handle ((MonoReflectionType*)mb->owner, error); @@ -4090,7 +4090,7 @@ reflection_create_dynamic_method (MonoReflectionDynamicMethodHandle ref_mb, Mono MonoReflectionDynamicMethod *method = (MonoReflectionDynamicMethod*)l->data; MonoMethodWrapper *wrapper = (MonoMethodWrapper*)method->mhandle; gpointer *data; - + g_assert (method->mhandle); data = (gpointer*)wrapper->method_data; diff --git a/src/mono/mono/metadata/tabledefs.h b/src/mono/mono/metadata/tabledefs.h index 6cfc4c8ffe756..52521435fc3b5 100644 --- a/src/mono/mono/metadata/tabledefs.h +++ b/src/mono/mono/metadata/tabledefs.h @@ -10,12 +10,12 @@ * * From the ECMA documentation */ - + #ifndef _MONO_METADATA_TABLEDEFS_H_ #define _MONO_METADATA_TABLEDEFS_H_ /* - * 22.1.1 Values for AssemblyHashAlgorithm + * 22.1.1 Values for AssemblyHashAlgorithm */ enum { @@ -42,7 +42,7 @@ enum { FILE_CONTAINS_NO_METADATA = 1 }; -/* keep in synch with System.Security.Permissions.SecurityAction enum +/* keep in synch with System.Security.Permissions.SecurityAction enum (except for the special non-CAS cases) */ enum { SECURITY_ACTION_DEMAND = 2, diff --git a/src/mono/mono/metadata/tokentype.h b/src/mono/mono/metadata/tokentype.h index a1c58944d7404..c7ae1178aff74 100644 --- a/src/mono/mono/metadata/tokentype.h +++ b/src/mono/mono/metadata/tokentype.h @@ -9,13 +9,13 @@ * These tokens match the table ID except for the last * three (string, name and base type which are special) */ - + typedef enum { MONO_TOKEN_MODULE = 0x00000000, MONO_TOKEN_TYPE_REF = 0x01000000, MONO_TOKEN_TYPE_DEF = 0x02000000, MONO_TOKEN_FIELD_DEF = 0x04000000, - MONO_TOKEN_METHOD_DEF = 0x06000000, + MONO_TOKEN_METHOD_DEF = 0x06000000, MONO_TOKEN_PARAM_DEF = 0x08000000, MONO_TOKEN_INTERFACE_IMPL = 0x09000000, MONO_TOKEN_MEMBER_REF = 0x0a000000, diff --git a/src/mono/mono/metadata/verify.h b/src/mono/mono/metadata/verify.h index 9ec9f2e07d2ac..6efb0fd3373b1 100644 --- a/src/mono/mono/metadata/verify.h +++ b/src/mono/mono/metadata/verify.h @@ -23,7 +23,7 @@ typedef enum { MONO_VERIFY_NOT_VERIFIABLE = 8, /*OR it with other flags*/ - + /* Abort the verification if the code is not verifiable. * The standard behavior is to abort if the code is not valid. * */ diff --git a/src/mono/mono/metadata/w32file-unix.c b/src/mono/mono/metadata/w32file-unix.c index 50da28bf8468b..ee1e2fe89d557 100644 --- a/src/mono/mono/metadata/w32file-unix.c +++ b/src/mono/mono/metadata/w32file-unix.c @@ -298,7 +298,7 @@ static void _wapi_set_last_path_error_from_errno (const gchar *dir, } else { dirname = g_strdup (dir); } - + if (_wapi_access (dirname, F_OK) == 0) { mono_w32error_set_last (ERROR_FILE_NOT_FOUND); } else { @@ -316,18 +316,18 @@ file_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 * { gint ret; MonoThreadInfo *info = mono_thread_info_current (); - + if(byteswritten!=NULL) { *byteswritten=0; } - + if(!(filehandle->fileaccess & GENERIC_WRITE) && !(filehandle->fileaccess & GENERIC_ALL)) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); } - + do { MONO_ENTER_GC_SAFE; ret = write (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); @@ -340,7 +340,7 @@ file_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 * ret = 0; } else { _wapi_set_last_error_from_errno (); - + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); return(FALSE); @@ -357,18 +357,18 @@ console_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint3 { gint ret; MonoThreadInfo *info = mono_thread_info_current (); - + if(byteswritten!=NULL) { *byteswritten=0; } - + if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); } - + do { MONO_ENTER_GC_SAFE; ret = write(((MonoFDHandle*) filehandle)->fd, buffer, numbytes); @@ -381,7 +381,7 @@ console_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint3 ret = 0; } else { _wapi_set_last_error_from_errno (); - + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); return(FALSE); @@ -390,7 +390,7 @@ console_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint3 if(byteswritten!=NULL) { *byteswritten=ret; } - + return(TRUE); } @@ -399,18 +399,18 @@ pipe_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 * { gint ret; MonoThreadInfo *info = mono_thread_info_current (); - + if(byteswritten!=NULL) { *byteswritten=0; } - + if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); } - + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: writing up to %" G_GUINT32_FORMAT " bytes to pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); do { @@ -425,7 +425,7 @@ pipe_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 * ret = 0; } else { _wapi_set_last_error_from_errno (); - + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); return(FALSE); @@ -434,14 +434,14 @@ pipe_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 * if(byteswritten!=NULL) { *byteswritten=ret; } - + return(TRUE); } static gint convert_flags(guint32 fileaccess, guint32 createmode) { gint flags=0; - + switch(fileaccess) { case GENERIC_READ: flags=O_RDONLY; @@ -478,7 +478,7 @@ static gint convert_flags(guint32 fileaccess, guint32 createmode) createmode); break; } - + return(flags); } @@ -490,7 +490,7 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, guint32 file_existing_share, file_existing_access; file_already_shared = file_share_get (statbuf->st_dev, statbuf->st_ino, sharemode, fileaccess, &file_existing_share, &file_existing_access, share_info); - + if (file_already_shared) { /* The reference to this share info was incremented * when we looked it up, so be careful to put it back @@ -502,7 +502,7 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, file_share_release (*share_info); *share_info = NULL; - + return(FALSE); } @@ -515,7 +515,7 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, file_share_release (*share_info); *share_info = NULL; - + return(FALSE); } } else { @@ -560,12 +560,12 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode if (attrs & FILE_ATTRIBUTE_TEMPORARY) perms = 0600; - + if (attrs & FILE_ATTRIBUTE_ENCRYPTED){ mono_w32error_set_last (ERROR_ENCRYPTION_FAILED); return INVALID_HANDLE_VALUE; } - + if (name == NULL) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); @@ -581,12 +581,12 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode mono_w32error_set_last (ERROR_INVALID_NAME); return(INVALID_HANDLE_VALUE); } - + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Opening %s with share 0x%" PRIx32 " and access 0x%" PRIx32, __func__, filename, sharemode, fileaccess); - + fd = _wapi_open (filename, flags, perms); - + /* If we were trying to open a directory with write permissions * (e.g. O_WRONLY or O_RDWR), this call will fail with * EISDIR. However, this is a bit bogus because calls to @@ -600,7 +600,7 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode /* Try again but don't try to make it writable */ fd = _wapi_open (filename, flags & ~(O_RDWR|O_WRONLY), perms); } - + if (fd == -1) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Error opening file %s: %s", __func__, filename, g_strerror(errno)); _wapi_set_last_path_error_from_errno (NULL, filename); @@ -647,7 +647,7 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode MONO_ENTER_GC_SAFE; close (((MonoFDHandle*) filehandle)->fd); MONO_EXIT_GC_SAFE; - + mono_fdhandle_unref ((MonoFDHandle*) filehandle); return (INVALID_HANDLE_VALUE); } @@ -659,7 +659,7 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode MONO_ENTER_GC_SAFE; close (((MonoFDHandle*) filehandle)->fd); MONO_EXIT_GC_SAFE; - + mono_fdhandle_unref ((MonoFDHandle*) filehandle); return(INVALID_HANDLE_VALUE); } diff --git a/src/mono/mono/metadata/w32handle.h b/src/mono/mono/metadata/w32handle.h index 6ec82b812e077..3ab448759ec0d 100644 --- a/src/mono/mono/metadata/w32handle.h +++ b/src/mono/mono/metadata/w32handle.h @@ -47,7 +47,7 @@ typedef enum { MONO_W32HANDLE_WAIT_RET_NOT_OWNED_BY_CALLER = -5 } MonoW32HandleWaitRet; -typedef struct +typedef struct { void (*close)(gpointer data); diff --git a/src/mono/mono/mini/abcremoval.c b/src/mono/mono/mini/abcremoval.c index ec87d201c06ee..6568a7003c540 100644 --- a/src/mono/mono/mini/abcremoval.c +++ b/src/mono/mono/mini/abcremoval.c @@ -148,7 +148,7 @@ print_evaluation_context_status (MonoRelationsEvaluationStatus status) { printf ("EVALUATION_NOT_STARTED"); } else { gboolean print_or = FALSE; - + printf ("("); if (status & MONO_RELATIONS_EVALUATION_IN_PROGRESS) { if (print_or) printf ("|"); @@ -257,7 +257,7 @@ get_relation_from_ins (MonoVariableRelationsEvaluationArea *area, MonoInst *ins, { MonoIntegerValueKind value_kind; MonoSummarizedValue *value = &result->related_value; - + if (ins->type == STACK_I8) { value_kind = MONO_INTEGER_VALUE_SIZE_8; } else if (ins->type == STACK_I4) { @@ -401,7 +401,7 @@ get_relation_from_ins (MonoVariableRelationsEvaluationArea *area, MonoInst *ins, * 462 i8const * 472 call */ - + break; } return value_kind; @@ -462,10 +462,10 @@ get_relations_from_previous_bb (MonoVariableRelationsEvaluationArea *area, MonoB relations->relation1.variable = -1; INITIALIZE_VALUE_RELATION (&(relations->relation2.relation)); relations->relation2.relation.relation_is_static_definition = FALSE; - relations->relation2.relation.next = NULL; + relations->relation2.relation.next = NULL; relations->relation2.insertion_point = NULL; relations->relation2.variable = -1; - + if (bb->in_count == 1) { /* Should write the code to "sum" conditions... */ in_bb = bb->in_bb [0]; @@ -527,7 +527,7 @@ static void apply_change_to_evaluation_area (MonoVariableRelationsEvaluationArea *area, MonoAdditionalVariableRelation *change) { MonoSummarizedValueRelation *base_relation; - + if (change->relation.relation != MONO_ANY_RELATION) { base_relation = &(area->relations [change->variable]); while ((base_relation->next != NULL) && (base_relation->next->relation_is_static_definition)) { @@ -698,24 +698,24 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are { MonoRelationsEvaluationContext * const context = &(area->contexts [variable]); MonoRelationsEvaluationStatus * const status = &(area->statuses [variable]); - + // First of all, we check the evaluation status // (what must be done is *very* different in each case) switch (*status) { case MONO_RELATIONS_EVALUATION_NOT_STARTED: { MonoSummarizedValueRelation *relation = &(area->relations [variable]); - + if (TRACE_ABC_REMOVAL) { printf ("Evaluating variable %d (target variable %d); ", variable, target_variable); print_summarized_value_relation (relation); printf ("\n"); } - + // We properly inizialize the context *status = MONO_RELATIONS_EVALUATION_IN_PROGRESS; context->father = father_context; MONO_MAKE_RELATIONS_EVALUATION_RANGES_WEAK (context->ranges); - + // If we have found the target variable, we can set the range // related to it in the context to "equal" (which is [0,0]) if (variable == target_variable) { @@ -725,18 +725,18 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are context->ranges.variable.lower = 0; context->ranges.variable.upper = 0; } - + // Examine all relations for this variable (scan the list) // The contribute of each relation will be intersected (logical and) while (relation != NULL) { context->current_relation = relation; - + if (TRACE_ABC_REMOVAL) { printf ("Processing (%d): ", variable); print_summarized_value_relation (relation); printf ("\n"); } - + // We decie what to do according the the type of the related value switch (relation->related_value.type) { case MONO_ANY_SUMMARIZED_VALUE: @@ -749,13 +749,13 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are case MONO_VARIABLE_SUMMARIZED_VALUE: // Generally, evaluate related variable and intersect ranges. // However, some check is necessary... - + // If the relation is "ANY", nothing to do (no added information) if (relation->relation != MONO_ANY_RELATION) { int related_variable = relation->related_value.value.variable.variable; MonoRelationsEvaluationContext *related_context = &(area->contexts [related_variable]); MonoRelationsEvaluationStatus related_status = area->statuses [related_variable]; - + // The second condition in the "or" avoids messing with "back edges" in the graph traversal // (they are simply ignored instead of triggering the handling of recursion) if ( (related_status == MONO_RELATIONS_EVALUATION_NOT_STARTED) || ! @@ -763,14 +763,14 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are (related_context->current_relation->related_value.value.variable.variable == variable))) { // Evaluate the related variable evaluate_relation_with_target_variable (area, related_variable, target_variable, context); - + // Check if we are part of a recursive loop if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) { if (TRACE_ABC_REMOVAL) { printf ("Recursivity detected for variable %d (target variable %d), status ", variable, target_variable); print_evaluation_context_status (*status); } - + // If we are, check if the evaluation of the related variable is complete if (related_status == MONO_RELATIONS_EVALUATION_COMPLETED) { // If it is complete, we are part of a recursive definition. @@ -811,13 +811,13 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are int phi; gboolean is_ascending = FALSE; gboolean is_descending = FALSE; - + MONO_MAKE_RELATIONS_EVALUATION_RANGES_IMPOSSIBLE (phi_ranges); phi_ranges.zero.nullness = relation->related_value.value.phi.number_of_alternatives > 0 ? MONO_VALUE_NOT_NULL : MONO_VALUE_MAYBE_NULL; for (phi = 0; phi < relation->related_value.value.phi.number_of_alternatives; phi++) { int phi_alternative = relation->related_value.value.phi.phi_alternatives [phi]; evaluate_relation_with_target_variable (area, phi_alternative, target_variable, context); - + // This means we are part of a recursive loop if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) { if (TRACE_ABC_REMOVAL) { @@ -836,7 +836,7 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are is_descending = TRUE; } phi_ranges.zero.nullness = MONO_VALUE_MAYBE_NULL; - + // Clear "recursivity" bits in the status (recursion has been handled) *status = MONO_RELATIONS_EVALUATION_IN_PROGRESS; } else { @@ -844,7 +844,7 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are union_nullness (&phi_ranges.zero, area->contexts [phi_alternative].ranges.zero.nullness); } } - + // Apply the effects of all recursive loops if (is_ascending) { phi_ranges.zero.upper = INT_MAX; @@ -854,7 +854,7 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are phi_ranges.zero.lower = INT_MIN; phi_ranges.variable.lower = INT_MIN; } - + // Intersect final result MONO_RELATIONS_EVALUATION_RANGES_INTERSECTION (context->ranges, phi_ranges); intersect_nullness (&context->ranges.zero, phi_ranges.zero.nullness, MONO_EQ_RELATION); @@ -863,11 +863,11 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are default: g_assert_not_reached(); } - + // Pass to next relation relation = relation->next; } - + // Check if any recursivity bits are still in the status, and in any case clear them if (*status & MONO_RELATIONS_EVALUATION_IS_RECURSIVE) { if (TRACE_ABC_REMOVAL) { @@ -897,21 +897,21 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are gboolean evaluation_can_be_recursive = TRUE; gboolean evaluation_is_definition = TRUE; int path_value = 0; - + if (TRACE_ABC_REMOVAL) { printf ("Evaluation of variable %d (target variable %d) already in progress\n", variable, target_variable); print_evaluation_context (context, *status); print_summarized_value_relation (context->current_relation); printf ("\n"); } - + // We must check if the loop can be a recursive definition (we scan the whole loop) while (current_context != last_context) { if (current_context == NULL) { printf ("Broken recursive ring in ABC removal\n"); g_assert_not_reached (); } - + if (current_context->current_relation->relation_is_static_definition) { if (current_context->current_relation->related_value.type == MONO_VARIABLE_SUMMARIZED_VALUE) { /* No need to check path_value for over/under-flow, since delta should be safe */ @@ -923,10 +923,10 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are evaluation_is_definition = FALSE; evaluation_can_be_recursive = FALSE; } - + current_context = current_context->father; } - + // If this is a recursive definition, we properly flag the status in all the involved contexts if (evaluation_is_definition) { MonoRelationsEvaluationStatus recursive_status; @@ -941,13 +941,13 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are } else { recursive_status = MONO_RELATIONS_EVALUATION_IS_RECURSIVELY_INDEFINITE; } - + if (TRACE_ABC_REMOVAL) { printf ("Recursivity accepted ("); print_evaluation_context_status (recursive_status); printf (")\n"); } - + current_context = father_context; while (current_context != last_context) { int index = current_context - area->contexts; @@ -974,7 +974,7 @@ evaluate_relation_with_target_variable (MonoVariableRelationsEvaluationArea *are } break; } - + } /* @@ -1032,9 +1032,9 @@ remove_abc_from_inst (MonoInst *ins, MonoVariableRelationsEvaluationArea *area) int index_variable = ins->sreg2; MonoRelationsEvaluationContext *array_context = &(area->contexts [array_variable]); MonoRelationsEvaluationContext *index_context = &(area->contexts [index_variable]); - + clean_contexts (area, area->cfg->next_vreg); - + evaluate_relation_with_target_variable (area, index_variable, array_variable, NULL); evaluate_relation_with_target_variable (area, array_variable, array_variable, NULL); @@ -1066,7 +1066,7 @@ eval_non_null (MonoVariableRelationsEvaluationArea *area, int reg) clean_contexts (area, area->cfg->next_vreg); evaluate_relation_with_target_variable (area, reg, reg, NULL); - + return context->ranges.zero.nullness == MONO_VALUE_NOT_NULL; } @@ -1107,7 +1107,7 @@ process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvalua MonoAdditionalVariableRelationsForBB additional_relations; GSList *dominated_bb, *l; GSList *check_relations = NULL; - + if (TRACE_ABC_REMOVAL) { printf ("\nABCREM BLOCK/2 %d [dfn %d]...\n", bb->block_num, bb->dfn); } @@ -1141,7 +1141,7 @@ process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvalua if (ins->opcode == OP_BOUNDS_CHECK) { /* Handle OP_LDELEMA2D, too */ array_var = ins->sreg1; index_var = ins->sreg2; - + remove_abc_from_inst (ins, area); /* We can derive additional relations from the bounds check */ @@ -1229,15 +1229,15 @@ process_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoVariableRelationsEvalua } */ } - } - + } + for (dominated_bb = bb->dominated; dominated_bb != NULL; dominated_bb = dominated_bb->next) { process_block (cfg, (MonoBasicBlock*) (dominated_bb->data), area); } for (l = check_relations; l; l = l->next) remove_change_from_evaluation_area ((MonoAdditionalVariableRelation *)l->data); - + remove_change_from_evaluation_area (&(additional_relations.relation1)); remove_change_from_evaluation_area (&(additional_relations.relation2)); } @@ -1295,7 +1295,7 @@ type_to_value_kind (MonoType *type) * - Allocate memory for the evaluation contexts in the evaluation area * - Recursively process all the BBs in the dominator tree (it is enough * to invoke the processing on the entry BB) - * + * * cfg: the method code */ void @@ -1304,7 +1304,7 @@ mono_perform_abc_removal (MonoCompile *cfg) MonoVariableRelationsEvaluationArea area; MonoBasicBlock *bb; int i; - + verbose_level = cfg->verbose_level; area.cfg = cfg; @@ -1338,7 +1338,7 @@ mono_perform_abc_removal (MonoCompile *cfg) for (ins = bb->code; ins; ins = ins->next) { const char *spec = INS_INFO (ins->opcode); gint32 idx, *reg; - + if (spec [MONO_INST_DEST] == ' ' || MONO_IS_STORE_MEMBASE (ins)) continue; @@ -1371,7 +1371,7 @@ mono_perform_abc_removal (MonoCompile *cfg) MONO_MAKE_RELATIONS_EVALUATION_RANGE_WEAK (range); apply_value_kind_to_range (&range, area.variable_value_kind [ins->dreg]); apply_value_kind_to_range (&range, effective_value_kind); - + if (range.upper < INT_MAX) { type_relation = (MonoSummarizedValueRelation *) mono_mempool_alloc (cfg->mempool, sizeof (MonoSummarizedValueRelation)); type_relation->relation = MONO_LE_RELATION; @@ -1414,17 +1414,17 @@ mono_perform_abc_removal (MonoCompile *cfg) if (area.relations [i].related_value.value.variable.nullness & MONO_VALUE_IS_VARIABLE) { symmetric_nullness = area.relations [i].related_value.value.variable.nullness; } - + area.relations [related_index].relation = MONO_EQ_RELATION; area.relations [related_index].relation_is_static_definition = TRUE; area.relations [related_index].related_value.type = MONO_VARIABLE_SUMMARIZED_VALUE; area.relations [related_index].related_value.value.variable.variable = i; area.relations [related_index].related_value.value.variable.delta = - area.relations [i].related_value.value.variable.delta; area.relations [related_index].related_value.value.variable.nullness = symmetric_nullness; - + area.relations [related_index].next = area.relations [related_variable].next; area.relations [related_variable].next = &(area.relations [related_index]); - + if (TRACE_ABC_REMOVAL) { printf ("Added symmetric summarized value for variable variable %d (to %d): ", i, related_variable); print_summarized_value (&(area.relations [related_index].related_value)); diff --git a/src/mono/mono/mini/abcremoval.h b/src/mono/mono/mini/abcremoval.h index 8bc91ad4d7053..585a9072fbca3 100644 --- a/src/mono/mono/mini/abcremoval.h +++ b/src/mono/mono/mini/abcremoval.h @@ -159,7 +159,7 @@ typedef struct MonoSummarizedValueRelation { * The bits are handled separately because the same evaluation context could * belong to more than one loop, so that each loop would set its bits. * After the backtracking, the bits are examined and a decision is taken. - * + * */ typedef enum { MONO_RELATIONS_EVALUATION_NOT_STARTED = 0, @@ -333,7 +333,7 @@ typedef struct MonoVariableRelationsEvaluationArea { * coming to dominate the running time of abcremoval. By * storing the statuses together, we can memset the entire * region. - */ + */ MonoRelationsEvaluationStatus *statuses; MonoRelationsEvaluationContext *contexts; diff --git a/src/mono/mono/mini/alias-analysis.c b/src/mono/mono/mini/alias-analysis.c index 522e62d850915..206c16274331d 100644 --- a/src/mono/mono/mini/alias-analysis.c +++ b/src/mono/mono/mini/alias-analysis.c @@ -53,8 +53,8 @@ lower_load (MonoCompile *cfg, MonoInst *load, MonoInst *ldaddr) } if (replaced_op != load->opcode) { - if (cfg->verbose_level > 2) - printf ("Incompatible load type: expected %s but got %s\n", + if (cfg->verbose_level > 2) + printf ("Incompatible load type: expected %s but got %s\n", mono_inst_name (replaced_op), mono_inst_name (load->opcode)); return FALSE; @@ -84,8 +84,8 @@ lower_store (MonoCompile *cfg, MonoInst *store, MonoInst *ldaddr) if (replaced_op != store->opcode) { - if (cfg->verbose_level > 2) - printf ("Incompatible store_reg type: expected %s but got %s\n", + if (cfg->verbose_level > 2) + printf ("Incompatible store_reg type: expected %s but got %s\n", mono_inst_name (replaced_op), mono_inst_name (store->opcode)); return FALSE; @@ -131,7 +131,7 @@ lower_store_imm (MonoCompile *cfg, MonoInst *store, MonoInst *ldaddr) #if TARGET_SIZEOF_VOID_P == 8 case OP_STORE_MEMBASE_IMM: -#endif +#endif case OP_STOREI8_MEMBASE_IMM: if (!is_long_stack_size (var->type)) { if (cfg->verbose_level > 2) printf ("Incompatible variable of size != 8\n"); diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index c4b0b821a25dc..cddb53c8649b4 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -184,12 +184,12 @@ static GHashTable *aot_modules; #define mono_aot_unlock() mono_os_mutex_unlock (&aot_mutex) static mono_mutex_t aot_mutex; -/* +/* * Maps assembly names to the mono_aot_module__info symbols in the * AOT modules registered by mono_aot_register_module (). */ static GHashTable *static_aot_modules; -/* +/* * Same as above, but tracks module that must be loaded before others are * This allows us to have a "container" module which contains resources for * other modules. Since it doesn't provide methods for a managed assembly, @@ -346,7 +346,7 @@ decode_value (guint8 *ptr, guint8 **rptr) { guint8 b = *ptr; gint32 len; - + if ((b & 0x80) == 0){ len = b; ++ptr; @@ -385,7 +385,7 @@ mono_aot_get_offset (guint32 *table, int index) guint8 *data_start, *p; guint32 *index32 = NULL; guint16 *index16 = NULL; - + /* noffsets = table [0]; */ group_size = table [1]; ngroups = table [2]; @@ -571,7 +571,7 @@ decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError if (is_not_anonymous) { gboolean is_method = decode_value (p, &p); - + if (is_method) { MonoMethod *method_def; g_assert (type == MONO_TYPE_MVAR); @@ -899,7 +899,7 @@ sig_matches_target (MonoAotModule *module, MonoMethod *target, guint8 *buf, guin MonoMethodSignature *sig; gboolean res; guint8 *p = buf; - + sig = decode_signature_with_target (module, mono_method_signature_internal (target), p, &p); res = sig && mono_metadata_signature_equal (mono_method_signature_internal (target), sig); g_free (sig); @@ -997,7 +997,7 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod ref->method = mono_marshal_get_stelemref (); } else if (subtype == WRAPPER_SUBTYPE_VIRTUAL_STELEMREF) { int kind; - + kind = decode_value (p, &p); ref->method = mono_marshal_get_virtual_stelemref_wrapper ((MonoStelemrefKind)kind); @@ -1311,8 +1311,8 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod MonoGenericContext ctx; guint32 token_index; - /* - * These methods do not have a token which resolves them, so we + /* + * These methods do not have a token which resolves them, so we * resolve them immediately. */ klass = decode_klass_ref (module, p, &p, error); @@ -1339,11 +1339,11 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod if (FALSE && mono_class_is_ginst (klass)) { ctx.class_inst = mono_class_get_generic_class (klass)->context.class_inst; ctx.method_inst = NULL; - + ref->method = mono_class_inflate_generic_method_full_checked (ref->method, klass, &ctx, error); if (!ref->method) return FALSE; - } + } memset (&ctx, 0, sizeof (ctx)); @@ -1449,7 +1449,7 @@ find_symbol (MonoDl *module, gpointer *globals, const char *name, gpointer *valu int global_index; guint16 *table, *entry; guint16 table_size; - guint32 hash; + guint32 hash; char *symbol = (char*)name; #ifdef TARGET_MACH @@ -1906,7 +1906,7 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer return; if (assembly->image->aot_module) - /* + /* * Already loaded. This can happen because the assembly loading code might invoke * the assembly load hooks multiple times for the same assembly. */ @@ -2112,7 +2112,7 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer aname->culture = g_strdup (table); table += strlen (table) + 1; memcpy (aname->public_key_token, table, strlen (table) + 1); - table += strlen (table) + 1; + table += strlen (table) + 1; table = (char *)ALIGN_PTR_TO (table, 8); aname->flags = *(guint32*)table; @@ -2310,7 +2310,7 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer * mono_aot_register_module: * * This should be called by embedding code to register normal AOT modules statically linked - * into the executable. + * into the executable. * * \param aot_info the value of the 'mono_aot_module__info' global symbol from the AOT module. */ @@ -2451,7 +2451,7 @@ decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guin *endbuf = buf; return TRUE; -} +} gpointer mono_aot_get_method_from_vt_slot (MonoVTable *vtable, int slot, MonoError *error) @@ -2524,7 +2524,7 @@ mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res) * using a cache stored in the AOT file. * Stores the resulting class in *KLASS if found, stores NULL otherwise. * - * Returns: TRUE if the klass was found/not found in the cache, FALSE if no aot file was + * Returns: TRUE if the klass was found/not found in the cache, FALSE if no aot file was * found. */ gboolean @@ -2624,7 +2624,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch } amodule_unlock (amodule); - + return TRUE; } @@ -2842,7 +2842,7 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoJitInfo *jinfo, /* Clear thumb flag */ code_start = (guint8*)(((gsize)code_start) & ~1); - fde = amodule->mono_eh_frame + table [(pos * 2) + 1]; + fde = amodule->mono_eh_frame + table [(pos * 2) + 1]; /* This won't overflow because there is +1 entry in the table */ fde_len = table [(pos * 2) + 2 + 1] - table [(pos * 2) + 1]; @@ -3272,7 +3272,7 @@ decode_exception_debug_info (MonoAotModule *amodule, int map_size = decode_value (p, &p); /* The GC map requires 4 bytes of alignment */ while ((guint64)(gsize)p % 4) - p ++; + p ++; jinfo->gc_info = p; p += map_size; } @@ -3282,7 +3282,7 @@ decode_exception_debug_info (MonoAotModule *amodule, if (!ji_to_amodule) ji_to_amodule = g_hash_table_new (NULL, NULL); g_hash_table_insert (ji_to_amodule, jinfo, amodule); - mono_aot_unlock (); + mono_aot_unlock (); } return jinfo; @@ -3644,7 +3644,7 @@ mono_aot_find_jit_info (MonoImage *image, gpointer addr) if ((guint8*)addr >= (guint8*)jinfo->code_start + jinfo->code_size) /* addr is in the padding between methods, see the adjustment of code_size in decode_exception_debug_info () */ return NULL; - + return jinfo; } @@ -3757,7 +3757,7 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin case MONO_PATCH_INFO_R4: case MONO_PATCH_INFO_R4_GOT: { guint32 val; - + ji->data.target = mono_mem_manager_alloc0 (mem_manager, sizeof (float)); val = decode_value (p, &p); *(float*)ji->data.target = *(float*)&val; @@ -3849,7 +3849,7 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin entry->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo)); entry->data->type = (MonoJumpInfoType)((val >> 9) & 0xff); mono_error_cleanup (error); /* FIXME don't swallow the error */ - + res = decode_patch (aot_module, mp, entry->data, p, &p); if (!res) goto cleanup; @@ -3877,7 +3877,7 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin case MONO_PATCH_INFO_GSHAREDVT_METHOD: { MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (mp, sizeof (MonoGSharedVtMethodInfo)); int i; - + info->method = decode_resolve_method_ref (aot_module, p, &p, error); mono_error_assert_ok (error); /* FIXME don't swallow the error */ @@ -4035,7 +4035,7 @@ register_jump_target_got_slot (MonoMethod *method, gpointer *got_slot) MonoMethod *shared_method = mini_method_to_shared (method); method = shared_method ? shared_method : method; - jit_mm = jit_mm_for_method (method); + jit_mm = jit_mm_for_method (method); jit_mm_lock (jit_mm); if (!jit_mm->jump_target_got_slot_hash) jit_mm->jump_target_got_slot_hash = g_hash_table_new (NULL, NULL); @@ -4243,7 +4243,7 @@ load_method (MonoAotModule *amodule, MonoImage *image, MonoMethod *method, guint } /** find_aot_method_in_amodule - * + * * \param code_amodule The AOT module containing the code pointer * \param method The method to find the code index for * \param hash_full The hash for the method @@ -4257,7 +4257,7 @@ find_aot_method_in_amodule (MonoAotModule *code_amodule, MonoMethod *method, gui guint32 index; static guint32 n_extra_decodes; - // The AOT module containing the MonoMethod + // The AOT module containing the MonoMethod // The reference to the metadata amodule will differ among multiple dedup methods // which mangle to the same name but live in different assemblies. This leads to // the caching breaking. The solution seems to be to cache using the "metadata" amodule. @@ -4414,7 +4414,7 @@ find_aot_method (MonoMethod *method, MonoAotModule **out_amodule) int i; guint32 hash = mono_aot_method_hash (method); - /* Try the place we expect to have moved the method only + /* Try the place we expect to have moved the method only * We don't probe, as that causes hard-to-debug issues when we fail * to find the method */ if (container_amodule && mono_aot_can_dedup (method)) { @@ -4429,7 +4429,7 @@ find_aot_method (MonoMethod *method, MonoAotModule **out_amodule) if (index != 0xffffff) return index; - /* + /* * Try all other modules. * This is needed because generic instances klass->image points to the image * containing the generic definition, but the native code is generated to the @@ -4453,7 +4453,7 @@ find_aot_method (MonoMethod *method, MonoAotModule **out_amodule) break; } } - + g_ptr_array_free (modules, TRUE); return index; @@ -4687,7 +4687,7 @@ mono_aot_get_method (MonoMethod *method, MonoError *error) if (method->is_inflated && !method->wrapper_type && mono_method_is_generic_sharable_full (method, TRUE, FALSE, FALSE) && !dedupable) { MonoMethod *orig_method = method; - /* + /* * For generic methods, we store the fully shared instance in place of the * original method. */ @@ -4754,7 +4754,7 @@ mono_aot_get_method (MonoMethod *method, MonoError *error) if (!m) g_error ("AOT runtime could not load method due to %s", mono_error_get_message (error)); /* FIXME don't swallow the error */ - /* + /* * Get the code for the instantiation which should be emitted into * the mscorlib aot image by the AOT compiler. */ @@ -4914,7 +4914,7 @@ mono_aot_is_got_entry (guint8 *code, guint8 *addr) mono_aot_lock (); g_hash_table_foreach (aot_modules, check_is_got_entry, &user_data); mono_aot_unlock (); - + return user_data.res; } @@ -4947,11 +4947,11 @@ find_aot_module (guint8 *code) user_data.addr = code; user_data.module = NULL; - + mono_aot_lock (); g_hash_table_foreach (aot_modules, find_aot_module_cb, &user_data); mono_aot_unlock (); - + return user_data.module; } @@ -5022,7 +5022,7 @@ mono_aot_plt_resolve (gpointer aot_module, host_mgreg_t *regs, guint8 *code, Mon using_gsharedvt = TRUE; #endif - /* + /* * Avoid calling resolve_patch_target in the full-aot case if possible, since * it would create a trampoline, and we don't need that. * We could do this only if the method does not need the special handling @@ -5163,7 +5163,7 @@ mono_aot_get_plt_entry (host_mgreg_t *regs, guint8 *code) while (target != NULL) { if ((target >= (guint8*)(amodule->plt)) && (target < (guint8*)(amodule->plt_end))) return target; - + // Add 4 since mono_arch_get_call_target assumes we're passing // the instruction after the actual branch instruction. target = mono_arch_get_call_target (target + 4); @@ -5223,7 +5223,7 @@ mono_create_ftnptr_malloc (guint8 *code) /* * load_function_full: * - * Load the function named NAME from the aot image. + * Load the function named NAME from the aot image. */ static gpointer load_function_full (MonoAotModule *amodule, const char *name, MonoTrampInfo **out_tinfo) @@ -5696,7 +5696,7 @@ get_numerous_trampoline (MonoAotTrampoline tramp_type, int n_got_slots, MonoAotM #define MONOTOUCH_TRAMPOLINES_ERROR "" #endif if (amodule->trampoline_index [tramp_type] == amodule->info.num_trampolines [tramp_type]) { - g_error ("Ran out of trampolines of type %d in '%s' (limit %d)%s\n", + g_error ("Ran out of trampolines of type %d in '%s' (limit %d)%s\n", tramp_type, image ? image->name : MONO_ASSEMBLY_CORLIB_NAME, amodule->info.num_trampolines [tramp_type], MONOTOUCH_TRAMPOLINES_ERROR); } index = amodule->trampoline_index [tramp_type] ++; @@ -5789,7 +5789,7 @@ mono_aot_get_static_rgctx_trampoline (gpointer ctx, gpointer addr) code = (guint8 *)get_numerous_trampoline (MONO_AOT_TRAMP_STATIC_RGCTX, 2, &amodule, &got_offset, NULL); amodule->got [got_offset] = ctx; - amodule->got [got_offset + 1] = addr; + amodule->got [got_offset + 1] = addr; } /* The caller expects an ftnptr */ @@ -6041,7 +6041,7 @@ mono_aot_get_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entries, buf = (void **)m_class_alloc0 (vtable->klass, (real_count + 1) * 2 * sizeof (gpointer)); index = 0; for (i = 0; i < count; ++i) { - MonoIMTCheckItem *item = imt_entries [i]; + MonoIMTCheckItem *item = imt_entries [i]; if (!item->is_equals) continue; @@ -6060,7 +6060,7 @@ mono_aot_get_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entries, } buf [(index * 2)] = NULL; buf [(index * 2) + 1] = fail_tramp; - + if (USE_PAGE_TRAMPOLINES) { code = get_new_imt_trampoline_from_page (buf); } else { @@ -6085,7 +6085,7 @@ mono_aot_get_gsharedvt_arg_trampoline (gpointer arg, gpointer addr) code = (guint8 *)get_numerous_trampoline (MONO_AOT_TRAMP_GSHAREDVT_ARG, 2, &amodule, &got_offset, NULL); amodule->got [got_offset] = arg; - amodule->got [got_offset + 1] = addr; + amodule->got [got_offset + 1] = addr; } /* The caller expects an ftnptr */ @@ -6130,7 +6130,7 @@ mono_aot_set_make_unreadable (gboolean unreadable) if (make_unreadable && !inited) { mono_counters_register ("AOT: pagefaults", MONO_COUNTER_JIT | MONO_COUNTER_INT, &n_pagefaults); - } + } } typedef struct { @@ -6179,7 +6179,7 @@ mono_aot_is_pagefault (void *ptr) if (!make_unreadable) return FALSE; - /* + /* * Not signal safe, but SIGSEGV's are synchronous, and * this is only turned on by a MONO_DEBUG option. */ @@ -6368,7 +6368,7 @@ mono_aot_get_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entries, { g_assert_not_reached (); return NULL; -} +} gpointer mono_aot_get_gsharedvt_arg_trampoline (gpointer arg, gpointer addr) diff --git a/src/mono/mono/mini/arch-stubs.c b/src/mono/mono/mini/arch-stubs.c index 853f92d5a52c0..bd09fb0066ae8 100644 --- a/src/mono/mono/mini/arch-stubs.c +++ b/src/mono/mono/mini/arch-stubs.c @@ -134,7 +134,7 @@ mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) return NULL; } -gpointer +gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { g_assert_not_reached (); diff --git a/src/mono/mono/mini/branch-opts.c b/src/mono/mono/mini/branch-opts.c index df8954784aefe..bdf889f57953e 100644 --- a/src/mono/mono/mini/branch-opts.c +++ b/src/mono/mono/mini/branch-opts.c @@ -19,7 +19,7 @@ /* * Returns true if @bb is a basic block which falls through the next block. - * TODO verify if it helps to check if the bb last ins is a branch to its successor. + * TODO verify if it helps to check if the bb last ins is a branch to its successor. */ static gboolean mono_bb_is_fall_through (MonoCompile *cfg, MonoBasicBlock *bb) @@ -30,7 +30,7 @@ mono_bb_is_fall_through (MonoCompile *cfg, MonoBasicBlock *bb) /* * Used by the arch code to replace the exception handling - * with a direct branch. This is safe to do if the + * with a direct branch. This is safe to do if the * exception object isn't used, no rethrow statement and * no filter statement (verify). * @@ -57,9 +57,9 @@ mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, con if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE && clause->data.catch_class && mono_class_is_assignable_from_internal (clause->data.catch_class, exclass)) { MonoBasicBlock *tbb; - /* get the basic block for the handler and + /* get the basic block for the handler and * check if the exception object is used. - * Flag is set during method_to_ir due to + * Flag is set during method_to_ir due to * pop-op is optmized away in codegen (burg). */ tbb = cfg->cil_offset_to_bb [clause->handler_offset]; @@ -69,7 +69,7 @@ mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, con /* Check if this catch clause is ok to optimize by * looking for the BB_EXCEPTION_UNSAFE in every BB that - * belongs to the same region. + * belongs to the same region. * * UNSAFE flag is set during method_to_ir (OP_RETHROW) */ @@ -93,11 +93,11 @@ mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, con jump->inst_i1 = (MonoInst *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst)); jump->inst_true_bb = targetbb; - if (cfg->verbose_level > 2) + if (cfg->verbose_level > 2) g_print ("found exception to optimize - returning branch to BB%d (%s) (instead of throw) for method %s:%s\n", targetbb->block_num, m_class_get_name (clause->data.catch_class), m_class_get_name (cfg->method->klass), cfg->method->name); return jump; - } + } return NULL; } else { @@ -168,7 +168,7 @@ br_to_br_un (int opcode) * mono_replace_ins: * * Replace INS with its decomposition which is stored in a series of bblocks starting - * at FIRST_BB and ending at LAST_BB. On enter, PREV points to the predecessor of INS. + * at FIRST_BB and ending at LAST_BB. On enter, PREV points to the predecessor of INS. * On return, it will be set to the last ins of the decomposition. */ void @@ -183,7 +183,7 @@ mono_replace_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst } if (first_bb == last_bb) { - /* + /* * Only one replacement bb, merge the code into * the current bb. */ @@ -295,7 +295,7 @@ mono_if_conversion (MonoCompile *cfg) // FIXME: Make this work with extended bblocks - /* + /* * This pass requires somewhat optimized IR code so it should be run after * local cprop/deadce. Also, it should be run before dominator computation, since * it changes control flow. @@ -349,7 +349,7 @@ mono_if_conversion (MonoCompile *cfg) true_bb = branch->inst_true_bb; false_bb = branch->inst_false_bb; - /* + /* * Check that bb1 and bb2 are 'simple' and both assign to the same * variable. */ @@ -364,7 +364,7 @@ mono_if_conversion (MonoCompile *cfg) for (tmp = ins1->next; tmp; tmp = tmp->next) if (!((tmp->opcode == OP_NOP) || (tmp->opcode == OP_IL_SEQ_POINT) || (tmp->opcode == OP_BR))) simple = FALSE; - + for (tmp = ins2->next; tmp; tmp = tmp->next) if (!((tmp->opcode == OP_NOP) || (tmp->opcode == OP_IL_SEQ_POINT) || (tmp->opcode == OP_BR))) simple = FALSE; @@ -549,7 +549,7 @@ mono_if_conversion (MonoCompile *cfg) continue; if (!(cfg->opt & MONO_OPT_DEADCE)) - /* + /* * It is possible that dreg is never set before, so we can't use * it as an sreg of the cmov instruction (#582322). */ @@ -618,10 +618,10 @@ mono_if_conversion (MonoCompile *cfg) (bb->region == bb->out_bb [0]->region)) { mono_merge_basic_blocks (cfg, bb, bb->out_bb [0]); - /* - * bbn might have fallen through to the next bb without a branch, + /* + * bbn might have fallen through to the next bb without a branch, * have to add one now (#474718). - * FIXME: Maybe need to do this more generally in + * FIXME: Maybe need to do this more generally in * merge_basic_blocks () ? */ if (!(bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) && bb->out_count) { @@ -717,7 +717,7 @@ mono_if_conversion (MonoCompile *cfg) mono_unlink_bblock (cfg, bb, branch1->inst_true_bb); mono_unlink_bblock (cfg, bb, branch1->inst_false_bb); branch1->inst_target_bb = next_bb; - mono_link_bblock (cfg, bb, next_bb); + mono_link_bblock (cfg, bb, next_bb); /* Rewrite the second branch */ branch2->opcode = br_to_br_un (branch2->opcode); @@ -774,7 +774,7 @@ mono_if_conversion (MonoCompile *cfg) } void -mono_nullify_basic_block (MonoBasicBlock *bb) +mono_nullify_basic_block (MonoBasicBlock *bb) { bb->in_count = 0; bb->out_count = 0; @@ -785,7 +785,7 @@ mono_nullify_basic_block (MonoBasicBlock *bb) bb->cil_code = NULL; } -static void +static void replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) { int i; @@ -805,7 +805,7 @@ replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *re } } -static void +static void replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) { int i; @@ -829,7 +829,7 @@ static void replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) { MonoInst *ins; - + for (ins = bb->code; ins != NULL; ins = ins->next) { switch (ins->opcode) { case OP_BR: @@ -885,7 +885,7 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p bb->not_useless = TRUE; return FALSE; } - + MONO_BB_FOR_EACH_INS (bb, inst) { switch (inst->opcode) { case OP_NOP: @@ -899,7 +899,7 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p return FALSE; } } - + if (target_bb == NULL) { if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) { target_bb = bb->next_bb; @@ -908,25 +908,25 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p return FALSE; } } - + /* Do not touch BBs following a switch (they are the "default" branch) */ if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == OP_SWITCH)) { return FALSE; } - + /* Do not touch BBs following the entry BB and jumping to something that is not */ /* thiry "next" bb (the entry BB cannot contain the branch) */ if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) { return FALSE; } - /* - * Do not touch BBs following a try block as the code in + /* + * Do not touch BBs following a try block as the code in * mini_method_compile needs them to compute the length of the try block. */ if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY)) return FALSE; - + /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */ if ((target_bb != NULL) && (target_bb != bb)) { int i; @@ -934,7 +934,7 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p if (cfg->verbose_level > 1) { printf ("remove_block_if_useless, removed BB%d\n", bb->block_num); } - + /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */ while (bb->in_count) { MonoBasicBlock *in_bb = bb->in_bb [0]; @@ -942,7 +942,7 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p mono_link_bblock (cfg, in_bb, target_bb); replace_out_block_in_code (in_bb, bb, target_bb); } - + mono_unlink_bblock (cfg, bb, target_bb); if (previous_bb != cfg->bb_entry && mono_bb_is_fall_through (cfg, previous_bb)) { for (i = 0; i < previous_bb->out_count; i++) { @@ -956,10 +956,10 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p } } } - + previous_bb->next_bb = bb->next_bb; mono_nullify_basic_block (bb); - + return TRUE; } else { return FALSE; @@ -967,7 +967,7 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p } void -mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *bbn) +mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *bbn) { MonoInst *inst; MonoBasicBlock *prev_bb; @@ -1048,7 +1048,7 @@ mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *b } mono_nullify_basic_block (bbn); - /* + /* * If bbn fell through to its next bblock, have to add a branch, since bb * will not fall though to the same bblock (#513931). */ @@ -1087,7 +1087,7 @@ move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb) MONO_ADD_INS (bb, ins); mono_link_bblock (cfg, bb, next); ins->inst_target_bb = next; - } + } } /* @@ -1096,7 +1096,7 @@ move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb) * Remove BB from the control flow graph */ void -mono_remove_bblock (MonoCompile *cfg, MonoBasicBlock *bb) +mono_remove_bblock (MonoCompile *cfg, MonoBasicBlock *bb) { MonoBasicBlock *tmp_bb; @@ -1112,7 +1112,7 @@ mono_remove_critical_edges (MonoCompile *cfg) { MonoBasicBlock *bb; MonoBasicBlock *previous_bb; - + if (cfg->verbose_level > 3) { for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { int i; @@ -1132,15 +1132,15 @@ mono_remove_critical_edges (MonoCompile *cfg) printf ("\n"); } } - + for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) { if (bb->in_count > 1) { int in_bb_index; for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) { MonoBasicBlock *in_bb = bb->in_bb [in_bb_index]; - /* + /* * Have to remove non-critical edges whose source ends with a BR_REG - * ins too, since inserting a computation before the BR_REG could + * ins too, since inserting a computation before the BR_REG could * overwrite the sreg1 of the ins. */ if ((in_bb->out_count > 1) || (in_bb->out_count == 1 && in_bb->last_ins && in_bb->last_ins->opcode == OP_BR_REG)) { @@ -1148,7 +1148,7 @@ mono_remove_critical_edges (MonoCompile *cfg) new_bb->block_num = cfg->num_bblocks++; // new_bb->real_offset = bb->real_offset; new_bb->region = bb->region; - + /* Do not alter the CFG while altering the BB list */ if (mono_bb_is_fall_through (cfg, previous_bb)) { if (previous_bb != cfg->bb_entry) { @@ -1172,7 +1172,7 @@ mono_remove_critical_edges (MonoCompile *cfg) new_bb_after_entry->block_num = cfg->num_bblocks++; // new_bb_after_entry->real_offset = bb->real_offset; new_bb_after_entry->region = bb->region; - + MONO_INST_NEW (cfg, jump, OP_BR); MONO_ADD_INS (new_bb_after_entry, jump); jump->cil_code = bb->cil_code; @@ -1181,7 +1181,7 @@ mono_remove_critical_edges (MonoCompile *cfg) mono_unlink_bblock (cfg, previous_bb, bb); mono_link_bblock (cfg, new_bb_after_entry, bb); mono_link_bblock (cfg, previous_bb, new_bb_after_entry); - + previous_bb->next_bb = new_bb_after_entry; previous_bb = new_bb_after_entry; @@ -1190,12 +1190,12 @@ mono_remove_critical_edges (MonoCompile *cfg) } } } - + /* Insert new_bb in the BB list */ previous_bb->next_bb = new_bb; new_bb->next_bb = bb; previous_bb = new_bb; - + /* Setup in_bb and out_bb */ new_bb->in_bb = (MonoBasicBlock **)mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*)); new_bb->in_bb [0] = in_bb; @@ -1203,12 +1203,12 @@ mono_remove_critical_edges (MonoCompile *cfg) new_bb->out_bb = (MonoBasicBlock **)mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*)); new_bb->out_bb [0] = bb; new_bb->out_count = 1; - + /* Relink in_bb and bb to (from) new_bb */ replace_out_block (in_bb, bb, new_bb); replace_out_block_in_code (in_bb, bb, new_bb); replace_in_block (bb, in_bb, new_bb); - + if (cfg->verbose_level > 2) { printf ("remove_critical_edges, removed critical edge from BB%d to BB%d (added BB%d)\n", in_bb->block_num, bb->block_num, new_bb->block_num); } @@ -1216,7 +1216,7 @@ mono_remove_critical_edges (MonoCompile *cfg) } } } - + if (cfg->verbose_level > 3) { for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { int i; @@ -1260,7 +1260,7 @@ mono_optimize_branches (MonoCompile *cfg) niterations = cfg->num_bblocks * 2; else niterations = 1000; - + do { MonoBasicBlock *previous_bb; changed = FALSE; @@ -1291,7 +1291,7 @@ mono_optimize_branches (MonoCompile *cfg) for (i = 0; i < bbn->out_count; i++) replace_in_block (bbn->out_bb [i], bbn, NULL); - mono_nullify_basic_block (bbn); + mono_nullify_basic_block (bbn); changed = TRUE; } @@ -1341,7 +1341,7 @@ mono_optimize_branches (MonoCompile *cfg) for (i = 0; i < bbn->out_count; i++) replace_in_block (bbn->out_bb [i], bbn, NULL); - mono_nullify_basic_block (bbn); + mono_nullify_basic_block (bbn); changed = TRUE; continue; } @@ -1355,7 +1355,7 @@ mono_optimize_branches (MonoCompile *cfg) if (bb->region == bbn->region && bbn_first_inst && bbn_first_inst->opcode == OP_BR && bbn_first_inst->inst_target_bb != bbn && bbn_first_inst->inst_target_bb->region == bb->region) { - + if (cfg->verbose_level > 2) g_print ("branch to branch triggered %d -> %d -> %d\n", bb->block_num, bbn->block_num, bbn_first_inst->inst_target_bb->block_num); @@ -1387,7 +1387,7 @@ mono_optimize_branches (MonoCompile *cfg) untaken_branch_target = bb->last_ins->inst_true_bb; } if (taken_branch_target) { - /* if mono_eval_cond_branch () is ever taken to handle + /* if mono_eval_cond_branch () is ever taken to handle * non-constant values to compare, issue a pop here. */ bb->last_ins->opcode = OP_BR; @@ -1401,12 +1401,12 @@ mono_optimize_branches (MonoCompile *cfg) bbn_first_inst = mono_bb_first_inst (bbn, filter); if (bb->region == bbn->region && bbn_first_inst && bbn_first_inst->opcode == OP_BR && bbn_first_inst->inst_target_bb->region == bb->region) { - if (cfg->verbose_level > 2) - g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", - bb->block_num, bbn->block_num, bbn_first_inst->inst_target_bb->block_num, + if (cfg->verbose_level > 2) + g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", + bb->block_num, bbn->block_num, bbn_first_inst->inst_target_bb->block_num, bbn_first_inst->opcode); - /* + /* * Unlink, then relink bblocks to avoid various * tricky situations when the two targets of the branch * are equal, or will become equal after the change. @@ -1428,8 +1428,8 @@ mono_optimize_branches (MonoCompile *cfg) if (bbn && bb->region == bbn->region && bbn_first_inst && bbn_first_inst->opcode == OP_BR && bbn_first_inst->inst_target_bb->region == bb->region) { if (cfg->verbose_level > 2) - g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", - bb->block_num, bbn->block_num, bbn_first_inst->inst_target_bb->block_num, + g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", + bb->block_num, bbn->block_num, bbn_first_inst->inst_target_bb->block_num, bbn_first_inst->opcode); mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb); @@ -1449,7 +1449,7 @@ mono_optimize_branches (MonoCompile *cfg) * If bb is an extended bb, it could contain an inside branch to bbn. * FIXME: Enable the optimization if that is not true. * If bblocks_linked () is true, then merging bb and bbn - * would require addition of an extra branch at the end of bbn + * would require addition of an extra branch at the end of bbn * slowing down loops. */ if (bbn && bb->region == bbn->region && bbn->in_count == 1 && cfg->enable_extended_bblocks && bbn != cfg->bb_exit && !bb->extended && !bbn->out_of_line && !mono_bblocks_linked (bbn, bb)) { @@ -1472,7 +1472,7 @@ mono_optimize_branches (MonoCompile *cfg) move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb); if (cfg->verbose_level > 2) - g_print ("cbranch to throw block triggered %d.\n", + g_print ("cbranch to throw block triggered %d.\n", bb->block_num); } } diff --git a/src/mono/mono/mini/calls.c b/src/mono/mono/mini/calls.c index e4877f6d98c03..e6eed77d6884c 100644 --- a/src/mono/mono/mini/calls.c +++ b/src/mono/mono/mini/calls.c @@ -105,7 +105,7 @@ ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt) case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: + case MONO_TYPE_ARRAY: return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL; case MONO_TYPE_I8: case MONO_TYPE_U8: @@ -139,7 +139,7 @@ ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt) } MonoCallInst * -mini_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, +mini_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, gboolean calli, gboolean virtual_, gboolean tailcall, gboolean rgctx, gboolean unbox_trampoline, MonoMethod *target) { @@ -218,8 +218,8 @@ mini_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK if (COMPILE_SOFT_FLOAT (cfg)) { - /* - * If the call has a float argument, we would need to do an r8->r4 conversion using + /* + * If the call has a float argument, we would need to do an r8->r4 conversion using * an icall, but that cannot be done during the call sequence since it would clobber * the call registers + the stack. So we do it before emitting the call. */ @@ -260,7 +260,7 @@ mini_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, cfg->param_area = MAX (cfg->param_area, call->stack_usage); cfg->flags |= MONO_CFG_HAS_CALLS; - + return call; } @@ -289,7 +289,7 @@ set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rg #ifdef ENABLE_LLVM call->rgctx_arg_reg = rgctx_reg; #endif -} +} /* Either METHOD or IMT_ARG needs to be set */ static void @@ -524,7 +524,7 @@ mini_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign FIXME: a dummy use is not the best way to do it as the local register allocator will put it on a caller save register and spill it around the call. - Ideally, we would either put it on a callee save register or only do the store part. + Ideally, we would either put it on a callee save register or only do the store part. */ EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]); @@ -533,7 +533,7 @@ mini_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign if ((!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || (MONO_METHOD_IS_FINAL (method)))) { - /* + /* * the method is not virtual, we just need to ensure this is not null * and then we can call the method directly. */ @@ -635,13 +635,13 @@ mono_emit_jit_icall_id (MonoCompile *cfg, MonoJitICallId jit_icall_id, MonoInst * Emit a call to the runtime function described by PATCH_TYPE and DATA. */ MonoInst* -mini_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, +mini_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, MonoMethodSignature *sig, MonoInst **args) { MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data); MonoInst *ins; - /* + /* * We pass ji as the call address, the PATCH_INFO_ABS resolving code will * handle it. * FIXME: Is the abs_patches hashtable avoidable? diff --git a/src/mono/mono/mini/cfold.c b/src/mono/mono/mini/cfold.c index 89c4f7b9563ac..fea708e4ef6d7 100644 --- a/src/mono/mono/mini/cfold.c +++ b/src/mono/mono/mini/cfold.c @@ -110,7 +110,7 @@ mono_constant_fold_ins (MonoCompile *cfg, MonoInst *ins, MonoInst *arg1, MonoIns FOLD_FBINOP (OP_FMUL, *); } dest->opcode = OP_R8CONST; - MONO_INST_NULLIFY_SREGS (dest); + MONO_INST_NULLIFY_SREGS (dest); } break; case OP_RADD: @@ -122,7 +122,7 @@ mono_constant_fold_ins (MonoCompile *cfg, MonoInst *ins, MonoInst *arg1, MonoIns FOLD_RBINOP (OP_RMUL, *); } dest->opcode = OP_R4CONST; - MONO_INST_NULLIFY_SREGS (dest); + MONO_INST_NULLIFY_SREGS (dest); } break; case OP_IMUL: @@ -144,7 +144,7 @@ mono_constant_fold_ins (MonoCompile *cfg, MonoInst *ins, MonoInst *arg1, MonoIns MONO_INST_NULLIFY_SREGS (dest); } } else if (arg1->opcode == OP_ICONST) { - /* + /* * This is commutative so swap the arguments, allowing the _imm variant * to be used later. */ @@ -380,8 +380,8 @@ mono_constant_fold_ins (MonoCompile *cfg, MonoInst *ins, MonoInst *arg1, MonoIns } if (overwrite) { - /* - * Can't nullify OP_COMPARE here since the decompose long branch + /* + * Can't nullify OP_COMPARE here since the decompose long branch * opcodes depend on it being executed. Also, the branch might not * be eliminated after all if loop opts is disabled, for example. */ @@ -443,17 +443,17 @@ mono_constant_fold_ins (MonoCompile *cfg, MonoInst *ins, MonoInst *arg1, MonoIns } /* - * TODO: + * TODO: * conv.* opcodes. * *ovf* opcodes? It's slow and hard to do in C. - * switch can be replaced by a simple jump + * switch can be replaced by a simple jump */ default: return NULL; } - + return dest; -} +} #endif /* DISABLE_JIT */ diff --git a/src/mono/mono/mini/debug-mini.c b/src/mono/mono/mini/debug-mini.c index 2fdb64d2c12b2..a665dd012738d 100644 --- a/src/mono/mono/mini/debug-mini.c +++ b/src/mono/mono/mini/debug-mini.c @@ -76,7 +76,7 @@ mono_debug_open_method (MonoCompile *cfg) header = cfg->header; g_assert (header); - + info->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1); info->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry)); jit->num_locals = header->num_locals; @@ -118,7 +118,7 @@ write_variable (MonoInst *inst, MonoDebugVarInfo *var) * * Register symbol information for the method with valgrind */ -static void +static void mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit) { #ifdef VALGRIND_ADD_LINE_INFO @@ -143,7 +143,7 @@ mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit) addresses = g_new0 (guint32, header->code_size + 1); lines = g_new0 (guint32, header->code_size + 1); - /* + /* * Very simple code to convert the addr->offset mappings that mono has * into [addr-addr] ->line number mappings. */ @@ -183,7 +183,7 @@ mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit) else address = addresses [i]; } - + address = 0; line_number = 0; i = 0; @@ -193,7 +193,7 @@ mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit) else { if (line_number > 0) { //g_assert (addresses [i] - 1 >= address); - + if (addresses [i] - 1 >= address) { VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + addresses [i] - 1, filename, line_number); //printf ("[%d-%d] -> %d.\n", address, addresses [i] - 1, line_number); @@ -294,7 +294,7 @@ mono_debug_free_method (MonoCompile *cfg) if (info->line_numbers) g_array_free (info->line_numbers, TRUE); g_free (info); - cfg->debug_info = NULL; + cfg->debug_info = NULL; } } @@ -359,7 +359,7 @@ encode_value (gint32 value, guint8 *buf, guint8 **endbuf) //printf ("ENCODE: %d 0x%x.\n", value, value); - /* + /* * Same encoding as the one used in the metadata, extended to handle values * greater than 0x1fffffff. */ @@ -393,7 +393,7 @@ decode_value (guint8 *ptr, guint8 **rptr) { guint8 b = *ptr; gint32 len; - + if ((b & 0x80) == 0){ len = b; ++ptr; @@ -597,7 +597,7 @@ deserialize_debug_info (MonoMethod *method, guint8 *code_start, guint8 *buf, gui } void -mono_debug_add_aot_method (MonoMethod *method, guint8 *code_start, +mono_debug_add_aot_method (MonoMethod *method, guint8 *code_start, guint8 *debug_info, guint32 debug_info_len) { MonoDebugMethodJitInfo *jit; @@ -654,7 +654,7 @@ print_var_info (MonoDebugVarInfo *info, int idx, const char *name, const char *t * * Prints to stdout the information about the local variables in * a method (if \p only_arguments is false) or about the arguments. - * The information includes the storage info (where the variable + * The information includes the storage info (where the variable * lives, in a register or in memory). * The method is found by looking up what method has been emitted at * the instruction address \p ip. diff --git a/src/mono/mono/mini/debugger-agent-external.c b/src/mono/mono/mini/debugger-agent-external.c index 2fc584c5ad949..67298c2363b7e 100644 --- a/src/mono/mono/mini/debugger-agent-external.c +++ b/src/mono/mono/mini/debugger-agent-external.c @@ -49,7 +49,7 @@ mono_debugger_agent_parse_options (char *options) } DebuggerTransport * -mono_debugger_agent_get_transports (int *ntrans) +mono_debugger_agent_get_transports (int *ntrans) { *ntrans = ntransports; return transports; diff --git a/src/mono/mono/mini/decompose.c b/src/mono/mono/mini/decompose.c index efc8bfd6f06bc..8e6db0073f589 100644 --- a/src/mono/mono/mini/decompose.c +++ b/src/mono/mono/mini/decompose.c @@ -129,7 +129,7 @@ decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins) break; } #endif - + case OP_ICONV_TO_OVF_I8: case OP_ICONV_TO_OVF_I: ins->opcode = OP_SEXT_I4; @@ -310,7 +310,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins) mono_arch_decompose_opts (cfg, ins); /* - * The code below assumes that we are called immediately after emitting + * The code below assumes that we are called immediately after emitting * ins. This means we can emit code using the normal code generation * macros. */ @@ -600,7 +600,7 @@ mono_decompose_long_opts (MonoCompile *cfg) */ /** - * Create a dummy bblock and emit code into it so we can use the normal + * Create a dummy bblock and emit code into it so we can use the normal * code generation macros. */ cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)); @@ -980,7 +980,7 @@ mono_decompose_long_opts (MonoCompile *cfg) break; case OP_LCEQ: { int d1, d2; - + /* Branchless version based on gcc code */ d1 = alloc_ireg (cfg); d2 = alloc_ireg (cfg); @@ -998,7 +998,7 @@ mono_decompose_long_opts (MonoCompile *cfg) case OP_LCGT: case OP_LCGT_UN: { MonoBasicBlock *set_to_0, *set_to_1; - + NEW_BBLOCK (cfg, set_to_0); NEW_BBLOCK (cfg, set_to_1); @@ -1013,7 +1013,7 @@ mono_decompose_long_opts (MonoCompile *cfg) MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1); MONO_START_BB (cfg, set_to_0); NULLIFY_INS (next); - break; + break; } default: g_assert_not_reached (); @@ -1067,7 +1067,7 @@ mono_decompose_long_opts (MonoCompile *cfg) break; case OP_LCEQ: { int d1, d2; - + /* Branchless version based on gcc code */ d1 = alloc_ireg (cfg); d2 = alloc_ireg (cfg); @@ -1085,7 +1085,7 @@ mono_decompose_long_opts (MonoCompile *cfg) case OP_LCGT: case OP_LCGT_UN: { MonoBasicBlock *set_to_0, *set_to_1; - + NEW_BBLOCK (cfg, set_to_0); NEW_BBLOCK (cfg, set_to_1); @@ -1100,7 +1100,7 @@ mono_decompose_long_opts (MonoCompile *cfg) MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1); MONO_START_BB (cfg, set_to_0); NULLIFY_INS (next); - break; + break; } default: g_assert_not_reached (); @@ -1161,23 +1161,23 @@ mono_decompose_vtype_opts (MonoCompile *cfg) * everywhere. * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed, * enabling optimizations to work on vtypes too. - * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it + * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it * can be executed anytime. It should be executed as late as possible so vtype * opcodes can be optimized by the other passes. * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation. - * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the + * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the * var to 1. - * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass + * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass * when OP_VMOVE opcodes are decomposed. */ - /* + /* * Vregs have no associated type information, so we store the type of the vregs * in ins->klass. */ /** - * Create a dummy bblock and emit code into it so we can use the normal + * Create a dummy bblock and emit code into it so we can use the normal * code generation macros. */ cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)); @@ -1238,11 +1238,11 @@ mono_decompose_vtype_opts (MonoCompile *cfg) EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, m_class_get_byval_arg (ins->klass)); mini_emit_initobj (cfg, dest, NULL, ins->klass); - + if (cfg->compute_gc_maps) { MonoInst *tmp; - /* + /* * Tell the GC map code that the vtype is considered live after * the initialization. */ @@ -1491,12 +1491,12 @@ mono_decompose_array_access_opts (MonoCompile *cfg) MonoBasicBlock *bb, *first_bb; /* - * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it + * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it * can be executed anytime. It should be run before decompose_long */ /** - * Create a dummy bblock and emit code into it so we can use the normal + * Create a dummy bblock and emit code into it so we can use the normal * code generation macros. */ cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)); @@ -1628,7 +1628,7 @@ mono_decompose_soft_float (MonoCompile *cfg) */ /** - * Create a dummy bblock and emit code into it so we can use the normal + * Create a dummy bblock and emit code into it so we can use the normal * code generation macros. */ cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)); @@ -1717,7 +1717,7 @@ mono_decompose_soft_float (MonoCompile *cfg) conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs); conv->dreg = ins->dreg; break; - } + } case OP_FCALL: case OP_FCALL_REG: case OP_FCALL_MEMBASE: { @@ -1809,7 +1809,7 @@ mono_decompose_soft_float (MonoCompile *cfg) cmp->sreg1 = call->dreg; cmp->inst_imm = 0; MONO_ADD_INS (cfg->cbb, cmp); - + MONO_INST_NEW (cfg, br, OP_IBNE_UN); br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2); br->inst_true_bb = ins->next->inst_true_bb; diff --git a/src/mono/mono/mini/dominators.c b/src/mono/mono/mini/dominators.c index 01093eb9d11e3..3e8197c6a64db 100644 --- a/src/mono/mono/mini/dominators.c +++ b/src/mono/mono/mini/dominators.c @@ -28,7 +28,7 @@ /* * Compute dominators and immediate dominators using the algorithm in the - * paper "A Simple, Fast Dominance Algorithm" by Keith D. Cooper, + * paper "A Simple, Fast Dominance Algorithm" by Keith D. Cooper, * Timothy J. Harvey, and Ken Kennedy: * http://citeseer.ist.psu.edu/cooper01simple.html */ @@ -169,7 +169,7 @@ check_dominance_frontier (MonoBasicBlock *x, MonoBasicBlock *t) if (!(t->flags & BB_VISITED)) { int found = FALSE; check_dominance_frontier (x, t->out_bb [i]); - + for (j = 0; j < t->out_bb [i]->in_count; j++) { if (t->out_bb [i]->in_bb [j] == t) found = TRUE; @@ -183,7 +183,7 @@ check_dominance_frontier (MonoBasicBlock *x, MonoBasicBlock *t) g_assert_not_reached (); } } -} +} #endif @@ -203,7 +203,7 @@ compute_dominance_frontier (MonoCompile *cfg) bitsize = mono_bitset_alloc_size (cfg->num_bblocks, 0); mem = (char *)mono_mempool_alloc0 (cfg->mempool, bitsize * cfg->num_bblocks); - + for (i = 0; i < cfg->num_bblocks; ++i) { MonoBasicBlock *bb = cfg->bblocks [i]; bb->dfrontier = mono_bitset_mem_new (mem, cfg->num_bblocks, 0); @@ -230,7 +230,7 @@ compute_dominance_frontier (MonoCompile *cfg) #if 0 for (i = 0; i < cfg->num_bblocks; ++i) { MonoBasicBlock *bb = cfg->bblocks [i]; - + printf ("DFRONT %s BB%d: ", mono_method_full_name (cfg->method, TRUE), bb->block_num); mono_blockset_print (cfg, bb->dfrontier, NULL, -1); } @@ -240,14 +240,14 @@ compute_dominance_frontier (MonoCompile *cfg) /* this is a check for the dominator frontier */ for (i = 0; i < m->num_bblocks; ++i) { MonoBasicBlock *x = m->bblocks [i]; - + mono_bitset_foreach_bit ((x->dfrontier), j, (m->num_bblocks)) { MonoBasicBlock *w = m->bblocks [j]; int k; /* x must not strictly dominates w */ if (mono_bitset_test_fast (w->dominators, x->dfn) && w != x) g_assert_not_reached (); - + for (k = 0; k < m->num_bblocks; ++k) m->bblocks [k]->flags &= ~BB_VISITED; @@ -260,7 +260,7 @@ compute_dominance_frontier (MonoCompile *cfg) } static void -df_set (MonoCompile *m, MonoBitSet* dest, MonoBitSet *set) +df_set (MonoCompile *m, MonoBitSet* dest, MonoBitSet *set) { int i; @@ -285,11 +285,11 @@ mono_compile_iterated_dfrontier (MonoCompile *m, MonoBitSet *set) df_set (m, result, result); count2 = mono_bitset_count (result); } while (count2 > count1); - + return result; } -void +void mono_compile_dominator_info (MonoCompile *cfg, int dom_flags) { if ((dom_flags & MONO_COMP_DOM) && !(cfg->comp_done & MONO_COMP_DOM)) @@ -301,7 +301,7 @@ mono_compile_dominator_info (MonoCompile *cfg, int dom_flags) /* * code to detect loops and loop nesting level */ -void +void mono_compute_natural_loops (MonoCompile *cfg) { int i, j, k; @@ -340,8 +340,8 @@ mono_compute_natural_loops (MonoCompile *cfg) mono_bitset_set_fast (in_loop_blocks, b->dfn); } } - todo = g_slist_prepend (NULL, n); - + todo = g_slist_prepend (NULL, n); + while (todo) { MonoBasicBlock *cb = (MonoBasicBlock *)todo->data; todo = g_slist_delete_link (todo, todo); @@ -424,27 +424,27 @@ static void clear_idominators (MonoCompile *cfg) { guint i; - + for (i = 0; i < cfg->num_bblocks; ++i) { if (cfg->bblocks[i]->dominated) { cfg->bblocks[i]->dominated = NULL; } } - cfg->comp_done &= ~MONO_COMP_IDOM; + cfg->comp_done &= ~MONO_COMP_IDOM; } static void clear_loops (MonoCompile *cfg) { guint i; - + for (i = 0; i < cfg->num_bblocks; ++i) { cfg->bblocks[i]->nesting = 0; cfg->bblocks[i]->loop_blocks = NULL; } - cfg->comp_done &= ~MONO_COMP_LOOPS; + cfg->comp_done &= ~MONO_COMP_LOOPS; } void diff --git a/src/mono/mono/mini/exceptions-arm.c b/src/mono/mono/mini/exceptions-arm.c index 146cf26e1e366..afa4a5f976c14 100644 --- a/src/mono/mono/mini/exceptions-arm.c +++ b/src/mono/mono/mini/exceptions-arm.c @@ -61,7 +61,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) start = code = mono_global_codeman_reserve (128); - /* + /* * Move things to their proper place so we can restore all the registers with * one instruction. */ @@ -99,7 +99,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) * arch_get_call_filter: * * Returns a pointer to a method which calls an exception filter. We - * also use this function to call finally handlers (we pass NULL as + * also use this function to call finally handlers (we pass NULL as * @exc object in this case). */ gpointer @@ -214,13 +214,13 @@ mono_arm_resume_unwind (guint32 dummy1, host_mgreg_t pc, host_mgreg_t sp, host_m /** * get_throw_trampoline: * - * Returns a function pointer which can be used to raise - * exceptions. The returned function has the following + * Returns a function pointer which can be used to raise + * exceptions. The returned function has the following * signature: void (*func) (MonoException *exc); or * void (*func) (guint32 ex_token, guint8* ip); * */ -static gpointer +static gpointer get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm, gboolean resume_unwind, const char *tramp_name, MonoTrampInfo **info, gboolean aot, gboolean preserve_ips) { guint8 *start; @@ -335,16 +335,16 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm /** * arch_get_throw_exception: * - * Returns a function pointer which can be used to raise - * exceptions. The returned function has the following - * signature: void (*func) (MonoException *exc); + * Returns a function pointer which can be used to raise + * exceptions. The returned function has the following + * signature: void (*func) (MonoException *exc); * For example to raise an arithmetic exception you can use: * - * x86_push_imm (code, mono_get_exception_arithmetic ()); - * x86_call_code (code, arch_get_throw_exception ()); + * x86_push_imm (code, mono_get_exception_arithmetic ()); + * x86_call_code (code, arch_get_throw_exception ()); * */ -gpointer +gpointer mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) { return get_throw_trampoline (132, FALSE, FALSE, FALSE, FALSE, "throw_exception", info, aot, FALSE); @@ -353,9 +353,9 @@ mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) /** * mono_arch_get_rethrow_exception: * - * Returns a function pointer which can be used to rethrow - * exceptions. The returned function has the following - * signature: void (*func) (MonoException *exc); + * Returns a function pointer which can be used to rethrow + * exceptions. The returned function has the following + * signature: void (*func) (MonoException *exc); * */ gpointer @@ -364,7 +364,7 @@ mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) return get_throw_trampoline (132, FALSE, TRUE, FALSE, FALSE, "rethrow_exception", info, aot, FALSE); } -gpointer +gpointer mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) { return get_throw_trampoline (132, FALSE, TRUE, FALSE, FALSE, "rethrow_preserve_exception", info, aot, TRUE); @@ -372,19 +372,19 @@ mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) /** * mono_arch_get_throw_corlib_exception: - * \returns a function pointer which can be used to raise - * corlib exceptions. The returned function has the following - * signature: void (*func) (guint32 ex_token, guint32 offset); - * Here, \c offset is the offset which needs to be substracted from the caller IP - * to get the IP of the throw. Passing the offset has the advantage that it + * \returns a function pointer which can be used to raise + * corlib exceptions. The returned function has the following + * signature: void (*func) (guint32 ex_token, guint32 offset); + * Here, \c offset is the offset which needs to be substracted from the caller IP + * to get the IP of the throw. Passing the offset has the advantage that it * needs no relocations in the caller. * On ARM, the ip is passed instead of an offset. */ -gpointer +gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { return get_throw_trampoline (168, TRUE, FALSE, FALSE, FALSE, "throw_corlib_exception", info, aot, FALSE); -} +} GSList* mono_arm_get_exception_trampolines (gboolean aot) @@ -398,7 +398,7 @@ mono_arm_get_exception_trampolines (gboolean aot) get_throw_trampoline (168, TRUE, FALSE, FALSE, FALSE, "llvm_throw_corlib_exception_trampoline", &info, aot, FALSE); info->jit_icall_info = &mono_get_jit_icall_info ()->mono_llvm_throw_corlib_exception_trampoline; tramps = g_slist_prepend (tramps, info); - + get_throw_trampoline (168, TRUE, FALSE, TRUE, FALSE, "llvm_throw_corlib_exception_abs_trampoline", &info, aot, FALSE); info->jit_icall_info = &mono_get_jit_icall_info ()->mono_llvm_throw_corlib_exception_abs_trampoline; tramps = g_slist_prepend (tramps, info); @@ -426,7 +426,7 @@ mono_arch_exceptions_init (void) { gpointer tramp; GSList *tramps, *l; - + if (mono_aot_only) { // FIXME Macroize. @@ -451,7 +451,7 @@ mono_arch_exceptions_init (void) } } -/* +/* * mono_arch_unwind_frame: * * See exceptions-amd64.c for docs; @@ -525,7 +525,7 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, g_assert ((((guint64)(*lmf)->previous_lmf) & 2) == 0); frame->type = FRAME_TYPE_MANAGED_TO_NATIVE; - + if ((ji = mini_jit_info_table_find ((gpointer)(gsize)(*lmf)->ip))) { frame->ji = ji; } else { @@ -635,7 +635,7 @@ mono_arch_handle_exception (void *ctx, gpointer obj) result = mono_handle_exception (&mctx, obj); /* restore the context so that returning from the signal handler will invoke - * the catch clause + * the catch clause */ mono_monoctx_to_sigctx (&mctx, ctx); return result; diff --git a/src/mono/mono/mini/exceptions-arm64.c b/src/mono/mono/mini/exceptions-arm64.c index 30f0612f4fe88..adf650de2d02e 100644 --- a/src/mono/mono/mini/exceptions-arm64.c +++ b/src/mono/mono/mini/exceptions-arm64.c @@ -59,7 +59,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) /* ip0 = sp */ arm_ldrx (code, ARMREG_IP0, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_SP * 8)); /* Restore sp, ctx is no longer valid */ - arm_movspx (code, ARMREG_SP, ARMREG_IP0); + arm_movspx (code, ARMREG_SP, ARMREG_IP0); /* Branch to pc */ code = mono_arm_emit_brx (code, ARMREG_IP1); /* Not reached */ @@ -166,7 +166,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) return MINI_ADDR_TO_FTNPTR (start); } -static gpointer +static gpointer get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm, gboolean resume_unwind, const char *tramp_name, MonoTrampInfo **info, gboolean aot, gboolean preserve_ips) { guint8 *start, *code; @@ -206,7 +206,7 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm arm_ldrx (code, ARMREG_IP0, ARMREG_FP, 0); arm_strx (code, ARMREG_IP0, ARMREG_FP, gregs_offset + (ARMREG_FP * 8)); arm_addx_imm (code, ARMREG_IP0, ARMREG_FP, frame_size); - arm_strx (code, ARMREG_IP0, ARMREG_FP, gregs_offset + (ARMREG_SP * 8)); + arm_strx (code, ARMREG_IP0, ARMREG_FP, gregs_offset + (ARMREG_SP * 8)); /* Save fregs */ for (i = 0; i < num_fregs; ++i) arm_strfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8)); @@ -270,7 +270,7 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm return MINI_ADDR_TO_FTNPTR (start); } -gpointer +gpointer mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) { return get_throw_trampoline (256, FALSE, FALSE, FALSE, FALSE, "throw_exception", info, aot, FALSE); @@ -288,7 +288,7 @@ mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) return get_throw_trampoline (256, FALSE, TRUE, FALSE, FALSE, "rethrow_preserve_exception", info, aot, TRUE); } -gpointer +gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { return get_throw_trampoline (256, TRUE, FALSE, FALSE, FALSE, "throw_corlib_exception", info, aot, FALSE); @@ -423,14 +423,14 @@ mono_arm_resume_unwind (gpointer arg, host_mgreg_t pc, host_mgreg_t *int_regs, g mono_resume_unwind (&ctx); } -/* +/* * mono_arch_unwind_frame: * * See exceptions-amd64.c for docs; */ gboolean -mono_arch_unwind_frame (MonoJitTlsData *jit_tls, - MonoJitInfo *ji, MonoContext *ctx, +mono_arch_unwind_frame (MonoJitTlsData *jit_tls, + MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, StackFrameInfo *frame) diff --git a/src/mono/mono/mini/exceptions-mips.c b/src/mono/mono/mini/exceptions-mips.c index eea3b637eee1d..9e26eef50080f 100644 --- a/src/mono/mono/mini/exceptions-mips.c +++ b/src/mono/mono/mini/exceptions-mips.c @@ -88,7 +88,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) * mono_arch_get_call_filter: * * Returns a pointer to a method which calls an exception filter. We - * also use this function to call finally handlers (we pass NULL as + * also use this function to call finally handlers (we pass NULL as * @exc object in this case). * * This function is invoked as @@ -222,13 +222,13 @@ throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gboolean /** * arch_get_throw_exception_generic: * - * Returns a function pointer which can be used to raise - * exceptions. The returned function has the following + * Returns a function pointer which can be used to raise + * exceptions. The returned function has the following * signature: void (*func) (MonoException *exc); or * void (*func) (char *exc_name); * */ -static gpointer +static gpointer mono_arch_get_throw_exception_generic (guint8 *start, int size, int corlib, gboolean rethrow, gboolean preserve_ips) { guint8 *code; @@ -298,9 +298,9 @@ mono_arch_get_throw_exception_generic (guint8 *start, int size, int corlib, gboo /** * mono_arch_get_rethrow_exception: - * \returns a function pointer which can be used to rethrow - * exceptions. The returned function has the following - * signature: void (*func) (MonoException *exc); + * \returns a function pointer which can be used to rethrow + * exceptions. The returned function has the following + * signature: void (*func) (MonoException *exc); */ gpointer mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) @@ -323,8 +323,8 @@ mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) * mono_arch_get_rethrow_preserve_exception: * \returns a function pointer which can be used to rethrow * exceptions while avoiding modification of saved trace_ips. - * The returned function has the following - * signature: void (*func) (MonoException *exc); + * The returned function has the following + * signature: void (*func) (MonoException *exc); */ gpointer mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) @@ -346,13 +346,13 @@ mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) /** * arch_get_throw_exception: * - * Returns a function pointer which can be used to raise - * exceptions. The returned function has the following - * signature: void (*func) (MonoException *exc); + * Returns a function pointer which can be used to raise + * exceptions. The returned function has the following + * signature: void (*func) (MonoException *exc); * For example to raise an arithmetic exception you can use: * - * x86_push_imm (code, mono_get_exception_arithmetic ()); - * x86_call_code (code, arch_get_throw_exception ()); + * x86_push_imm (code, mono_get_exception_arithmetic ()); + * x86_call_code (code, arch_get_throw_exception ()); * */ gpointer @@ -372,13 +372,13 @@ mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) return start; } -gpointer +gpointer mono_arch_get_throw_exception_by_name (void) { guint8 *start, *code; int size = 64; - /* Not used on MIPS */ + /* Not used on MIPS */ start = code = mono_global_codeman_reserve (size); mips_break (code, 0xfd); mono_arch_flush_icache (start, code - start); @@ -388,9 +388,9 @@ mono_arch_get_throw_exception_by_name (void) /** * mono_arch_get_throw_corlib_exception: - * \returns a function pointer which can be used to raise - * corlib exceptions. The returned function has the following - * signature: void (*func) (guint32 ex_token, guint32 offset); + * \returns a function pointer which can be used to raise + * corlib exceptions. The returned function has the following + * signature: void (*func) (guint32 ex_token, guint32 offset); * On MIPS, the offset argument is missing. */ gpointer @@ -419,9 +419,9 @@ mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) * Returns TRUE on success, FALSE otherwise. */ gboolean -mono_arch_unwind_frame (MonoJitTlsData *jit_tls, - MonoJitInfo *ji, MonoContext *ctx, - MonoContext *new_ctx, MonoLMF **lmf, +mono_arch_unwind_frame (MonoJitTlsData *jit_tls, + MonoJitInfo *ji, MonoContext *ctx, + MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, StackFrameInfo *frame) { @@ -448,7 +448,7 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, for (i = 0; i < MONO_MAX_IREGS; ++i) regs [i] = new_ctx->sc_regs [i]; - gboolean success = mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, + gboolean success = mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, (guint8*)ji->code_start + ji->code_size, ip, NULL, regs, MONO_MAX_IREGS, save_locations, MONO_MAX_IREGS, &cfa); @@ -562,7 +562,7 @@ mono_arch_handle_exception (void *ctx, gpointer obj) result = mono_handle_exception (&mctx, obj); /* restore the context so that returning from the signal handler will invoke - * the catch clause + * the catch clause */ mono_monoctx_to_sigctx (&mctx, ctx); return result; diff --git a/src/mono/mono/mini/exceptions-ppc.c b/src/mono/mono/mini/exceptions-ppc.c index d1584191ff6af..829da843d282a 100644 --- a/src/mono/mono/mini/exceptions-ppc.c +++ b/src/mono/mono/mini/exceptions-ppc.c @@ -36,62 +36,62 @@ /* struct sigcontext { - int sc_onstack; // sigstack state to restore - int sc_mask; // signal mask to restore - int sc_ir; // pc - int sc_psw; // processor status word - int sc_sp; // stack pointer if sc_regs == NULL - void *sc_regs; // (kernel private) saved state + int sc_onstack; // sigstack state to restore + int sc_mask; // signal mask to restore + int sc_ir; // pc + int sc_psw; // processor status word + int sc_sp; // stack pointer if sc_regs == NULL + void *sc_regs; // (kernel private) saved state }; struct ucontext { int uc_onstack; - sigset_t uc_sigmask; // signal mask used by this context - stack_t uc_stack; // stack used by this context - struct ucontext *uc_link; // pointer to resuming context - size_t uc_mcsize; // size of the machine context passed in - mcontext_t uc_mcontext; // machine specific context + sigset_t uc_sigmask; // signal mask used by this context + stack_t uc_stack; // stack used by this context + struct ucontext *uc_link; // pointer to resuming context + size_t uc_mcsize; // size of the machine context passed in + mcontext_t uc_mcontext; // machine specific context }; typedef struct ppc_exception_state { - unsigned long dar; // Fault registers for coredump + unsigned long dar; // Fault registers for coredump unsigned long dsisr; - unsigned long exception;// number of powerpc exception taken - unsigned long pad0; // align to 16 bytes + unsigned long exception;// number of powerpc exception taken + unsigned long pad0; // align to 16 bytes - unsigned long pad1[4]; // space in PCB "just in case" + unsigned long pad1[4]; // space in PCB "just in case" } ppc_exception_state_t; typedef struct ppc_vector_state { unsigned long save_vr[32][4]; unsigned long save_vscr[4]; unsigned int save_pad5[4]; - unsigned int save_vrvalid; // VRs that have been saved + unsigned int save_vrvalid; // VRs that have been saved unsigned int save_pad6[7]; } ppc_vector_state_t; typedef struct ppc_float_state { double fpregs[32]; - unsigned int fpscr_pad; // fpscr is 64 bits, 32 bits of rubbish - unsigned int fpscr; // floating point status register + unsigned int fpscr_pad; // fpscr is 64 bits, 32 bits of rubbish + unsigned int fpscr; // floating point status register } ppc_float_state_t; typedef struct ppc_thread_state { - unsigned int srr0; // Instruction address register (PC) - unsigned int srr1; // Machine state register (supervisor) + unsigned int srr0; // Instruction address register (PC) + unsigned int srr1; // Machine state register (supervisor) unsigned int r0; unsigned int r1; unsigned int r2; - ... + ... unsigned int r31; - unsigned int cr; // Condition register - unsigned int xer; // User's integer exception register - unsigned int lr; // Link register - unsigned int ctr; // Count register - unsigned int mq; // MQ register (601 only) + unsigned int cr; // Condition register + unsigned int xer; // User's integer exception register + unsigned int lr; // Link register + unsigned int ctr; // Count register + unsigned int mq; // MQ register (601 only) - unsigned int vrsave; // Vector Save Register + unsigned int vrsave; // Vector Save Register } ppc_thread_state_t; struct mcontext { @@ -115,19 +115,19 @@ struct pt_regs { unsigned long gpr[32]; unsigned long nip; unsigned long msr; - unsigned long orig_gpr3; // Used for restarting system calls + unsigned long orig_gpr3; // Used for restarting system calls unsigned long ctr; unsigned long link; unsigned long xer; unsigned long ccr; - unsigned long mq; // 601 only (not used at present) - // Used on APUS to hold IPL value. - unsigned long trap; // Reason for being here + unsigned long mq; // 601 only (not used at present) + // Used on APUS to hold IPL value. + unsigned long trap; // Reason for being here // N.B. for critical exceptions on 4xx, the dar and dsisr - // fields are overloaded to hold srr0 and srr1. - unsigned long dar; // Fault registers - unsigned long dsisr; // on 4xx/Book-E used for ESR - unsigned long result; // Result of a system call + // fields are overloaded to hold srr0 and srr1. + unsigned long dar; // Fault registers + unsigned long dsisr; // on 4xx/Book-E used for ESR + unsigned long result; // Result of a system call }; struct mcontext { elf_gregset_t mc_gregs; @@ -141,22 +141,22 @@ struct ucontext { struct ucontext *uc_link; stack_t uc_stack; int uc_pad[7]; - struct mcontext *uc_regs; // points to uc_mcontext field + struct mcontext *uc_regs; // points to uc_mcontext field sigset_t uc_sigmask; - // glibc has 1024-bit signal masks, ours are 64-bit + // glibc has 1024-bit signal masks, ours are 64-bit int uc_maskext[30]; int uc_pad2[3]; struct mcontext uc_mcontext; }; -#define ELF_NGREG 48 // includes nip, msr, lr, etc. -#define ELF_NFPREG 33 // includes fpscr +#define ELF_NGREG 48 // includes nip, msr, lr, etc. +#define ELF_NFPREG 33 // includes fpscr -// General registers +// General registers typedef unsigned long elf_greg_t; typedef elf_greg_t elf_gregset_t[ELF_NGREG]; -// Floating point registers +// Floating point registers typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; @@ -256,7 +256,7 @@ emit_save_saved_regs (guint8 *code, int pos) * mono_arch_get_call_filter: * * Returns a pointer to a method which calls an exception filter. We - * also use this function to call finally handlers (we pass NULL as + * also use this function to call finally handlers (we pass NULL as * @exc object in this case). */ gpointer @@ -357,8 +357,8 @@ mono_ppc_throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, /** * arch_get_throw_exception_generic: * - * Returns a function pointer which can be used to raise - * exceptions. The returned function has the following + * Returns a function pointer which can be used to raise + * exceptions. The returned function has the following * signature: void (*func) (MonoException *exc); or * void (*func) (guint32 ex_token, gpointer ip) * @@ -461,8 +461,8 @@ mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, int corli * mono_arch_get_rethrow_preserve_exception: * \returns a function pointer which can be used to rethrow * exceptions and completely preserve trace_ips. - * The returned function has the following - * signature: void (*func) (MonoException *exc); + * The returned function has the following + * signature: void (*func) (MonoException *exc); */ gpointer mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) @@ -476,9 +476,9 @@ mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) /** * mono_arch_get_rethrow_exception: - * \returns a function pointer which can be used to rethrow - * exceptions. The returned function has the following - * signature: void (*func) (MonoException *exc); + * \returns a function pointer which can be used to rethrow + * exceptions. The returned function has the following + * signature: void (*func) (MonoException *exc); */ gpointer mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) @@ -493,13 +493,13 @@ mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) /** * arch_get_throw_exception: * - * Returns a function pointer which can be used to raise - * exceptions. The returned function has the following - * signature: void (*func) (MonoException *exc); + * Returns a function pointer which can be used to raise + * exceptions. The returned function has the following + * signature: void (*func) (MonoException *exc); * For example to raise an arithmetic exception you can use: * - * x86_push_imm (code, mono_get_exception_arithmetic ()); - * x86_call_code (code, arch_get_throw_exception ()); + * x86_push_imm (code, mono_get_exception_arithmetic ()); + * x86_call_code (code, arch_get_throw_exception ()); * */ gpointer @@ -514,9 +514,9 @@ mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) /** * mono_arch_get_throw_corlib_exception: - * \returns a function pointer which can be used to raise - * corlib exceptions. The returned function has the following - * signature: void (*func) (guint32 ex_token, guint32 offset); + * \returns a function pointer which can be used to raise + * corlib exceptions. The returned function has the following + * signature: void (*func) (guint32 ex_token, guint32 offset); * On PPC, we pass the ip instead of the offset */ gpointer @@ -535,8 +535,8 @@ mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) * See exceptions-amd64.c for docs. */ gboolean -mono_arch_unwind_frame (MonoJitTlsData *jit_tls, - MonoJitInfo *ji, MonoContext *ctx, +mono_arch_unwind_frame (MonoJitTlsData *jit_tls, + MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, StackFrameInfo *frame) @@ -581,7 +581,7 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, for (i = MONO_PPC_FIRST_SAVED_GREG; i < MONO_MAX_IREGS; ++i) regs [i] = ctx->regs [i]; - gboolean success = mono_unwind_frame (unwind_info, unwind_info_len, (guint8*)ji->code_start, + gboolean success = mono_unwind_frame (unwind_info, unwind_info_len, (guint8*)ji->code_start, (guint8*)ji->code_start + ji->code_size, (guint8*)ip, NULL, regs, ppc_lr + 1, save_locations, MONO_MAX_IREGS, &cfa); @@ -599,7 +599,7 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, return TRUE; } else if (*lmf) { - + if ((ji = mini_jit_info_table_find ((gpointer)(*lmf)->eip))) { } else { if (!(*lmf)->method) @@ -796,7 +796,7 @@ mono_arch_handle_exception (void *ctx, gpointer obj) result = mono_handle_exception (&mctx, obj); /* restore the context so that returning from the signal handler will invoke - * the catch clause + * the catch clause */ mono_monoctx_to_sigctx (&mctx, ctx); return result; diff --git a/src/mono/mono/mini/exceptions-s390x.c b/src/mono/mono/mini/exceptions-s390x.c index c1e0e420c6873..c13ede7e922fd 100644 --- a/src/mono/mono/mini/exceptions-s390x.c +++ b/src/mono/mono/mini/exceptions-s390x.c @@ -70,9 +70,9 @@ /* P r o t o t y p e s */ /*------------------------------------------------------------------*/ -static void throw_exception (MonoObject *, unsigned long, unsigned long, +static void throw_exception (MonoObject *, unsigned long, unsigned long, host_mgreg_t *, gdouble *, gint32 *, guint, gboolean, gboolean); -static gpointer mono_arch_get_throw_exception_generic (int, MonoTrampInfo **, +static gpointer mono_arch_get_throw_exception_generic (int, MonoTrampInfo **, int, gboolean, gboolean, gboolean); static void handle_signal_exception (gpointer); @@ -169,7 +169,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) /*------------------------------------------------------*/ /* Load all registers with values from the context */ /*------------------------------------------------------*/ - s390_lmg (code, s390_r3, s390_r12, s390_r13, + s390_lmg (code, s390_r3, s390_r12, s390_r13, G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[3])); pos = G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs[0]); for (i = 0; i < 16; ++i) { @@ -222,7 +222,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); s390_br (code, s390_r14); - g_assert ((code - start) < SZ_THROW); + g_assert ((code - start) < SZ_THROW); mono_arch_flush_icache(start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); @@ -246,7 +246,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) /*------------------------------------------------------------------*/ static void -throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp, +throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp, host_mgreg_t *int_regs, gdouble *fp_regs, gint32 *acc_regs, guint fpc, gboolean rethrow, gboolean preserve_ips) { @@ -271,7 +271,7 @@ throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp, MONO_CONTEXT_SET_BP (&ctx, sp); MONO_CONTEXT_SET_IP (&ctx, ip); - + if (mono_object_isinst_checked (exc, mono_defaults.exception_class, error)) { MonoException *mono_ex = (MonoException*)exc; if (!rethrow && !mono_ex->caught_in_unmanaged) { @@ -303,8 +303,8 @@ throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp, /* */ /*------------------------------------------------------------------*/ -static gpointer -mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, int corlib, +static gpointer +mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, int corlib, gboolean rethrow, gboolean aot, gboolean preserve_ips) { guint8 *code, *start; @@ -387,9 +387,9 @@ mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, int corli MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) - *info = mono_tramp_info_create (corlib ? "throw_corlib_exception" - : (rethrow ? "rethrow_exception" - : (preserve_ips ? "rethrow_preserve_exception" + *info = mono_tramp_info_create (corlib ? "throw_corlib_exception" + : (rethrow ? "rethrow_exception" + : (preserve_ips ? "rethrow_preserve_exception" : "throw_exception")), start, code - start, ji, unwind_ops); @@ -433,7 +433,7 @@ mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) /* */ /*------------------------------------------------------------------*/ -gpointer +gpointer mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) { g_assert (!aot); @@ -456,7 +456,7 @@ mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) /* */ /*------------------------------------------------------------------*/ -gpointer +gpointer mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) { g_assert (!aot); @@ -487,7 +487,7 @@ mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) *info = NULL; return (mono_arch_get_throw_exception_generic (SZ_THROW, info, TRUE, FALSE, aot, FALSE)); -} +} /*========================= End of Function ========================*/ @@ -500,8 +500,8 @@ mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) /*------------------------------------------------------------------*/ gboolean -mono_arch_unwind_frame (MonoJitTlsData *jit_tls, - MonoJitInfo *ji, MonoContext *ctx, +mono_arch_unwind_frame (MonoJitTlsData *jit_tls, + MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, StackFrameInfo *frame) @@ -548,7 +548,7 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MONO_CONTEXT_SET_IP(new_ctx, regs[14] - 2); MONO_CONTEXT_SET_BP(new_ctx, regs[15]); MONO_CONTEXT_SET_SP(new_ctx, regs[15]); - + return TRUE; } else if (*lmf) { @@ -556,7 +556,7 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, if (!ji) { if (!(*lmf)->method) return FALSE; - + frame->method = (*lmf)->method; } @@ -782,7 +782,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) /*========================= End of Function ========================*/ /** - * + * * @brief Setup CTX so execution resumes at FUNC * * @param[in] Context to be resumed @@ -829,19 +829,19 @@ mono_arch_is_int_overflow (void *uc, void *info) /*----------------------------------------------------------*/ switch (code[0]) { case 0x1d : /* Divide Register */ - regNo = code[1] & 0x0f; + regNo = code[1] & 0x0f; if (ctx->uc_mcontext.gregs[regNo] == 0) arithExc = FALSE; break; case 0x5d : /* Divide */ - regNo = (code[2] & 0xf0 >> 8); + regNo = (code[2] & 0xf0 >> 8); idxNo = (code[1] & 0x0f); offset = *((guint16 *) code+2) & 0x0fff; operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset); if (idxNo != 0) operand += ctx->uc_mcontext.gregs[idxNo]; if (*operand == 0) - arithExc = FALSE; + arithExc = FALSE; break; case 0xb9 : /* DL[GR] or DS[GR] */ if ((code[1] == 0x97) || (code[1] == 0x87) || @@ -854,15 +854,15 @@ mono_arch_is_int_overflow (void *uc, void *info) case 0xe3 : /* DL[G] | DS[G] */ if ((code[5] == 0x97) || (code[5] == 0x87) || (code[5] == 0x0d) || (code[5] == 0x1d)) { - regNo = (code[2] & 0xf0 >> 8); + regNo = (code[2] & 0xf0 >> 8); idxNo = (code[1] & 0x0f); - offset = (code[2] & 0x0f << 8) + + offset = (code[2] & 0x0f << 8) + code[3] + (code[4] << 12); operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset); if (idxNo != 0) operand += ctx->uc_mcontext.gregs[idxNo]; if (*operand == 0) - arithExc = FALSE; + arithExc = FALSE; } break; default: diff --git a/src/mono/mono/mini/exceptions-sparc.c b/src/mono/mono/mini/exceptions-sparc.c index bd41fdbe55ebb..01dc27d1acf60 100644 --- a/src/mono/mono/mini/exceptions-sparc.c +++ b/src/mono/mono/mini/exceptions-sparc.c @@ -76,7 +76,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) * mono_arch_get_call_filter: * * Returns a pointer to a method which calls an exception filter. We - * also use this function to call finally handlers (we pass NULL as + * also use this function to call finally handlers (we pass NULL as * @exc object in this case). * * call_filter (MonoContext *ctx, gpointer ip) @@ -127,7 +127,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) sparc_mov_reg_reg (code, sparc_fp, sparc_o7); - /* + /* * Modify the second frame so it is identical to the one used in the * method containing the filter. */ @@ -173,7 +173,7 @@ throw_exception (MonoObject *exc, gpointer sp, gpointer ip, gboolean rethrow, gb MonoContext ctx; static void (*restore_context) (MonoContext *); gpointer *window; - + if (!restore_context) restore_context = mono_get_restore_context (); @@ -198,7 +198,7 @@ throw_exception (MonoObject *exc, gpointer sp, gpointer ip, gboolean rethrow, gb g_assert_not_reached (); } -static gpointer +static gpointer get_throw_exception (gboolean rethrow, gboolean preserve_ips) { guint32 *start, *code; @@ -228,8 +228,8 @@ get_throw_exception (gboolean rethrow, gboolean preserve_ips) /** * mono_arch_get_throw_exception: * \returns a function pointer which can be used to raise exceptions. - * The returned function has the following - * signature: void (*func) (MonoException *exc); + * The returned function has the following + * signature: void (*func) (MonoException *exc); */ gpointer mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) @@ -293,11 +293,11 @@ mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) /** * mono_arch_get_throw_corlib_exception: - * \returns a function pointer which can be used to raise - * corlib exceptions. The returned function has the following - * signature: void (*func) (guint32 ex_token, guint32 offset); - * Here, offset is the offset which needs to be substracted from the caller IP - * to get the IP of the throw. Passing the offset has the advantage that it + * \returns a function pointer which can be used to raise + * corlib exceptions. The returned function has the following + * signature: void (*func) (guint32 ex_token, guint32 offset); + * Here, offset is the offset which needs to be substracted from the caller IP + * to get the IP of the throw. Passing the offset has the advantage that it * needs no relocations in the caller. */ gpointer @@ -356,16 +356,16 @@ mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) /* mono_arch_unwind_frame: * - * This function is used to gather information from @ctx. It return the + * This function is used to gather information from @ctx. It return the * MonoJitInfo of the corresponding function, unwinds one stack frame and - * stores the resulting context into @new_ctx. It also stores a string + * stores the resulting context into @new_ctx. It also stores a string * describing the stack location into @trace (if not NULL), and modifies - * the @lmf if necessary. @native_offset return the IP offset from the + * the @lmf if necessary. @native_offset return the IP offset from the * start of the function or -1 if that info is not available. */ gboolean -mono_arch_unwind_frame (MonoJitTlsData *jit_tls, - MonoJitInfo *ji, MonoContext *ctx, +mono_arch_unwind_frame (MonoJitTlsData *jit_tls, + MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, StackFrameInfo *frame) @@ -490,7 +490,7 @@ mono_arch_handle_exception (void *sigctx, gpointer obj) mctx.fp = window [sparc_fp - 16]; mono_handle_exception (&mctx, obj); - + /* We can't use restore_context to return from a signal handler */ ctx->uc_mcontext.gregs [REG_PC] = mctx.ip; ctx->uc_mcontext.gregs [REG_nPC] = mctx.ip + 4; diff --git a/src/mono/mono/mini/exceptions-wasm.c b/src/mono/mono/mini/exceptions-wasm.c index 05a1cbad2f3eb..14545de35369b 100644 --- a/src/mono/mono/mini/exceptions-wasm.c +++ b/src/mono/mono/mini/exceptions-wasm.c @@ -38,7 +38,7 @@ wasm_throw_corlib_exception (void) } gboolean -mono_arch_unwind_frame (MonoJitTlsData *jit_tls, +mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, @@ -96,7 +96,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) *info = mono_tramp_info_create ("restore_context", (guint8*)wasm_restore_context, 1, NULL, NULL); return (gpointer)wasm_restore_context; } -gpointer +gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { if (info) diff --git a/src/mono/mono/mini/exceptions-x86.c b/src/mono/mono/mini/exceptions-x86.c index 1c451717415c6..db6a76e5e06ed 100644 --- a/src/mono/mono/mini/exceptions-x86.c +++ b/src/mono/mono/mini/exceptions-x86.c @@ -130,19 +130,19 @@ mono_win32_get_handle_stackoverflow (void) * * Stack walking part of this method is from mono_handle_exception * - * The idea is simple; + * The idea is simple; * - walk the stack to free some space (64k) * - set esp to new stack location * - call mono_arch_handle_exception with stack overflow exception * - set esp to SEH handlers stack * - done */ -static void +static void win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, CONTEXT *sctx) { MonoJitInfo rji; MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); - MonoLMF *lmf = jit_tls->lmf; + MonoLMF *lmf = jit_tls->lmf; MonoContext initial_ctx; MonoContext ctx; guint32 free_stack = 0; @@ -295,7 +295,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) const int size = 128; start = code = mono_global_codeman_reserve (size); - + /* load ctx */ x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); @@ -371,7 +371,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) * mono_arch_get_call_filter: * * Returns a pointer to a method which calls an exception filter. We - * also use this function to call finally handlers (we pass NULL as + * also use this function to call finally handlers (we pass NULL as * @exc object in this case). */ gpointer @@ -495,7 +495,7 @@ mono_x86_throw_exception (host_mgreg_t *regs, MonoObject *exc, } void -mono_x86_throw_corlib_exception (host_mgreg_t *regs, guint32 ex_token_index, +mono_x86_throw_corlib_exception (host_mgreg_t *regs, guint32 ex_token_index, host_mgreg_t eip, gint32 pc_offset) { guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index; @@ -512,7 +512,7 @@ mono_x86_throw_corlib_exception (host_mgreg_t *regs, guint32 ex_token_index, } static void -mono_x86_resume_unwind (host_mgreg_t *regs, MonoObject *exc, +mono_x86_resume_unwind (host_mgreg_t *regs, MonoObject *exc, host_mgreg_t eip, gboolean rethrow) { MonoContext ctx; @@ -535,7 +535,7 @@ mono_x86_resume_unwind (host_mgreg_t *regs, MonoObject *exc, * * Generate a call to mono_x86_throw_exception/ * mono_x86_throw_corlib_exception. - * If LLVM is true, generate code which assumes the caller is LLVM generated code, + * If LLVM is true, generate code which assumes the caller is LLVM generated code, * which doesn't push the arguments. */ static guint8* @@ -551,7 +551,7 @@ get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolea stack_size = 128; - /* + /* * On apple, the stack is misaligned by the pushing of the return address. */ if (!llvm && corlib) @@ -644,7 +644,7 @@ get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolea } else if (corlib) { x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 8, 4); if (llvm_abs) { - /* + /* * The caller is LLVM code which passes the absolute address not a pc offset, * so compensate by passing 0 as 'ip' and passing the negated abs address as * the pc offset. @@ -691,28 +691,28 @@ get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolea /** * mono_arch_get_throw_exception: - * \returns a function pointer which can be used to raise - * exceptions. The returned function has the following - * signature: void (*func) (MonoException *exc); + * \returns a function pointer which can be used to raise + * exceptions. The returned function has the following + * signature: void (*func) (MonoException *exc); * For example to raise an arithmetic exception you can use: * - * x86_push_imm (code, mono_get_exception_arithmetic ()); - * x86_call_code (code, arch_get_throw_exception ()); + * x86_push_imm (code, mono_get_exception_arithmetic ()); + * x86_call_code (code, arch_get_throw_exception ()); * */ -gpointer +gpointer mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) { return get_throw_trampoline ("throw_exception", FALSE, FALSE, FALSE, FALSE, FALSE, info, aot, FALSE); } -gpointer +gpointer mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) { return get_throw_trampoline ("rethrow_exception", TRUE, FALSE, FALSE, FALSE, FALSE, info, aot, FALSE); } -gpointer +gpointer mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) { return get_throw_trampoline ("rethrow_preserve_exception", TRUE, FALSE, FALSE, FALSE, FALSE, info, aot, TRUE); @@ -720,14 +720,14 @@ mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) /** * mono_arch_get_throw_corlib_exception: - * \returns a function pointer which can be used to raise - * corlib exceptions. The returned function has the following - * signature: void (*func) (guint32 ex_token, guint32 offset); - * Here, offset is the offset which needs to be substracted from the caller IP - * to get the IP of the throw. Passing the offset has the advantage that it + * \returns a function pointer which can be used to raise + * corlib exceptions. The returned function has the following + * signature: void (*func) (guint32 ex_token, guint32 offset); + * Here, offset is the offset which needs to be substracted from the caller IP + * to get the IP of the throw. Passing the offset has the advantage that it * needs no relocations in the caller. */ -gpointer +gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { return get_throw_trampoline ("throw_corlib_exception", FALSE, FALSE, TRUE, FALSE, FALSE, info, aot, FALSE); @@ -739,8 +739,8 @@ mono_arch_exceptions_init (void) guint8 *tramp; MonoTrampInfo *tinfo; -/* - * If we're running WoW64, we need to set the usermode exception policy +/* + * If we're running WoW64, we need to set the usermode exception policy * for SEHs to behave. This requires hotfix http://support.microsoft.com/kb/976038 * or (eventually) Windows 7 SP1. */ @@ -799,8 +799,8 @@ mono_arch_exceptions_init (void) * See exceptions-amd64.c for docs. */ gboolean -mono_arch_unwind_frame (MonoJitTlsData *jit_tls, - MonoJitInfo *ji, MonoContext *ctx, +mono_arch_unwind_frame (MonoJitTlsData *jit_tls, + MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, StackFrameInfo *frame) @@ -1074,7 +1074,7 @@ restore_soft_guard_pages (void) return NULL; } -/* +/* * this function modifies mctx so that when it is restored, it * won't execcute starting at mctx.eip, but in a function that * will restore the protection on the soft-guard pages and return back to diff --git a/src/mono/mono/mini/graph.c b/src/mono/mono/mini/graph.c index 4d6902d34a83a..f078f9c0e9502 100644 --- a/src/mono/mono/mini/graph.c +++ b/src/mono/mono/mini/graph.c @@ -52,7 +52,7 @@ dtree_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h) level = h->nesting; fprintf (fp, "subgraph cluster_%d {\n", h->block_num); fprintf (fp, "label=\"loop_%d\"\n", h->block_num); - } + } for (i = 1; i < cfg->num_bblocks; ++i) { bb = cfg->bblocks [i]; @@ -61,14 +61,14 @@ dtree_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h) if (bb->nesting == level) { fprintf (fp, "BB%d -> BB%d;\n", bb->idom->block_num, bb->block_num); } - + if (bb->nesting == (level + 1) && bb->loop_blocks) { fprintf (fp, "BB%d -> BB%d;\n", bb->idom->block_num, bb->block_num); dtree_emit_one_loop_level (cfg, fp, bb); } } } - + if (h) { fprintf (fp, "}\n"); } @@ -84,7 +84,7 @@ cfg_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h) level = h->nesting; fprintf (fp, "subgraph cluster_%d {\n", h->block_num); fprintf (fp, "label=\"loop_%d\"\n", h->block_num); - } + } for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) { if (bb->region != -1) { @@ -107,18 +107,18 @@ cfg_emit_one_loop_level (MonoCompile *cfg, FILE *fp, MonoBasicBlock *h) if (!h || (g_list_find (h->loop_blocks, bb) && bb != h)) { if (bb->nesting == level) { - for (j = 0; j < bb->in_count; j++) + for (j = 0; j < bb->in_count; j++) fprintf (fp, "BB%d -> BB%d;\n", bb->in_bb [j]->block_num, bb->block_num); } - + if (bb->nesting == (level + 1) && bb->loop_blocks) { - for (j = 0; j < bb->in_count; j++) + for (j = 0; j < bb->in_count; j++) fprintf (fp, "BB%d -> BB%d;\n", bb->in_bb [j]->block_num, bb->block_num); cfg_emit_one_loop_level (cfg, fp, bb); } } } - + if (h) { fprintf (fp, "}\n"); } @@ -160,7 +160,7 @@ static void mono_draw_code_cfg (MonoCompile *cfg, FILE *fp) { MonoBasicBlock *bb; - + fprintf (fp, "digraph %s {\n", convert_name (cfg->method->name)); fprintf (fp, "node [fontsize=12.0]\nedge [len=1,color=red]\n"); fprintf (fp, "label=\"CFG for %s\";\n", mono_method_full_name (cfg->method, TRUE)); @@ -181,13 +181,13 @@ mono_draw_code_cfg (MonoCompile *cfg, FILE *fp) color = ""; fprintf (fp, "BB%d [%sshape=record,labeljust=l,label=\"{BB%d|", bb->block_num, color, bb->block_num); - + MONO_BB_FOR_EACH_INS (bb, inst) { //mono_print_label (fp, inst); - fprintf (fp, "\\n"); + fprintf (fp, "\\n"); } - fprintf (fp, "}\"];\n"); + fprintf (fp, "}\"];\n"); } cfg_emit_one_loop_level (cfg, fp, NULL); diff --git a/src/mono/mono/mini/helpers.c b/src/mono/mono/mini/helpers.c index 47525d02fec1a..0d83439c775f8 100644 --- a/src/mono/mono/mini/helpers.c +++ b/src/mono/mono/mini/helpers.c @@ -88,20 +88,20 @@ mono_inst_name (int op) { } void -mono_blockset_print (MonoCompile *cfg, MonoBitSet *set, const char *name, guint idom) +mono_blockset_print (MonoCompile *cfg, MonoBitSet *set, const char *name, guint idom) { #ifndef DISABLE_LOGGING int i; if (name) g_print ("%s:", name); - + mono_bitset_foreach_bit (set, i, cfg->num_bblocks) { if (idom == i) g_print (" [BB%d]", cfg->bblocks [i]->block_num); else g_print (" BB%d", cfg->bblocks [i]->block_num); - + } g_print ("\n"); #endif @@ -129,11 +129,11 @@ mono_disassemble_code (MonoCompile *cfg, guint8 *code, int size, char *id) int unused G_GNUC_UNUSED; #ifdef HOST_WIN32 - as_file = g_strdup_printf ("%s/test.s", tmp); + as_file = g_strdup_printf ("%s/test.s", tmp); if (!(ofd = fopen (as_file, "w"))) g_assert_not_reached (); -#else +#else i = g_file_open_tmp (NULL, &as_file, NULL); ofd = fdopen (i, "w"); g_assert (ofd); @@ -247,14 +247,14 @@ mono_disassemble_code (MonoCompile *cfg, guint8 *code, int size, char *id) #ifdef HOST_WIN32 o_file = g_strdup_printf ("%s/test.o", tmp); -#else +#else i = g_file_open_tmp (NULL, &o_file, NULL); close (i); #endif #ifdef HAVE_SYSTEM char *cmd = g_strdup_printf (ARCH_PREFIX AS_CMD " %s -o %s", as_file, o_file); - unused = system (cmd); + unused = system (cmd); g_free (cmd); char *objdump_args = g_getenv ("MONO_OBJDUMP_ARGS"); if (!objdump_args) @@ -263,8 +263,8 @@ mono_disassemble_code (MonoCompile *cfg, guint8 *code, int size, char *id) fflush (stdout); #if (defined(__arm__) || defined(__aarch64__)) && !defined(TARGET_OSX) - /* - * The arm assembler inserts ELF directives instructing objdump to display + /* + * The arm assembler inserts ELF directives instructing objdump to display * everything as data. */ cmd = g_strdup_printf (ARCH_PREFIX "strip -s %s", o_file); diff --git a/src/mono/mono/mini/interp/interp-internals.h b/src/mono/mono/mini/interp/interp-internals.h index c239cab5ab7fc..164a7080a7fc6 100644 --- a/src/mono/mono/mini/interp/interp-internals.h +++ b/src/mono/mono/mini/interp/interp-internals.h @@ -101,8 +101,8 @@ typedef enum { #define INTERP_IMETHOD_IS_TAGGED_UNBOX(im) ((mono_u)(im) & 1) #define INTERP_IMETHOD_UNTAG_UNBOX(im) ((InterpMethod*)((mono_u)(im) & ~1)) -/* - * Structure representing a method transformed for the interpreter +/* + * Structure representing a method transformed for the interpreter */ typedef struct InterpMethod InterpMethod; struct InterpMethod { diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 4e30c67c85dd8..7dc808d2def83 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -217,7 +217,7 @@ llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign if (fsig->param_count == 2 && fsig->params [0]->type == MONO_TYPE_R8 && fsig->params [1]->type == MONO_TYPE_R8) { // Max and Min can only be optimized in fast math mode if (!strcmp (cmethod->name, "Max") && mono_use_fast_math) { - opcode = OP_FMAX; + opcode = OP_FMAX; } else if (!strcmp (cmethod->name, "Min") && mono_use_fast_math) { opcode = OP_FMIN; } else if (!strcmp (cmethod->name, "Pow")) { @@ -243,7 +243,7 @@ llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign // (float, float) if (fsig->param_count == 2 && fsig->params [0]->type == MONO_TYPE_R4 && fsig->params [1]->type == MONO_TYPE_R4) { if (!strcmp (cmethod->name, "Max") && mono_use_fast_math) { - opcode = OP_RMAX; + opcode = OP_RMAX; } else if (!strcmp (cmethod->name, "Min") && mono_use_fast_math) { opcode = OP_RMIN; } else if (!strcmp (cmethod->name, "Pow")) { @@ -772,19 +772,19 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } #else index_reg = args [1]->dreg; -#endif +#endif MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg); #if defined(TARGET_X86) || defined(TARGET_AMD64) EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars)); add_reg = ins->dreg; - EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, + EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, add_reg, 0); #else int mult_reg = alloc_preg (cfg); MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1); MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg); - EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, + EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, add_reg, MONO_STRUCT_OFFSET (MonoString, chars)); #endif mini_type_from_op (cfg, ins, NULL, NULL); @@ -799,7 +799,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign cfg->flags |= MONO_CFG_NEEDS_DECOMPOSE; return ins; - } else + } else return NULL; } else if (cmethod->klass == mono_defaults.object_class) { if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) { @@ -816,7 +816,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) { int dreg = alloc_ireg (cfg); int t1 = alloc_ireg (cfg); - + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, t1, args [0]->dreg, 3); EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u); ins->type = STACK_I4; @@ -891,7 +891,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg); ins->type = STACK_I4; - + return ins; } #endif @@ -902,7 +902,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) { int dreg = alloc_ireg (cfg); int vtable_reg = alloc_preg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, + MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable)); EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank)); @@ -912,7 +912,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) { int dreg = alloc_ireg (cfg); - EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, + EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length)); mini_type_from_op (cfg, ins, NULL, NULL); @@ -1722,8 +1722,8 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign return ins; } } else if (cmethod->klass == mono_class_try_get_math_class ()) { - /* - * There is general branchless code for Min/Max, but it does not work for + /* + * There is general branchless code for Min/Max, but it does not work for * all inputs: * http://everything2.com/?node_id=1051618 */ @@ -1738,7 +1738,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign int opcode = 0; const char *mname = cmethod->name; char c = mname [0]; - + if (c == 'A'){ if (strcmp (mname, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) { opcode = OP_ABS; @@ -1758,7 +1758,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } else if (strcmp (mname, "Atanh") == 0){ if (fabs (source) < 1) opcode = OP_ATANH; - } + } } else if (c == 'C'){ if (strcmp (mname, "Cos") == 0) { if (!isinf (source)) @@ -1797,7 +1797,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign ins->type = STACK_R8; ins->dreg = mono_alloc_dreg (cfg, (MonoStackType) ins->type); ins->inst_p0 = dest; - + switch (opcode){ case OP_ABS: result = fabs (source); @@ -2040,10 +2040,10 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } } - // Return false for IsSupported for all types in System.Runtime.Intrinsics.* + // Return false for IsSupported for all types in System.Runtime.Intrinsics.* // if it's not handled in mono_emit_simd_intrinsics - if (in_corlib && - !strncmp ("System.Runtime.Intrinsics", cmethod_klass_name_space, 25) && + if (in_corlib && + !strncmp ("System.Runtime.Intrinsics", cmethod_klass_name_space, 25) && !strcmp (cmethod->name, "get_IsSupported")) { EMIT_NEW_ICONST (cfg, ins, 0); ins->type = STACK_I4; @@ -2143,7 +2143,7 @@ static MonoInst* emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set) { MonoClass *eklass; - + if (is_set) eklass = mono_class_from_mono_type_internal (fsig->params [2]); else diff --git a/src/mono/mono/mini/ir-emit.h b/src/mono/mono/mini/ir-emit.h index 6177261f3507f..a36efe38fbb43 100644 --- a/src/mono/mono/mini/ir-emit.h +++ b/src/mono/mono/mini/ir-emit.h @@ -113,9 +113,9 @@ alloc_dreg (MonoCompile *cfg, MonoStackType stack_type) * Macros used to generate intermediate representation macros * * The macros use a `MonoConfig` object as its context, and among other - * things it is used to associate instructions with the memory pool with + * things it is used to associate instructions with the memory pool with * it. - * + * * The macros come in three variations with slightly different * features, the patter is: NEW_OP, EMIT_NEW_OP, MONO_EMIT_NEW_OP, * the differences are as follows: @@ -131,25 +131,25 @@ alloc_dreg (MonoCompile *cfg, MonoStackType stack_type) * * `MONO_EMIT_NEW_OP`: These variations of the instructions are used when * you are merely interested in emitting the instruction into the `MonoConfig` - * parameter. + * parameter. */ #undef MONO_INST_NEW -/* - * FIXME: zeroing out some fields is not needed with the new IR, but the old +/* + * FIXME: zeroing out some fields is not needed with the new IR, but the old * JIT code still uses the left and right fields, so it has to stay. */ /* * MONO_INST_NEW: create a new MonoInst instance that is allocated on the MonoConfig pool. * - * @cfg: the MonoConfig object that will be used as the context for the + * @cfg: the MonoConfig object that will be used as the context for the * instruction. * @dest: this is the place where the instance of the `MonoInst` is stored. * @op: the value that should be stored in the MonoInst.opcode field * * This initializes an empty MonoInst that has been nulled out, it is allocated * from the memory pool associated with the MonoConfig, but it is not linked anywhere. - * the cil_code is set to the cfg->ip address. + * the cil_code is set to the cfg->ip address. */ #define MONO_INST_NEW(cfg,dest,op) do { \ (dest) = (MonoInst *)mono_mempool_alloc ((cfg)->mempool, sizeof (MonoInst)); \ @@ -173,8 +173,8 @@ alloc_dreg (MonoCompile *cfg, MonoStackType stack_type) (dest)->dreg = alloc_dreg ((cfg), STACK_I4); \ } while (0) -/* - * Avoid using this with a non-NULL val if possible as it is not AOT +/* + * Avoid using this with a non-NULL val if possible as it is not AOT * compatible. Use one of the NEW_xxxCONST variants instead. */ #define NEW_PCONST(cfg,dest,val) do { \ @@ -217,7 +217,7 @@ alloc_dreg (MonoCompile *cfg, MonoStackType stack_type) MONO_INST_NEW ((cfg), (dest), (op)); \ (dest)->dreg = dr; \ (dest)->sreg1 = sr1; \ - } while (0) + } while (0) #define NEW_BIALU(cfg,dest,op,dr,sr1,sr2) do { \ MONO_INST_NEW ((cfg), (dest), (op)); \ diff --git a/src/mono/mono/mini/jit.h b/src/mono/mono/mini/jit.h index 7f7e46403efee..c3413106b1ccd 100644 --- a/src/mono/mono/mini/jit.h +++ b/src/mono/mono/mini/jit.h @@ -13,19 +13,19 @@ MONO_BEGIN_DECLS -MONO_API MONO_RT_EXTERNAL_ONLY MonoDomain * +MONO_API MONO_RT_EXTERNAL_ONLY MonoDomain * mono_jit_init (const char *file); -MONO_API MONO_RT_EXTERNAL_ONLY MonoDomain * +MONO_API MONO_RT_EXTERNAL_ONLY MonoDomain * mono_jit_init_version (const char *root_domain_name, const char *runtime_version); -MONO_API MonoDomain * +MONO_API MonoDomain * mono_jit_init_version_for_test_only (const char *root_domain_name, const char *runtime_version); MONO_API int -mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, +mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[]); -MONO_API void +MONO_API void mono_jit_cleanup (MonoDomain *domain); MONO_API mono_bool diff --git a/src/mono/mono/mini/liveness.c b/src/mono/mono/mini/liveness.c index 81416eb3115ca..866f10be6889f 100644 --- a/src/mono/mono/mini/liveness.c +++ b/src/mono/mono/mini/liveness.c @@ -25,7 +25,7 @@ #define BB_ID_SHIFT 18 -/* +/* * The liveness2 pass can't handle long vars on 32 bit platforms because the component * vars have the same 'idx'. */ @@ -100,7 +100,7 @@ static void optimize_initlocals (MonoCompile *cfg); /* mono_bitset_mp_new: - * + * * allocates a MonoBitSet inside a memory pool */ static MonoBitSet* @@ -156,7 +156,7 @@ visit_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoPtrSet *visited) /* DREG */ regtype = spec [MONO_INST_DEST]; g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' '))); - + if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) { MonoInst *var = get_vreg_to_inst (cfg, ins->dreg); int idx = var->inst_c0; @@ -169,7 +169,7 @@ visit_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoPtrSet *visited) get_vreg_to_inst (cfg, MONO_LVREG_MS (var->dreg))->flags |= MONO_INST_VOLATILE; } } - + /* SREGS */ num_sregs = mono_inst_get_src_registers (ins, sregs); for (srcindex = 0; srcindex < num_sregs; ++srcindex) { @@ -193,7 +193,7 @@ visit_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoPtrSet *visited) mono_ptrset_add (visited, bb); - /* + /* * Need to visit all bblocks reachable from this one since they can be * reached during exception handling. */ @@ -211,7 +211,7 @@ mono_liveness_handle_exception_clauses (MonoCompile *cfg) int i, j; gboolean *outer_try; - /* + /* * Determine which clauses are outer try clauses, i.e. they are not contained in any * other non-try clause. */ @@ -283,7 +283,7 @@ analyze_liveness_bb (MonoCompile *cfg, MonoBasicBlock *bb) int sreg, inst_num; MonoMethodVar *vars = cfg->vars; guint32 abs_pos = (bb->dfn << BB_ID_SHIFT); - + /* Start inst_num from > 0, so last_use.abs_pos is only 0 for dead variables */ for (inst_num = 2, ins = bb->code; ins; ins = ins->next, inst_num += 2) { const char *spec = INS_INFO (ins->opcode); @@ -308,11 +308,11 @@ analyze_liveness_bb (MonoCompile *cfg, MonoBasicBlock *bb) if (cfg->verbose_level > 1) printf ("\tGEN: R%d(%d)\n", var->dreg, idx); #endif - update_live_range (&vars [idx], abs_pos + inst_num); + update_live_range (&vars [idx], abs_pos + inst_num); if (!mono_bitset_test_fast (bb->kill_set, idx)) mono_bitset_set_fast (bb->gen_set, idx); vi->spill_costs += SPILL_COST_INCREMENT; - } + } /* SREGs must come first, so MOVE r <- r is handled correctly */ num_sregs = mono_inst_get_src_registers (ins, sregs); @@ -327,7 +327,7 @@ analyze_liveness_bb (MonoCompile *cfg, MonoBasicBlock *bb) if (cfg->verbose_level > 1) printf ("\tGEN: R%d(%d)\n", sreg, idx); #endif - update_live_range (&vars [idx], abs_pos + inst_num); + update_live_range (&vars [idx], abs_pos + inst_num); if (!mono_bitset_test_fast (bb->kill_set, idx)) mono_bitset_set_fast (bb->gen_set, idx); vi->spill_costs += SPILL_COST_INCREMENT; @@ -341,7 +341,7 @@ analyze_liveness_bb (MonoCompile *cfg, MonoBasicBlock *bb) MonoMethodVar *vi = MONO_VARINFO (cfg, idx); if (MONO_IS_STORE_MEMBASE (ins)) { - update_live_range (&vars [idx], abs_pos + inst_num); + update_live_range (&vars [idx], abs_pos + inst_num); if (!mono_bitset_test_fast (bb->kill_set, idx)) mono_bitset_set_fast (bb->gen_set, idx); vi->spill_costs += SPILL_COST_INCREMENT; @@ -350,7 +350,7 @@ analyze_liveness_bb (MonoCompile *cfg, MonoBasicBlock *bb) if (cfg->verbose_level > 1) printf ("\tKILL: R%d(%d)\n", ins->dreg, idx); #endif - update_live_range (&vars [idx], abs_pos + inst_num + 1); + update_live_range (&vars [idx], abs_pos + inst_num + 1); mono_bitset_set_fast (bb->kill_set, idx); vi->spill_costs += SPILL_COST_INCREMENT; } @@ -358,7 +358,7 @@ analyze_liveness_bb (MonoCompile *cfg, MonoBasicBlock *bb) } } -/* generic liveness analysis code. CFG specific parts are +/* generic liveness analysis code. CFG specific parts are * in update_gen_kill_set() */ void @@ -380,7 +380,7 @@ mono_analyze_liveness (MonoCompile *cfg) g_assert (!(cfg->comp_done & MONO_COMP_LIVENESS)); cfg->comp_done |= MONO_COMP_LIVENESS; - + if (max_vars == 0) return; @@ -401,9 +401,9 @@ mono_analyze_liveness (MonoCompile *cfg) #ifdef DEBUG_LIVENESS if (cfg->verbose_level > 1) { printf ("BLOCK BB%d (", bb->block_num); - for (j = 0; j < bb->out_count; j++) + for (j = 0; j < bb->out_count; j++) printf ("BB%d, ", bb->out_bb [j]->block_num); - + printf ("):\n"); } #endif @@ -454,10 +454,10 @@ mono_analyze_liveness (MonoCompile *cfg) #ifdef DEBUG_LIVENESS if (cfg->verbose_level > 1) { printf ("P: BB%d(%d): IN: ", bb->block_num, bb->dfn); - for (j = 0; j < bb->in_count; ++j) + for (j = 0; j < bb->in_count; ++j) printf ("BB%d ", bb->in_bb [j]->block_num); printf ("OUT:"); - for (j = 0; j < bb->out_count; ++j) + for (j = 0; j < bb->out_count; ++j) printf ("BB%d ", bb->out_bb [j]->block_num); printf ("\n"); } @@ -477,7 +477,7 @@ mono_analyze_liveness (MonoCompile *cfg) changed = FALSE; mono_bitset_copyto_fast (bb->live_out_set, old_live_out_set); } - + for (j = 0; j < bb->out_count; j++) { out_bb = bb->out_bb [j]; @@ -495,7 +495,7 @@ mono_analyze_liveness (MonoCompile *cfg) mono_bitset_union_fast (bb->live_out_set, out_bb->live_in_set); } } - + if (changed || !mono_bitset_equal (old_live_out_set, bb->live_out_set)) { if (!bb->live_in_set) bb->live_in_set = mono_bitset_mp_new_noinit (cfg->mempool, bitsize, max_vars); @@ -505,8 +505,8 @@ mono_analyze_liveness (MonoCompile *cfg) for (j = 0; j < bb->in_count; j++) { MonoBasicBlock *in_bb = bb->in_bb [j]; - /* - * Some basic blocks do not seem to be in the + /* + * Some basic blocks do not seem to be in the * cfg->bblocks array... */ if (in_bb->gen_set && !in_worklist [in_bb->dfn]) { @@ -525,9 +525,9 @@ mono_analyze_liveness (MonoCompile *cfg) } if (G_UNLIKELY (cfg->verbose_level > 1)) { - printf ("\tLIVE IN BB%d: ", bb->block_num); - mono_bitset_print (bb->live_in_set); - } + printf ("\tLIVE IN BB%d: ", bb->block_num); + mono_bitset_print (bb->live_in_set); + } } #ifdef DEBUG_LIVENESS @@ -594,7 +594,7 @@ mono_analyze_liveness (MonoCompile *cfg) MonoMethodVar *vi = MONO_VARINFO (cfg, i); if (cfg->varinfo [vi->idx]->opcode == OP_ARG) { if (vi->range.last_use.abs_pos == 0 && !(cfg->varinfo [vi->idx]->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) { - /* + /* * Can't eliminate the this variable in gshared code, since * it is needed during exception handling to identify the * method. @@ -613,11 +613,11 @@ mono_analyze_liveness (MonoCompile *cfg) if (cfg->verbose_level > 1) { for (i = cfg->num_bblocks - 1; i >= 0; i--) { MonoBasicBlock *bb = cfg->bblocks [i]; - - printf ("LIVE IN BB%d: ", bb->block_num); - mono_bitset_print (bb->live_in_set); - printf ("LIVE OUT BB%d: ", bb->block_num); - mono_bitset_print (bb->live_out_set); + + printf ("LIVE IN BB%d: ", bb->block_num); + mono_bitset_print (bb->live_in_set); + printf ("LIVE OUT BB%d: ", bb->block_num); + mono_bitset_print (bb->live_out_set); } for (i = 0; i < max_vars; i ++) { @@ -681,7 +681,7 @@ optimize_initlocals (MonoCompile *cfg) if ((ins->opcode == OP_ICONST) || (ins->opcode == OP_I8CONST) || (ins->opcode == OP_R8CONST) || (ins->opcode == OP_R4CONST)) { NULLIFY_INS (ins); MONO_VARINFO (cfg, var->inst_c0)->spill_costs -= 1; - /* + /* * We should shorten the liveness interval of these vars as well, but * don't have enough info to do that. */ @@ -801,7 +801,7 @@ mono_linterval_get_intersect_pos (MonoLiveInterval *i1, MonoLiveInterval *i2) return -1; } - + /** * mono_linterval_split * @@ -973,7 +973,7 @@ mono_analyze_liveness2 (MonoCompile *cfg) LIVENESS_DEBUG (printf ("LIVENESS BLOCK BB%d:\n", bb->block_num)); memset (last_use, 0, max_vars * sizeof (gint32)); - + /* For variables in bb->live_out, set last_use to block_to */ max = ((max_vars + (BITS_PER_CHUNK -1)) / BITS_PER_CHUNK); @@ -982,7 +982,7 @@ mono_analyze_liveness2 (MonoCompile *cfg) int k; bits_out = mono_bitset_get_fast (bb->live_out_set, j); - k = (j * BITS_PER_CHUNK); + k = (j * BITS_PER_CHUNK); while (bits_out) { if (bits_out & 1) { LIVENESS_DEBUG (printf ("Var R%d live at exit, set last_use to %x\n", cfg->varinfo [k]->dreg, block_to)); @@ -1030,7 +1030,7 @@ mono_analyze_liveness2 (MonoCompile *cfg) #if 0 for (idx = 0; idx < max_vars; ++idx) { MonoMethodVar *vi = MONO_VARINFO (cfg, idx); - + LIVENESS_DEBUG (printf ("LIVENESS R%d: ", cfg->varinfo [idx]->dreg)); LIVENESS_DEBUG (mono_linterval_print (vi->interval)); LIVENESS_DEBUG (printf ("\n")); @@ -1149,7 +1149,7 @@ mono_analyze_liveness_gc (MonoCompile *cfg) continue; memset (last_use, 0, max_vars * sizeof (gint32)); - + /* For variables in bb->live_out, set last_use to block_to */ max = ((max_vars + (BITS_PER_CHUNK -1)) / BITS_PER_CHUNK); @@ -1162,7 +1162,7 @@ mono_analyze_liveness_gc (MonoCompile *cfg) continue; bits_out = mono_bitset_get_fast (bb->live_out_set, j); - k = (j * BITS_PER_CHUNK); + k = (j * BITS_PER_CHUNK); while (bits_out) { if ((bits_out & 1) && cfg->varinfo [k]->flags & MONO_INST_GC_TRACK) { int vreg = get_vreg_from_var (cfg, cfg->varinfo [k]); diff --git a/src/mono/mono/mini/llvm-runtime.h b/src/mono/mono/mini/llvm-runtime.h index 22d4d136e49c8..bc1eaca1a2c7c 100644 --- a/src/mono/mono/mini/llvm-runtime.h +++ b/src/mono/mono/mini/llvm-runtime.h @@ -26,6 +26,6 @@ mono_llvm_cpp_catch_exception (MonoLLVMInvokeCallback cb, gpointer arg, gboolean G_END_DECLS #endif /* __MONO_LLVM_RUNTIME_H__ */ - + diff --git a/src/mono/mono/mini/llvmonly-runtime.c b/src/mono/mono/mini/llvmonly-runtime.c index 8da3e60cce81b..2aeb93b16a69f 100644 --- a/src/mono/mono/mini/llvmonly-runtime.c +++ b/src/mono/mono/mini/llvmonly-runtime.c @@ -111,7 +111,7 @@ mini_llvmonly_get_delegate_arg (MonoMethod *method, gpointer method_ptr) * This is used for: * - generic sharing (ARG is the rgctx) * - gsharedvt signature wrappers (ARG is a function descriptor) - * + * */ MonoFtnDesc* mini_llvmonly_create_ftndesc (MonoMethod *m, gpointer addr, gpointer arg) @@ -160,7 +160,7 @@ mini_llvmonly_add_method_wrappers (MonoMethod *m, gpointer compiled_method, gboo addr = compiled_method; if (add_unbox_tramp) { - /* + /* * The unbox trampolines call the method directly, so need to add * an rgctx tramp before them. */ diff --git a/src/mono/mono/mini/local-propagation.c b/src/mono/mono/mini/local-propagation.c index 19801edd1f281..8eb4db79b5581 100644 --- a/src/mono/mono/mini/local-propagation.c +++ b/src/mono/mono/mini/local-propagation.c @@ -383,7 +383,7 @@ mono_strength_reduction_ins (MonoCompile *cfg, MonoInst *ins, const char **spec) ins->opcode = OP_ICONST; MONO_INST_NULLIFY_SREGS (ins); ins->inst_c0 = 0; - } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && + } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1) && (!cfg->backend->optimized_div)) { gboolean is_long = ins->opcode == OP_LREM_IMM; int compensator_reg = alloc_ireg (cfg); @@ -600,21 +600,21 @@ mono_local_cprop (MonoCompile *cfg) def = defs [sreg]; /* Copy propagation */ - /* - * The first check makes sure the source of the copy did not change since + /* + * The first check makes sure the source of the copy did not change since * the copy was made. * The second check avoids volatile variables. - * The third check avoids copy propagating local vregs through a call, - * since the lvreg will be spilled + * The third check avoids copy propagating local vregs through a call, + * since the lvreg will be spilled * The fourth check avoids copy propagating a vreg in cases where * it would be eliminated anyway by reverse copy propagation later, - * because propagating it would create another use for it, thus making + * because propagating it would create another use for it, thus making * it impossible to use reverse copy propagation. */ /* Enabling this for floats trips up the fp stack */ - /* - * Enabling this for floats on amd64 seems to cause a failure in - * basic-math.cs, most likely because it gets rid of some r8->r4 + /* + * Enabling this for floats on amd64 seems to cause a failure in + * basic-math.cs, most likely because it gets rid of some r8->r4 * conversions. */ if (MONO_IS_MOVE (def) && @@ -707,7 +707,7 @@ mono_local_cprop (MonoCompile *cfg) } else if (((def->opcode == OP_ADD_IMM) || (def->opcode == OP_LADD_IMM)) && (MONO_IS_LOAD_MEMBASE (ins) || MONO_ARCH_IS_OP_MEMBASE (ins->opcode))) { /* ADD_IMM is created by spill_global_vars */ - /* + /* * We have to guarantee that def->sreg1 haven't changed since def->dreg * was defined. cfg->frame_reg is assumed to remain constant. */ @@ -806,7 +806,7 @@ mono_local_cprop (MonoCompile *cfg) def_index [ins->dreg] = ins_index; } } - + if (MONO_IS_CALL (ins)) last_call_index = ins_index; @@ -825,7 +825,7 @@ reg_is_softreg_no_fpstack (int reg, const char spec) #endif || (spec == 'v'); } - + static gboolean reg_is_softreg (int reg, const char spec) { @@ -864,7 +864,7 @@ mono_is_simd_accessor (MonoInst *ins) /** * mono_local_deadce: * - * Get rid of the dead assignments to local vregs like the ones created by the + * Get rid of the dead assignments to local vregs like the ones created by the * copyprop pass. */ void @@ -933,7 +933,7 @@ mono_local_deadce (MonoCompile *cfg) def = prev_f; spec2 = INS_INFO (def->opcode); - /* + /* * Perform a limited kind of reverse copy propagation, i.e. * transform B <- FOO; A <- B into A <- FOO * This isn't copyprop, not deadce, but it can only be performed @@ -953,17 +953,17 @@ mono_local_deadce (MonoCompile *cfg) /* Enabling this on x86 could screw up the fp stack */ if (reg_is_softreg_no_fpstack (ins->dreg, spec [MONO_INST_DEST])) { - /* + /* * Assignments to global vregs can only be eliminated if there is another * assignment to the same vreg later in the same bblock. */ - if (!mono_bitset_test_fast (used, ins->dreg) && + if (!mono_bitset_test_fast (used, ins->dreg) && (!get_vreg_to_inst (cfg, ins->dreg) || (!bb->extended && !vreg_is_volatile (cfg, ins->dreg) && mono_bitset_test_fast (defined, ins->dreg))) && MONO_INS_HAS_NO_SIDE_EFFECT (ins)) { /* Happens with CMOV instructions */ if (prev_f && prev_f->opcode == OP_ICOMPARE_IMM) { MonoInst *prev = prev_f; - /* + /* * Can't use DELETE_INS since that would interfere with the * FOR_EACH_INS loop. */ @@ -996,7 +996,7 @@ mono_local_deadce (MonoCompile *cfg) regpair = (guint32)(gssize)(l->data); reg = regpair & 0xffffff; - + mono_bitset_set_fast (used, reg); } } @@ -1007,7 +1007,7 @@ mono_local_deadce (MonoCompile *cfg) regpair = (guint32)(gssize)(l->data); reg = regpair & 0xffffff; - + mono_bitset_set_fast (used, reg); } } diff --git a/src/mono/mono/mini/main-core.c b/src/mono/mono/mini/main-core.c index 11866090e1704..66e85d713c947 100644 --- a/src/mono/mono/mini/main-core.c +++ b/src/mono/mono/mini/main-core.c @@ -48,7 +48,7 @@ MONO_API int STDAPICALLTYPE coreclr_create_delegate (void* hostHandle, unsigned // propertyKeys - Keys of properties of the app domain // propertyValues - Values of properties of the app domain // hostHandle - Output parameter, handle of the created host -// domainId - Output parameter, id of the created app domain +// domainId - Output parameter, id of the created app domain // // Returns: // HRESULT indicating status of the operation. S_OK if the assembly was successfully executed @@ -65,7 +65,7 @@ int STDAPICALLTYPE coreclr_initialize (const char* exePath, const char* appDomai // // Parameters: // hostHandle - Handle of the host -// domainId - Id of the domain +// domainId - Id of the domain // argc - Number of arguments passed to the executed assembly // argv - Array of arguments passed to the executed assembly // managedAssemblyPath - Path of the managed assembly to execute (or NULL if using a custom entrypoint). @@ -86,7 +86,7 @@ int STDAPICALLTYPE coreclr_execute_assembly (void* hostHandle, unsigned int doma // // Parameters: // hostHandle - Handle of the host -// domainId - Id of the domain +// domainId - Id of the domain // latchedExitCode - Latched exit code after domain unloaded // // Returns: @@ -102,7 +102,7 @@ int STDAPICALLTYPE coreclr_shutdown_2 (void* hostHandle, unsigned int domainId, // // Parameters: // hostHandle - Handle of the host -// domainId - Id of the domain +// domainId - Id of the domain // entryPointAssemblyName - Name of the assembly which holds the custom entry point // entryPointTypeName - Name of the type which holds the custom entry point // entryPointMethodName - Name of the method which is the custom entry point diff --git a/src/mono/mono/mini/main.c b/src/mono/mono/mini/main.c index 36f5b4dce54bc..2e1bf2fd6decc 100644 --- a/src/mono/mono/mini/main.c +++ b/src/mono/mono/mini/main.c @@ -3,7 +3,7 @@ * The main entry point for the mono executable * * The main entry point does a few things: - * + * * * It probes whether the executable has a bundle appended * at the end, and if so, registers the various bundled * resources with Mono and executes the contained bundle @@ -90,7 +90,7 @@ mono_main_with_options (int argc, char *argv []) * "config:NAME" A configuration file (usually file.dll.config) in the payload that is * loaded as the config file for an assembly * "systemconfig:" Treats as a Mono system configuration, payload contains the config file. - * "options:" The payload contains command line options to initialize Mono, as if you + * "options:" The payload contains command line options to initialize Mono, as if you had set them on MONO_ENV_OPTIONS * "config_dir:DIR" Configures the MONO_PATH to point to point to DIR * "machineconfig:" The payload contains the machine.config file to use at runtime @@ -269,7 +269,7 @@ probe_embedded (const char *program, int *ref_argc, char **ref_argv []) p += 8; item_size = STREAM_INT (p); p += 4; - + if (mapaddress == NULL) { char *error_message = NULL; mapaddress = (guchar*)mono_file_map_error (directory_location - offset, MONO_MMAP_READ | MONO_MMAP_PRIVATE, @@ -323,9 +323,9 @@ probe_embedded (const char *program, int *ref_argc, char **ref_argv []) new_argv [j+1] = (*ref_argv)[j]; *ref_argv = new_argv; (*ref_argc)++; - + return TRUE; - + dofree: g_free (directory); doclose: diff --git a/src/mono/mono/mini/memory-access.c b/src/mono/mono/mini/memory-access.c index 51c748c9bbfdb..4af7668fe83d9 100644 --- a/src/mono/mono/mini/memory-access.c +++ b/src/mono/mono/mini/memory-access.c @@ -20,7 +20,7 @@ #define MAX_INLINE_COPIES 16 #define MAX_INLINE_COPY_SIZE 10000 -void +void mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align) { int val_reg; @@ -109,7 +109,7 @@ mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, } } -void +void mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align) { int cur_reg; diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index d6ef76676cfb4..7a5f5db4fab6e 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -220,7 +220,7 @@ mini_ins_info[] = { #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)), #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))), -/* +/* * This should contain the index of the last sreg + 1. This is not the same * as the number of sregs for opcodes like IA64_CMP_EQ_IMM. */ @@ -325,7 +325,7 @@ mono_type_to_regmove (MonoCompile *cfg, MonoType *type) case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: + case MONO_TYPE_ARRAY: return OP_MOVE; case MONO_TYPE_I8: case MONO_TYPE_U8: @@ -450,7 +450,7 @@ mini_set_inline_failure (MonoCompile *cfg, const char *msg) } /* - * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. + * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. * foo (int i) { ldarg.0; box T; } */ #define UNVERIFIED do { \ @@ -729,7 +729,7 @@ mono_find_leave_clauses (MonoCompile *cfg, guchar *ip, guchar *target) for (i = 0; i < header->num_clauses; ++i) { clause = &header->clauses [i]; - if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && + if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) { MonoLeaveClause *leave = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoLeaveClause)); leave->index = i; @@ -820,7 +820,7 @@ mini_type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst) case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: + case MONO_TYPE_ARRAY: inst->type = STACK_OBJ; return; case MONO_TYPE_I8: @@ -884,7 +884,7 @@ bin_num_table [STACK_MAX] [STACK_MAX] = { {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4} }; -static const char +static const char neg_table [] = { STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4 }; @@ -1029,7 +1029,7 @@ type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2) case OP_ICOMPARE_IMM: ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV; if ((src1->type == STACK_I8) || ((TARGET_SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP)))) - ins->opcode = OP_LCOMPARE_IMM; + ins->opcode = OP_LCOMPARE_IMM; break; case MONO_CEE_BEQ: case MONO_CEE_BGE: @@ -1081,7 +1081,7 @@ type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2) ins->opcode = OP_ICONV_TO_R_UN; break; case STACK_I8: - ins->opcode = OP_LCONV_TO_R_UN; + ins->opcode = OP_LCONV_TO_R_UN; break; case STACK_R4: ins->opcode = OP_RCONV_TO_R8; @@ -1167,7 +1167,7 @@ type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2) ins->opcode += unops_op_map [src1->type]; break; case OP_CKFINITE: - ins->type = STACK_R8; + ins->type = STACK_R8; break; case MONO_CEE_CONV_U2: case MONO_CEE_CONV_U1: @@ -1330,7 +1330,7 @@ check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignatu #endif /* - * The got_var contains the address of the Global Offset Table when AOT + * The got_var contains the address of the Global Offset Table when AOT * compiling. */ MonoInst * @@ -1415,7 +1415,7 @@ mini_type_to_stack_type (MonoCompile *cfg, MonoType *t) case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: + case MONO_TYPE_ARRAY: return STACK_OBJ; case MONO_TYPE_I8: case MONO_TYPE_U8: @@ -1492,7 +1492,7 @@ mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins) type = type_from_stack_type (ins); - /* inlining can result in deeper stacks */ + /* inlining can result in deeper stacks */ if (cfg->inline_depth || slot >= cfg->header->max_stack) return mono_compile_create_var (cfg, type, OP_LOCAL); @@ -1519,7 +1519,7 @@ mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins) static void mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key) { - /* + /* * Don't use this if a generic_context is set, since that means AOT can't * look up the method using just the image+token. * table == 0 means this is a reference made from a wrapper. @@ -1577,13 +1577,13 @@ handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count) if (!found) { bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count); for (i = 0; i < count; ++i) { - /* + /* * try to reuse temps already allocated for this purpouse, if they occupy the same * stack slot and if they are of the same type. - * This won't cause conflicts since if 'local' is used to + * This won't cause conflicts since if 'local' is used to * store one of the values in the in_stack of a bblock, then - * the same variable will be used for the same outgoing stack - * slot as well. + * the same variable will be used for the same outgoing stack + * slot as well. * This doesn't work when inlining methods, since the bblocks * in the inlined methods do not inherit their in_stack from * the bblock they are inlined to. See bug #58863 for an @@ -1623,7 +1623,7 @@ handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count) /* * It is possible that the out bblocks already have in_stack assigned, and - * the in_stacks differ. In this case, we will store to all the different + * the in_stacks differ. In this case, we will store to all the different * in_stacks. */ @@ -1880,7 +1880,7 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg) case MONO_TYPE_I: case MONO_TYPE_U: case MONO_TYPE_FNPTR: - /* + /* * Some opcodes like ldloca returns 'transient pointers' which can be stored in * in native int. (#688008). */ @@ -1891,7 +1891,7 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg) case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: + case MONO_TYPE_ARRAY: if (arg->type != STACK_OBJ) return 1; /* FIXME: check type compatibility */ @@ -2051,7 +2051,7 @@ check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **arg case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: + case MONO_TYPE_ARRAY: if (args [i]->type != STACK_OBJ) return TRUE; continue; @@ -2224,7 +2224,7 @@ mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo * } return mono_emit_jit_icall_id (cfg, mono_jit_icall_info_id (info), args); } - + static MonoInst* mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig) { @@ -2232,8 +2232,8 @@ mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature * if ((fsig->pinvoke || LLVM_ENABLED) && !m_type_is_byref (fsig->ret)) { int widen_op = -1; - /* - * Native code might return non register sized integers + /* + * Native code might return non register sized integers * without initializing the upper bits. */ switch (mono_type_to_load_membase (cfg, fsig->ret)) { @@ -2543,7 +2543,7 @@ emit_get_rgctx (MonoCompile *cfg, int context_used) /* We are passed a this pointer, return this->vtable */ EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, mono_get_object_type ()); - + vtable_reg = alloc_preg (cfg); EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable)); return ins; @@ -3046,14 +3046,14 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, (gssize)vtable); } } - + MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException"); mini_reset_cast_details (cfg); } /** - * Handles unbox of a Nullable. If context_used is non zero, then shared + * Handles unbox of a Nullable. If context_used is non zero, then shared * generic code is generated. */ static MonoInst* @@ -3119,7 +3119,7 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use /* FIXME: generics */ g_assert (m_class_get_rank (klass) == 0); - + // Check rank == 0 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0); MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException"); @@ -3303,10 +3303,10 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_ return mono_emit_jit_icall_id (cfg, alloc_ftn, iargs); } - + /* * Returns NULL and set the cfg exception on error. - */ + */ MonoInst* mini_emit_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used) { @@ -3383,7 +3383,7 @@ mini_emit_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_us res->type = STACK_OBJ; res->klass = klass; MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb); - + /* Ref case */ MONO_START_BB (cfg, is_ref_bb); @@ -3607,7 +3607,7 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono } } - /* + /* * To avoid looking up the compiled code belonging to the target method * in mono_delegate_trampoline (), we allocate a per-domain memory slot to * store it, and we fill it after the method has been compiled. @@ -3842,7 +3842,7 @@ mono_emit_load_got_addr (MonoCompile *cfg) cfg->got_var_allocated = TRUE; - /* + /* * Add a dummy use to keep the got_var alive, since real uses might * only be generated by the back ends. * Add it to end_bblock, so the variable's lifetime covers the whole @@ -4056,7 +4056,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method) if (method_does_not_return (method)) return FALSE; - + return TRUE; } @@ -4169,7 +4169,7 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono return ins; } -#endif +#endif add_reg = alloc_ireg_mp (cfg); @@ -4235,21 +4235,21 @@ mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono #endif /* range checking */ - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds)); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound)); MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length)); MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg); MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound)); MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length)); MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg); MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); @@ -4387,7 +4387,7 @@ mini_emit_memory_barrier (MonoCompile *cfg, int kind) * redirection. */ inline static MonoInst* -mini_redirect_call (MonoCompile *cfg, MonoMethod *method, +mini_redirect_call (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins) { if (method->klass == mono_defaults.string_class) { @@ -4424,7 +4424,7 @@ mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp) * FIXME: We should use *args++ = sp [0], but that would mean the arg * would be different than the MonoInst's used to represent arguments, and * the ldelema implementation can't deal with that. - * Solution: When ldelema is used on an inline argument, create a var for + * Solution: When ldelema is used on an inline argument, create a var for * it, emit ldelema on that var, and emit the saving code below in * inline_method () if needed. */ @@ -4446,7 +4446,7 @@ check_inline_called_method_name_limit (MonoMethod *called_method) { int strncmp_result; static const char *limit = NULL; - + if (limit == NULL) { const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT"); @@ -4461,7 +4461,7 @@ check_inline_called_method_name_limit (MonoMethod *called_method) strncmp_result = strncmp (called_method_name, limit, strlen (limit)); g_free (called_method_name); - + //return (strncmp_result <= 0); return (strncmp_result == 0); } else { @@ -4476,7 +4476,7 @@ check_inline_caller_method_name_limit (MonoMethod *caller_method) { int strncmp_result; static const char *limit = NULL; - + if (limit == NULL) { const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT"); if (limit_string != NULL) { @@ -4491,7 +4491,7 @@ check_inline_caller_method_name_limit (MonoMethod *caller_method) strncmp_result = strncmp (caller_method_name, limit, strlen (limit)); g_free (caller_method_name); - + //return (strncmp_result <= 0); return (strncmp_result == 0); } else { @@ -4731,7 +4731,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, prev_cbb->next_bb = sbblock; link_bblock (cfg, prev_cbb, sbblock); - /* + /* * Get rid of the begin and end bblocks if possible to aid local * optimizations. */ @@ -4756,7 +4756,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, cfg->cbb = ebblock; } } else { - /* + /* * Its possible that the rvar is set in some prev bblock, but not in others. * (#1835). */ @@ -4779,7 +4779,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, if (rvar) { /* - * If the inlined method contains only a throw, then the ret var is not + * If the inlined method contains only a throw, then the ret var is not * set, so set it to a dummy value. */ if (!ret_var_set) @@ -4808,16 +4808,16 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, /* * Some of these comments may well be out-of-date. - * Design decisions: we do a single pass over the IL code (and we do bblock + * Design decisions: we do a single pass over the IL code (and we do bblock * splitting/merging in the few cases when it's required: a back jump to an IL * address that was not already seen as bblock starting point). * Code is validated as we go (full verification is still better left to metadata/verify.c). - * Complex operations are decomposed in simpler ones right away. We need to let the - * arch-specific code peek and poke inside this process somehow (except when the + * Complex operations are decomposed in simpler ones right away. We need to let the + * arch-specific code peek and poke inside this process somehow (except when the * optimizations can take advantage of the full semantic info of coarse opcodes). * All the opcodes of the form opcode.s are 'normalized' to opcode. - * MonoInst->opcode initially is the IL opcode or some simplification of that - * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific + * MonoInst->opcode initially is the IL opcode or some simplification of that + * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific * opcode with value bigger than OP_LAST. * At this point the IR can be handed over to an interpreter, a dumb code generator * or to the optimizing code generator that will translate it to SSA form. @@ -4825,7 +4825,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, * Profiling directed optimizations. * We may compile by default with few or no optimizations and instrument the code * or the user may indicate what methods to optimize the most either in a config file - * or through repeated runs where the compiler applies offline the optimizations to + * or through repeated runs where the compiler applies offline the optimizations to * each method and then decides if it was worth it. */ @@ -4867,7 +4867,7 @@ get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, opcode = &mono_opcodes [i]; switch (opcode->argument) { case MonoInlineNone: - ip++; + ip++; break; case MonoInlineString: case MonoInlineType: @@ -4907,7 +4907,7 @@ get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, cli_addr += 5 + 4 * n; target = start + cli_addr; GET_BBLOCK (cfg, bblock, target); - + for (j = 0; j < n; ++j) { target = start + cli_addr + (gint32)read32 (ip); GET_BBLOCK (cfg, bblock, target); @@ -4925,7 +4925,7 @@ get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, if (i == CEE_THROW) { guchar *bb_start = ip - 1; - + /* Find the start of the bblock containing the throw */ bblock = NULL; while ((bb_start >= start) && !bblock) { @@ -4998,7 +4998,7 @@ mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *conte } /* - * Return the original method is a wrapper is specified. We can only access + * Return the original method is a wrapper is specified. We can only access * the custom attributes from the original method. */ static MonoMethod* @@ -5154,7 +5154,7 @@ initialize_array_data (MonoCompile *cfg, MonoMethod *method, gboolean aot, gucha if (aot && data_ptr) data_ptr = (const char *)GUINT_TO_POINTER (rva); } else { - /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ + /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ g_assert (!aot); data_ptr = mono_field_get_data (field); } @@ -5263,7 +5263,7 @@ emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n) if (!cfg->deopt && (opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0] && ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) { /* Optimize reg-reg moves away */ - /* + /* * Can't optimize other opcodes, since sp[0] might point to * the last ins of a decomposed opcode. */ @@ -6105,7 +6105,7 @@ mono_opcode_decode (guchar *ip, guint op_size, MonoOpcodeEnum il_op, MonoOpcodeP * * @start_bblock: if not NULL, the starting basic block, used during inlining. * @end_bblock: if not NULL, the ending basic block, used during inlining. - * @return_var: if not NULL, the place where the return value is stored, used during inlining. + * @return_var: if not NULL, the place where the return value is stored, used during inlining. * @inline_args: if not NULL, contains the arguments to the inline call * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise. * @is_virtual_call: whether this method is being called as a result of a call to callvirt @@ -6115,12 +6115,12 @@ mono_opcode_decode (guchar *ip, guint op_size, MonoOpcodeEnum il_op, MonoOpcodeP * inlining existing methods. In the former case, the @start_bblock, * @end_bblock, @return_var, @inline_args are all set to NULL, and the * inline_offset is set to zero. - * + * * Returns: the inline cost, or -1 if there was an error processing this method. */ int -mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, - MonoInst *return_var, MonoInst **inline_args, +mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, + MonoInst *return_var, MonoInst **inline_args, guint inline_offset, gboolean is_virtual_call) { ERROR_DECL (error); @@ -6251,7 +6251,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } } - /* + /* * Methods without init_locals set could cause asserts in various passes * (#497220). To work around this, we emit dummy initialization opcodes * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported @@ -6348,7 +6348,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) mono_create_exvar_for_offset (cfg, clause->handler_offset); /* - * Linking the try block with the EH block hinders inlining as we won't be able to + * Linking the try block with the EH block hinders inlining as we won't be able to * merge the bblocks from inlining and produce an artificial hole for no good reason. */ if (COMPILE_LLVM (cfg)) @@ -6401,7 +6401,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b #else MonoInst *dummy_use; - /* + /* * Add a dummy use for the exvar so its liveness info will be * correct. */ @@ -6543,7 +6543,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b ins->sreg1 = dreg; MONO_ADD_INS (cfg->cbb, ins); cfg->gsharedvt_locals_var_ins = ins; - + cfg->flags |= MONO_CFG_HAS_ALLOCA; /* if (init_locals) @@ -7014,7 +7014,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_ADD_INS (cfg->cbb, ins); } *f = parameter.f; - *sp++ = ins; + *sp++ = ins; break; } case MONO_CEE_LDC_R8: { @@ -7092,7 +7092,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* FIXME: check the signature matches */ cmethod = mini_get_method (cfg, method, token, NULL, generic_context); CHECK_CFG_ERROR; - + if (cfg->gshared && mono_method_check_context_used (cmethod)) GENERIC_SHARING_FAILURE (CEE_JMP); @@ -7551,7 +7551,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoBasicBlock *tbb; GET_BBLOCK (cfg, tbb, next_ip); - /* + /* * Only extend try blocks with a finally, to avoid catching exceptions thrown * from Monitor.Enter like ArgumentNullException. */ @@ -7576,7 +7576,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } CHECK_CFG_ERROR; - /* + /* * If the callee is a shared method, then its static cctor * might not get called after the call was patched. */ @@ -7678,8 +7678,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b g_assert (!vtable_arg); if (!cfg->compile_aot) { - /* - * emit_get_rgctx_method () calls mono_class_vtable () so check + /* + * emit_get_rgctx_method () calls mono_class_vtable () so check * for type load errors before. */ mono_class_setup_vtable (cmethod->klass); @@ -8013,7 +8013,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (array_rank) { MonoInst *addr; - if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ + if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ MonoInst *val = sp [fsig->param_count]; if (val->type == STACK_OBJ) { @@ -8199,7 +8199,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } ins_flag = 0; constrained_class = NULL; - + if (need_seq_point) { //check is is a nested call and remove the non_empty_stack of the last call, only for non native methods if (!(method->flags & METHOD_IMPL_ATTRIBUTE_NATIVE)) { @@ -8222,10 +8222,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (cfg->method != method) { /* return from inlined method */ - /* + /* * If in_count == 0, that means the ret is unreachable due to * being preceded by a throw. In that case, inline_method () will - * handle setting the return value + * handle setting the return value * (test case: test_0_inline_throw ()). */ if (return_var && cfg->cbb->in_count) { @@ -8242,7 +8242,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b //g_assert (returnvar != -1); EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp); cfg->ret_var_set = TRUE; - } + } } else { if (cfg->lmf_var && cfg->cbb->in_count && (!cfg->llvm_only || cfg->deopt)) emit_pop_lmf (cfg); @@ -8251,7 +8251,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoType *ret_type = mini_get_underlying_type (mono_method_signature_internal (method)->ret); if (seq_points && !sym_seq_points) { - /* + /* * Place a seq point here too even through the IL stack is not * empty, so a step over on * call @@ -8415,7 +8415,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b n = read32 (ip + 1); --sp; src1 = sp [0]; - if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) + if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) UNVERIFIED; ip += 5; @@ -8432,7 +8432,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } if (sp != stack_start) { - /* + /* * Link the current bb with the targets as well, so handle_stack_args * will set their in_stack correctly. */ @@ -8843,8 +8843,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoInst *iargs [2]; if (image == mono_defaults.corlib) { - /* - * Avoid relocations in AOT and save some space by using a + /* + * Avoid relocations in AOT and save some space by using a * version of helper_ldstr specialized to mscorlib. */ EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n)); @@ -8855,13 +8855,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n)); *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs); } - } + } else if (cfg->compile_aot) { NEW_LDSTRCONST (cfg, ins, image, n); *sp = ins; MONO_ADD_INS (cfg->cbb, ins); - } + } else { NEW_PCONST (cfg, ins, NULL); ins->type = STACK_OBJ; @@ -8930,13 +8930,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b n = fsig->param_count; CHECK_STACK (n); - /* + /* * Generate smaller code for the common newobj instruction in * argument checking code. */ if (cfg->cbb->out_of_line && m_class_get_image (cmethod->klass) == mono_defaults.corlib && is_exception_class (cmethod->klass) && n <= 2 && - ((n < 1) || (!m_type_is_byref (fsig->params [0]) && fsig->params [0]->type == MONO_TYPE_STRING)) && + ((n < 1) || (!m_type_is_byref (fsig->params [0]) && fsig->params [0]->type == MONO_TYPE_STRING)) && ((n < 2) || (!m_type_is_byref (fsig->params [1]) && fsig->params [1]->type == MONO_TYPE_STRING))) { MonoInst *iargs [3]; @@ -9047,7 +9047,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b g_assert (!context_used); g_assert (!vtable_arg); /* we simply pass a null pointer */ - EMIT_NEW_PCONST (cfg, *sp, NULL); + EMIT_NEW_PCONST (cfg, *sp, NULL); /* now call the string ctor */ alloc = mini_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL); } else { @@ -9058,7 +9058,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b alloc = NULL; - /* + /* * The code generated by mini_emit_virtual_call () expects * iargs [0] to be a boxed instance, but luckily the vcall * will be transformed into a normal call there. @@ -9113,7 +9113,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } else { *sp++ = alloc; } - + inline_costs += 5; if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, next_ip - header->code))) emit_seq_point (cfg, method, next_ip, FALSE, TRUE); @@ -9278,8 +9278,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } // Optimize - // - // box + // + // box // call object::GetType() // guint32 gettype_token; @@ -9297,7 +9297,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } ins->type = STACK_OBJ; ins->klass = mono_defaults.systemtype_class; - *sp++ = ins; + *sp++ = ins; next_ip = ip; break; } @@ -9305,13 +9305,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } // Optimize - // + // // box // ldnull // ceq (or cgt.un) - // + // // to just - // + // // ldc.i4.0 (or 1) guchar* ldnull_ip; if ((ldnull_ip = il_read_op (next_ip, end, CEE_LDNULL, MONO_CEE_LDNULL)) && ip_in_bb (cfg, cfg->cbb, ldnull_ip)) { @@ -9321,7 +9321,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b else if ((ip = il_read_op (ldnull_ip, end, CEE_PREFIX1, MONO_CEE_CGT_UN))) is_neq = TRUE; - if ((is_eq || is_neq) && ip_in_bb (cfg, cfg->cbb, ip) && + if ((is_eq || is_neq) && ip_in_bb (cfg, cfg->cbb, ip) && !mono_class_is_nullable (klass) && !mini_is_gsharedvt_klass (klass)) { next_ip = ip; il_op = (MonoOpcodeEnum) (is_eq ? CEE_LDC_I4_0 : CEE_LDC_I4_1); @@ -9331,7 +9331,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b break; } } - + guint32 isinst_tk = 0; if ((ip = il_read_op_and_token (next_ip, end, CEE_ISINST, MONO_CEE_ISINST, &isinst_tk)) && ip_in_bb (cfg, cfg->cbb, ip)) { @@ -9342,13 +9342,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b !mono_class_is_open_constructed_type (m_class_get_byval_arg (isinst_class))) { // Optimize - // + // // box // isinst [Type] // brfalse/brtrue - // + // // to - // + // // ldc.i4.0 (or 1) // brfalse/brtrue // @@ -9366,14 +9366,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } // Optimize - // + // // box // isinst [Type] // ldnull // ceq/cgt.un - // + // // to - // + // // ldc.i4.0 (or 1) // guchar* ldnull_ip = NULL; @@ -9384,7 +9384,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b else if ((ip = il_read_op (ldnull_ip, end, CEE_PREFIX1, MONO_CEE_CGT_UN))) is_neq = TRUE; - if ((is_eq || is_neq) && ip_in_bb (cfg, cfg->cbb, ip) && + if ((is_eq || is_neq) && ip_in_bb (cfg, cfg->cbb, ip) && !mono_class_is_nullable (klass) && !mini_is_gsharedvt_klass (klass)) { gboolean isinst = mono_class_is_assignable_from_internal (isinst_class, klass); next_ip = ip; @@ -9399,13 +9399,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } // Optimize - // + // // box // isinst [Type] // unbox.any - // + // // to - // + // // nop // guchar* unbox_ip = NULL; @@ -9448,7 +9448,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b printf ("\n"); } - /* + /* * We need to link both bblocks, since it is needed for handling stack * arguments correctly (See test_0_box_brtrue_opt_regress_81102). * Branching to only one of them would lead to inconsistencies, so @@ -9968,7 +9968,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b case MONO_TYPE_I1: EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr)); sp++; - break; + break; case MONO_TYPE_CHAR: case MONO_TYPE_U2: EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr)); @@ -9982,7 +9982,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b case MONO_TYPE_I4: EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr)); sp++; - break; + break; case MONO_TYPE_U4: EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr)); sp++; @@ -10134,7 +10134,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b *sp++ = ins; inline_costs += 1; - /* + /* * we inline/optimize the initialization sequence if possible. * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing * for small sizes open code the memcpy @@ -10515,7 +10515,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_INST_NEW (cfg, ins, OP_NOT_REACHED); MONO_ADD_INS (cfg->cbb, ins); sp = stack_start; - + link_bblock (cfg, cfg->cbb, end_bblock); start_new_bblock = 1; /* This can complicate code generation for llvm since the return value might not be defined */ @@ -10549,7 +10549,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b g_assert (sp >= stack_start); sp = stack_start; - /* + /* * If this leave statement is in a catch block, check for a * pending exception, and rethrow it if necessary. * We avoid doing this in runtime invoke wrappers, since those are called @@ -10558,7 +10558,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b for (i = 0; i < header->num_clauses; ++i) { MonoExceptionClause *clause = &header->clauses [i]; - /* + /* * Use <= in the final comparison to handle clauses with multiple * leave statements, like in bug #78024. * The ordering of the exception clauses guarantees that we find the @@ -10579,9 +10579,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b NEW_BBLOCK (cfg, dont_throw); /* - * Currently, we always rethrow the abort exception, despite the - * fact that this is not correct. See thread6.cs for an example. - * But propagating the abort exception is more important than + * Currently, we always rethrow the abort exception, despite the + * fact that this is not correct. See thread6.cs for an example. + * But propagating the abort exception is more important than * getting the semantics right. */ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0); @@ -10645,7 +10645,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (COMPILE_LLVM (cfg)) { MonoBasicBlock *target_bb; - /* + /* * Link the finally bblock with the target, since it will * conceptually branch there. */ @@ -10654,7 +10654,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b link_bblock (cfg, tblock, target_bb); } } - } + } MONO_INST_NEW (cfg, ins, OP_BR); MONO_ADD_INS (cfg->cbb, ins); @@ -11167,7 +11167,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b case MONO_CEE_ARGLIST: { /* somewhat similar to LDTOKEN */ MonoInst *addr, *vtvar; - vtvar = mono_compile_create_var (cfg, m_class_get_byval_arg (mono_defaults.argumenthandle_class), OP_LOCAL); + vtvar = mono_compile_create_var (cfg, m_class_get_byval_arg (mono_defaults.argumenthandle_class), OP_LOCAL); EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0); EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg); @@ -11767,7 +11767,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b g_free (mname); } - if ((cfg->verbose_level > 2) && (cfg->method == method)) + if ((cfg->verbose_level > 2) && (cfg->method == method)) mono_print_code (cfg, "AFTER METHOD-TO-IR"); goto cleanup; @@ -11778,7 +11778,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b g_assert (!is_ok (cfg->error)); goto cleanup; - + exception_exit: if (cfg->verbose_level > 3) g_print ("exiting due to exception"); @@ -11822,7 +11822,7 @@ store_membase_reg_to_store_membase_imm (int opcode) } return -1; -} +} int mono_op_to_op_imm (int opcode) @@ -12128,7 +12128,7 @@ op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode) #ifdef TARGET_X86 if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))) return -1; - + switch (opcode) { case OP_COMPARE: case OP_ICOMPARE: @@ -12300,7 +12300,7 @@ mono_handle_global_vregs (MonoCompile *cfg) /* Find local vregs used in more than one bb */ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { - MonoInst *ins = bb->code; + MonoInst *ins = bb->code; int block_num = bb->block_num; if (cfg->verbose_level > 2) @@ -12439,7 +12439,7 @@ mono_handle_global_vregs (MonoCompile *cfg) /* Putting R4 vars into registers doesn't work currently */ /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */ if ((var->opcode != OP_ARG) && (var != cfg->ret) && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && (vreg_to_bb [var->dreg] != -1) && (m_class_get_byval_arg (var->klass)->type != MONO_TYPE_R4) && !cfg->disable_vreg_to_lvreg && var != cfg->gsharedvt_info_var && var != cfg->gsharedvt_locals_var && var != cfg->lmf_addr_var) { - /* + /* * Make that the variable's liveness interval doesn't contain a call, since * that would cause the lvreg to be spilled, making the whole optimization * useless. @@ -12488,7 +12488,7 @@ mono_handle_global_vregs (MonoCompile *cfg) } } - /* + /* * Compress the varinfo and vars tables so the liveness computation is faster and * takes up less space. */ @@ -12559,7 +12559,7 @@ mono_allocate_gsharedvt_vars (MonoCompile *cfg) /** * mono_spill_global_vars: * - * Generate spill code for variables which are not allocated to registers, + * Generate spill code for variables which are not allocated to registers, * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if * code is generated which could be optimized by the local optimization passes. */ @@ -12634,11 +12634,11 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) ins->flags |= MONO_INST_GC_TRACK; } } - + /* FIXME: widening and truncation */ /* - * As an optimization, when a variable allocated to the stack is first loaded into + * As an optimization, when a variable allocated to the stack is first loaded into * an lvreg, we will remember the lvreg and use it the next time instead of loading * the variable again. */ @@ -12648,7 +12648,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * lvregs_size); lvregs_len = 0; - /* + /* * These arrays contain the first and last instructions accessing a given * variable. * Since we emit bblocks in the same order we process them here, and we @@ -12665,7 +12665,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) live_range_end = g_new0 (MonoInst*, cfg->next_vreg); live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg); live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg); - + /* Add spill loads/stores */ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { MonoInst *ins; @@ -12691,7 +12691,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) if (ins->opcode == OP_NOP) continue; - /* + /* * We handle LDADDR here as well, since it can only be decomposed * when variable addresses are known. */ @@ -12835,7 +12835,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) if (var->opcode == OP_REGVAR) { ins->dreg = var->dreg; } else if ((ins->dreg == ins->sreg1) && (spec [MONO_INST_DEST] == 'i') && (spec [MONO_INST_SRC1] == 'i') && !vreg_to_lvreg [ins->dreg] && (op_to_op_dest_membase (store_opcode, ins->opcode) != -1)) { - /* + /* * Instead of emitting a load+store, use a _membase opcode. */ g_assert (var->opcode == OP_REGOFFSET); @@ -12924,7 +12924,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) def_ins = store_ins; - /* + /* * We can't assign ins->dreg to var->dreg here, since the * sregs could use it. So set a flag, and do it after * the sregs. @@ -13142,7 +13142,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) } } } - + /* * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them * by storing the current native offset into MonoMethodVar->live_range_start/end. @@ -13199,7 +13199,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) * - get rid of TEMPLOADs if possible and use vregs instead * - clean up usage of OP_P/OP_ opcodes * - cleanup usage of DUMMY_USE - * - cleanup the setting of ins->type for MonoInst's which are pushed on the + * - cleanup the setting of ins->type for MonoInst's which are pushed on the * stack * - set the stack type and allocate a dreg in the EMIT_NEW macros * - get rid of all the 2 stuff when the new JIT is ready. @@ -13211,7 +13211,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) * - most back ends unify fp compare+branch, fp compare+ceq * - integrate mono_save_args into inline_method * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2 - * - handle long shift opts on 32 bit platforms somehow: they require + * - handle long shift opts on 32 bit platforms somehow: they require * 3 sregs (2 for arg1 and 1 for arg2) * - make byref a 'normal' type. * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a @@ -13232,7 +13232,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) * - promote RuntimeXHandles to vregs * - vtype cleanups: * - add a NEW_VARLOADA_VREG macro - * - the vtype optimizations are blocked by the LDADDR opcodes generated for + * - the vtype optimizations are blocked by the LDADDR opcodes generated for * accessing vtype fields. * - get rid of I8CONST on 64 bit platforms * - dealing with the increase in code size due to branches created during opcode @@ -13255,7 +13255,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts) * specific function. * - unify the float comparison opcodes with the other comparison opcodes, i.e. * fcompare + branchCC. - * - create a helper function for allocating a stack slot, taking into account + * - create a helper function for allocating a stack slot, taking into account * MONO_CFG_HAS_SPILLUP. * - merge r68207. * - optimize mono_regstate2_alloc_int/float. @@ -13281,8 +13281,8 @@ NOTES no longer contains the necessary information. But it is easier to do. - later: harder to implement, enables more optimizations. - Branches inside bblocks: - - created when decomposing complex opcodes. - - branches to another bblock: harmless, but not tracked by the branch + - created when decomposing complex opcodes. + - branches to another bblock: harmless, but not tracked by the branch optimizations, so need to branch to a label at the start of the bblock. - branches to inside the same bblock: very problematic, trips up the local reg allocator. Can be fixed by spitting the current bblock, but that is a @@ -13297,7 +13297,7 @@ NOTES - earlier -> saves work later on since the IR will be smaller/simpler - later -> can work on more instructions - Handling of valuetypes: - - When a vtype is pushed on the stack, a new temporary is created, an + - When a vtype is pushed on the stack, a new temporary is created, an instruction computing its address (LDADDR) is emitted and pushed on the stack. Need to optimize cases when the vtype is used immediately as in argument passing, stloc etc. diff --git a/src/mono/mono/mini/mini-amd64-gsharedvt.c b/src/mono/mono/mini/mini-amd64-gsharedvt.c index 77fc0e3b89189..b2a202195ca58 100644 --- a/src/mono/mono/mini/mini-amd64-gsharedvt.c +++ b/src/mono/mono/mini/mini-amd64-gsharedvt.c @@ -62,7 +62,7 @@ arg_info_desc (ArgInfo *info) g_string_append_printf (str, "offset %d reg %s storage %s nregs %d", info->offset, mono_arch_regname (info->reg), storage_name (info->storage), info->nregs); if (info->storage == ArgValuetypeInReg) - g_string_append_printf (str, " {(%s %s), (%s %s)", + g_string_append_printf (str, " {(%s %s), (%s %s)", storage_name (info->pair_storage [0]), mono_arch_regname (info->pair_regs [0]), storage_name (info->pair_storage [1]), @@ -432,7 +432,7 @@ mono_arch_get_gsharedvt_call_info (MonoMemoryManager *mem_manager, gpointer addr #ifdef DEBUG_AMD64_GSHAREDVT printf ("final map:\n"); for (i = 0; i < map->len; i += 2) { - printf ("\t[%d] src %x dst %x\n ", + printf ("\t[%d] src %x dst %x\n ", i / 2, GPOINTER_TO_UINT (g_ptr_array_index (map, i)), GPOINTER_TO_UINT (g_ptr_array_index (map, i + 1))); diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 7e1f5a879ea6e..72c5d1e34060e 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -100,7 +100,7 @@ mono_arch_regname (int reg) case AMD64_RBX: return "%rbx"; case AMD64_RCX: return "%rcx"; case AMD64_RDX: return "%rdx"; - case AMD64_RSP: return "%rsp"; + case AMD64_RSP: return "%rsp"; case AMD64_RBP: return "%rbp"; case AMD64_RDI: return "%rdi"; case AMD64_RSI: return "%rsi"; @@ -505,7 +505,7 @@ allocate_storage_for_valuetype_win64 (ArgInfo *arg_info, MonoType *type, gboolea if (!allocate_parameter_register_for_valuetype_win64 (arg_info, !MONO_TYPE_ISSTRUCT (type) ? arg_class : ARG_CLASS_INTEGER, arg_size, current_int_reg, current_float_reg)) { /* No more registers, fallback passing parameter on stack as value. */ assert (arg_info->pair_storage [0] == ArgNone && arg_info->pair_storage [1] == ArgNone && arg_info->pair_size [0] == 0 && arg_info->pair_size [1] == 0 && arg_info->nregs == 0); - + /* Passing value directly on stack, so use size of value. */ arg_info->storage = ArgOnStack; arg_size = ALIGN_TO (arg_size, sizeof (target_mgreg_t)); @@ -519,7 +519,7 @@ allocate_storage_for_valuetype_win64 (ArgInfo *arg_info, MonoType *type, gboolea if (!allocate_parameter_register_for_valuetype_win64 (arg_info, ARG_CLASS_INTEGER, arg_size, current_int_reg, current_float_reg)) { /* No more registers, fallback passing address to parameter on stack. */ assert (arg_info->pair_storage [0] == ArgNone && arg_info->pair_storage [1] == ArgNone && arg_info->pair_size [0] == 0 && arg_info->pair_size [1] == 0 && arg_info->nregs == 0); - + /* Passing an address to value on stack, so use size of register as argument size. */ arg_info->storage = ArgValuetypeAddrOnStack; arg_size = sizeof (target_mgreg_t); @@ -561,7 +561,7 @@ get_valuetype_size_win64 (MonoClass *klass, gboolean pinvoke, ArgInfo *arg_info, *arg_class = ARG_CLASS_NO_CLASS; assert (klass != NULL && arg_info != NULL && type != NULL && arg_class != NULL && arg_size != NULL); - + if (pinvoke) { /* Calculate argument class type and size of marshalled type. */ MonoMarshalType *info = mono_marshal_load_type_info (klass); @@ -602,7 +602,7 @@ add_valuetype_win64 (MonoMethodSignature *signature, ArgInfo *arg_info, MonoType guint32 arg_size = SIZEOF_REGISTER; MonoClass *klass = NULL; ArgumentClass arg_class; - + assert (signature != NULL && arg_info != NULL && type != NULL && current_int_reg != NULL && current_float_reg != NULL && stack_size != NULL); klass = mono_class_from_mono_type_internal (type); @@ -972,7 +972,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) { gr = PARAM_REGS; fr = FLOAT_PARAM_REGS; - + /* Emit the signature cookie just before the implicit arguments */ add_general (&gr, &stack_size, &cinfo->sig_cookie); } @@ -991,8 +991,8 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) { /* We allways pass the sig cookie on the stack for simplicity */ - /* - * Prevent implicit arguments + the sig cookie from being passed + /* + * Prevent implicit arguments + the sig cookie from being passed * in registers. */ gr = PARAM_REGS; @@ -1077,7 +1077,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) { gr = PARAM_REGS; fr = FLOAT_PARAM_REGS; - + /* Emit the signature cookie just before the implicit arguments */ add_general (&gr, &stack_size, &cinfo->sig_cookie); } @@ -1349,7 +1349,7 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo * @arg_info: an array to store the result infos * * Gathers information on parameters such as size, alignment and - * padding. arg_info should be large enought to hold param_count + 1 entries. + * padding. arg_info should be large enought to hold param_count + 1 entries. * * Returns the size of the argument area on the stack. */ @@ -1518,7 +1518,7 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg) if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos) continue; - if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || + if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG)) continue; @@ -1584,7 +1584,7 @@ mono_arch_compute_omit_fp (MonoCompile *cfg) ArgInfo *ainfo = &cinfo->args [i]; if (ainfo->storage == ArgOnStack || ainfo->storage == ArgValuetypeAddrInIReg || ainfo->storage == ArgValuetypeAddrOnStack) { - /* + /* * The stack offset can only be determined when the frame * size is known. */ @@ -1628,7 +1628,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* * mono_arch_regalloc_cost: * - * Return the cost, in number of memory references, of the action of + * Return the cost, in number of memory references, of the action of * allocating the variable VMV into a register during global register * allocation. */ @@ -1666,8 +1666,8 @@ mono_arch_fill_argument_info (MonoCompile *cfg) /* * Contrary to mono_arch_allocate_vars (), the information should describe - * where the arguments are at the beginning of the method, not where they can be - * accessed during the execution of the method. The later makes no sense for the + * where the arguments are at the beginning of the method, not where they can be + * accessed during the execution of the method. The later makes no sense for the * global register allocator, since a variable can be in more than one location. */ switch (cinfo->ret.storage) { @@ -1714,7 +1714,7 @@ mono_arch_fill_argument_info (MonoCompile *cfg) } } } - + void mono_arch_allocate_vars (MonoCompile *cfg) { @@ -1832,7 +1832,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->locals_min_stack_offset = - (offset + locals_stack_size); cfg->locals_max_stack_offset = - offset; } - + for (i = cfg->locals_start; i < cfg->num_varinfo; i++) { if (offsets [i] != -1) { MonoInst *ins = cfg->varinfo [i]; @@ -1863,7 +1863,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) inreg = FALSE; - /* + /* * Under AMD64, all registers used to pass arguments to functions * are volatile across calls. * FIXME: Optimize this. @@ -1910,10 +1910,10 @@ mono_arch_allocate_vars (MonoCompile *cfg) indir->inst_basereg = cfg->frame_reg; indir->inst_offset = ainfo->offset + ARGS_OFFSET; } - + ins->opcode = OP_VTARG_ADDR; ins->inst_left = indir; - + break; } default: @@ -2056,11 +2056,11 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) NOT_IMPLEMENTED; g_assert (cinfo->sig_cookie.storage == ArgOnStack); - + /* - * mono_ArgIterator_Setup assumes the signature cookie is + * mono_ArgIterator_Setup assumes the signature cookie is * passed first and all the arguments which were before it are - * passed on the stack after the signature. So compensate by + * passed on the stack after the signature. So compensate by * passing a different signature. */ tmp_sig = mono_metadata_signature_dup_full (m_class_get_image (cfg->method->klass), call->signature); @@ -2112,7 +2112,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) /* * LLVM always uses the native ABI while we use our own ABI, the * only difference is the handling of vtypes: - * - we only pass/receive them in registers in some cases, and only + * - we only pass/receive them in registers in some cases, and only * in 1 or 2 integer registers. */ switch (cinfo->ret.storage) { @@ -2228,7 +2228,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) return; } - /* + /* * Emit all arguments which are passed on the stack to prevent register * allocation problems. */ @@ -2460,7 +2460,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) MonoInst *vtaddr, *load; g_assert (ainfo->storage == ArgValuetypeAddrInIReg || (ainfo->storage == ArgValuetypeAddrOnStack && ainfo->pair_storage [0] == ArgNone)); - + vtaddr = mono_compile_create_var (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL); vtaddr->backend.is_pinvoke = call->signature->pinvoke && !call->signature->marshalling_disabled; @@ -2528,7 +2528,7 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg); return; } - + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg); } @@ -2591,7 +2591,7 @@ dyn_call_supported (MonoMethodSignature *sig, CallInfo *cinfo) /* * mono_arch_dyn_call_prepare: * - * Return a pointer to an arch-specific structure which contains information + * Return a pointer to an arch-specific structure which contains information * needed by mono_arch_get_dyn_call_args (). Return NULL if OP_DYN_CALL is not * supported for SIG. * This function is equivalent to ffi_prep_cif in libffi. @@ -2658,7 +2658,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) /* Align to 16 bytes */ if (info->nstack_args & 1) info->nstack_args ++; - + return (MonoDynCallInfo*)info; } @@ -2697,7 +2697,7 @@ mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info) * RET should point to a memory buffer large enought to hold the result of the * call. * This function should be as fast as possible, any work which does not depend - * on the actual values of the arguments should be done in + * on the actual values of the arguments should be done in * mono_arch_dyn_call_prepare (). * start_dyn_call + OP_DYN_CALL + finish_dyn_call is equivalent to ffi_call in * libffi. @@ -2909,7 +2909,7 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g * Store the result of a dyn call into the return value buffer passed to * start_dyn_call (). * This function should be as fast as possible, any work which does not depend - * on the actual values of the arguments should be done in + * on the actual values of the arguments should be done in * mono_arch_dyn_call_prepare (). */ void @@ -3014,7 +3014,7 @@ mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf) } else { \ EMIT_COND_BRANCH (tins, cond, signed); \ } \ - } while (0); + } while (0); #define EMIT_SSE2_FPFUNC(code, op, dreg, sreg1) do { \ amd64_movsd_membase_reg (code, AMD64_RSP, -8, (sreg1)); \ @@ -3045,7 +3045,7 @@ emit_call (MonoCompile *cfg, MonoCallInst *call, guint8 *code, MonoJitICallId ji patch.target = call->fptr; } - /* + /* * FIXME: Add support for thunks */ { @@ -3053,7 +3053,7 @@ emit_call (MonoCompile *cfg, MonoCallInst *call, guint8 *code, MonoJitICallId ji /* * Indirect calls are expensive so try to make a near call if possible. - * The caller memory is allocated by the code manager so it is + * The caller memory is allocated by the code manager so it is * guaranteed to be at a 32 bit offset. */ @@ -3073,7 +3073,7 @@ emit_call (MonoCompile *cfg, MonoCallInst *call, guint8 *code, MonoJitICallId ji /* The target is in malloc-ed memory */ near_call = FALSE; } else { - /* + /* * The call might go directly to a native function without * the wrapper. */ @@ -3095,7 +3095,7 @@ emit_call (MonoCompile *cfg, MonoCallInst *call, guint8 *code, MonoJitICallId ji near_call = TRUE; no_patch = TRUE; } else { - /* + /* * This is not really an optimization, but required because the * generic class init trampolines use R11 to pass the vtable. */ @@ -3144,7 +3144,7 @@ emit_call (MonoCompile *cfg, MonoCallInst *call, guint8 *code, MonoJitICallId ji } if (near_call) { - /* + /* * Align the call displacement to an address divisible by 4 so it does * not span cache lines. This is required for code patching to work on SMP * systems. @@ -3209,9 +3209,9 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IADD_IMM: case OP_LADD_IMM: if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS) && (ins->inst_imm > 0)) { - /* + /* * X86_LEA is like ADD, but doesn't have the - * sreg1==dreg restriction. inst_imm > 0 is needed since LEA sign-extends + * sreg1==dreg restriction. inst_imm > 0 is needed since LEA sign-extends * its operand to 64 bit. */ ins->opcode = ins->opcode == OP_IADD_IMM ? OP_X86_LEA_MEMBASE : OP_AMD64_LEA_MEMBASE; @@ -3223,8 +3223,8 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) if ((ins->sreg1 == ins->sreg2) && (ins->sreg1 == ins->dreg)) { MonoInst *ins2; - /* - * Replace STORE_MEMBASE_IMM 0 with STORE_MEMBASE_REG since + /* + * Replace STORE_MEMBASE_IMM 0 with STORE_MEMBASE_REG since * the latter has length 2-3 instead of 6 (reverse constant * propagation). These instruction sequences are very common * in the initlocals bblock. @@ -3248,9 +3248,9 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_COMPARE_IMM: case OP_LCOMPARE_IMM: - /* OP_COMPARE_IMM (reg, 0) - * --> - * OP_AMD64_TEST_NULL (reg) + /* OP_COMPARE_IMM (reg, 0) + * --> + * OP_AMD64_TEST_NULL (reg) */ if (!ins->inst_imm) ins->opcode = OP_AMD64_TEST_NULL; @@ -3260,7 +3260,7 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) ins->opcode = OP_X86_TEST_NULL; break; case OP_AMD64_ICOMPARE_MEMBASE_IMM: - /* + /* * OP_STORE_MEMBASE_REG reg, offset(basereg) * OP_X86_COMPARE_MEMBASE_IMM offset(basereg), imm * --> @@ -3310,7 +3310,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) } case OP_LXOR: /* - * Use IXOR to avoid a rex prefix if possible. The cpu will sign extend the + * Use IXOR to avoid a rex prefix if possible. The cpu will sign extend the * 0 result into 64 bits. */ if ((ins->sreg1 == ins->sreg2) && (ins->sreg1 == ins->dreg)) { @@ -3321,8 +3321,8 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) if ((ins->sreg1 == ins->sreg2) && (ins->sreg1 == ins->dreg)) { MonoInst *ins2; - /* - * Replace STORE_MEMBASE_IMM 0 with STORE_MEMBASE_REG since + /* + * Replace STORE_MEMBASE_IMM 0 with STORE_MEMBASE_REG since * the latter has length 2-3 instead of 6 (reverse constant * propagation). These instruction sequences are very common * in the initlocals bblock. @@ -3649,7 +3649,7 @@ emit_simd_gt_un_op (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, int typ case MONO_TYPE_U1: USE_MAX: { // dreg = max(sreg1, sreg2) != sreg2 - + int temp_reg1 = mono_alloc_ireg (cfg); int temp_reg2 = mono_alloc_ireg (cfg); int temp_reg3 = mono_alloc_ireg (cfg); @@ -3812,7 +3812,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) MonoInst *ins, *n, *temp; /* - * FIXME: Need to add more instructions, but the current machine + * FIXME: Need to add more instructions, but the current machine * description can't model some parts of the composite instructions like * cdq. */ @@ -4091,7 +4091,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) bb->max_vreg = cfg->next_vreg; } -static const int +static const int branch_cc_table [] = { X86_CC_EQ, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT, X86_CC_NE, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT, @@ -4197,19 +4197,19 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree) amd64_push_reg (code, AMD64_RDI); offset += 8; } - + amd64_shift_reg_imm (code, X86_SHR, sreg, 3); if (sreg != AMD64_RCX) amd64_mov_reg_reg (code, AMD64_RCX, sreg, 8); amd64_alu_reg_reg (code, X86_XOR, AMD64_RAX, AMD64_RAX); - + amd64_lea_membase (code, AMD64_RDI, AMD64_RSP, offset); if (cfg->param_area) amd64_alu_reg_imm (code, X86_ADD, AMD64_RDI, cfg->param_area); amd64_cld (code); amd64_prefix (code, X86_REP_PREFIX); amd64_stosl (code); - + if (tree->dreg != AMD64_RDI && sreg != AMD64_RDI) amd64_pop_reg (code, AMD64_RDI); if (tree->dreg != AMD64_RCX && sreg != AMD64_RCX) @@ -4455,10 +4455,10 @@ mono_amd64_emit_tls_set (guint8 *code, int sreg, int tls_offset) static guint8* emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, int cfa_offset) { - /* + /* * The ip field is not set, the exception handling code will obtain it from the stack location pointed to by the sp field. */ - /* + /* * sp is saved right before calls but we need to save it here too so * async stack walks would work. */ @@ -4956,8 +4956,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_patch (label, code); } - /* - * This is the address which is saved in seq points, + /* + * This is the address which is saved in seq points, */ mono_add_seq_point (cfg, bb, ins, code - cfg->native_code); @@ -5056,7 +5056,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_LMUL_IMM: case OP_IMUL_IMM: { guint32 size = (ins->opcode == OP_IMUL_IMM) ? 4 : 8; - + switch (ins->inst_imm) { case 2: /* MOV r1, r2 */ @@ -5639,7 +5639,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* Set argument registers */ for (i = 0; i < PARAM_REGS; ++i) amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, regs) + (i * sizeof (target_mgreg_t)), sizeof (target_mgreg_t)); - + /* Make the call */ amd64_call_reg (code, AMD64_R10); @@ -5745,7 +5745,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) for (i = 0; i < size; i += 8) amd64_mov_membase_reg (code, AMD64_RSP, i, ins->dreg, 8); - amd64_mov_reg_reg (code, ins->dreg, AMD64_RSP, 8); + amd64_mov_reg_reg (code, ins->dreg, AMD64_RSP, 8); } else { amd64_mov_reg_imm (code, ins->dreg, size); ins->sreg1 = ins->dreg; @@ -5775,7 +5775,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ins->backend.pc_offset = code - cfg->native_code; break; } - case OP_CALL_HANDLER: + case OP_CALL_HANDLER: /* Align stack */ amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8); mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb); @@ -5830,13 +5830,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins) //break; if (ins->inst_target_bb->native_offset) { - amd64_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); + amd64_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); } else { mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb); if (optimize_branch_pred && x86_is_imm8 (ins->inst_target_bb->max_offset - offset)) x86_jump8 (code, 0); - else + else x86_jump32 (code, 0); } break; @@ -5893,14 +5893,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_COND_EXC_NO: case OP_COND_EXC_C: case OP_COND_EXC_NC: - EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], + EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], (ins->opcode < OP_COND_EXC_NE_UN), (const char *)ins->inst_p1); break; case OP_COND_EXC_IOV: case OP_COND_EXC_INO: case OP_COND_EXC_IC: case OP_COND_EXC_INC: - EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_IEQ], + EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_IEQ], (ins->opcode < OP_COND_EXC_INE_UN), (const char *)ins->inst_p1); break; @@ -6008,7 +6008,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE); break; case OP_FCONV_TO_U4: - code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE); + code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE); break; case OP_FCONV_TO_I4: case OP_FCONV_TO_I: @@ -6053,7 +6053,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_sse_movss_reg_reg (code, ins->dreg, ins->sreg1); break; - case OP_LCONV_TO_R_UN: { + case OP_LCONV_TO_R_UN: { guint8 *br [2]; /* Based on gcc code */ @@ -6124,13 +6124,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FSUB: amd64_sse_subsd_reg_reg (code, ins->dreg, ins->sreg2); - break; + break; case OP_FMUL: amd64_sse_mulsd_reg_reg (code, ins->dreg, ins->sreg2); - break; + break; case OP_FDIV: amd64_sse_divsd_reg_reg (code, ins->dreg, ins->sreg2); - break; + break; case OP_FNEG: { static double r8_0 = -0.0; @@ -6244,11 +6244,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert (ins->dreg == ins->sreg1); amd64_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2); amd64_cmov_reg (code, X86_CC_LT, FALSE, ins->dreg, ins->sreg2); - break; + break; case OP_X86_FPOP: - break; + break; case OP_FCOMPARE: - /* + /* * The two arguments are swapped because the fbranch instructions * depend on this for the non-sse case to work. */ @@ -6264,7 +6264,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FCNEQ: case OP_FCEQ: { - /* zeroing the register at the start results in + /* zeroing the register at the start results in * shorter and faster code (we can also remove the widening op) */ guchar *unordered_check; @@ -6290,7 +6290,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } case OP_FCLT: case OP_FCLT_UN: { - /* zeroing the register at the start results in + /* zeroing the register at the start results in * shorter and faster code (we can also remove the widening op) */ amd64_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg); @@ -6322,7 +6322,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } case OP_FCGT: case OP_FCGT_UN: { - /* zeroing the register at the start results in + /* zeroing the register at the start results in * shorter and faster code (we can also remove the widening op) */ guchar *unordered_check; @@ -6576,7 +6576,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, size); /* dreg contains the old value, add with sreg2 value */ amd64_alu_reg_reg_size (code, X86_ADD, dreg, ins->sreg2, size); - + if (ins->dreg != dreg) amd64_mov_reg_reg (code, ins->dreg, dreg, size); @@ -6601,7 +6601,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) else size = 4; - /* + /* * See http://msdn.microsoft.com/en-us/magazine/cc302329.aspx for * an explanation of how this works. */ @@ -6970,7 +6970,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_PMAXD_UN: amd64_sse_pmaxud_reg_reg (code, ins->sreg1, ins->sreg2); break; - + case OP_PMAXB: amd64_sse_pmaxsb_reg_reg (code, ins->sreg1, ins->sreg2); break; @@ -7114,7 +7114,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_PSUBW_SAT: amd64_sse_psubsw_reg_reg (code, ins->sreg1, ins->sreg2); break; - + case OP_PMULW: amd64_sse_pmullw_reg_reg (code, ins->sreg1, ins->sreg2); break; @@ -7179,22 +7179,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_PSHRQ_REG: amd64_sse_psrlq_reg_reg (code, ins->dreg, ins->sreg2); break; - + /*TODO: This is appart of the sse spec but not added case OP_PSARQ: amd64_sse_psraq_reg_imm (code, ins->dreg, ins->inst_imm); break; case OP_PSARQ_REG: amd64_sse_psraq_reg_reg (code, ins->dreg, ins->sreg2); - break; + break; */ - + case OP_PSHLQ: amd64_sse_psllq_reg_imm (code, ins->dreg, ins->inst_imm); break; case OP_PSHLQ_REG: amd64_sse_psllq_reg_reg (code, ins->dreg, ins->sreg2); - break; + break; case OP_CVTDQ2PD: amd64_sse_cvtdq2pd_reg_reg (code, ins->dreg, ins->sreg1); break; @@ -7350,7 +7350,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /*FIXME the peephole pass should have killed this*/ if (ins->dreg != ins->sreg1) amd64_sse_movaps_reg_reg (code, ins->dreg, ins->sreg1); - break; + break; case OP_XZERO: amd64_sse_pxor_reg_reg (code, ins->dreg, ins->dreg); break; @@ -7382,7 +7382,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCONV_TO_U2: amd64_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE); break; - } + } break; case OP_EXPAND_I2: @@ -7544,7 +7544,7 @@ static int get_max_epilog_size (MonoCompile *cfg) { int max_epilog_size = 16; - + if (cfg->method->save_lmf) max_epilog_size += 256; @@ -7625,7 +7625,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* Offset between RSP and the CFA */ cfa_offset = 0; - /* + /* * The prolog consists of the following parts: * FP present: * - push rbp @@ -7674,7 +7674,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) } if (cfg->arch.omit_fp) { - /* + /* * On enter, the stack is misaligned by the pushing of the return * address. It is either made aligned by the pushing of %rbp, or by * this. @@ -7778,7 +7778,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) if (mini_debug_options.init_stacks) { /* Fill the stack frame with a dummy value to force deterministic behavior */ - + /* Save registers to the red zone */ amd64_mov_membase_reg (code, AMD64_RSP, -8, AMD64_RDI, 8); amd64_mov_membase_reg (code, AMD64_RSP, -16, AMD64_RCX, 8); @@ -7860,7 +7860,7 @@ MONO_RESTORE_WARNING /* Take prolog and epilog instrumentation into account */ if (bb == cfg->bb_entry || bb == cfg->bb_exit) max_length += max_epilog_size; - + bb->max_length = max_length; } } @@ -8112,7 +8112,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) mono_emit_unwind_op_remember_state (cfg, code); /* the code restoring the registers must be kept in sync with OP_TAILCALL */ - + if (method->save_lmf) { if (cfg->used_int_regs & (1 << AMD64_RBP)) amd64_mov_reg_membase (code, AMD64_RBP, cfg->frame_reg, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, rbp), 8); @@ -8368,7 +8368,7 @@ mono_arch_flush_register_windows (void) { } -gboolean +gboolean mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) { return amd64_use_imm32 (imm); @@ -8897,7 +8897,7 @@ mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMetho } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) { opcode = OP_ABS; } - + if (opcode && fsig->param_count == 1) { MONO_INST_NEW (cfg, ins, opcode); ins->type = STACK_R8; @@ -8928,7 +8928,7 @@ mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMetho opcode = OP_LMAX_UN; } } - + if (opcode && fsig->param_count == 2) { MONO_INST_NEW (cfg, ins, opcode); ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8; @@ -9086,7 +9086,7 @@ mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji) { g_assert_not_reached (); } - + /* * mono_arch_start_single_stepping: * @@ -9097,7 +9097,7 @@ mono_arch_start_single_stepping (void) { ss_trampoline = mini_get_single_step_trampoline (); } - + /* * mono_arch_stop_single_stepping: * diff --git a/src/mono/mono/mini/mini-arch.h b/src/mono/mono/mini/mini-arch.h index da89dbb0439e1..5a4c89f0bf868 100644 --- a/src/mono/mono/mini/mini-arch.h +++ b/src/mono/mono/mini/mini-arch.h @@ -39,4 +39,4 @@ #define MONO_ARCH_LOCALLOC_ALIGNMENT MONO_ARCH_FRAME_ALIGNMENT #endif -#endif /* __MONO_MINI_ARCH_H__ */ +#endif /* __MONO_MINI_ARCH_H__ */ diff --git a/src/mono/mono/mini/mini-arm.c b/src/mono/mono/mini/mini-arm.c index c9a8c319786a5..69360a1946d64 100644 --- a/src/mono/mono/mini/mini-arm.c +++ b/src/mono/mono/mini/mini-arm.c @@ -89,7 +89,7 @@ static gboolean thumb2_supported = FALSE; */ static gboolean eabi_supported = FALSE; -/* +/* * Whenever to use the iphone ABI extensions: * http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/index.html * Basically, r7 is used as a frame pointer and it should point to the saved r7 + lr. @@ -577,7 +577,7 @@ emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset) * @arg_info: an array to store the result infos * * Gathers information on parameters such as size, alignment and - * padding. arg_info should be large enought to hold param_count + 1 entries. + * padding. arg_info should be large enought to hold param_count + 1 entries. * * Returns the size of the activation frame. */ @@ -610,7 +610,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit /* ignore alignment for now */ align = 1; - frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); + frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); arg_info [k].pad = pad; frame_size += size; arg_info [k + 1].pad = 0; @@ -1012,7 +1012,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) mono_arch_compute_omit_fp (cfg); - /* + /* * FIXME: Interface calls might go through a static rgctx trampoline which * sets V5, but it doesn't save it, so we need to save it ourselves, and * avoid using it. @@ -1042,7 +1042,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* * mono_arch_regalloc_cost: * - * Return the cost, in number of memory references, of the action of + * Return the cost, in number of memory references, of the action of * allocating the variable VMV into a register during global register * allocation. */ @@ -1888,7 +1888,7 @@ mono_arch_compute_omit_fp (MonoCompile *cfg) ArgInfo *ainfo = &cinfo->args [i]; if (ainfo->storage == RegTypeBase || ainfo->storage == RegTypeBaseGen || ainfo->storage == RegTypeStructByVal) { - /* + /* * The stack offset can only be determined when the frame * size is known. */ @@ -1963,7 +1963,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) } } /* local vars are at a positive offset from the stack pointer */ - /* + /* * also note that if the function uses alloca, we use FP * to point at the local variables. */ @@ -2147,7 +2147,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) offset &= ~(align - 1); cfg->sig_cookie = offset; offset += size; - } + } for (i = 0; i < sig->param_count; ++i) { ainfo = cinfo->args + i; @@ -2273,11 +2273,11 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) NOT_IMPLEMENTED; g_assert (cinfo->sig_cookie.storage == RegTypeBase); - + /* - * mono_ArgIterator_Setup assumes the signature cookie is + * mono_ArgIterator_Setup assumes the signature cookie is * passed first and all the arguments which were before it are - * passed on the stack after the signature. So compensate by + * passed on the stack after the signature. So compensate by * passing a different signature. */ tmp_sig = mono_metadata_signature_dup (call->signature); @@ -2309,7 +2309,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) /* * LLVM always uses the native ABI while we use our own ABI, the * only difference is the handling of vtypes: - * - we only pass/receive them in registers in some cases, and only + * - we only pass/receive them in registers in some cases, and only * in 1 or 2 integer registers. */ switch (cinfo->ret.storage) { @@ -2404,7 +2404,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) sig = call->signature; n = sig->param_count + sig->hasthis; - + cinfo = get_call_info (cfg->mempool, sig); switch (cinfo->ret.storage) { @@ -2813,7 +2813,7 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) #endif /* #ifndef DISABLE_JIT */ -gboolean +gboolean mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) { return TRUE; @@ -2920,7 +2920,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) info->param_types = g_new0 (MonoType*, sig->param_count); for (i = 0; i < sig->param_count; ++i) info->param_types [i] = mini_get_underlying_type (sig->params [i]); - + return (MonoDynCallInfo*)info; } @@ -3186,7 +3186,7 @@ if (0 && ins->inst_true_bb->native_offset) { \ mono_add_patch_info (cfg, code - cfg->native_code, \ MONO_PATCH_INFO_EXC, exc_name); \ ARM_BL_COND (code, (condcode), 0); \ - } while (0); + } while (0); #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_cc_table [(cond)], (exc_name)) @@ -3204,17 +3204,17 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) MonoInst *last_ins = mono_inst_prev (ins, FILTER_IL_SEQ_POINT); switch (ins->opcode) { - case OP_MUL_IMM: - case OP_IMUL_IMM: + case OP_MUL_IMM: + case OP_IMUL_IMM: /* Already done by an arch-independent pass */ break; case OP_LOAD_MEMBASE: case OP_LOADI4_MEMBASE: - /* - * OP_STORE_MEMBASE_REG reg, offset(basereg) + /* + * OP_STORE_MEMBASE_REG reg, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg */ - if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG + if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG || last_ins->opcode == OP_STORE_MEMBASE_REG) && ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { @@ -3227,7 +3227,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->sreg1 = last_ins->sreg1; } - /* + /* * Note: reg1 must be different from the basereg in the second load * OP_LOAD_MEMBASE offset(basereg), reg1 * OP_LOAD_MEMBASE offset(basereg), reg2 @@ -3252,11 +3252,11 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) //g_assert_not_reached (); #if 0 - /* - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + /* + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg * --> - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_ICONST reg, imm */ } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM @@ -3276,7 +3276,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1; - ins->sreg1 = last_ins->sreg1; + ins->sreg1 = last_ins->sreg1; } break; case OP_LOADU2_MEMBASE: @@ -3285,20 +3285,20 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2; - ins->sreg1 = last_ins->sreg1; + ins->sreg1 = last_ins->sreg1; } break; case OP_MOVE: ins->opcode = OP_MOVE; - /* - * OP_MOVE reg, reg + /* + * OP_MOVE reg, reg */ if (ins->dreg == ins->sreg1) { MONO_DELETE_INS (bb, ins); continue; } - /* - * OP_MOVE sreg, dreg + /* + * OP_MOVE sreg, dreg * OP_MOVE dreg, sreg */ if (last_ins && last_ins->opcode == OP_MOVE && @@ -3312,7 +3312,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) } } -/* +/* * the branch_cc_table should maintain the order of these * opcodes. case CEE_BEQ: @@ -3326,17 +3326,17 @@ case CEE_BGT_UN: case CEE_BLE_UN: case CEE_BLT_UN: */ -static const guchar +static const guchar branch_cc_table [] = { - ARMCOND_EQ, - ARMCOND_GE, - ARMCOND_GT, + ARMCOND_EQ, + ARMCOND_GE, + ARMCOND_GT, ARMCOND_LE, - ARMCOND_LT, - - ARMCOND_NE, - ARMCOND_HS, - ARMCOND_HI, + ARMCOND_LT, + + ARMCOND_NE, + ARMCOND_HS, + ARMCOND_HI, ARMCOND_LS, ARMCOND_LO }; @@ -3902,7 +3902,7 @@ arm_patch_general (MonoCompile *cfg, guchar *code, const guchar *target) return; } } - + handle_thunk (cfg, code, target); return; } @@ -3930,7 +3930,7 @@ arm_patch_general (MonoCompile *cfg, guchar *code, const guchar *target) * address constant // execution never reaches here */ if ((ins & 0x0ffffff0) == 0x12fff10) { - /* Branch and exchange: the address is constructed in a reg + /* Branch and exchange: the address is constructed in a reg * We can patch BX when the code sequence is the following: * ldr ip, [pc, #0] ; 0x8 * b 0xc @@ -4009,7 +4009,7 @@ arm_patch (guchar *code, const guchar *target) arm_patch_general (NULL, code, target); } -/* +/* * Return the >= 0 uimm8 value if val can be represented with a byte + rotation * (with the rotation amount in *rot_amount. rot_amount is already adjusted * to be used with the emit macros. @@ -4562,8 +4562,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_BREAK: /* - * gdb does not like encountering the hw breakpoint ins in the debugged code. - * So instead of emitting a trap, we emit a call a C function and place a + * gdb does not like encountering the hw breakpoint ins in the debugged code. + * So instead of emitting a trap, we emit a call a C function and place a * breakpoint there. */ //*(int*)code = 0xef9f0001; @@ -4697,7 +4697,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) */ ARM_NOP (code); } else { - /* + /* * A placeholder for a possible breakpoint inserted by * mono_arch_set_breakpoint (). */ @@ -5308,7 +5308,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* Save result */ ARM_LDR_IMM (code, ARMREG_IP, var->inst_basereg, var->inst_offset); - ARM_STR_IMM (code, ARMREG_R0, ARMREG_IP, MONO_STRUCT_OFFSET (DynCallArgs, res)); + ARM_STR_IMM (code, ARMREG_R0, ARMREG_IP, MONO_STRUCT_OFFSET (DynCallArgs, res)); ARM_STR_IMM (code, ARMREG_R1, ARMREG_IP, MONO_STRUCT_OFFSET (DynCallArgs, res2)); if (IS_HARD_FLOAT) ARM_FSTD (code, ARM_VFP_D0, ARMREG_IP, MONO_STRUCT_OFFSET (DynCallArgs, fpregs)); @@ -5405,7 +5405,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); break; } - case OP_CALL_HANDLER: + case OP_CALL_HANDLER: mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb); code = mono_arm_patchable_bl (code, ARMCOND_AL); cfg->thunk_area += THUNK_SIZE; @@ -5423,17 +5423,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_BR: /*if (ins->inst_target_bb->native_offset) { ARM_B (code, 0); - //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); + //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); } else*/ { mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb); code = mono_arm_patchable_b (code, ARMCOND_AL); - } + } break; case OP_BR_REG: ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1); break; case OP_SWITCH: - /* + /* * In the normal case we have: * ldr pc, [pc, ins->sreg1 << 2] * nop @@ -5558,7 +5558,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) *(guint32*)code = ((guint32*)(ins->inst_p0))[1]; code += 4; } else { - /* FIXME: we can optimize the imm load by dealing with part of + /* FIXME: we can optimize the imm load by dealing with part of * the displacement in LDFD (aligning to 512). */ code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)(gsize)ins->inst_p0); @@ -5700,7 +5700,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_LCONV_TO_OVF_I4_2: { guint8 *high_bit_not_set, *valid_negative, *invalid_negative, *valid_positive; - /* + /* * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */ @@ -5713,7 +5713,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ARM_B_COND (code, ARMCOND_EQ, 0); /*branch if upper part == 0xFFFFFFFF (lower part has bit 31 set) */ invalid_negative = code; ARM_B_COND (code, ARMCOND_AL, 0); - + arm_patch (high_bit_not_set, code); ARM_CMP_REG_IMM8 (code, ins->sreg2, 0); @@ -5735,13 +5735,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FSUB: ARM_VFP_SUBD (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_FMUL: ARM_VFP_MULD (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_FDIV: ARM_VFP_DIVD (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_FNEG: ARM_NEGD (code, ins->dreg, ins->sreg1); break; @@ -5925,13 +5925,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_RSUB: ARM_VFP_SUBS (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_RMUL: ARM_VFP_MULS (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_RDIV: ARM_VFP_DIVS (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_RNEG: ARM_NEGS (code, ins->dreg, ins->sreg1); break; @@ -6050,7 +6050,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset); g_assert_not_reached (); } - + cpos += max_len; last_ins = ins; @@ -6141,7 +6141,7 @@ mono_arm_unaligned_stack (MonoMethod *method) /* * Stack frame layout: - * + * * ------------------- fp * MonoLMF structure or saved registers * ------------------- @@ -6176,7 +6176,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) prev_sp_offset = 0; if (iphone_abi) { - /* + /* * The iphone uses R7 as the frame pointer, and it points at the saved * r7+lr: * @@ -6340,7 +6340,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = cinfo->args + i; inst = cfg->args [i]; - + if (cfg->verbose_level > 2) g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage); @@ -6716,7 +6716,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) } mono_emit_unwind_op_def_cfa (cfg, code, ARMREG_SP, ((iphone_abi ? 3 : 0) + nused_int_regs) * 4); /* restore iregs */ - ARM_POP (code, regmask); + ARM_POP (code, regmask); if (iphone_abi) { for (i = 0; i < 16; i++) { if (regmask & (1 << i)) @@ -6790,8 +6790,8 @@ mono_arch_emit_exceptions (MonoCompile *cfg) } /* count the number of exception infos */ - - /* + + /* * make sure we have enough space for exceptions */ for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { @@ -7055,14 +7055,14 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (target_mgreg_t)); /* Restore registers and branch */ ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC); - + code = arm_emit_value_and_patch_ldr (code, target_code_ins, (gsize)item->value.target_code); } else { vtable_offset = DISTANCE (vtable, &vtable->vtable[item->value.vtable_slot]); if (!arm_is_imm12 (vtable_offset)) { - /* + /* * We need to branch to a computed address but we don't have - * a free register to store it, since IP must contain the + * a free register to store it, since IP must contain the * vtable address. So we push the two values to the stack, and * load them both using LDM. */ @@ -7074,7 +7074,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (target_mgreg_t)); /* Restore registers and branch */ ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC); - + code = arm_emit_value_and_patch_ldr (code, vtable_offset_ins, vtable_offset); } else { ARM_POP2 (code, ARMREG_R0, ARMREG_R1); @@ -7097,7 +7097,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoIMTCheckItem **imt_entri ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (target_mgreg_t)); /* Restore registers and branch */ ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC); - + code = arm_emit_value_and_patch_ldr (code, target_code_ins, (gsize)fail_tramp); item->jmp_code = NULL; } @@ -7233,7 +7233,7 @@ mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip) mono_arch_flush_icache (code - 16, 16); #if 0 - /* This is currently implemented by emitting an SWI instruction, which + /* This is currently implemented by emitting an SWI instruction, which * qemu/linux seems to convert to a SIGILL. */ *(int*)code = (0xef << 24) | 8; @@ -7275,7 +7275,7 @@ mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip) mono_arch_flush_icache (ip, code - ip); } } - + /* * mono_arch_start_single_stepping: * @@ -7289,7 +7289,7 @@ mono_arch_start_single_stepping (void) else single_step_tramp = mini_get_single_step_trampoline (); } - + /* * mono_arch_stop_single_stepping: * diff --git a/src/mono/mono/mini/mini-arm.h b/src/mono/mono/mini/mini-arm.h index f53c35cad848d..12581b13992b3 100644 --- a/src/mono/mono/mini/mini-arm.h +++ b/src/mono/mono/mini/mini-arm.h @@ -119,7 +119,7 @@ #define MONO_ARCH_FRAME_ALIGNMENT 8 #endif -/* fixme: align to 16byte instead of 32byte (we align to 32byte to get +/* fixme: align to 16byte instead of 32byte (we align to 32byte to get * reproduceable results for benchmarks */ #define MONO_ARCH_CODE_ALIGNMENT 32 @@ -273,7 +273,7 @@ typedef enum { /* keep the size of the structure a multiple of 8 */ struct MonoLMF { - /* + /* * If the second lowest bit is set to 1, then this is a MonoLMFExt structure, and * the other fields are not valid. */ diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index b93b4aa6a8567..64ed1fadc63f8 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -3,7 +3,7 @@ * ARM64 backend for the Mono code generator * * Copyright 2013 Xamarin, Inc (http://www.xamarin.com) - * + * * Based on mini-arm.c: * * Authors: @@ -1738,7 +1738,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) break; } } - + return (MonoDynCallInfo*)info; } @@ -2104,7 +2104,7 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg) if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos) continue; - if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || + if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG)) continue; @@ -2587,11 +2587,11 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) NOT_IMPLEMENTED; g_assert (cinfo->sig_cookie.storage == ArgOnStack); - + /* - * mono_ArgIterator_Setup assumes the signature cookie is + * mono_ArgIterator_Setup assumes the signature cookie is * passed first and all the arguments which were before it are - * passed on the stack after the signature. So compensate by + * passed on the stack after the signature. So compensate by * passing a different signature. */ tmp_sig = mono_metadata_signature_dup (call->signature); @@ -2876,7 +2876,7 @@ mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, #endif -gboolean +gboolean mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) { return (imm >= -((gint64)1<<31) && imm <= (((gint64)1<<31)-1)); @@ -3314,8 +3314,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_BREAK: /* - * gdb does not like encountering the hw breakpoint ins in the debugged code. - * So instead of emitting a trap, we emit a call a C function and place a + * gdb does not like encountering the hw breakpoint ins in the debugged code. + * So instead of emitting a trap, we emit a call a C function and place a * breakpoint there. */ code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break)); @@ -3428,7 +3428,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert (var->opcode == OP_REGOFFSET); /* Load the address of the bp trampoline into IP0 */ arm_ldrx (code, ARMREG_IP0, var->inst_basereg, var->inst_offset); - /* + /* * A placeholder for a possible breakpoint inserted by * mono_arch_set_breakpoint (). */ @@ -5148,12 +5148,12 @@ mono_arch_emit_prolog (MonoCompile *cfg) g_assert (ins->opcode == OP_REGOFFSET); - code = emit_strx (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset); + code = emit_strx (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset); mono_add_var_location (cfg, cfg->rgctx_var, TRUE, MONO_ARCH_RGCTX_REG, 0, 0, code - cfg->native_code); mono_add_var_location (cfg, cfg->rgctx_var, FALSE, ins->inst_basereg, ins->inst_offset, code - cfg->native_code, 0); } - + /* * Move arguments to their registers/stack locations. */ diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index 7555c5e7854f0..8feacf8f81e49 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -82,7 +82,7 @@ #define MONO_ARCH_LMF_REG_SP 11 struct MonoLMF { - /* + /* * If the second lowest bit is set to 1, then this is a MonoLMFExt structure, and * the other fields are not valid. */ diff --git a/src/mono/mono/mini/mini-codegen.c b/src/mono/mono/mini/mini-codegen.c index 77464dcf88cbb..171520d2818c1 100644 --- a/src/mono/mono/mini/mini-codegen.c +++ b/src/mono/mono/mini/mini-codegen.c @@ -69,9 +69,9 @@ static int translate_bank (MonoRegState *rs, int bank, int hreg) { } /* - * Every hardware register belongs to a register type or register bank. bank 0 + * Every hardware register belongs to a register type or register bank. bank 0 * contains the int registers, bank 1 contains the fp registers. - * int registers are used 99% of the time, so they are special cased in a lot of + * int registers are used 99% of the time, so they are special cased in a lot of * places. */ @@ -83,7 +83,7 @@ static const int regbank_size [] = { MONO_MAX_XREGS }; -static const int regbank_load_ops [] = { +static const int regbank_load_ops [] = { OP_LOADR_MEMBASE, OP_LOADR8_MEMBASE, OP_LOADR_MEMBASE, @@ -91,7 +91,7 @@ static const int regbank_load_ops [] = { OP_LOADX_MEMBASE }; -static const int regbank_store_ops [] = { +static const int regbank_store_ops [] = { OP_STORER_MEMBASE_REG, OP_STORER8_MEMBASE_REG, OP_STORER_MEMBASE_REG, @@ -99,7 +99,7 @@ static const int regbank_store_ops [] = { OP_STOREX_MEMBASE }; -static const int regbank_move_ops [] = { +static const int regbank_move_ops [] = { OP_MOVE, OP_FMOVE, OP_MOVE, @@ -315,7 +315,7 @@ resize_spill_info (MonoCompile *cfg, int bank) /* * returns the offset used by spillvar. It allocates a new - * spill variable if necessary. + * spill variable if necessary. */ static int mono_spillvar_offset (MonoCompile *cfg, int spillvar, int bank) @@ -381,7 +381,7 @@ mono_spillvar_offset (MonoCompile *cfg, int spillvar, int bank) #define sreg1_is_fp(spec) sreg_is_fp (0,(spec)) #define sreg2_is_fp(spec) sreg_is_fp (1,(spec)) -#define reg_is_simd(desc) ((desc) == 'x') +#define reg_is_simd(desc) ((desc) == 'x') #ifdef MONO_ARCH_NEED_SIMD_BANK @@ -612,7 +612,7 @@ mono_print_ins_index_strbuf (int i, MonoInst *ins) if (ins->opcode == OP_VCALL || ins->opcode == OP_VCALL_REG || ins->opcode == OP_VCALL_MEMBASE) { /* - * These are lowered opcodes, but they are in the .md files since the old + * These are lowered opcodes, but they are in the .md files since the old * JIT passes them to backends. */ if (ins->dreg != -1) @@ -744,7 +744,7 @@ print_regtrack (RegTrack *t, int num) int i; char buf [32]; const char *r; - + for (i = 0; i < num; ++i) { if (!t [i].born_in) continue; @@ -804,7 +804,7 @@ get_vreg_bank (MonoCompile *cfg, int reg, int bank) } /* - * Force the spilling of the variable in the symbolic register 'reg', and free + * Force the spilling of the variable in the symbolic register 'reg', and free * the hreg it was assigned to. */ static void @@ -923,7 +923,7 @@ get_register_spilling (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, Mo else i = mono_regstate_alloc_int (rs, regmask (sel)); g_assert (i == sel); - + return sel; } @@ -983,7 +983,7 @@ static void create_spilled_store (MonoCompile *cfg, MonoBasicBlock *bb, int spill, int reg, int prev_reg, MonoInst **last, MonoInst *ins, MonoInst *insert_before, int bank) { MonoInst *store, *def; - + bank = get_vreg_bank (cfg, prev_reg, bank); MONO_INST_NEW (cfg, store, regbank_store_ops [bank]); @@ -1120,7 +1120,7 @@ static gboolean desc_to_fixed_reg_inited = FALSE; * Local register allocation. * We first scan the list of instructions and we save the liveness info of * each register (when the register is first used, when it's value is set etc.). - * We also reverse the list of instructions because assigning registers backwards allows + * We also reverse the list of instructions because assigning registers backwards allows * for more tricks to be used. */ void @@ -1187,7 +1187,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) cfg->reginfo_len = MAX (1024, max * 2); reginfo = (RegTrack *)mono_mempool_alloc (cfg->mempool, sizeof (RegTrack) * cfg->reginfo_len); cfg->reginfo = reginfo; - } + } else g_assert (cfg->reginfo_len >= rs->next_vreg); @@ -1196,9 +1196,9 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) memset (cfg->reginfo, 0, cfg->reginfo_len * sizeof (RegTrack)); } - /* + /* * For large methods, next_vreg can be very large, so g_malloc0 time can - * be prohibitive. So we manually init the reginfo entries used by the + * be prohibitive. So we manually init the reginfo entries used by the * bblock. */ for (ins = bb->code; ins; ins = ins->next) { @@ -1212,7 +1212,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) if (MONO_ARCH_INST_IS_REGPAIR (spec [MONO_INST_DEST])) { /** * In the new IR, the two vregs of the regpair do not alias the - * original long vreg. shift the vreg here so the rest of the + * original long vreg. shift the vreg here so the rest of the * allocator doesn't have to care about it. */ ins->dreg ++; @@ -1252,7 +1252,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) if (G_UNLIKELY (spec == (gpointer)/*FIXME*/MONO_ARCH_CPU_SPEC)) { g_error ("Opcode '%s' missing from machine description file.", mono_inst_name (ins->opcode)); } - + DEBUG (mono_print_ins_index (i, ins)); num_sregs = mono_inst_get_src_registers (ins, sregs); @@ -1416,7 +1416,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) for (k = 0; k < num_sregs; ++k) { if (k != j) sreg_masks [k] &= ~ (regmask (dest_sreg)); - } + } /* * Spill sreg1/2 if they are assigned to dest_sreg. @@ -1466,9 +1466,9 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) if (k != j) sreg_masks [k] &= ~ (regmask (dest_sreg)); } - /* + /* * Prevent the dreg from being allocated to dest_sreg - * too, since it could force sreg1 to be allocated to + * too, since it could force sreg1 to be allocated to * the same reg on x86. */ dreg_mask &= ~ (regmask (dest_sreg)); @@ -1485,7 +1485,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) sreg_masks [k] &= ~ (regmask (dest_sreg)); } - /* + /* * First check if dreg is assigned to dest_sreg2, since we * can't spill a dreg. */ @@ -1494,9 +1494,9 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) else val = -1; if (val == dest_sreg && ins->dreg != sreg) { - /* - * the destination register is already assigned to - * dest_sreg2: we need to allocate another register for it + /* + * the destination register is already assigned to + * dest_sreg2: we need to allocate another register for it * and then copy from this to dest_sreg2. */ int new_dest; @@ -1527,7 +1527,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) /* sreg2 already assigned to another register */ /* * We couldn't emit a copy from val to dest_sreg2, because - * val might be spilled later while processing this + * val might be spilled later while processing this * instruction. So we spill sreg2 so it can be allocated to * dest_sreg2. */ @@ -1564,7 +1564,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) } if (spec_dest == 'b') { - /* + /* * The dest reg is read by the instruction, not written, so * avoid allocating sreg1/sreg2 to the same reg. */ @@ -1607,7 +1607,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) if (dreg_fixed_mask) { g_assert (!bank); if (is_global_ireg (ins->dreg)) { - /* + /* * The argument is already in a hard reg, but that reg is * not usable by this instruction, so allocate a new one. */ @@ -1678,7 +1678,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) mono_regstate_free_int (rs, rs->vassign [reg2]); } - } + } DEBUG (printf ("\tassigned dreg-high %s to dest R%d\n", mono_arch_regname (val), reg2)); assign_reg (cfg, rs, reg2, val, bank); @@ -1693,7 +1693,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) } if (prev_dreg >= 0 && is_soft_reg (prev_dreg, bank) && (spec_dest != 'b')) { - /* + /* * In theory, we could free up the hreg even if the vreg is alive, * but branches inside bblocks force us to assign the same hreg * to a vreg every time it is encountered. @@ -1728,7 +1728,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) } if (spec_dest == 'b') { - /* + /* * The dest reg is read by the instruction, not written, so * avoid allocating sreg1/sreg2 to the same reg. */ @@ -1818,13 +1818,13 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) MonoCallInst *call = (MonoCallInst*)ins; GSList *list; - /* + /* * This needs to be done before assigning sreg1, so sreg1 will * not be assigned one of the argument regs. */ - /* - * Assign all registers in call->out_reg_args to the proper + /* + * Assign all registers in call->out_reg_args to the proper * argument registers. */ @@ -1910,7 +1910,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) if (sreg_fixed_masks [0]) { g_assert (!bank); if (is_global_ireg (sregs [0])) { - /* + /* * The argument is already in a hard reg, but that reg is * not usable by this instruction, so allocate a new one. */ @@ -1951,8 +1951,8 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) } if ((ins->opcode == OP_MOVE) && !spill && !bank && is_local_ireg (ins->dreg) && (rs->ifree_mask & (regmask (ins->dreg)))) { - /* - * Allocate the same hreg to sreg1 as well so the + /* + * Allocate the same hreg to sreg1 as well so the * peephole can get rid of the move. */ sreg_masks [0] = regmask (ins->dreg); @@ -1981,7 +1981,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) sreg_masks [j] &= ~(regmask (dest_sregs [0])); val = dest_sregs [0]; } - + sregs [0] = val; } else { @@ -2029,7 +2029,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) mono_regstate_free_int (rs, rs->vassign [reg2]); #endif } - } + } sreg1_high = val; DEBUG (printf ("\tassigned sreg1 hreg %s to dest R%d\n", mono_arch_regname (val), reg2)); @@ -2043,7 +2043,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) int bank = reg_bank (spec_src1); if (ins->dreg == sregs [1]) { - /* + /* * copying sreg1 to dreg could clobber sreg2, so allocate a new * register for it. */ @@ -2065,7 +2065,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) /* FIXME: */ g_assert_not_reached (); - /* + /* * sreg1 and dest are already allocated to the same regpair by the * SREG1 allocation code. */ @@ -2176,7 +2176,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) DEBUG (printf ("freeable %s\n", mono_arch_regname (ins->sreg2))); mono_regstate_free_int (rs, ins->sreg2); }*/ - + DEBUG (mono_print_ins_index (i, ins)); } @@ -2222,7 +2222,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) if (sp - 1 - i > 0) { /* First move it to %st(0) */ DEBUG (printf ("\tswap %%st(0) and %%st(%d)\n", sp - 1 - i)); - + MONO_INST_NEW (cfg, fxch, OP_X86_FXCH); fxch->inst_imm = sp - 1 - i; @@ -2233,10 +2233,10 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) fpstack [sp - 1] = fpstack [i]; fpstack [i] = tmp; } - + /* Then move it to %st(1) */ DEBUG (printf ("\tswap %%st(0) and %%st(1)\n")); - + MONO_INST_NEW (cfg, fxch, OP_X86_FXCH); fxch->inst_imm = 1; @@ -2319,7 +2319,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) if (sp && bb != cfg->bb_exit && !(bb->out_count == 1 && bb->out_bb [0] == cfg->bb_exit)) { /* Remove remaining items from the fp stack */ - /* + /* * These can remain for example as a result of a dead fmove like in * System.Collections.Generic.EqualityComparer.Equals (). */ @@ -2534,7 +2534,7 @@ mono_peephole_ins (MonoBasicBlock *bb, MonoInst *ins) MonoInst *last_ins = mono_inst_prev (ins, filter); switch (ins->opcode) { - case OP_MUL_IMM: + case OP_MUL_IMM: /* remove unnecessary multiplication with 1 */ if (ins->inst_imm == 1) { if (ins->dreg != ins->sreg1) @@ -2545,10 +2545,10 @@ mono_peephole_ins (MonoBasicBlock *bb, MonoInst *ins) break; case OP_LOAD_MEMBASE: case OP_LOADI4_MEMBASE: - /* + /* * Note: if reg1 = reg2 the load op is removed * - * OP_STORE_MEMBASE_REG reg1, offset(basereg) + * OP_STORE_MEMBASE_REG reg1, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg2 * --> * OP_STORE_MEMBASE_REG reg1, offset(basereg) @@ -2568,8 +2568,8 @@ mono_peephole_ins (MonoBasicBlock *bb, MonoInst *ins) ins->opcode = OP_MOVE; ins->sreg1 = last_ins->sreg1; } - - /* + + /* * Note: reg1 must be different from the basereg in the second load * Note: if reg1 = reg2 is equal then second load is removed * @@ -2595,11 +2595,11 @@ mono_peephole_ins (MonoBasicBlock *bb, MonoInst *ins) //g_assert_not_reached (); #if 0 - /* - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + /* + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg * --> - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_ICONST reg, imm */ } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM @@ -2614,10 +2614,10 @@ mono_peephole_ins (MonoBasicBlock *bb, MonoInst *ins) break; case OP_LOADI1_MEMBASE: case OP_LOADU1_MEMBASE: - /* + /* * Note: if reg1 = reg2 the load op is removed * - * OP_STORE_MEMBASE_REG reg1, offset(basereg) + * OP_STORE_MEMBASE_REG reg1, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg2 * --> * OP_STORE_MEMBASE_REG reg1, offset(basereg) @@ -2632,10 +2632,10 @@ mono_peephole_ins (MonoBasicBlock *bb, MonoInst *ins) break; case OP_LOADI2_MEMBASE: case OP_LOADU2_MEMBASE: - /* + /* * Note: if reg1 = reg2 the load op is removed * - * OP_STORE_MEMBASE_REG reg1, offset(basereg) + * OP_STORE_MEMBASE_REG reg1, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg2 * --> * OP_STORE_MEMBASE_REG reg1, offset(basereg) @@ -2671,16 +2671,16 @@ mono_peephole_ins (MonoBasicBlock *bb, MonoInst *ins) /* * Removes: * - * OP_MOVE reg, reg + * OP_MOVE reg, reg */ if (ins->dreg == ins->sreg1) { MONO_DELETE_INS (bb, ins); break; } - /* + /* * Removes: * - * OP_MOVE sreg, dreg + * OP_MOVE sreg, dreg * OP_MOVE dreg, sreg */ if (last_ins && last_ins->opcode == ins->opcode && diff --git a/src/mono/mono/mini/mini-cross-helpers.c b/src/mono/mono/mini/mini-cross-helpers.c index e61ed81727d1f..3ccb2bc72d18d 100644 --- a/src/mono/mono/mini/mini-cross-helpers.c +++ b/src/mono/mono/mini/mini-cross-helpers.c @@ -66,7 +66,7 @@ mono_cross_helpers_run (void) if (g_hasenv ("DUMP_CROSS_OFFSETS")) mono_dump_jit_offsets (); #endif - + #if defined (HAS_CROSS_COMPILER_OFFSETS) && !defined (MONO_CROSS_COMPILE) mono_metadata_cross_helpers_run (); diff --git a/src/mono/mono/mini/mini-exceptions.c b/src/mono/mono/mini/mini-exceptions.c index 266c451c1715c..f814096630b0b 100644 --- a/src/mono/mono/mini/mini-exceptions.c +++ b/src/mono/mono/mini/mini-exceptions.c @@ -335,7 +335,7 @@ mono_get_rethrow_preserve_exception_addr (void) return &rethrow_preserve_exception_func; } -static gboolean +static gboolean is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip) { MonoTryBlockHoleTableJitInfo *table; @@ -554,11 +554,11 @@ find_jit_info (MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, /* mono_find_jit_info: * - * This function is used to gather information from @ctx. It return the + * This function is used to gather information from @ctx. It return the * MonoJitInfo of the corresponding function, unwinds one stack frame and - * stores the resulting context into @new_ctx. It also stores a string + * stores the resulting context into @new_ctx. It also stores a string * describing the stack location into @trace (if not NULL), and modifies - * the @lmf if necessary. @native_offset return the IP offset from the + * the @lmf if necessary. @native_offset return the IP offset from the * start of the function or -1 if that info is not available. */ MonoJitInfo * @@ -883,7 +883,7 @@ mono_get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_inf klass = mrgctx->class_vtable->klass; context.method_inst = mrgctx->method_inst; if (!mini_method_is_default_method (method)) - g_assert (context.method_inst); + g_assert (context.method_inst); } else { MonoVTable *vtable = (MonoVTable *)generic_info; @@ -926,7 +926,7 @@ get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) ERROR_DECL (error); MonoGenericContext context; MonoMethod *method; - + if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this) return jinfo_get_method (ji); context = mono_get_generic_context_from_stack_frame (ji, generic_info); @@ -949,7 +949,7 @@ get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) * The walk ends when no more stack frames are found or when the callback * returns a TRUE value. */ - + gboolean mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data) { @@ -1225,7 +1225,7 @@ mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnw * State must be valid (state->valid == TRUE). * * If you are using this function to unwind another thread, make sure it is suspended. - * + * * If \p state is null, we capture the current context. */ void @@ -1246,7 +1246,7 @@ mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, return; mono_walk_stack_full (func, - &state->ctx, + &state->ctx, (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS], (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF], unwind_options, user_data, FALSE); @@ -1403,14 +1403,14 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoJitTlsD if (new_reg_locations [i]) reg_locations [i] = new_reg_locations [i]; } - + ctx = new_ctx; } } MonoBoolean -ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, - MonoReflectionMethod **method, +ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, + MonoReflectionMethod **method, gint32 *iloffset, gint32 *native_offset, MonoString **file, gint32 *line, gint32 *column) { @@ -1864,7 +1864,7 @@ handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filt guint32 free_stack; int clause_index_start = 0; gboolean unwind_res = TRUE; - + StackFrameInfo frame; if (out_prev_ji) @@ -1944,7 +1944,7 @@ handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filt MonoJitExceptionInfo *ei = &ji->clauses [i]; gboolean filtered = FALSE; - /* + /* * During stack overflow, wait till the unwinding frees some stack * space before running handlers/finalizers. */ @@ -2124,7 +2124,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu mono_error_assert_ok (error); MONO_OBJECT_SETREF_INTERNAL (ex, message, msg); obj = (MonoObject *)ex; - } + } /* * Allocate a new exception object instead of the preconstructed ones. @@ -2157,7 +2157,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu if (mono_ex->caught_in_unmanaged) is_caught_unmanaged = TRUE; - + if (mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) { mono_ex = (MonoException*)obj; @@ -2305,7 +2305,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu gboolean unwind_res = TRUE; StackFrameInfo frame; gpointer ip; - + if (resume) { resume = FALSE; ji = jit_tls->resume_state.ji; @@ -2377,7 +2377,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu MonoJitExceptionInfo *ei = &ji->clauses [i]; gboolean filtered = FALSE; - /* + /* * During stack overflow, wait till the unwinding frees some stack * space before running handlers/finalizers. */ @@ -2415,8 +2415,8 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu #endif if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) { - /* - * Filter clauses should only be run in the + /* + * Filter clauses should only be run in the * first pass of exception handling. */ filtered = (filter_idx == first_filter_idx); @@ -2424,7 +2424,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu } error_init (error); - if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && + if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, error)) || filtered) { /* * This guards against the situation that we abort a thread that is executing a finally clause @@ -2534,7 +2534,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { mono_set_lmf (lmf); if (ji->from_llvm) { - /* + /* * LLVM compiled finally handlers follow the design * of the c++ ehabi, i.e. they call a resume function * at the end instead of returning to the caller. @@ -2978,7 +2978,7 @@ mono_handle_native_crash (const char *signal, MonoContext *mctx, MONO_SIG_HANDLE /* * A crash indicates something went very wrong so we can no longer depend - * on anything working. So try to print out lots of diagnostics, starting + * on anything working. So try to print out lots of diagnostics, starting * with ones which have a greater chance of working. */ @@ -3047,7 +3047,7 @@ mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx) mono_runtime_printf_err ("%s\n", text->str); //to print the native callstack #else mono_runtime_printf ("%s", text->str); -#endif +#endif #if HOST_WIN32 && TARGET_WIN32 && _DEBUG OutputDebugStringA(text->str); @@ -3627,7 +3627,7 @@ mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 reg break; } else mono_error_assert_ok (error); - + if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) { g_assert_not_reached (); } diff --git a/src/mono/mono/mini/mini-gc.c b/src/mono/mono/mini/mini-gc.c index 8e44adf6e81f7..9c1477bb68aa0 100644 --- a/src/mono/mono/mini/mini-gc.c +++ b/src/mono/mono/mini/mini-gc.c @@ -80,7 +80,7 @@ typedef struct { * runtime, since it includes columns which are 0. */ int stack_bitmap_width; - /* + /* * A bitmap whose width equals nslots, and whose height equals ncallsites. * The bitmap contains a 1 if the corresponding stack slot has type SLOT_REF at the * given callsite. @@ -157,7 +157,7 @@ typedef struct { /* Number of registers stored in gc maps */ #define NREGS MONO_MAX_IREGS -/* +/* * The GC Map itself. * Contains information needed to mark a stack frame. * This is a transient structure, created from a compressed representation on-demand. @@ -187,7 +187,7 @@ typedef struct { /* The offsets below are into an external bitmaps array */ - /* + /* * A bitmap whose width is equal to bitmap_width, and whose height is equal to ncallsites. * The bitmap contains a 1 if the corresponding stack slot has type SLOT_REF at the * given callsite. @@ -262,7 +262,7 @@ typedef struct { gint32 scanned_registers; gint32 scanned_native; gint32 scanned_other; - + gint32 all_slots; gint32 noref_slots; gint32 ref_slots; @@ -544,7 +544,7 @@ encode_gc_map (GCMap *map, guint8 *buf, guint8 **endbuf) encode_uleb128 (map->ncallsites, buf, &buf); *endbuf = buf; -} +} /* * decode_gc_map: @@ -907,7 +907,7 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end) /* All the other frames are at a call site */ if (tls->nframes == MAX_FRAMES) { - /* + /* * Can't save information since the array is full. So scan the rest of the * stack conservatively. */ @@ -949,7 +949,7 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end) } precise_frame_limit_inited = TRUE; } - + if (precise_frame_limit != -1) { if (precise_frame_count [FALSE] == precise_frame_limit) printf ("LAST PRECISE FRAME: %s\n", mono_method_full_name (method, TRUE)); @@ -1000,7 +1000,7 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end) } cindex = i; - /* + /* * This is not neccessary true on x86 because frames have a different size at each * call site. */ @@ -1048,7 +1048,7 @@ conservative_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end) for (i = 0; i < NREGS; ++i) { if (!(map->used_int_regs & (1 << i))) continue; - + if (!(map->reg_pin_mask & (1 << i))) continue; @@ -1176,8 +1176,8 @@ precise_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end, void *gc_dat DEBUG (char *fname = mono_method_full_name (jinfo_get_method (fi->ji), TRUE); fprintf (logfile, "Mark(1): %s\n", fname); g_free (fname)); - /* - * FIXME: Add a function to mark using a bitmap, to avoid doing a + /* + * FIXME: Add a function to mark using a bitmap, to avoid doing a * call for each object. */ @@ -1241,7 +1241,7 @@ precise_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end, void *gc_dat } else { DEBUG (fprintf (logfile, "\treg %s saved at %p: %p\n", mono_arch_regname (fi->regs [i]), ptr, obj)); } - } + } } /* @@ -1261,7 +1261,7 @@ precise_pass (TlsData *tls, guint8 *stack_start, guint8 *stack_end, void *gc_dat * * This is called by the GC twice to mark a thread stack. PRECISE is FALSE at the first * call, and TRUE at the second. USER_DATA points to a TlsData - * structure filled up by thread_suspend_func. + * structure filled up by thread_suspend_func. */ static void thread_mark_func (gpointer user_data, guint8 *stack_start, guint8 *stack_end, gboolean precise, void *gc_data) @@ -1571,7 +1571,7 @@ process_other_slots (MonoCompile *cfg) int cfa_slot = data >> 16; GCSlotType type = data & 0xff; int slot; - + /* * Map the cfa relative slot to an fp relative slot. * slot_addr == cfa - *4/8 @@ -1595,7 +1595,7 @@ process_other_slots (MonoCompile *cfg) int offset = data >> 16; GCSlotType type = data & 0xff; int slot; - + slot = fp_offset_to_slot (cfg, offset); set_slot_everywhere (gcfg, slot, type); @@ -1760,7 +1760,7 @@ process_variables (MonoCompile *cfg) gboolean pin = FALSE; int size; int size_in_slots; - + if (ins->backend.is_pinvoke) size = mono_class_native_size (ins->klass, NULL); else @@ -1912,7 +1912,7 @@ process_variables (MonoCompile *cfg) static int sp_offset_to_fp_offset (MonoCompile *cfg, int sp_offset) { - /* + /* * Convert a sp relative offset to a slot index. This is * platform specific. */ @@ -1926,7 +1926,7 @@ sp_offset_to_fp_offset (MonoCompile *cfg, int sp_offset) #ifdef MONO_X86_NO_PUSHES return (- cfg->arch.sp_fp_offset + sp_offset); #else - return (- cfg->arch.sp_fp_offset - sp_offset); + return (- cfg->arch.sp_fp_offset - sp_offset); #endif #else NOT_IMPLEMENTED; @@ -2028,7 +2028,7 @@ process_finally_clauses (MonoCompile *cfg) for (i = 0; i < cfg->header->num_clauses; ++i) { clause = &cfg->header->clauses [i]; - + if (MONO_OFFSET_IN_HANDLER (clause, bb->real_offset)) { if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { is_in_finally = TRUE; @@ -2237,7 +2237,7 @@ create_map (MonoCompile *cfg) nregs = gcfg->nregs; callsites = gcfg->callsites; - /* + /* * Compute the real size of the bitmap i.e. ignore NOREF columns at the beginning and at * the end. Also, compute whenever the map needs ref/pin bitmaps, and collect stats. */ @@ -2323,7 +2323,7 @@ create_map (MonoCompile *cfg) reg_pin_bitmap_width = ALIGN_TO (npin_regs, 8) / 8; reg_pin_bitmap_size = reg_pin_bitmap_width * ncallsites; bitmaps_size = (has_ref_slots ? stack_bitmap_size : 0) + (has_pin_slots ? stack_bitmap_size : 0) + (has_ref_regs ? reg_ref_bitmap_size : 0) + (has_pin_regs ? reg_pin_bitmap_size : 0); - + map = mono_mempool_alloc0 (cfg->mempool, sizeof (GCMap)); map->frame_reg = cfg->frame_reg; diff --git a/src/mono/mono/mini/mini-llvm-cpp.h b/src/mono/mono/mini/mini-llvm-cpp.h index aaf2ef031f30e..5d376c1de80e3 100644 --- a/src/mono/mono/mini/mini-llvm-cpp.h +++ b/src/mono/mono/mini/mini-llvm-cpp.h @@ -63,15 +63,15 @@ void mono_llvm_dump_type (LLVMTypeRef type); LLVMValueRef -mono_llvm_build_alloca (LLVMBuilderRef builder, LLVMTypeRef Ty, +mono_llvm_build_alloca (LLVMBuilderRef builder, LLVMTypeRef Ty, LLVMValueRef ArraySize, int alignment, const char *Name); -LLVMValueRef +LLVMValueRef mono_llvm_build_load (LLVMBuilderRef builder, LLVMValueRef PointerVal, const char *Name, gboolean is_volatile); -LLVMValueRef +LLVMValueRef mono_llvm_build_atomic_load (LLVMBuilderRef builder, LLVMValueRef PointerVal, const char *Name, gboolean is_volatile, int alignment, BarrierKind barrier); @@ -79,11 +79,11 @@ LLVMValueRef mono_llvm_build_aligned_load (LLVMBuilderRef builder, LLVMValueRef PointerVal, const char *Name, gboolean is_volatile, int alignment); -LLVMValueRef +LLVMValueRef mono_llvm_build_store (LLVMBuilderRef builder, LLVMValueRef Val, LLVMValueRef PointerVal, gboolean is_volatile, BarrierKind kind); -LLVMValueRef +LLVMValueRef mono_llvm_build_aligned_store (LLVMBuilderRef builder, LLVMValueRef Val, LLVMValueRef PointerVal, gboolean is_volatile, int alignment); @@ -233,4 +233,4 @@ mono_llvm_inline_asm (LLVMBuilderRef builder, LLVMTypeRef type, G_END_DECLS -#endif /* __MONO_MINI_LLVM_CPP_H__ */ +#endif /* __MONO_MINI_LLVM_CPP_H__ */ diff --git a/src/mono/mono/mini/mini-mips.c b/src/mono/mono/mini/mini-mips.c index 3db3a9debab41..d8fe51f52c8e0 100644 --- a/src/mono/mono/mini/mini-mips.c +++ b/src/mono/mono/mini/mini-mips.c @@ -95,7 +95,7 @@ static gpointer bp_trigger_page; do { \ code = mips_emit_exc_by_name (code, exc_name); \ cfg->bb_exit->max_offset += 16; \ - } while (0) + } while (0) #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \ MonoInst *inst; \ @@ -192,7 +192,7 @@ mono_arch_flush_register_windows (void) { } -gboolean +gboolean mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) { return TRUE; @@ -462,7 +462,7 @@ emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffse * @arg_info: an array to store the result infos * * Gathers information on parameters such as size, alignment and - * padding. arg_info should be large enought to hold param_count + 1 entries. + * padding. arg_info should be large enought to hold param_count + 1 entries. * * Returns the size of the activation frame. */ @@ -473,7 +473,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit guint32 size, align, pad; int offset = 0; - if (MONO_TYPE_ISSTRUCT (csig->ret)) { + if (MONO_TYPE_ISSTRUCT (csig->ret)) { frame_size += sizeof (target_mgreg_t); offset += 4; } @@ -493,7 +493,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit /* ignore alignment for now */ align = 1; - frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); + frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); arg_info [k].pad = pad; frame_size += size; arg_info [k + 1].pad = 0; @@ -768,7 +768,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* * mono_arch_regalloc_cost: * - * Return the cost, in number of memory references, of the action of + * Return the cost, in number of memory references, of the action of * allocating the variable VMV into a register during global register * allocation. */ @@ -1390,7 +1390,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) /* spill down, we'll fix it in a separate pass */ // cfg->flags |= MONO_CFG_HAS_SPILLUP; - /* this is bug #60332: remove when #59509 is fixed, so no weird vararg + /* this is bug #60332: remove when #59509 is fixed, so no weird vararg * call convs needs to be handled this way. */ if (cfg->flags & MONO_CFG_HAS_VARARGS) @@ -1480,7 +1480,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) offset &= ~(align - 1); cfg->sig_cookie = offset; offset += size; - } + } offset += SIZEOF_REGISTER - 1; offset &= ~(SIZEOF_REGISTER - 1); @@ -1537,7 +1537,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) inst = cfg->args [i]; if (inst->opcode != OP_REGVAR) { MonoType *arg_type; - + if (sig->hasthis && (i == 0)) arg_type = mono_get_object_type (); else @@ -1599,10 +1599,10 @@ mono_arch_create_vars (MonoCompile *cfg) } /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode, - * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info + * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info */ -/* +/* * take the arguments and generate the arch-specific * instructions to properly call the function in call. * This includes pushing, moving arguments to the right register @@ -1622,9 +1622,9 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) cfg->disable_aot = TRUE; /* - * mono_ArgIterator_Setup assumes the signature cookie is + * mono_ArgIterator_Setup assumes the signature cookie is * passed first and all the arguments which were before it are - * passed on the stack after the signature. So compensate by + * passed on the stack after the signature. So compensate by * passing a different signature. */ tmp_sig = mono_metadata_signature_dup (call->signature); @@ -1651,7 +1651,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) sig = call->signature; n = sig->param_count + sig->hasthis; - + cinfo = get_call_info (cfg->mempool, sig); if (cinfo->struct_ret) call->used_iregs |= 1 << cinfo->struct_ret; @@ -1827,7 +1827,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) #endif cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1); cfg->flags |= MONO_CFG_HAS_CALLS; - /* + /* * should set more info in call, such as the stack space * used by the args that needs to be added back to esp */ @@ -1846,7 +1846,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) #if 0 if (cfg->verbose_level > 0) { char* nm = mono_method_full_name (cfg->method, TRUE); - g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n", + g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n", nm, doffset, ainfo->size, ovf_size); g_free (nm); } @@ -1978,7 +1978,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) MonoInst *last_ins = ins->prev; switch (ins->opcode) { - case OP_MUL_IMM: + case OP_MUL_IMM: /* remove unnecessary multiplication with 1 */ if (ins->inst_imm == 1) { if (ins->dreg != ins->sreg1) { @@ -1997,11 +1997,11 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_LOAD_MEMBASE: case OP_LOADI4_MEMBASE: - /* - * OP_STORE_MEMBASE_REG reg, offset(basereg) + /* + * OP_STORE_MEMBASE_REG reg, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg */ - if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG + if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG || last_ins->opcode == OP_STORE_MEMBASE_REG) && ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { @@ -2015,7 +2015,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) } break; } - /* + /* * Note: reg1 must be different from the basereg in the second load * OP_LOAD_MEMBASE offset(basereg), reg1 * OP_LOAD_MEMBASE offset(basereg), reg2 @@ -2041,11 +2041,11 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) break; } #if 0 - /* - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + /* + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg * --> - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_ICONST reg, imm */ if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM @@ -2066,7 +2066,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1; - ins->sreg1 = last_ins->sreg1; + ins->sreg1 = last_ins->sreg1; } break; case OP_LOADU2_MEMBASE: @@ -2075,22 +2075,22 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2; - ins->sreg1 = last_ins->sreg1; + ins->sreg1 = last_ins->sreg1; } break; case OP_ICONV_TO_I4: case OP_ICONV_TO_U4: case OP_MOVE: ins->opcode = OP_MOVE; - /* - * OP_MOVE reg, reg + /* + * OP_MOVE reg, reg */ if (ins->dreg == ins->sreg1) { MONO_DELETE_INS (bb, ins); continue; } - /* - * OP_MOVE sreg, dreg + /* + * OP_MOVE sreg, dreg * OP_MOVE dreg, sreg */ if (last_ins && last_ins->opcode == OP_MOVE && @@ -2537,7 +2537,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) MONO_BB_FOR_EACH_INS (bb, ins) { mono_print_ins_index (idx++, ins); } - + } #endif @@ -2999,7 +2999,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) MONO_BB_FOR_EACH_INS (bb, ins) { mono_print_ins_index (idx++, ins); } - + } #endif @@ -3422,8 +3422,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_BREAK: /* - * gdb does not like encountering the hw breakpoint ins in the debugged code. - * So instead of emitting a trap, we emit a call a C function and place a + * gdb does not like encountering the hw breakpoint ins in the debugged code. + * So instead of emitting a trap, we emit a call a C function and place a * breakpoint there. */ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break)); @@ -3516,7 +3516,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mips_mfhi (code, ins->dreg); break; } - case OP_IDIV_UN: + case OP_IDIV_UN: case OP_IREM_UN: { guint32 *divisor_is_zero = (guint32 *)(void *)code; @@ -3927,7 +3927,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mips_nop (code); break; } - case OP_CALL_HANDLER: + case OP_CALL_HANDLER: mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb); mips_lui (code, mips_t9, mips_zero, 0); mips_addiu (code, mips_t9, mips_t9, 0); @@ -4281,16 +4281,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FSUB: mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_FMUL: mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_FDIV: mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_FNEG: mips_fnegd (code, ins->dreg, ins->sreg1); - break; + break; case OP_FCEQ: mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2); mips_addiu (code, ins->dreg, mips_zero, 1); @@ -4399,7 +4399,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mips_fbtrue (code, 0); mips_nop (code); } - + mips_fcmpd (code, cond, ins->sreg1, ins->sreg2); mips_nop (code); mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); @@ -4460,7 +4460,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset); g_assert_not_reached (); } - + cpos += max_len; last_ins = ins; @@ -4654,7 +4654,7 @@ mips_adjust_stackframe(MonoCompile *cfg) /* * Stack frame layout: - * + * * ------------------- sp + cfg->stack_usage + cfg->param_area * param area incoming * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET @@ -4663,7 +4663,7 @@ mips_adjust_stackframe(MonoCompile *cfg) * ra * ------------------- sp + cfg->stack_usage-4 * spilled regs - * ------------------- sp + + * ------------------- sp + * MonoLMF structure optional * ------------------- sp + cfg->arch.lmf_offset * saved registers s0-s8 @@ -4694,12 +4694,12 @@ mono_arch_emit_prolog (MonoCompile *cfg) guint32 lmf_offset = cfg->arch.lmf_offset; int cfa_offset = 0; MonoBasicBlock *bb; - + sig = mono_method_signature_internal (method); cfg->code_size = 768 + sig->param_count * 20; code = cfg->native_code = g_malloc (cfg->code_size); - /* + /* * compute max_offset in order to use short forward jumps. */ max_offset = 0; @@ -4872,7 +4872,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = cinfo->args + i; inst = cfg->args [pos]; - + if (cfg->verbose_level > 2) g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage); if (inst->opcode == OP_REGVAR) { @@ -5184,8 +5184,8 @@ mono_arch_emit_exceptions (MonoCompile *cfg) int max_epilog_size = 50; /* count the number of exception infos */ - - /* + + /* * make sure we have enough space for exceptions * 24 is the simulated call to throw_exception_by_name */ @@ -5230,7 +5230,7 @@ void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg) { int this_dreg = mips_a0; - + if (vt_reg != -1) this_dreg = mips_a1; @@ -5480,7 +5480,7 @@ mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip) mono_arch_flush_icache (ip, code - ip); } - + /* * mono_arch_start_single_stepping: * @@ -5491,7 +5491,7 @@ mono_arch_start_single_stepping (void) { mono_mprotect (ss_trigger_page, mono_pagesize (), 0); } - + /* * mono_arch_stop_single_stepping: * diff --git a/src/mono/mono/mini/mini-mips.h b/src/mono/mono/mini/mini-mips.h index e3fabff76d490..b3a9920adf4e7 100644 --- a/src/mono/mono/mini/mini-mips.h +++ b/src/mono/mono/mini/mini-mips.h @@ -193,7 +193,7 @@ typedef gdouble mips_freg; #define MONO_ARCH_FRAME_ALIGNMENT 8 -/* fixme: align to 16byte instead of 32byte (we align to 32byte to get +/* fixme: align to 16byte instead of 32byte (we align to 32byte to get * reproduceable results for benchmarks */ #define MONO_ARCH_CODE_ALIGNMENT 32 @@ -423,4 +423,4 @@ typedef struct { guint8 *mips_emit_load_const (guint8 *code, int dreg, target_mgreg_t v); -#endif /* __MONO_MINI_MIPS_H__ */ +#endif /* __MONO_MINI_MIPS_H__ */ diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index f41585485a911..f4b6fa56581dd 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -982,7 +982,7 @@ MINI_OP(OP_PMULQ, "pmulq", XREG, XREG, XREG) MINI_OP(OP_PMULW_HIGH_UN, "pmulw_high_un", XREG, XREG, XREG) MINI_OP(OP_PMULW_HIGH, "pmulw_high", XREG, XREG, XREG) -/*SSE2 Shift ops must have the _reg version right after as code depends on this ordering.*/ +/*SSE2 Shift ops must have the _reg version right after as code depends on this ordering.*/ MINI_OP(OP_PSHRW, "pshrw", XREG, XREG, NONE) MINI_OP(OP_PSHRW_REG, "pshrw_reg", XREG, XREG, XREG) @@ -1254,12 +1254,12 @@ MINI_OP(OP_CMOV_LLE_UN, "cmov_lle_un", IREG, IREG, IREG) MINI_OP(OP_CMOV_LLT_UN, "cmov_llt_un", IREG, IREG, IREG) /* Debugging support */ -/* +/* * Marks the start of the live range of the variable in inst_c0, that is the * first instruction where the variable has a value. */ MINI_OP(OP_LIVERANGE_START, "liverange_start", NONE, NONE, NONE) -/* +/* * Marks the end of the live range of the variable in inst_c0, that is the * first instruction where the variable no longer has a value. */ diff --git a/src/mono/mono/mini/mini-posix.c b/src/mono/mono/mini/mini-posix.c index a173516415bcb..b706de969f5ce 100644 --- a/src/mono/mono/mini/mini-posix.c +++ b/src/mono/mono/mini/mini-posix.c @@ -176,7 +176,7 @@ save_old_signal_handler (int signo, struct sigaction *old_action) } handler_to_save->sa_mask = old_action->sa_mask; handler_to_save->sa_flags = old_action->sa_flags; - + if (!mono_saved_signal_handlers) mono_saved_signal_handlers = g_hash_table_new_full (NULL, NULL, NULL, g_free); g_hash_table_insert (mono_saved_signal_handlers, GINT_TO_POINTER (signo), handler_to_save); @@ -321,7 +321,7 @@ add_signal_handler (int signo, MonoSignalHandler handler, int flags) #endif sa.sa_flags |= SA_ONSTACK; - /* + /* * libgc will crash when trying to do stack marking for threads which are on * an altstack, so delay the suspend signal after the signal handler has * executed. @@ -331,11 +331,11 @@ add_signal_handler (int signo, MonoSignalHandler handler, int flags) } #endif if (signo == SIGSEGV) { - /* + /* * Delay abort signals while handling SIGSEGVs since they could go unnoticed. */ sigset_t block_mask; - + sigemptyset (&block_mask); } #else @@ -347,7 +347,7 @@ add_signal_handler (int signo, MonoSignalHandler handler, int flags) /* if there was already a handler in place for this signal, store it */ if (! (previous_sa.sa_flags & SA_SIGINFO) && - (SIG_DFL == previous_sa.sa_handler)) { + (SIG_DFL == previous_sa.sa_handler)) { /* it there is no sa_sigaction function and the sa_handler is default, we can safely ignore this */ } else { if (mono_do_signal_chaining) @@ -958,7 +958,7 @@ mono_gdb_render_native_backtraces (pid_t crashed_pid) const char *argv [10]; memset (argv, 0, sizeof (char*) * 10); - char commands_filename [100]; + char commands_filename [100]; commands_filename [0] = '\0'; g_snprintf (commands_filename, sizeof (commands_filename), "/tmp/mono-gdb-commands.%d", crashed_pid); diff --git a/src/mono/mono/mini/mini-ppc.c b/src/mono/mono/mini/mini-ppc.c index 48174a3130ac3..ed8bf63f631a1 100644 --- a/src/mono/mono/mini/mini-ppc.c +++ b/src/mono/mono/mini/mini-ppc.c @@ -155,7 +155,7 @@ emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffse /* the hardware has multiple load/store units and the move is long enough to use more then one register, then use load/load/store/store to execute 2 instructions per cycle. */ - if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) { + if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) { while (size >= 16) { ppc_ldptr (code, ppc_r0, soffset, sreg); ppc_ldptr (code, ppc_r11, soffset+8, sreg); @@ -163,7 +163,7 @@ emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffse ppc_stptr (code, ppc_r11, doffset+8, dreg); size -= 16; soffset += 16; - doffset += 16; + doffset += 16; } } while (size >= 8) { @@ -174,7 +174,7 @@ emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffse doffset += 8; } #else - if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) { + if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) { while (size >= 8) { ppc_lwz (code, ppc_r0, soffset, sreg); ppc_lwz (code, ppc_r11, soffset+4, sreg); @@ -182,7 +182,7 @@ emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffse ppc_stw (code, ppc_r11, doffset+4, dreg); size -= 8; soffset += 8; - doffset += 8; + doffset += 8; } } #endif @@ -217,7 +217,7 @@ emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffse * @arg_info: an array to store the result infos * * Gathers information on parameters such as size, alignment and - * padding. arg_info should be large enought to hold param_count + 1 entries. + * padding. arg_info should be large enought to hold param_count + 1 entries. * * Returns the size of the activation frame. */ @@ -232,7 +232,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit int size, align, pad; int offset = 8; - if (MONO_TYPE_ISSTRUCT (csig->ret)) { + if (MONO_TYPE_ISSTRUCT (csig->ret)) { frame_size += sizeof (target_mgreg_t); offset += 4; } @@ -247,7 +247,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit arg_info [0].size = frame_size; for (k = 0; k < param_count; k++) { - + if (csig->pinvoke && !csig->marshalling_disabled) size = mono_type_native_stack_size (csig->params [k], (guint32*)&align); else @@ -256,7 +256,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit /* ignore alignment for now */ align = 1; - frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); + frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); arg_info [k].pad = pad; frame_size += size; arg_info [k + 1].pad = 0; @@ -483,7 +483,7 @@ typedef struct { } AuxVec; #define MAX_AUX_ENTRIES 128 -/* +/* * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL, * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features */ @@ -709,7 +709,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* * mono_arch_regalloc_cost: * - * Return the cost, in number of memory references, of the action of + * Return the cost, in number of memory references, of the action of * allocating the variable VMV into a register during global register * allocation. */ @@ -862,7 +862,7 @@ struct CallInfo { static gboolean is_float_struct_returnable_via_regs (MonoType *type, int* member_cnt, int* member_size) { - int local_member_cnt, local_member_size; + int local_member_cnt, local_member_size; if (!member_cnt) { member_cnt = &local_member_cnt; } @@ -1375,7 +1375,7 @@ mono_arch_allocate_vars (MonoCompile *m) m->flags |= MONO_CFG_HAS_SPILLUP; - /* this is bug #60332: remove when #59509 is fixed, so no weird vararg + /* this is bug #60332: remove when #59509 is fixed, so no weird vararg * call convs needs to be handled this way. */ if (m->flags & MONO_CFG_HAS_VARARGS) @@ -1389,7 +1389,7 @@ mono_arch_allocate_vars (MonoCompile *m) header = m->header; - /* + /* * We use the frame register also for any method that has * exception clauses. This way, when the handlers are called, * the code will reference local variables using the frame reg instead of @@ -1397,7 +1397,7 @@ mono_arch_allocate_vars (MonoCompile *m) * corrupt the method frames that are already on the stack (since * filters get called before stack unwinding happens) when the filter * code would call any method (this also applies to finally etc.). - */ + */ if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses) frame_reg = ppc_r31; m->frame_reg = frame_reg; @@ -1406,7 +1406,7 @@ mono_arch_allocate_vars (MonoCompile *m) } sig = mono_method_signature_internal (m->method); - + offset = 0; curinst = 0; if (MONO_TYPE_ISSTRUCT (sig->ret)) { @@ -1429,7 +1429,7 @@ mono_arch_allocate_vars (MonoCompile *m) } } /* local vars are at a positive offset from the stack pointer */ - /* + /* * also note that if the function uses alloca, we use ppc_r31 * to point at the local variables. */ @@ -1506,7 +1506,7 @@ mono_arch_allocate_vars (MonoCompile *m) } if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (target_mgreg_t)) size = align = sizeof (target_mgreg_t); - /* + /* * Use at least 4/8 byte alignment, since these might be passed in registers, and * they are saved using std in the prolog. */ @@ -1552,7 +1552,7 @@ mono_arch_create_vars (MonoCompile *cfg) } /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode, - * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info + * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info */ static void @@ -1578,7 +1578,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) sig = call->signature; n = sig->param_count + sig->hasthis; - + cinfo = get_call_info (sig); for (i = 0; i < n; ++i) { @@ -1913,7 +1913,7 @@ if (0 && ins->inst_true_bb->native_offset) { \ MONO_PATCH_INFO_EXC, exc_name); \ ppc_bcl (code, (b0), (b1), 0); \ } \ - } while (0); + } while (0); #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name)) @@ -1954,7 +1954,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) { switch (normalize_opcode (ins->opcode)) { - case OP_MUL_IMM: + case OP_MUL_IMM: /* remove unnecessary multiplication with 1 */ if (ins->inst_imm == 1) { if (ins->dreg != ins->sreg1) { @@ -1972,8 +1972,8 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_LOAD_MEMBASE: - /* - * OP_STORE_MEMBASE_REG reg, offset(basereg) + /* + * OP_STORE_MEMBASE_REG reg, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg */ if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG && @@ -1988,7 +1988,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->sreg1 = last_ins->sreg1; } - /* + /* * Note: reg1 must be different from the basereg in the second load * OP_LOAD_MEMBASE offset(basereg), reg1 * OP_LOAD_MEMBASE offset(basereg), reg2 @@ -2012,11 +2012,11 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) //g_assert_not_reached (); #if 0 - /* - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + /* + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg * --> - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_ICONST reg, imm */ } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM && @@ -2035,7 +2035,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1; - ins->sreg1 = last_ins->sreg1; + ins->sreg1 = last_ins->sreg1; } break; case OP_LOADU2_MEMBASE: @@ -2044,7 +2044,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2; - ins->sreg1 = last_ins->sreg1; + ins->sreg1 = last_ins->sreg1; } break; #ifdef __mono_ppc64__ @@ -2060,15 +2060,15 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) #endif case OP_MOVE: ins->opcode = OP_MOVE; - /* - * OP_MOVE reg, reg + /* + * OP_MOVE reg, reg */ if (ins->dreg == ins->sreg1) { MONO_DELETE_INS (bb, ins); continue; } - /* - * OP_MOVE sreg, dreg + /* + * OP_MOVE sreg, dreg * OP_MOVE dreg, sreg */ if (last_ins && last_ins->opcode == OP_MOVE && @@ -2232,7 +2232,7 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins) } } -/* +/* * the branch_b0_table should maintain the order of these * opcodes. case CEE_BEQ: @@ -2246,34 +2246,34 @@ case CEE_BGT_UN: case CEE_BLE_UN: case CEE_BLT_UN: */ -static const guchar +static const guchar branch_b0_table [] = { - PPC_BR_TRUE, - PPC_BR_FALSE, - PPC_BR_TRUE, - PPC_BR_FALSE, - PPC_BR_TRUE, - - PPC_BR_FALSE, - PPC_BR_FALSE, - PPC_BR_TRUE, + PPC_BR_TRUE, + PPC_BR_FALSE, + PPC_BR_TRUE, + PPC_BR_FALSE, + PPC_BR_TRUE, + + PPC_BR_FALSE, + PPC_BR_FALSE, + PPC_BR_TRUE, PPC_BR_FALSE, PPC_BR_TRUE }; -static const guchar +static const guchar branch_b1_table [] = { - PPC_BR_EQ, - PPC_BR_LT, - PPC_BR_GT, + PPC_BR_EQ, + PPC_BR_LT, PPC_BR_GT, - PPC_BR_LT, - - PPC_BR_EQ, - PPC_BR_LT, - PPC_BR_GT, PPC_BR_GT, - PPC_BR_LT + PPC_BR_LT, + + PPC_BR_EQ, + PPC_BR_LT, + PPC_BR_GT, + PPC_BR_GT, + PPC_BR_LT }; #define NEW_INS(cfg,dest,op) do { \ @@ -2621,7 +2621,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) last_ins = ins; } bb->last_ins = last_ins; - bb->max_vreg = cfg->next_vreg; + bb->max_vreg = cfg->next_vreg; } static guchar* @@ -2814,7 +2814,7 @@ ppc_patch_full (MonoCompile *cfg, guchar *code, const guchar *target, gboolean i return; } } - + if ((glong)target >= 0){ if ((glong)target <= 33554431){ ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2; @@ -2834,8 +2834,8 @@ ppc_patch_full (MonoCompile *cfg, guchar *code, const guchar *target, gboolean i g_assert_not_reached (); } - - + + if (prim == 16) { g_assert (!is_fd); // absolute address @@ -3054,7 +3054,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (cfg->compile_aot) NOT_IMPLEMENTED; - /* + /* * Read from the single stepping trigger page. This will cause a * SIGSEGV when single stepping is enabled. * We do this _before_ the breakpoint, so single stepping after @@ -3067,7 +3067,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_add_seq_point (cfg, bb, ins, code - cfg->native_code); - /* + /* * A placeholder for a possible breakpoint inserted by * mono_arch_set_breakpoint (). */ @@ -3313,8 +3313,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_BREAK: /* - * gdb does not like encountering a trap in the debugged code. So - * instead of emitting a trap, we emit a call a C function and place a + * gdb does not like encountering a trap in the debugged code. So + * instead of emitting a trap, we emit a call a C function and place a * breakpoint there. */ //ppc_break (code); @@ -3590,7 +3590,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_IMUL_OVF: CASE_PPC64 (OP_LMUL_OVF) - /* we annot use mcrxr, since it's not implemented on some processors + /* we annot use mcrxr, since it's not implemented on some processors * XER format: SO, OV, CA, reserved [21 bits], count [8 bits] */ if (ins->opcode == OP_IMUL_OVF) @@ -3606,7 +3606,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IMUL_OVF_UN: CASE_PPC64 (OP_LMUL_OVF_UN) /* we first multiply to get the high word and compare to 0 - * to set the flags, then the result is discarded and then + * to set the flags, then the result is discarded and then * we multiply to get the lower * bits result */ if (ins->opcode == OP_IMUL_OVF_UN) @@ -3958,7 +3958,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_blr (code); break; } - case OP_CALL_HANDLER: + case OP_CALL_HANDLER: mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb); ppc_bl (code, 0); for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev) @@ -3970,7 +3970,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_BR: /*if (ins->inst_target_bb->native_offset) { ppc_b (code, 0); - //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); + //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); } else*/ { mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb); ppc_b (code, 0); @@ -4193,7 +4193,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) msword_negative_branch = code; ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0); ppc_patch (msword_negative_branch, ovf_ex_target); - + ppc_patch (msword_positive_branch, code); if (ins->dreg != ins->sreg1) ppc_mr (code, ins->dreg, ins->sreg1); @@ -4226,16 +4226,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FSUB: ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_FMUL: ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_FDIV: ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2); - break; + break; case OP_FNEG: ppc_fneg (code, ins->dreg, ins->sreg1); - break; + break; case OP_FREM: /* emulated */ g_assert_not_reached (); @@ -4562,7 +4562,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset)); g_assert_not_reached (); } - + cpos += max_len; last_ins = ins; @@ -4710,7 +4710,7 @@ save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean /* * Stack frame layout: - * + * * ------------------- sp * MonoLMF structure or saved registers * ------------------- @@ -4806,7 +4806,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* compute max_offset in order to use short forward jumps * we always do it on ppc because the immediate displacement - * for jumps is too small + * for jumps is too small */ max_offset = 0; for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { @@ -4840,7 +4840,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = cinfo->args + i; inst = cfg->args [pos]; - + if (cfg->verbose_level > 2) g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype); if (inst->opcode == OP_REGVAR) { @@ -5204,7 +5204,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) if (cfg->method->save_lmf) max_epilog_size += 128; - + code = realloc_code (cfg, max_epilog_size); pos = 0; @@ -5332,8 +5332,8 @@ mono_arch_emit_exceptions (MonoCompile *cfg) } /* count the number of exception infos */ - - /* + + /* * make sure we have enough space for exceptions */ for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { @@ -5801,7 +5801,7 @@ mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, Mon * * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and * TARGET from the mscorlib GOT in full-aot code. - * On PPC, the GOT address is assumed to be in r30, and the result is placed into + * On PPC, the GOT address is assumed to be in r30, and the result is placed into * r12. */ guint8* @@ -5891,7 +5891,7 @@ mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji) /* * SINGLE STEPPING */ - + /* * mono_arch_start_single_stepping: * @@ -5902,7 +5902,7 @@ mono_arch_start_single_stepping (void) { mono_mprotect (ss_trigger_page, mono_pagesize (), 0); } - + /* * mono_arch_stop_single_stepping: * diff --git a/src/mono/mono/mini/mini-ppc.h b/src/mono/mono/mini/mini-ppc.h index 6f1ce5ff2e9a1..88a5415c5a925 100644 --- a/src/mono/mono/mini/mini-ppc.h +++ b/src/mono/mono/mini/mini-ppc.h @@ -28,7 +28,7 @@ #define MONO_ARCH_FRAME_ALIGNMENT 16 -/* fixme: align to 16byte instead of 32byte (we align to 32byte to get +/* fixme: align to 16byte instead of 32byte (we align to 32byte to get * reproduceable results for benchmarks */ #define MONO_ARCH_CODE_ALIGNMENT 32 @@ -71,9 +71,9 @@ typedef struct MonoCompileArch { * - for variables which contain values of registers, use host_mgreg_t or target_mgreg_t. * - for loading/saving pointers/ints, use the normal ppc_load_reg/ppc_save_reg () * macros. - * - for loading/saving register sized quantities, use the ppc_ldr/ppc_str + * - for loading/saving register sized quantities, use the ppc_ldr/ppc_str * macros. - * - make sure to not mix the two kinds of macros for the same memory location, + * - make sure to not mix the two kinds of macros for the same memory location, * since ppc is big endian, so a 8 byte store followed by a 4 byte load will * load the upper 32 bit of the value. * - use OP_LOADR_MEMBASE/OP_STORER_MEMBASE to load/store register sized diff --git a/src/mono/mono/mini/mini-profiler.c b/src/mono/mono/mini/mini-profiler.c index cc20f01d4a2ad..c3a78238e4d31 100644 --- a/src/mono/mono/mini/mini-profiler.c +++ b/src/mono/mono/mini/mini-profiler.c @@ -149,7 +149,7 @@ mini_profiler_emit_tail_call (MonoCompile *cfg, MonoMethod *target) EMIT_NEW_PCONST (cfg, iargs [1], NULL); if (target) - EMIT_NEW_METHODCONST (cfg, iargs [2], target); + EMIT_NEW_METHODCONST (cfg, iargs [2], target); else EMIT_NEW_PCONST (cfg, iargs [2], NULL); diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index 78d588f38a435..a52e6cb1a7628 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -126,7 +126,7 @@ gboolean mono_use_llvm = FALSE; gboolean mono_use_fast_math = FALSE; -// Lists of allowlisted and blocklisted CPU features +// Lists of allowlisted and blocklisted CPU features MonoCPUFeatures mono_cpu_features_enabled = (MonoCPUFeatures)0; #ifdef DISABLE_SIMD @@ -2021,7 +2021,7 @@ mono_enable_jit_dump (void) { if (perf_dump_pid == 0) perf_dump_pid = getpid(); - + if (!perf_dump_file) { char name [64]; FileHeader header; @@ -2029,18 +2029,18 @@ mono_enable_jit_dump (void) mono_os_mutex_init (&perf_dump_mutex); mono_os_mutex_lock (&perf_dump_mutex); - + g_snprintf (name, sizeof (name), "/tmp/jit-%d.dump", perf_dump_pid); unlink (name); perf_dump_file = fopen (name, "w"); - + add_file_header_info (&header); if (perf_dump_file) { fwrite (&header, sizeof (header), 1, perf_dump_file); //This informs perf of the presence of the jitdump file and support for the feature. perf_dump_mmap_addr = mmap (NULL, sizeof (header), PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno (perf_dump_file), 0); } - + mono_os_mutex_unlock (&perf_dump_mutex); } } @@ -2062,12 +2062,12 @@ void mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code) { static uint64_t code_index; - + if (perf_dump_file) { JitCodeLoadRecord record; size_t nameLen = strlen (jinfo->d.method->name); memset (&record, 0, sizeof (record)); - + add_basic_JitCodeLoadRecord_info (&record); record.header.total_size = sizeof (record) + nameLen + 1 + jinfo->code_size; record.vma = (guint64)jinfo->code_start; @@ -2075,13 +2075,13 @@ mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code) record.code_size = (guint64)jinfo->code_size; mono_os_mutex_lock (&perf_dump_mutex); - + record.code_index = ++code_index; - + // TODO: write debugInfo and unwindInfo immediately before the JitCodeLoadRecord (while lock is held). - + record.header.timestamp = mono_clock_get_time_ns (clock_id); - + fwrite (&record, sizeof (record), 1, perf_dump_file); fwrite (jinfo->d.method->name, nameLen + 1, 1, perf_dump_file); fwrite (code, jinfo->code_size, 1, perf_dump_file); @@ -2812,7 +2812,7 @@ mono_jit_free_method (MonoMethod *method) mono_debug_remove_method (method, NULL); mono_lldb_remove_method (method, ji); - + //seq_points are always on get_default_jit_mm jit_mm = get_default_jit_mm (); jit_mm_lock (jit_mm); @@ -4402,7 +4402,7 @@ mini_init (const char *filename, const char *runtime_version) mono_ee_interp_init (mono_interp_opts_string); #endif mono_components_init (); - + mono_component_debugger ()->parse_options (mono_debugger_agent_get_sdb_options ()); mono_os_mutex_init_recursive (&jit_mutex); diff --git a/src/mono/mono/mini/mini-runtime.h b/src/mono/mono/mini/mini-runtime.h index d1e822a35e7a2..4f348797326d3 100644 --- a/src/mono/mono/mini/mini-runtime.h +++ b/src/mono/mono/mini/mini-runtime.h @@ -159,14 +159,14 @@ struct MonoJitTlsData { /* context to be used by the guard trampoline when resuming interruption.*/ MonoContext handler_block_context; - /* + /* * Stores the state at the exception throw site to be used by mono_stack_walk () * when it is called from profiler functions during exception handling. */ MonoContext orig_ex_ctx; gboolean orig_ex_ctx_set; - /* + /* * The current exception in flight */ MonoGCHandle thrown_exc; diff --git a/src/mono/mono/mini/mini-s390x.c b/src/mono/mono/mini/mini-s390x.c index 5e4aca54eadb6..3cc263ec280da 100644 --- a/src/mono/mono/mini/mini-s390x.c +++ b/src/mono/mono/mini/mini-s390x.c @@ -62,7 +62,7 @@ if (ins->inst_target_bb->native_offset) { \ mono_add_patch_info (cfg, code - cfg->native_code, \ MONO_PATCH_INFO_EXC, exc_name); \ s390_jcl (code, cond, 0); \ - } while (0); + } while (0); #define EMIT_COMP_AND_BRANCH(ins, cab, cmp) \ { \ @@ -213,7 +213,7 @@ if (ins->inst_true_bb->native_offset) { \ } \ s390_ ## op (code, ins->dreg, ins->sreg2, m, s390_f14); \ } \ - s390_ldgr (code, s390_f14, s390_r1); + s390_ldgr (code, s390_f14, s390_r1); #undef DEBUG #define DEBUG(a) if (cfg->verbose_level > 1) a @@ -279,7 +279,7 @@ typedef struct { code_size, parm_size, retStruct; -} size_data; +} size_data; /** * ABI - register use in calls etc. @@ -390,7 +390,7 @@ static const char * fpNames[] = { * Constants used in debugging - map vector register names */ static const char * vrNames[] = { - "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7", + "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7", "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15", "vr16", "vr17", "vr18", "vr19", "vr20", "vr21", "vr22", "vr23", "vr24", "vr25", "vr26", "vr27", "vr28", "vr29", "vr30", "vr31" @@ -400,7 +400,7 @@ static const char * vrNames[] = { /** * Constants used in debugging - ABI register types */ -static const char *typeParm[] = { "General", "Base", "FPR8", "FPR4", "StructByVal", +static const char *typeParm[] = { "General", "Base", "FPR8", "FPR4", "StructByVal", "StructByValInFP", "ByAddr"}; #endif @@ -410,9 +410,9 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (math, "System", "Math") static GENERATE_TRY_GET_CLASS_WITH_CACHE (mathf, "System", "MathF") /** - * + * * @brief Return general register name - * + * * @param[in] register number * @returns Name of register * @@ -420,7 +420,7 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (mathf, "System", "MathF") */ const char* -mono_arch_regname (int reg) +mono_arch_regname (int reg) { if (reg >= 0 && reg < 16) return grNames [reg]; @@ -431,9 +431,9 @@ mono_arch_regname (int reg) /*========================= End of Function ========================*/ /** - * + * * @brief Return floating point register name - * + * * @param[in] register number * @returns Name of register * @@ -441,7 +441,7 @@ mono_arch_regname (int reg) */ const char* -mono_arch_fregname (int reg) +mono_arch_fregname (int reg) { if (reg >= 0 && reg < 16) return fpNames [reg]; @@ -452,9 +452,9 @@ mono_arch_fregname (int reg) /*========================= End of Function ========================*/ /** - * + * * @brief Return vector register name - * + * * @param[in] register number * @returns Name of register * @@ -473,28 +473,28 @@ mono_arch_xregname (int reg) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific return argument information - * + * * @param[in] @csig - Method signature * @param[in] @param_count - Number of parameters to consider * @param[out] @arg_info - An array in which to store results * @returns Size of the activation frame * - * Gathers information on parameters such as size, alignment, and padding. - * arg_info should be large * enough to hold param_count + 1 entries. + * Gathers information on parameters such as size, alignment, and padding. + * arg_info should be large * enough to hold param_count + 1 entries. */ int -mono_arch_get_argument_info (MonoMethodSignature *csig, - int param_count, +mono_arch_get_argument_info (MonoMethodSignature *csig, + int param_count, MonoJitArgumentInfo *arg_info) { int k, frame_size = 0; int size, align, pad; int offset = 8; - if (MONO_TYPE_ISSTRUCT (csig->ret)) { + if (MONO_TYPE_ISSTRUCT (csig->ret)) { frame_size += sizeof (target_mgreg_t); offset += 8; } @@ -509,13 +509,13 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, arg_info [0].size = frame_size; for (k = 0; k < param_count; k++) { - + if (csig->pinvoke && !csig->marshalling_disabled) size = mono_type_native_stack_size (csig->params [k], (guint32 *) &align); else size = mini_type_stack_size (csig->params [k], &align); - frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); + frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); arg_info [k].pad = pad; frame_size += size; arg_info [k + 1].pad = 0; @@ -535,9 +535,9 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, /*========================= End of Function ========================*/ /** - * + * * @brief Emit an s390x move operation - * + * * @param[in] @cfg - MonoCompile control block * @param[in] @dr - Destination register * @param[in] @ins - Current instruction @@ -553,9 +553,9 @@ emit_new_move(MonoCompile *cfg, int dr, MonoInst *ins, MonoInst *src) ArgInfo *ainfo = (ArgInfo *) ins->inst_p1; MonoInst *vtcopy = mono_compile_create_var (cfg, m_class_get_byval_arg (src->klass), OP_LOCAL); MonoInst *load; - MonoInst *move; + MonoInst *move; int size; - + if (call->signature->pinvoke && !call->signature->marshalling_disabled) { size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL); vtcopy->backend.is_pinvoke = 1; @@ -570,26 +570,26 @@ emit_new_move(MonoCompile *cfg, int dr, MonoInst *ins, MonoInst *src) move->inst_offset = 0; move->sreg1 = src->dreg; move->inst_imm = 0; - move->backend.size = size; - MONO_ADD_INS (cfg->cbb, move); + move->backend.size = size; + MONO_ADD_INS (cfg->cbb, move); if (dr != 0) MONO_EMIT_NEW_UNALU(cfg, OP_MOVE, dr, load->dreg); else MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, ainfo->reg, ainfo->offset, load->dreg); -} +} /*========================= End of Function ========================*/ /** - * + * * @brief Generate output sequence for VT register parameters - * + * * @param[in] @cfg - MonoCompile control block * @param[in] @dr - Destination register * @param[in] @ins - Current instruction - * @param[in] @src - Instruction representing the source - * + * @param[in] @src - Instruction representing the source + * * Emit the output of structures for calls whose address is placed in a register. */ @@ -620,7 +620,7 @@ emit_outarg_vtr(MonoCompile *cfg, MonoInst *ins, MonoInst *src) MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI8_MEMBASE, reg, src->dreg, 0); break; - default: + default: emit_new_move (cfg, reg, ins, src); } mono_call_inst_add_outarg_reg(cfg, call, reg, ainfo->reg, FALSE); @@ -629,14 +629,14 @@ emit_outarg_vtr(MonoCompile *cfg, MonoInst *ins, MonoInst *src) /*========================= End of Function ========================*/ /** - * + * * @brief Generate output sequence for VT stack parameters - * + * * @param[in] @cfg - MonoCompile control block * @param[in] @dr - Destination register * @param[in] @ins - Current instruction - * @param[in] @src - Instruction representing the source - * + * @param[in] @src - Instruction representing the source + * * Emit the output of structures for calls whose address is placed on the stack */ @@ -644,12 +644,12 @@ static void __inline__ emit_outarg_vts(MonoCompile *cfg, MonoInst *ins, MonoInst *src) { ArgInfo *ainfo = (ArgInfo *) ins->inst_p1; - int tmpr = mono_alloc_preg (cfg); + int tmpr = mono_alloc_preg (cfg); switch (ins->backend.size) { case 0: MONO_EMIT_NEW_ICONST(cfg, tmpr, 0); - MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, ainfo->reg, ainfo->offset, tmpr); break; case 1: @@ -685,15 +685,15 @@ emit_outarg_vts(MonoCompile *cfg, MonoInst *ins, MonoInst *src) /*========================= End of Function ========================*/ /** - * + * * @brief Generate unwind information for range of registers - * + * * @param[in] @cfg - MonoCompile control block * @param[in] @code - Location of code * @param[in] @start - Starting register * @param[in] @end - Ending register * @param[in] @offset - Offset in stack - * + * * Emit unwind information for a range of registers. */ @@ -712,13 +712,13 @@ emit_unwind_regs(MonoCompile *cfg, guint8 *code, int start, int end, long offset /*========================= End of Function ========================*/ /** - * + * * @brief Get previous stack frame pointer - * + * * @param[in] @cfg - MonoCompile control block * @param[in] @code - Location of code * @returns Previous stack pointer - * + * * Retrieve the stack pointer of the previous frame */ @@ -751,9 +751,9 @@ backUpStackPtr(MonoCompile *cfg, guint8 *code) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific CPU initialization - * + * * Perform CPU specific initialization to execute managed code. */ @@ -765,10 +765,10 @@ mono_arch_cpu_init (void) /*========================= End of Function ========================*/ /** - * + * * @brief Archictecture specific initialization - * - * + * + * * Initialize architecture specific code: * - Define trigger pages for debugger * - Generate breakpoint code stub @@ -786,10 +786,10 @@ mono_arch_init (void) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific cleaup code - * - * + * + * * Clean up before termination: * - Free the trigger pages */ @@ -802,12 +802,12 @@ mono_arch_cleanup (void) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific check for fast TLS access - * + * * @returns True - * - * Returns whether we use fast inlined thread local storage managed access, + * + * Returns whether we use fast inlined thread local storage managed access, * instead of falling back to native code. */ @@ -820,12 +820,12 @@ mono_arch_have_fast_tls (void) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific check of mono optimizations - * + * * @param[out] @exclude_mask - Optimization exclusion mask * @returns Optimizations supported on this CPU - * + * * Returns the optimizations supported on this CPU */ @@ -844,12 +844,12 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific allocation of integer variables - * + * * @param[in] @cfg - MonoCompile control block * @returns A list of integer variables - * + * * Returns a list of allocatable integer variables */ @@ -867,7 +867,7 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg) if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos) continue; - if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || + if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG)) continue; @@ -885,12 +885,12 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific determination of usable integer registers - * + * * @param[in] @cfg - MonoCompile control block * @returns A list of allocatable registers - * + * * Returns a list of usable integer registers */ @@ -909,7 +909,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* FIXME: s390_r12 is reserved for bkchain_reg. Only reserve it if needed */ top = 12; for (i = 8; i < top; ++i) { - if ((cfg->frame_reg != i) && + if ((cfg->frame_reg != i) && //!((cfg->uses_rgctx_reg) && (i == MONO_ARCH_IMT_REG))) (i != MONO_ARCH_IMT_REG)) regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); @@ -921,12 +921,12 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific flush of instruction cache - * + * * @param[in] @code - Start of code * @param[in] @size - Amount to be flushed - * + * * Flush the CPU icache. */ @@ -938,13 +938,13 @@ mono_arch_flush_icache (guint8 *code, gint size) /*========================= End of Function ========================*/ /** - * - * @brief Add an integer register parameter - * + * + * @brief Add an integer register parameter + * * @param[in] @gr - Address of current register number * @param[in] @sz - Stack size data * @param[in] @ainfo - Parameter information - * + * * Assign a parameter to a general register or spill it onto the stack */ @@ -957,11 +957,11 @@ add_general (guint *gr, size_data *sz, ArgInfo *ainfo) ainfo->reg = STK_BASE; ainfo->regtype = RegTypeBase; sz->stack_size += sizeof(long); - sz->code_size += 12; + sz->code_size += 12; } else { ainfo->reg = *gr; ainfo->regtype = RegTypeGeneral; - sz->code_size += 8; + sz->code_size += 8; } (*gr) ++; } @@ -969,15 +969,15 @@ add_general (guint *gr, size_data *sz, ArgInfo *ainfo) /*========================= End of Function ========================*/ /** - * + * * @brief Add a structure variable to parameter list - * + * * @param[in] @gr - Address of current register number * @param[in] @sz - Stack size data * @param[in] @ainfo - Parameter information * @param[in] @size - Size of parameter * @param[in] @type - Type of stack parameter (reference or value) - * + * * Assign a structure address to a register or spill it onto the stack */ @@ -1003,14 +1003,14 @@ add_stackParm (guint *gr, size_data *sz, ArgInfo *ainfo, gint size, ArgStorage t /*========================= End of Function ========================*/ /** - * + * * @brief Add a floating point register parameter - * + * * @param[in] @fr - Address of current register number * @param[in] @sz - Stack size data * @param[in] @ainfo - Parameter information * @param[in] @isDouble - Precision of parameter - * + * * Assign a parameter to a FP register or spill it onto the stack */ @@ -1038,15 +1038,15 @@ add_float (guint *fr, size_data *sz, ArgInfo *ainfo, gboolean isDouble) /*========================= End of Function ========================*/ /** - * + * * @brief Extract information about call parameters and stack use - * + * * @param[in] @mp - Mono Memory Pool * @param[in] @sig - Mono Method Signature * @returns Information about the parameters and stack usage for a call - * - * Determine the amount of space required for code and stack. In addition - * determine starting points for stack-based parameters, and area for + * + * Determine the amount of space required for code and stack. In addition + * determine starting points for stack-based parameters, and area for * structures being returned on the stack. */ @@ -1131,7 +1131,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) goto enum_retvalue; } size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled); - + cinfo->struct_ret = 1; cinfo->ret.size = size; cinfo->ret.vtsize = size; @@ -1140,7 +1140,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) case MONO_TYPE_TYPEDBYREF: { MonoClass *klass = mono_class_from_mono_type_internal (sig->ret); size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled); - + cinfo->struct_ret = 1; cinfo->ret.size = size; cinfo->ret.vtsize = size; @@ -1161,9 +1161,9 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) * are sometimes made using calli without sig->hasthis set, like in the delegate * invoke wrappers. */ - if (cinfo->struct_ret && !is_pinvoke && - (sig->hasthis || - (sig->param_count > 0 && + if (cinfo->struct_ret && !is_pinvoke && + (sig->hasthis || + (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) { if (sig->hasthis) { cinfo->args[nParm].size = sizeof (target_mgreg_t); @@ -1331,7 +1331,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) case 8: add_general(&gr, sz, cinfo->args+nParm); cinfo->args[nParm].size = size; - cinfo->args[nParm].regtype = RegTypeStructByVal; + cinfo->args[nParm].regtype = RegTypeStructByVal; nParm++; break; default: @@ -1364,7 +1364,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) /* * If we are passing a structure back then we make room at - * the end of the parameters that may have been placed on + * the end of the parameters that may have been placed on * the stack */ if (cinfo->struct_ret) { @@ -1382,13 +1382,13 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific allocation of variables - * + * * @param[in] @cfg - Compile control block - * - * Set var information according to the calling convention for s390x. - * + * + * Set var information according to the calling convention for s390x. + * */ void @@ -1406,8 +1406,8 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->flags |= MONO_CFG_HAS_SPILLUP; - /*---------------------------------------------------------*/ - /* We use the frame register also for any method that has */ + /*---------------------------------------------------------*/ + /* We use the frame register also for any method that has */ /* filter clauses. This way, when the handlers are called, */ /* the code will reference local variables using the frame */ /* reg instead of the stack pointer: if we had to restore */ @@ -1415,7 +1415,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) /* are already on the stack (since filters get called */ /* before stack unwinding happens) when the filter code */ /* would call any method. */ - /*---------------------------------------------------------*/ + /*---------------------------------------------------------*/ if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses) frame_reg = s390_r11; @@ -1423,11 +1423,11 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->arch.bkchain_reg = -1; - if (frame_reg != STK_BASE) - cfg->used_int_regs |= (1LL << frame_reg); + if (frame_reg != STK_BASE) + cfg->used_int_regs |= (1LL << frame_reg); sig = mono_method_signature_internal (cfg->method); - + if (!cfg->arch.cinfo) cfg->arch.cinfo = get_call_info (cfg->mempool, sig); cinfo = cfg->arch.cinfo; @@ -1525,7 +1525,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) switch(size) { case 0: case 1: case 2: case 4: case 8: offStruct = (size < 8 ? sizeof(uintptr_t) - size : 0); - default: + default: inst->opcode = OP_REGOFFSET; inst->dreg = mono_alloc_preg (cfg); inst->inst_basereg = cfg->arch.bkchain_reg; @@ -1552,9 +1552,9 @@ mono_arch_allocate_vars (MonoCompile *cfg) default : if (cinfo->args [iParm].reg == STK_BASE) { /* - * These arguments are in the previous frame, so we can't + * These arguments are in the previous frame, so we can't * compute their offset from the current frame pointer right - * now, since cfg->stack_offset is not yet known, so dedicate a + * now, since cfg->stack_offset is not yet known, so dedicate a * register holding the previous frame pointer. */ cfg->arch.bkchain_reg = s390_r12; @@ -1571,10 +1571,10 @@ mono_arch_allocate_vars (MonoCompile *cfg) inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; size = (cinfo->args[iParm].size < 8 - ? sizeof(int) + ? sizeof(int) : sizeof(long)); offset = S390_ALIGN(offset, size); - if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) + if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) inst->inst_offset = offset; else inst->inst_offset = offset + (8 - size); @@ -1590,7 +1590,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) curinst = cfg->locals_start; for (iVar = curinst; iVar < cfg->num_varinfo; ++iVar) { inst = cfg->varinfo [iVar]; - if ((inst->flags & MONO_INST_IS_DEAD) || + if ((inst->flags & MONO_INST_IS_DEAD) || (inst->opcode == OP_REGVAR)) continue; @@ -1600,7 +1600,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) /* when they call functions returning structure */ /*--------------------------------------------------*/ if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype)) - size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), + size = mono_class_native_size (mono_class_from_mono_type_internal (inst->inst_vtype), (guint32 *) &align); else size = mono_type_size (inst->inst_vtype, &align); @@ -1610,7 +1610,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; offset += size; - DEBUG (g_print("allocating local %d to %ld, size: %d\n", + DEBUG (g_print("allocating local %d to %ld, size: %d\n", iVar, inst->inst_offset, size)); } offset = S390_ALIGN(offset, sizeof(uintptr_t)); @@ -1644,13 +1644,13 @@ mono_arch_allocate_vars (MonoCompile *cfg) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific creation of variables - * + * * @param[in] @cfg - Compile control block - * + * * Create variables for the method. - * + * */ void @@ -1687,15 +1687,15 @@ mono_arch_create_vars (MonoCompile *cfg) /*========================= End of Function ========================*/ /** - * + * * @brief Add a register to the call operation - * + * * @param[in] @cfg - Compile control block * @param[in] @call - Call Instruction * @param[in] @storage - Register use type * @param[in] @reg - Register number * @param[in] @tree - Call arguments - * + * * Add register use information to the call sequence */ @@ -1734,13 +1734,13 @@ add_outarg_reg2 (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int r /*========================= End of Function ========================*/ /** - * + * * @brief Emit a signature cookine - * + * * @param[in] @cfg - Compile control block * @param[in] @call - Call Instruction * @param[in] @cinfo - Call Information - * + * * Emit the signature cooke as a parameter */ @@ -1749,7 +1749,7 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) { MonoMethodSignature *tmpSig; MonoInst *sig_arg; - + cfg->disable_aot = TRUE; /* @@ -1762,8 +1762,8 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) tmpSig->param_count -= call->signature->sentinelpos; tmpSig->sentinelpos = 0; if (tmpSig->param_count > 0) - memcpy (tmpSig->params, - call->signature->params + call->signature->sentinelpos, + memcpy (tmpSig->params, + call->signature->params + call->signature->sentinelpos, tmpSig->param_count * sizeof(MonoType *)); MONO_INST_NEW (cfg, sig_arg, OP_ICONST); @@ -1771,20 +1771,20 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) sig_arg->inst_p0 = tmpSig; MONO_ADD_INS (cfg->cbb, sig_arg); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, STK_BASE, + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, STK_BASE, cinfo->sigCookie.offset, sig_arg->dreg); } /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific emission of a call operation - * + * * @param[in] @cfg - Compile control block * @param[in] @call - Call Instruction - * - * Process all parameters for a call and generate the sequence of + * + * Process all parameters for a call and generate the sequence of * operations to perform the call according to the s390x ABI. */ @@ -1797,12 +1797,12 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) int i, n, lParamArea; CallInfo *cinfo; ArgInfo *ainfo = NULL; - int stackSize; + int stackSize; sig = call->signature; n = sig->param_count + sig->hasthis; DEBUG (g_print ("Call requires: %d parameters\n",n)); - + cinfo = get_call_info (cfg->mempool, sig); stackSize = cinfo->sz.stack_size + cinfo->sz.parm_size; @@ -1870,11 +1870,11 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) } case RegTypeBase : if (!m_type_is_byref (t) && t->type == MONO_TYPE_R4) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, STK_BASE, ainfo->offset + 4, in->dreg); } else if (!m_type_is_byref (t) && (t->type == MONO_TYPE_R8)) { - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, STK_BASE, ainfo->offset, in->dreg); } else { @@ -1892,7 +1892,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) } /* - * Handle the case where there are no implicit arguments + * Handle the case where there are no implicit arguments */ if ((sig->call_convention == MONO_CALL_VARARG) && (!sig->pinvoke) && @@ -1905,13 +1905,13 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific Value Type parameter processing - * + * * @param[in] @cfg - Compile control block * @param[in] @call - Call Instruction * @param[in] @src - Source parameter - * + * * Process value type parameters for a call operation */ @@ -1926,7 +1926,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) emit_outarg_vtr (cfg, ins, src); } else { emit_outarg_vts (cfg, ins, src); - } + } } else if (ainfo->regtype == RegTypeStructByValInFP) { int dreg = mono_alloc_freg (cfg); @@ -1985,13 +1985,13 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific call value return processing - * + * * @param[in] @cfg - Compile control block * @param[in] @method - Method * @param[in] @val - Instruction representing the result returned to method - * + * * Create the sequence to unload the value returned from a call */ @@ -2009,21 +2009,21 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) return; } } - + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg); } /*========================= End of Function ========================*/ /** - * + * * @brief Replace compound compare/branch operations with single operation - * + * * @param[in] @bb - Basic block * @param[in] @ins - Current instruction * @param[in] @cc - Condition code of branch * @param[in] @logical - Whether comparison is signed or logical - * + * * Form a peephole pass at the code looking for simple optimizations * that will combine compare/branch instructions into a single operation. */ @@ -2078,12 +2078,12 @@ compare_and_branch(MonoBasicBlock *bb, MonoInst *ins, int cc, gboolean logical) /*========================= End of Function ========================*/ /** - * + * * @brief Architecure-specific peephole pass 1 processing - * + * * @param[in] @cfg - Compile control block * @param[in] @bb - Basic block - * + * * Form a peephole pass at the code looking for compare and branch * optimizations. */ @@ -2145,12 +2145,12 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) /*========================= End of Function ========================*/ /** - * + * * @brief Architecure-specific peephole pass 2 processing - * + * * @param[in] @cfg - Compile control block * @param[in] @bb - Basic block - * + * * Form a peephole pass at the code looking for simple optimizations. */ @@ -2178,12 +2178,12 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) /*========================= End of Function ========================*/ /** - * + * * @brief Architecure-specific lowering pass processing - * + * * @param[in] @cfg - Compile control block * @param[in] @bb - Basic block - * + * * Form a lowering pass at the code looking for simple optimizations. */ @@ -2223,9 +2223,9 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) /*========================= End of Function ========================*/ /** - * + * * @brief Emit float-to-int sequence - * + * * @param[in] @cfg - Compile control block * @param[in] @code - Current instruction area * @param[in] @dreg - Destination general register @@ -2233,7 +2233,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) * @param[in] @size - Size of destination * @param[in] @is_signed - Destination is signed/unsigned * @returns Next instruction location - * + * * Emit instructions to convert a single precision floating point value to an integer */ @@ -2276,7 +2276,7 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, PTRSLOT (code, o[0]); s390_cfebr (code, dreg, 5, sreg); switch (size) { - case 1: + case 1: s390_lghi (code, s390_r0, 0xff); s390_ngr (code, dreg, s390_r0); break; @@ -2294,9 +2294,9 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, /*========================= End of Function ========================*/ /** - * + * * @brief Emit double-to-int sequence - * + * * @param[in] @cfg - Compile control block * @param[in] @code - Current instruction area * @param[in] @dreg - Destination general register @@ -2304,7 +2304,7 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, * @param[in] @size - Size of destination * @param[in] @is_signed - Destination is signed/unsigned * @returns Next instruction location - * + * * Emit instructions to convert a single precision floating point value to an integer */ @@ -2347,7 +2347,7 @@ emit_double_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size PTRSLOT (code, o[0]); s390_cfdbr (code, dreg, 5, sreg); switch (size) { - case 1: + case 1: s390_lghi (code, s390_r0, 0xff); s390_ngr (code, dreg, s390_r0); break; @@ -2365,21 +2365,21 @@ emit_double_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size /*========================= End of Function ========================*/ /** - * + * * @brief Check if branch is for unsigned comparison - * + * * @param[in] @next - Next instruction * @returns True if the branch is for an unsigned comparison - * + * * Determine if next instruction is a branch for an unsigned comparison */ -static gboolean +static gboolean is_unsigned (MonoInst *next) { - if ((next) && + if ((next) && (((next->opcode >= OP_IBNE_UN) && - (next->opcode <= OP_IBLT_UN)) || + (next->opcode <= OP_IBLT_UN)) || ((next->opcode >= OP_LBNE_UN) && (next->opcode <= OP_LBLT_UN)) || ((next->opcode >= OP_COND_EXC_NE_UN) && @@ -2402,12 +2402,12 @@ is_unsigned (MonoInst *next) /*========================= End of Function ========================*/ /** - * + * * @brief Architecutre-specific processing of a basic block - * + * * @param[in] @cfg - Compile control block * @param[in] @bb - Basic block - * + * * Process instructions within basic block emitting s390x instructions * based on the VM operation codes */ @@ -2436,47 +2436,47 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) switch (ins->opcode) { case OP_STOREI1_MEMBASE_IMM: { s390_lghi (code, s390_r0, ins->inst_imm); - S390_LONG (code, stcy, stc, s390_r0, 0, + S390_LONG (code, stcy, stc, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset); } break; case OP_STOREI2_MEMBASE_IMM: { s390_lghi (code, s390_r0, ins->inst_imm); - S390_LONG (code, sthy, sth, s390_r0, 0, + S390_LONG (code, sthy, sth, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset); } break; case OP_STOREI4_MEMBASE_IMM: { s390_lgfi (code, s390_r0, ins->inst_imm); - S390_LONG (code, sty, st, s390_r0, 0, + S390_LONG (code, sty, st, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset); } break; case OP_STORE_MEMBASE_IMM: case OP_STOREI8_MEMBASE_IMM: { S390_SET (code, s390_r0, ins->inst_imm); - S390_LONG (code, stg, stg, s390_r0, 0, + S390_LONG (code, stg, stg, s390_r0, 0, ins->inst_destbasereg, ins->inst_offset); } break; case OP_STOREI1_MEMBASE_REG: { - S390_LONG (code, stcy, stc, ins->sreg1, 0, + S390_LONG (code, stcy, stc, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset); } break; case OP_STOREI2_MEMBASE_REG: { - S390_LONG (code, sthy, sth, ins->sreg1, 0, + S390_LONG (code, sthy, sth, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset); } break; case OP_STOREI4_MEMBASE_REG: { - S390_LONG (code, sty, st, ins->sreg1, 0, + S390_LONG (code, sty, st, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset); } break; case OP_STORE_MEMBASE_REG: case OP_STOREI8_MEMBASE_REG: { - S390_LONG (code, stg, stg, ins->sreg1, 0, + S390_LONG (code, stg, stg, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset); } break; @@ -2485,37 +2485,37 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_LOAD_MEMBASE: case OP_LOADI8_MEMBASE: { - S390_LONG (code, lg, lg, ins->dreg, 0, + S390_LONG (code, lg, lg, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } break; case OP_LOADI4_MEMBASE: { - S390_LONG (code, lgf, lgf, ins->dreg, 0, + S390_LONG (code, lgf, lgf, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } break; case OP_LOADU4_MEMBASE: { - S390_LONG (code, llgf, llgf, ins->dreg, 0, + S390_LONG (code, llgf, llgf, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } break; case OP_LOADU1_MEMBASE: { - S390_LONG (code, llgc, llgc, ins->dreg, 0, + S390_LONG (code, llgc, llgc, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } break; case OP_LOADI1_MEMBASE: { - S390_LONG (code, lgb, lgb, ins->dreg, 0, + S390_LONG (code, lgb, lgb, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } break; case OP_LOADU2_MEMBASE: { - S390_LONG (code, llgh, llgh, ins->dreg, 0, + S390_LONG (code, llgh, llgh, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } break; case OP_LOADI2_MEMBASE: { - S390_LONG (code, lgh, lgh, ins->dreg, 0, + S390_LONG (code, lgh, lgh, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } break; @@ -2559,7 +2559,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lgfr (code, ins->dreg, ins->sreg1); } break; - case OP_COMPARE: + case OP_COMPARE: case OP_LCOMPARE: { if (is_unsigned (ins->next)) s390_clgr (code, ins->sreg1, ins->sreg2); @@ -2660,7 +2660,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) S390_SET (code, s390_r0, ins->inst_imm); s390_agrk (code, ins->dreg, ins->sreg1, s390_r0); } - } else { + } else { if (ins->dreg != ins->sreg1) { s390_lgr (code, ins->dreg, ins->sreg1); } @@ -2806,10 +2806,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } else { if (ins->sreg1 == ins->dreg) { s390_ngr (code, ins->dreg, ins->sreg2); - } else { - if (ins->sreg2 == ins->dreg) { + } else { + if (ins->sreg2 == ins->dreg) { s390_ngr (code, ins->dreg, ins->sreg1); - } else { + } else { s390_lgr (code, ins->dreg, ins->sreg1); s390_ngr (code, ins->dreg, ins->sreg2); } @@ -2872,10 +2872,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } else { if (ins->sreg1 == ins->dreg) { s390_ogr (code, ins->dreg, ins->sreg2); - } else { - if (ins->sreg2 == ins->dreg) { + } else { + if (ins->sreg2 == ins->dreg) { s390_ogr (code, ins->dreg, ins->sreg1); - } else { + } else { s390_lgr (code, ins->dreg, ins->sreg1); s390_ogr (code, ins->dreg, ins->sreg2); } @@ -2901,12 +2901,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } else { if (ins->sreg1 == ins->dreg) { s390_xgr (code, ins->dreg, ins->sreg2); - } - else { - if (ins->sreg2 == ins->dreg) { + } + else { + if (ins->sreg2 == ins->dreg) { s390_xgr (code, ins->dreg, ins->sreg1); } - else { + else { s390_lgr (code, ins->dreg, ins->sreg1); s390_xgr (code, ins->dreg, ins->sreg2); } @@ -2931,7 +2931,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_sllg (code, ins->dreg, ins->dreg, src2, 0); } break; - case OP_SHL_IMM: + case OP_SHL_IMM: case OP_LSHL_IMM: { if (ins->sreg1 != ins->dreg) { s390_lgr (code, ins->dreg, ins->sreg1); @@ -2952,7 +2952,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_srag (code, ins->dreg, ins->dreg, 0, (ins->inst_imm & 0x3f)); } break; - case OP_SHR_UN_IMM: + case OP_SHR_UN_IMM: case OP_LSHR_UN_IMM: { if (ins->sreg1 != ins->dreg) { s390_lgr (code, ins->dreg, ins->sreg1); @@ -2982,7 +2982,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_msgr (code, ins->dreg, src2); } break; - case OP_MUL_IMM: + case OP_MUL_IMM: case OP_LMUL_IMM: { if (ins->dreg != ins->sreg1) { s390_lgr (code, ins->dreg, ins->sreg1); @@ -3020,7 +3020,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_srlg (code, s390_r0, s390_r0, 0, 63); s390_ltgr (code, s390_r0, s390_r0); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NZ, "OverflowException"); - PTRSLOT (code, o[0]); + PTRSLOT (code, o[0]); PTRSLOT (code, o[1]); s390_lgr (code, ins->dreg, s390_r1); } @@ -3066,7 +3066,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IADC_IMM: { if (ins->dreg != ins->sreg1) { s390_lgfr (code, ins->dreg, ins->sreg1); - } + } if (s390_is_imm16 (ins->inst_imm)) { s390_lghi (code, s390_r0, ins->inst_imm); s390_alcgr (code, ins->dreg, s390_r0); @@ -3080,7 +3080,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_S390_LADD_OVF: { if (mono_hwcap_s390x_has_mlt) { s390_agrk (code, ins->dreg, ins->sreg1, ins->sreg2); - } else { + } else { CHECK_SRCDST_COM; s390_agr (code, ins->dreg, src2); } @@ -3091,7 +3091,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_S390_LADD_OVF_UN: { if (mono_hwcap_s390x_has_mlt) { s390_algrk (code, ins->dreg, ins->sreg1, ins->sreg2); - } else { + } else { CHECK_SRCDST_COM; s390_algr (code, ins->dreg, src2); } @@ -3142,7 +3142,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (mono_hwcap_s390x_has_mlt) { s390_srk (code, ins->dreg, ins->sreg1, ins->sreg2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); - } else { + } else { CHECK_SRCDST_NCOM; s390_sr (code, ins->dreg, src2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); @@ -3393,19 +3393,19 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lgfr (code, ins->dreg, s390_r1); } break; - case OP_ICONST: + case OP_ICONST: case OP_I8CONST: { S390_SET (code, ins->dreg, ins->inst_c0); } break; case OP_AOTCONST: { - mono_add_patch_info (cfg, code - cfg->native_code, + mono_add_patch_info (cfg, code - cfg->native_code, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0); S390_LOAD_TEMPLATE (code, ins->dreg); } break; case OP_JUMP_TABLE: { - mono_add_patch_info (cfg, code - cfg->native_code, + mono_add_patch_info (cfg, code - cfg->native_code, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0); S390_LOAD_TEMPLATE (code, ins->dreg); } @@ -3460,10 +3460,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ins->dreg != ins->sreg1) s390_ldr (code, ins->dreg, ins->sreg1); break; - case OP_MOVE_F_TO_I8: + case OP_MOVE_F_TO_I8: s390_lgdr (code, ins->dreg, ins->sreg1); break; - case OP_MOVE_I8_TO_F: + case OP_MOVE_I8_TO_F: s390_ldgr (code, ins->dreg, ins->sreg1); break; case OP_MOVE_F_TO_I4: @@ -3475,7 +3475,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } s390_srag (code, ins->dreg, ins->dreg, 0, 32); break; - case OP_MOVE_I4_TO_F: + case OP_MOVE_I4_TO_F: s390_slag (code, s390_r0, ins->sreg1, 0, 32); s390_ldgr (code, ins->dreg, s390_r0); if (!cfg->r4fp) @@ -3532,13 +3532,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* * Restore SP to caller's SP - */ + */ code = backUpStackPtr(cfg, code); /* * If the destination is specified as a register or membase then * save destination so it doesn't get overwritten by the restores - */ + */ if (ins->opcode != OP_TAILCALL) s390_lgr (code, s390_r1, ins->sreg1); @@ -3561,7 +3561,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* * Restore any FP registers that have been altered - */ + */ if (cfg->arch.fpSize != 0) { int fpOffset = -cfg->arch.fpSize; for (int i = 8; i < 16; i++) { @@ -3574,7 +3574,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ins->opcode == OP_TAILCALL_REG) { s390_br (code, s390_r1); - } else { + } else { if (ins->opcode == OP_TAILCALL_MEMBASE) { if (mono_hwcap_s390x_has_mie2) { s390_bi (code, 0, s390_r1, ins->inst_offset); @@ -3584,7 +3584,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } else { mono_add_patch_info_rel (cfg, code - cfg->native_code, - MONO_PATCH_INFO_METHOD_JUMP, + MONO_PATCH_INFO_METHOD_JUMP, call->method, MONO_R_S390_THUNKED); S390_BR_TEMPLATE (code, s390_r1); cfg->thunk_area += THUNK_SIZE; @@ -3692,7 +3692,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lg (code, s390_r13, 0, STK_BASE, 0); /* - * Round object size to doubleword + * Round object size to doubleword */ s390_lgr (code, s390_r1, ins->sreg1); s390_aghi (code, s390_r1, 7); @@ -3701,7 +3701,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (mono_hwcap_s390x_has_gie) { if (ins->flags & MONO_INST_INIT) - s390_lgr (code, s390_r0, s390_r1); + s390_lgr (code, s390_r0, s390_r1); s390_risbg (code, ins->dreg, s390_r1, 0, 0xb3, 0); s390_sgrk (code, ins->dreg, STK_BASE, ins->dreg); @@ -3734,7 +3734,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lghi (code, s390_r0, 0); s390_stg (code, s390_r0, 0, STK_BASE, 4088); s390_j (code, -11); /* j L0 */ - + s390_lghi (code, ins->dreg, 4095); /* L1: */ s390_ngr (code, ins->dreg, s390_r1); s390_ltgr (code, ins->dreg, ins->dreg); @@ -3744,11 +3744,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_stg (code, ins->dreg, s390_r1, STK_BASE, -8); /* L2: */ if (ins->flags & MONO_INST_INIT) - s390_lgr (code, s390_r0, s390_r1); + s390_lgr (code, s390_r0, s390_r1); } - /* - * Compute address of localloc'd object + /* + * Compute address of localloc'd object */ s390_lgr (code, s390_r1, STK_BASE); if (s390_is_imm16(area_offset)) @@ -3811,7 +3811,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); S390_LONG (code, stg, stg, s390_r14, 0, - spvar->inst_basereg, + spvar->inst_basereg, spvar->inst_offset); } break; @@ -3821,7 +3821,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ins->sreg1 != s390_r2) s390_lgr(code, s390_r2, ins->sreg1); S390_LONG (code, lg, lg, s390_r14, 0, - spvar->inst_basereg, + spvar->inst_basereg, spvar->inst_offset); s390_br (code, s390_r14); } @@ -3830,7 +3830,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); S390_LONG (code, lg, lg, s390_r14, 0, - spvar->inst_basereg, + spvar->inst_basereg, spvar->inst_offset); s390_br (code, s390_r14); } @@ -3887,9 +3887,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) displace = ((uintptr_t) code - (uintptr_t) o[0]) / 2; o[0]->i2 = displace; } - - /* - * This is the address which is saved in seq points, + + /* + * This is the address which is saved in seq points, */ mono_add_seq_point (cfg, bb, ins, code - cfg->native_code); @@ -3944,14 +3944,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ins->backend.pc_offset = code - cfg->native_code; break; } - case OP_BR: + case OP_BR: EMIT_UNCOND_BRANCH(ins); break; case OP_BR_REG: { s390_br (code, ins->sreg1); } break; - case OP_CEQ: + case OP_CEQ: case OP_ICEQ: case OP_LCEQ: { s390_lghi(code, ins->dreg, 1); @@ -3959,7 +3959,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lghi(code, ins->dreg, 0); } break; - case OP_CLT: + case OP_CLT: case OP_ICLT: case OP_LCLT: { s390_lghi(code, ins->dreg, 1); @@ -3975,7 +3975,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lghi(code, ins->dreg, 0); } break; - case OP_CGT: + case OP_CGT: case OP_ICGT: case OP_LCGT: { s390_lghi(code, ins->dreg, 1); @@ -4072,29 +4072,29 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_LBEQ: case OP_IBEQ: EMIT_COND_BRANCH (ins, S390_CC_EQ); - break; + break; case OP_LBNE_UN: case OP_IBNE_UN: EMIT_COND_BRANCH (ins, S390_CC_NE); - break; + break; case OP_LBLT: case OP_LBLT_UN: case OP_IBLT: case OP_IBLT_UN: EMIT_COND_BRANCH (ins, S390_CC_LT); - break; + break; case OP_LBGT: case OP_LBGT_UN: case OP_IBGT: case OP_IBGT_UN: EMIT_COND_BRANCH (ins, S390_CC_GT); - break; + break; case OP_LBGE: case OP_LBGE_UN: case OP_IBGE: case OP_IBGE_UN: EMIT_COND_BRANCH (ins, S390_CC_GE); - break; + break; case OP_LBLE: case OP_LBLE_UN: case OP_IBLE: @@ -4170,22 +4170,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_STORER8_MEMBASE_REG: { - S390_LONG (code, stdy, std, ins->sreg1, 0, + S390_LONG (code, stdy, std, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset); } break; case OP_LOADR8_MEMBASE: { - S390_LONG (code, ldy, ld, ins->dreg, 0, + S390_LONG (code, ldy, ld, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } break; case OP_STORER4_MEMBASE_REG: { if (cfg->r4fp) { - S390_LONG (code, stey, ste, ins->sreg1, 0, + S390_LONG (code, stey, ste, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset); } else { s390_ledbr (code, ins->sreg1, ins->sreg1); - S390_LONG (code, stey, ste, ins->sreg1, 0, + S390_LONG (code, stey, ste, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset); s390_ldebr (code, ins->sreg1, ins->sreg1); } @@ -4193,10 +4193,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_LOADR4_MEMBASE: { if (cfg->r4fp) { - S390_LONG (code, ley, le, ins->dreg, 0, + S390_LONG (code, ley, le, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } else { - S390_LONG (code, ley, le, ins->dreg, 0, + S390_LONG (code, ley, le, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); s390_ldebr (code, ins->dreg, ins->dreg); } @@ -4379,7 +4379,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_jz (code, 0); CODEPTR(code, o[4]); PTRSLOT(code, o[1]); PTRSLOT(code, o[2]); - mono_add_patch_info (cfg, code - cfg->native_code, + mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException"); s390_brasl (code, s390_r14, 0); PTRSLOT(code, o[3]); @@ -4435,37 +4435,37 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FSUB: { CHECK_SRCDST_NCOM_F(sdbr); } - break; + break; case OP_RSUB: { CHECK_SRCDST_NCOM_F(sebr); } - break; + break; case OP_FMUL: { CHECK_SRCDST_COM_F; s390_mdbr (code, ins->dreg, src2); } - break; + break; case OP_RMUL: { CHECK_SRCDST_COM_F; s390_meer (code, ins->dreg, src2); } - break; + break; case OP_FDIV: { CHECK_SRCDST_NCOM_F(ddbr); } - break; + break; case OP_RDIV: { CHECK_SRCDST_NCOM_F(debr); } - break; + break; case OP_FNEG: { s390_lcdbr (code, ins->dreg, ins->sreg1); } - break; + break; case OP_RNEG: { s390_lcebr (code, ins->dreg, ins->sreg1); } - break; + break; case OP_FREM: { CHECK_SRCDST_NCOM_FR(didbr, 5); } @@ -4673,7 +4673,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lhi (code, s390_r13, 0x7f); s390_tcdb (code, ins->sreg1, 0, s390_r13, 0); s390_jz (code, 0); CODEPTR(code, o); - mono_add_patch_info (cfg, code - cfg->native_code, + mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException"); s390_brasl (code, s390_r14,0); PTRSLOT(code, o); @@ -4682,7 +4682,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_S390_MOVE: { if (ins->backend.size > 0) { if (ins->backend.size <= 256) { - s390_mvc (code, ins->backend.size, ins->sreg2, + s390_mvc (code, ins->backend.size, ins->sreg2, ins->inst_offset, ins->sreg1, ins->inst_imm); } else { s390_lgr (code, s390_r0, ins->sreg2); @@ -4740,14 +4740,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lgr (code, ins->dreg, s390_r1); } } - break; + break; case OP_ATOMIC_EXCHANGE_I8: { s390_lg (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset); s390_csg (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset); s390_jnz (code, -6); s390_lgr (code, ins->dreg, s390_r0); } - break; + break; case OP_ATOMIC_ADD_I4: { if (mono_hwcap_s390x_has_ia) { s390_laa (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset); @@ -4762,14 +4762,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lgfr(code, ins->dreg, s390_r1); } } - break; + break; case OP_ATOMIC_EXCHANGE_I4: { s390_l (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset); s390_cs (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset); s390_jnz (code, -4); s390_lgfr(code, ins->dreg, s390_r0); } - break; + break; case OP_S390_BKCHAIN: { s390_lgr (code, ins->dreg, ins->sreg1); if (s390_is_imm16 (cfg->stack_offset)) { @@ -4781,7 +4781,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_agr (code, ins->dreg, s390_r13); } } - break; + break; case OP_MEMORY_BARRIER: s390_mem (code); break; @@ -4826,7 +4826,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_GC_SAFE_POINT: { short *br; - s390_ltg (code, s390_r0, 0, ins->sreg1, 0); + s390_ltg (code, s390_r0, 0, ins->sreg1, 0); s390_jz (code, 0); CODEPTR(code, br); code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_threads_state_poll)); @@ -5022,7 +5022,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_PMAXD_UN: s390x_pmaxud (code, ins->sreg1, ins->sreg2); break; - + case OP_PMAXB: s390x_pmaxsb (code, ins->sreg1, ins->sreg2); break; @@ -5166,7 +5166,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_PSUBW_SAT: s390x_psubsw (code, ins->sreg1, ins->sreg2); break; - + case OP_PMULW: s390x_pmullw (code, ins->sreg1, ins->sreg2); break; @@ -5231,22 +5231,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_PSHRQ_REG: s390x_psrlq (code, ins->dreg, ins->sreg2); break; - + /*TODO: This is appart of the sse spec but not added case OP_PSARQ: s390x_psraq_reg_imm (code, ins->dreg, ins->inst_imm); break; case OP_PSARQ_REG: s390x_psraq (code, ins->dreg, ins->sreg2); - break; + break; */ - + case OP_PSHLQ: s390x_psllq_reg_imm (code, ins->dreg, ins->inst_imm); break; case OP_PSHLQ_REG: s390x_psllq (code, ins->dreg, ins->sreg2); - break; + break; case OP_CVTDQ2PD: s390x_cvtdq2pd (code, ins->dreg, ins->sreg1); break; @@ -5404,7 +5404,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /*FIXME the peephole pass should have killed this*/ if (ins->dreg != ins->sreg1) s390x_movaps (code, ins->dreg, ins->sreg1); - break; + break; case OP_XZERO: s390x_pxor (code, ins->dreg, ins->dreg); break; @@ -5431,7 +5431,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCONV_TO_U2: amd64_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE); break; - } + } break; case OP_EXPAND_I2: @@ -5479,9 +5479,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific registration of lowlevel calls - * + * * Register routines to register optimized lowlevel operations */ @@ -5493,7 +5493,7 @@ mono_arch_register_lowlevel_calls (void) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific patching * @param[in] @cfg - Compilation control block * @param[in] @code - Start of code @@ -5544,14 +5544,14 @@ emit_patch_full (MonoCompile *cfg, MonoJumpInfo *ji, guint8 *code, /** * * @brief Architecture-specific patching of instructions and data - * + * * @param[in] @cfg - Compile control block * @param[in] @method - Current method * @param[in] @code - Current code block - * @param[in] @ji - Jump information + * @param[in] @ji - Jump information * @param[in] @target - Target of patch * - * Process the patch data created during the instruction build process. + * Process the patch data created during the instruction build process. * This resolves jumps, calls, variables etc. */ @@ -5561,8 +5561,8 @@ mono_arch_patch_code_new (MonoCompile *cfg, guint8 *code, MonoJumpInfo *ji, gpoi switch (ji->type) { case MONO_PATCH_INFO_IP: case MONO_PATCH_INFO_LDSTR: - case MONO_PATCH_INFO_TYPE_FROM_HANDLE: - case MONO_PATCH_INFO_LDTOKEN: + case MONO_PATCH_INFO_TYPE_FROM_HANDLE: + case MONO_PATCH_INFO_LDTOKEN: case MONO_PATCH_INFO_EXC: emit_patch_full (cfg, ji, code, target, MONO_R_S390_ADDR); break; @@ -5578,7 +5578,7 @@ mono_arch_patch_code_new (MonoCompile *cfg, guint8 *code, MonoJumpInfo *ji, gpoi case MONO_PATCH_INFO_ABS: emit_patch_full (cfg, ji, code, target, MONO_R_S390_THUNKED); break; - case MONO_PATCH_INFO_SWITCH: + case MONO_PATCH_INFO_SWITCH: emit_patch_full(cfg, ji, code, target, MONO_R_S390_SWITCH); break; case MONO_PATCH_INFO_METHODCONST: @@ -5599,9 +5599,9 @@ mono_arch_patch_code_new (MonoCompile *cfg, guint8 *code, MonoJumpInfo *ji, gpoi /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific prolog generation - * + * * @param[in] @cfg - Compile control block * @returns Location of code code generated * @@ -5636,7 +5636,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) /** * Create unwind information - */ + */ mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, S390_CFA_OFFSET); s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); emit_unwind_regs(cfg, code, s390_r6, s390_r15, S390_REG_SAVE_OFFSET - S390_CFA_OFFSET); @@ -5645,17 +5645,17 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* * If there are local allocations the R11 becomes the frame register - */ + */ if (cfg->flags & MONO_CFG_HAS_ALLOCA) { cfg->used_int_regs |= 1 << s390_r11; } /* * Check if FP registers need preserving - */ + */ if ((cfg->arch.used_fp_regs & S390_FP_SAVE_MASK) != 0) { for (int i = s390_f8; i <= s390_f15; i++) { - if (cfg->arch.used_fp_regs & (1 << i)) + if (cfg->arch.used_fp_regs & (1 << i)) fpOffset += sizeof(double); } fpOffset = S390_ALIGN(fpOffset, sizeof(double)); @@ -5664,14 +5664,14 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* * Calculate stack requirements - */ + */ alloc_size = cfg->stack_offset + fpOffset; cfg->stack_usage = cfa_offset = alloc_size; s390_lgr (code, s390_r11, STK_BASE); if (s390_is_imm16 (alloc_size)) { s390_aghi (code, STK_BASE, -alloc_size); - } else if (s390_is_imm32 (alloc_size)) { + } else if (s390_is_imm32 (alloc_size)) { s390_agfi (code, STK_BASE, -alloc_size); } else { int stackSize = alloc_size; @@ -5692,7 +5692,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) for (int i = s390_f8; i <= s390_f15; i++) { if (cfg->arch.used_fp_regs & (1 << i)) { s390_std (code, i, 0, s390_r1, stkOffset); - emit_unwind_regs(cfg, code, 16+i, 16+i, stkOffset+fpOffset - S390_CFA_OFFSET); + emit_unwind_regs(cfg, code, 16+i, 16+i, stkOffset+fpOffset - S390_CFA_OFFSET); stkOffset += sizeof(double); } } @@ -5707,8 +5707,8 @@ mono_arch_emit_prolog (MonoCompile *cfg) if (cfg->rgctx_var) { g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET); - s390_stg (code, MONO_ARCH_RGCTX_REG, 0, - cfg->rgctx_var->inst_basereg, + s390_stg (code, MONO_ARCH_RGCTX_REG, 0, + cfg->rgctx_var->inst_basereg, cfg->rgctx_var->inst_offset); } @@ -5717,7 +5717,7 @@ char *methodName = getenv("MONO_TRACE_METHOD"); if (methodName != NULL) { printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,method->name);fflush(stdout); // Tests:set_ip -//if ((strcmp(method->klass->name_space,"") == 0) && +//if ((strcmp(method->klass->name_space,"") == 0) && // (strcmp(method->klass->name,"Tests") == 0) && // (strcmp(method->name, "set_ip") == 0)) { // (strcmp("CancellationToken,TaskCreationOptions,TaskContinuationOptions,TaskScheduler",mono_signature_get_desc(method->signature, FALSE)) != 0)) { @@ -5730,7 +5730,7 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth /* compute max_offset in order to use short forward jumps * we always do it on s390 because the immediate displacement - * for jumps is too small + * for jumps is too small */ max_offset = 0; for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { @@ -5764,7 +5764,7 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = cinfo->args + i; inst = cfg->args [pos]; - + if (inst->opcode == OP_VTARG_ADDR) inst = inst->inst_left; @@ -5776,7 +5776,7 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth s390_ldr (code, inst->dreg, ainfo->reg); } } else if (ainfo->regtype == RegTypeFPR4) { - if (!cfg->r4fp) + if (!cfg->r4fp) s390_ledbr (code, inst->dreg, ainfo->reg); } else if (ainfo->regtype == RegTypeBase) { s390_lgr (code, s390_r13, STK_BASE); @@ -5786,7 +5786,7 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth g_assert_not_reached (); if (cfg->verbose_level > 2) - g_print ("Argument %d assigned to register %s\n", + g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg)); } else { if (ainfo->regtype == RegTypeGeneral) { @@ -5799,7 +5799,7 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth case 2: s390_sth (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); break; - case 4: + case 4: s390_st (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); break; case 8: @@ -5849,15 +5849,15 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth if (method->save_lmf) { /** - * Build the MonoLMF structure on the stack - see mini-s390x.h + * Build the MonoLMF structure on the stack - see mini-s390x.h */ - lmfOffset = alloc_size - sizeof(MonoLMF); - - s390_lgr (code, s390_r13, cfg->frame_reg); - s390_aghi (code, s390_r13, lmfOffset); - + lmfOffset = alloc_size - sizeof(MonoLMF); + + s390_lgr (code, s390_r13, cfg->frame_reg); + s390_aghi (code, s390_r13, lmfOffset); + /* - * Preserve the parameter registers while we fix up the lmf + * Preserve the parameter registers while we fix up the lmf */ s390_stmg (code, s390_r2, s390_r6, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, pregs)); @@ -5874,65 +5874,65 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth /* * Set lmf.lmf_addr = jit_tls->lmf */ - s390_stg (code, s390_r2, 0, s390_r13, - MONO_STRUCT_OFFSET(MonoLMF, lmf_addr)); + s390_stg (code, s390_r2, 0, s390_r13, + MONO_STRUCT_OFFSET(MonoLMF, lmf_addr)); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, lmf_addr), SLOT_NOREF); - + /* * Get current lmf */ - s390_lg (code, s390_r0, 0, s390_r2, 0); - + s390_lg (code, s390_r0, 0, s390_r2, 0); + /* * Set our lmf as the current lmf */ - s390_stg (code, s390_r13, 0, s390_r2, 0); - + s390_stg (code, s390_r13, 0, s390_r2, 0); + /* * Have our lmf.previous_lmf point to the last lmf */ - s390_stg (code, s390_r0, 0, s390_r13, - MONO_STRUCT_OFFSET(MonoLMF, previous_lmf)); + s390_stg (code, s390_r0, 0, s390_r13, + MONO_STRUCT_OFFSET(MonoLMF, previous_lmf)); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), SLOT_NOREF); - + /* * Save method info */ S390_SET (code, s390_r1, method); - s390_stg (code, s390_r1, 0, s390_r13, - MONO_STRUCT_OFFSET(MonoLMF, method)); + s390_stg (code, s390_r1, 0, s390_r13, + MONO_STRUCT_OFFSET(MonoLMF, method)); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, method), SLOT_NOREF); - + /* * Save the current IP */ s390_stg (code, STK_BASE, 0, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, ebp)); s390_basr (code, s390_r1, 0); - s390_stg (code, s390_r1, 0, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, eip)); + s390_stg (code, s390_r1, 0, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, eip)); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, ebp), SLOT_NOREF); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, eip), SLOT_NOREF); - + /* * Save general and floating point registers */ - s390_stmg (code, s390_r2, s390_r12, s390_r13, - MONO_STRUCT_OFFSET(MonoLMF, gregs) + 2 * sizeof(gulong)); + s390_stmg (code, s390_r2, s390_r12, s390_r13, + MONO_STRUCT_OFFSET(MonoLMF, gregs) + 2 * sizeof(gulong)); for (i = 0; i < 11; i++) mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, gregs) + i * sizeof(gulong), SLOT_NOREF); fpOffset = lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, fregs); - for (i = 0; i < 16; i++) { - s390_std (code, i, 0, s390_r13, + for (i = 0; i < 16; i++) { + s390_std (code, i, 0, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, fregs) + i * sizeof(gulong)); mini_gc_set_slot_type_from_fp (cfg, fpOffset, SLOT_NOREF); fpOffset += sizeof(double); - } + } /* * Restore the parameter registers now that we've set up the lmf */ - s390_lmg (code, s390_r2, s390_r6, s390_r13, - MONO_STRUCT_OFFSET(MonoLMF, pregs)); + s390_lmg (code, s390_r2, s390_r6, s390_r13, + MONO_STRUCT_OFFSET(MonoLMF, pregs)); } if (cfg->method->save_lmf) @@ -5965,9 +5965,9 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth if (inst->opcode != OP_REGVAR) { switch (ainfo->regtype) { case RegTypeGeneral: { - if (((next->opcode == OP_LOAD_MEMBASE) || - (next->opcode == OP_LOADI4_MEMBASE)) && - next->inst_basereg == inst->inst_basereg && + if (((next->opcode == OP_LOAD_MEMBASE) || + (next->opcode == OP_LOADI4_MEMBASE)) && + next->inst_basereg == inst->inst_basereg && next->inst_offset == inst->inst_offset) { if (next->dreg == ainfo->reg) { NULLIFY_INS (next); @@ -5989,8 +5989,8 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth /* Argument allocated to (non-volatile) register */ switch (ainfo->regtype) { case RegTypeGeneral: - if (next->opcode == OP_MOVE && - next->sreg1 == inst->dreg && + if (next->opcode == OP_MOVE && + next->sreg1 == inst->dreg && next->dreg == ainfo->reg) { NULLIFY_INS (next); match = TRUE; @@ -6035,9 +6035,9 @@ printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,meth /*========================= End of Function ========================*/ /** - * + * * @brief Architecutre-specific epilog generation - * + * * @param[in] @cfg - Compile control block * * Create the instruction sequence for exit from a method @@ -6050,10 +6050,10 @@ mono_arch_emit_epilog (MonoCompile *cfg) guint8 *code; int max_epilog_size = 96, i; int fpOffset = 0; - + if (cfg->method->save_lmf) max_epilog_size += 128; - + code = realloc_code (cfg, max_epilog_size); cfg->has_unwind_info_for_epilog = TRUE; @@ -6064,7 +6064,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) /* Save the uwind state which is needed by the out-of-line code */ mono_emit_unwind_op_remember_state (cfg, code); - if (method->save_lmf) + if (method->save_lmf) restoreLMF(code, cfg->frame_reg, cfg->stack_usage); code = backUpStackPtr(cfg, code); @@ -6083,7 +6083,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) } s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); - for (i = s390_r6; i < s390_r15; i++) + for (i = s390_r6; i < s390_r15; i++) mono_emit_unwind_op_same_value (cfg, code, i); s390_br (code, s390_r14); @@ -6100,16 +6100,16 @@ mono_arch_emit_epilog (MonoCompile *cfg) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific exception emission - * + * * @param[in] @cfg - Compile control block * * Create the instruction sequence for exception handling */ void -mono_arch_emit_exceptions (MonoCompile *cfg) +mono_arch_emit_exceptions (MonoCompile *cfg) { MonoJumpInfo *patch_info; guint8 *code; @@ -6120,8 +6120,8 @@ mono_arch_emit_exceptions (MonoCompile *cfg) MonoClass *exc_classes [MAX_EXC]; guint8 *exc_throw_start [MAX_EXC]; - for (patch_info = cfg->patch_info; - patch_info; + for (patch_info = cfg->patch_info; + patch_info; patch_info = patch_info->next) { if (patch_info->type == MONO_PATCH_INFO_EXC) exc_count++; @@ -6132,7 +6132,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg) code = realloc_code (cfg, code_size); /* - * Add code to raise exceptions + * Add code to raise exceptions */ for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { switch (patch_info->type) { @@ -6146,24 +6146,24 @@ mono_arch_emit_exceptions (MonoCompile *cfg) s390_patch_rel (ip + 2, (guint64) S390_RELATIVE(code,ip)); exc_class = mono_class_load_from_name (mono_defaults.corlib, - "System", + "System", patch_info->data.name); for (iExc = 0; iExc < nThrows; ++iExc) if (exc_classes [iExc] == exc_class) break; - + if (iExc < nThrows) { - s390_jcl (code, S390_CC_UN, + s390_jcl (code, S390_CC_UN, (guint64) exc_throw_start [iExc]); patch_info->type = MONO_PATCH_INFO_NONE; } else { - + if (nThrows < MAX_EXC) { exc_classes [nThrows] = exc_class; exc_throw_start [nThrows] = code; } - + /* * Patch the parameter passed to the handler */ @@ -6200,9 +6200,9 @@ mono_arch_emit_exceptions (MonoCompile *cfg) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific finishing of initialization - * + * * Perform any architectural-specific operations at the conclusion of * the initialization phase */ @@ -6215,7 +6215,7 @@ mono_arch_finish_init (void) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific instruction emission for method * * @param[in] @cfg - Compile Control block @@ -6223,7 +6223,7 @@ mono_arch_finish_init (void) * @param[in] @fsig - Method signature * @param[in] @args - Arguments to method * @returns Instruction(s) required for architecture - * + * * Provide any architectural shortcuts for specific methods. */ @@ -6330,20 +6330,20 @@ mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMetho /*========================= End of Function ========================*/ /** - * + * * @brief Decompose opcode into a System z operation * * @param[in] @cfg - Compile Control block * @param[in] @ins - Mono Instruction - * + * * Substitute a System z instruction for a Mono operation. */ void mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) { - /* - * Have to rename these to avoid being decomposed normally, since the normal + /* + * Have to rename these to avoid being decomposed normally, since the normal * decomposition does not work on S390. */ switch (ins->opcode) { @@ -6379,15 +6379,15 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) /*========================= End of Function ========================*/ /** - * + * * @brief Determine the cost of allocation a variable * * @param[in] @cfg - Compile Control block * @param[in] @vmv - Mono Method Variable * @returns Cost (hardcoded on s390x to 2) - * - * Determine the cost, in the number of memory references, of the action - * of allocating the variable VMV into a register during global register + * + * Determine the cost, in the number of memory references, of the action + * of allocating the variable VMV into a register during global register * allocation. * */ @@ -6402,14 +6402,14 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv) /*========================= End of Function ========================*/ /** - * + * * @brief Architectural specific register window flushing * * Not applicable for s390x so we just do nothing * */ -void +void mono_arch_flush_register_windows (void) { } @@ -6417,20 +6417,20 @@ mono_arch_flush_register_windows (void) /*========================= End of Function ========================*/ /** - * + * * @brief Architectural specific check if value may be immediate * * @param[in] @opcode - Operation code * @param[in] @imm_opcode - Immediate operation code * @param[in] @imm - Value to be examined * @returns True if it is a valid immediate value - * + * * Determine if operand qualifies as an immediate value. For s390x * this is a value in the range -2**32/2**32-1 * */ -gboolean +gboolean mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) { return s390_is_imm32 (imm); @@ -6439,12 +6439,12 @@ mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) /*========================= End of Function ========================*/ /** - * + * * @brief Architectural specific patch offset value for AOT * * @param[in] @code - Location of code to check * @returns Offset - * + * * Dummy entry point if/when s390x supports AOT. */ @@ -6457,13 +6457,13 @@ mono_arch_get_patch_offset (guint8 *code) /*========================= End of Function ========================*/ /** - * + * * @brief Architectural specific returning of register from context * * @param[in] @ctx - Mono context * @param[in] @reg - Register number to be returned * @returns Contents of the register from the context - * + * * Return a register from the context. */ @@ -6482,13 +6482,13 @@ mono_arch_context_get_int_reg_address (MonoContext *ctx, int reg) /*========================= End of Function ========================*/ /** - * + * * @brief Architectural specific setting of a register in the context * * @param[in] @ctx - Mono context * @param[in] @reg - Register number to be returned * @param[in] @val - Value to be set - * + * * Set the specified register in the context with the value passed */ @@ -6501,14 +6501,14 @@ mono_arch_context_set_int_reg (MonoContext *ctx, int reg, host_mgreg_t val) /*========================= End of Function ========================*/ /** - * + * * @brief Architectural specific returning of the "this" value from context * * @param[in] @ctx - Mono context * @param[in] @code - Current location * @returns Pointer to the "this" object - * - * Extract register 2 from the context as for s390x this is where the + * + * Extract register 2 from the context as for s390x this is where the * this parameter is passed */ @@ -6519,9 +6519,9 @@ mono_arch_get_this_arg_from_call (host_mgreg_t *regs, guint8 *code) } /*========================= End of Function ========================*/ - + /** - * + * * @brief Delegation trampoline processing * * @param[in] @info - Trampoline information @@ -6529,7 +6529,7 @@ mono_arch_get_this_arg_from_call (host_mgreg_t *regs, guint8 *code) * @param[in] @param_count - Count of parameters * @param[in] @aot - AOT indicator * @returns Next instruction location - * + * * Process the delegation trampolines */ @@ -6571,7 +6571,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, MonoMethodS iReg++; break; default : - s390_mvc (code, sizeof(uintptr_t), STK_BASE, offset, STK_BASE, offset+sizeof(uintptr_t)); + s390_mvc (code, sizeof(uintptr_t), STK_BASE, offset, STK_BASE, offset+sizeof(uintptr_t)); offset += sizeof(uintptr_t); } } @@ -6599,11 +6599,11 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, MonoMethodS /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific delegation trampolines processing * * @returns List of trampolines - * + * * Return a list of MonoTrampInfo structures for the delegate invoke impl trampolines. */ @@ -6629,13 +6629,13 @@ mono_arch_get_delegate_invoke_impls (void) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific delegation trampoline processing * * @param[in] @sig - Method signature * @param[in] @has_target - Whether delegation contains a target * @returns Trampoline - * + * * Return a pointer to a delegation trampoline */ @@ -6702,7 +6702,7 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific delegation virtual trampoline processing * * @param[in] @sig - Method signature @@ -6710,12 +6710,12 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe * @param[in] @offset - Offset into vtable * @param[in] @load_imt_reg - Whether to load the LMT register * @returns Trampoline - * + * * Return a pointer to a delegation virtual trampoline */ gpointer -mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, +mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg) { guint8 *code, *start; @@ -6727,7 +6727,7 @@ mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod * Replace the "this" argument with the target */ s390_lgr (code, s390_r1, s390_r2); - s390_lg (code, s390_r2, 0, s390_r1, MONO_STRUCT_OFFSET(MonoDelegate, target)); + s390_lg (code, s390_r2, 0, s390_r1, MONO_STRUCT_OFFSET(MonoDelegate, target)); /* * Load the IMT register, if needed @@ -6755,7 +6755,7 @@ mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific build of IMT trampoline * * @param[in] @vtable - Mono VTable @@ -6764,7 +6764,7 @@ mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod * @param[in] @count - Count of items * @param[in] @fail_tramp - Pointer to a failure trampoline * @returns Trampoline - * + * * Return a pointer to an IMT trampoline */ @@ -6787,11 +6787,11 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, if (item->has_target_code) item->chunk_size += BR_SIZE + JUMP_SIZE + LOADCON_SIZE; else - item->chunk_size += BR_SIZE + JUMP_SIZE + LOADCON_SIZE + + item->chunk_size += BR_SIZE + JUMP_SIZE + LOADCON_SIZE + LOAD_SIZE; } else { if (fail_tramp) { - item->chunk_size += CMP_SIZE + 2 * BR_SIZE + JUMP_SIZE + + item->chunk_size += CMP_SIZE + 2 * BR_SIZE + JUMP_SIZE + 2 * LOADCON_SIZE; if (!item->has_target_code) item->chunk_size += LOAD_SIZE; @@ -6828,7 +6828,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, } item->jmp_code = (guint8*) code; s390_jcl (code, S390_CC_NE, 0); - + if (item->has_target_code) { S390_SET (code, s390_r1, item->value.target_code); } else { @@ -6848,7 +6848,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, S390_SET (code, s390_r1, item->value.target_code); } else { g_assert (vtable); - S390_SET (code, s390_r1, + S390_SET (code, s390_r1, (&(vtable->vtable [item->value.vtable_slot]))); s390_lg (code, s390_r1, 0, s390_r1, 0); } @@ -6875,8 +6875,8 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, s390_jcl (code, S390_CC_GE, 0); } } - /* - * patch the branches to get to the target items + /* + * patch the branches to get to the target items */ for (i = 0; i < count; ++i) { MonoIMTCheckItem *item = imt_entries [i]; @@ -6893,7 +6893,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, mono_arch_flush_icache ((guint8*)start, (code - start)); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); - if (!fail_tramp) + if (!fail_tramp) UnlockedAdd (&mono_stats.imt_trampolines_size, code - start); g_assert (code - start <= size); @@ -6906,13 +6906,13 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific return of pointer to IMT method * * @param[in] @regs - Context registers * @param[in] @code - Current location * @returns Pointer to IMT method - * + * * Extract the value of the IMT register from the context */ @@ -6925,13 +6925,13 @@ mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific return of pointer static call vtable. * * @param[in] @regs - Context registers * @param[in] @code - Current location * @returns Pointer to static call vtable - * + * * Extract the value of the RGCTX register from the context which * points to the static call vtable. */ @@ -6945,7 +6945,7 @@ mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific return of unwind bytecode for DWARF CIE * * @returns Unwind byte code @@ -6968,13 +6968,13 @@ mono_arch_get_cie_program (void) #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED /** - * + * * @brief Architecture-specific setting of a breakpoint * * @param[in] @ji - Mono JIT Information * @param[in] @ip - Insruction pointer * - * Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET. + * Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET. * The location should contain code emitted by OP_SEQ_POINT. */ @@ -6993,7 +6993,7 @@ mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific clearing of a breakpoint * * @param[in] @ji - Mono JIT Information @@ -7017,7 +7017,7 @@ mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific check if this is a breakpoint event * * @param[in] @info - Signal information @@ -7037,7 +7037,7 @@ mono_arch_is_breakpoint_event (void *info, void *sigctx) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific skip of a breakpoint * * @param[in] @ctx - Mono Context @@ -7053,9 +7053,9 @@ mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji) } /*========================= End of Function ========================*/ - + /** - * + * * @brief Architecture-specific start of single stepping * * Unprotect the trigger page to enable single stepping @@ -7068,9 +7068,9 @@ mono_arch_start_single_stepping (void) } /*========================= End of Function ========================*/ - + /** - * + * * @brief Architecture-specific stop of single stepping * * Write-protect the trigger page to disable single stepping @@ -7085,7 +7085,7 @@ mono_arch_stop_single_stepping (void) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific check if single stepping event * * @param[in] @info - Signal information @@ -7106,7 +7106,7 @@ mono_arch_is_single_step_event (void *info, void *sigctx) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific skip of a single stepping event * * @param[in] @ctx - Mono Context @@ -7125,14 +7125,14 @@ mono_arch_skip_single_step (MonoContext *ctx) /*========================= End of Function ========================*/ /** - * + * * @brief Architecture-specific creation of sequence point information * * @param[in] @domain - Mono Domain * @param[in] @code - Current location pointer * @returns Sequence Point Information * - * Return a pointer to a data struction which is used by the sequence + * Return a pointer to a data struction which is used by the sequence * point implementation in AOTed code. A no-op on s390x until AOT is * ever supported. */ @@ -7173,7 +7173,7 @@ mono_arch_get_seq_point_info (guint8 *code) #endif /** - * + * * @brief Architecture-specific check of supported operation codes * * @param[in] @opcode - Operation code to be checked @@ -7201,7 +7201,7 @@ mono_arch_opcode_supported (int opcode) #ifndef DISABLE_JIT /** - * + * * @brief Architecture-specific check of tailcall support * * @param[in] @cfg - Mono Compile control block @@ -7225,7 +7225,7 @@ mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, gboolean res = IS_SUPPORTED_TAILCALL (callee_info->stack_usage <= caller_info->stack_usage); - // Any call that would result in parameters being placed on the stack cannot be "tailed" as it may + // Any call that would result in parameters being placed on the stack cannot be "tailed" as it may // result in the callers parameter variables being overwritten. ArgInfo const * const ainfo = callee_info->args + callee_sig->hasthis; for (int i = 0; res && i < callee_sig->param_count; ++i) { @@ -7279,7 +7279,7 @@ mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, #endif /** - * + * * @brief Architecture-specific load function * * @param[in] @jit_call_id - JIT callee identifier diff --git a/src/mono/mono/mini/mini-s390x.h b/src/mono/mono/mini/mini-s390x.h index 9a1aee5721aca..e251b8c23b789 100644 --- a/src/mono/mono/mini/mini-s390x.h +++ b/src/mono/mono/mini/mini-s390x.h @@ -192,7 +192,7 @@ static void inline s390_patch_rel (guchar *code, guint64 target) { guint32 *offset = (guint32 *) code; - + if (target != 0) { *offset = (guint32) target; } @@ -212,7 +212,7 @@ static void inline s390_patch_addr (guchar *code, guint64 target) { guint64 *offset = (guint64 *) code; - + if (target != 0) { *offset = target; } @@ -350,4 +350,4 @@ s390_patch_addr (guchar *code, guint64 target) *(guint32 *) p = lo; \ } while (0) -#endif /* __MONO_MINI_S390X_H__ */ +#endif /* __MONO_MINI_S390X_H__ */ diff --git a/src/mono/mono/mini/mini-sparc.c b/src/mono/mono/mini/mini-sparc.c index 2efe4ba06e74e..8a51c738ed79b 100644 --- a/src/mono/mono/mini/mini-sparc.c +++ b/src/mono/mono/mini/mini-sparc.c @@ -44,20 +44,20 @@ * - the instruction set * - the ABI * - * V9 instructions are only usable if the underlying processor is 64 bit. Most Sparc - * processors in use are 64 bit processors. The V9 ABI is only usable if the + * V9 instructions are only usable if the underlying processor is 64 bit. Most Sparc + * processors in use are 64 bit processors. The V9 ABI is only usable if the * mono executable is a 64 bit executable. So it would make sense to use the 64 bit * instructions without using the 64 bit ABI. */ /* * Register usage: - * - %i0..%i hold the incoming arguments, these are never written by JITted + * - %i0..%i hold the incoming arguments, these are never written by JITted * code. Unused input registers are used for global register allocation. * - %o0..%o5 and %l7 is used for local register allocation and passing arguments * - %l0..%l6 is used for global register allocation * - %o7 and %g1 is used as scratch registers in opcodes - * - all floating point registers are used for local register allocation except %f0. + * - all floating point registers are used for local register allocation except %f0. * Only double precision registers are used. * In 64 bit mode: * - fp registers %d0..%d30 are used for parameter passing, and %d32..%d62 are @@ -77,8 +77,8 @@ * This test casts (guint64)-1 to double and then back to guint64 again. * Under x86, it returns 0, while under sparc it returns -1. * - * In addition to this, the runtime requires the trunc function, or its - * solaris counterpart, aintl, to do some double->int conversions. If this + * In addition to this, the runtime requires the trunc function, or its + * solaris counterpart, aintl, to do some double->int conversions. If this * function is not available, it is emulated somewhat, but the results can be * strange. */ @@ -179,11 +179,11 @@ mono_arch_regname (int reg) { const char* mono_arch_fregname (int reg) { static const char *rnames [] = { - "sparc_f0", "sparc_f1", "sparc_f2", "sparc_f3", "sparc_f4", + "sparc_f0", "sparc_f1", "sparc_f2", "sparc_f3", "sparc_f4", "sparc_f5", "sparc_f6", "sparc_f7", "sparc_f8", "sparc_f9", - "sparc_f10", "sparc_f11", "sparc_f12", "sparc_f13", "sparc_f14", + "sparc_f10", "sparc_f11", "sparc_f12", "sparc_f13", "sparc_f14", "sparc_f15", "sparc_f16", "sparc_f17", "sparc_f18", "sparc_f19", - "sparc_f20", "sparc_f21", "sparc_f22", "sparc_f23", "sparc_f24", + "sparc_f20", "sparc_f21", "sparc_f22", "sparc_f23", "sparc_f24", "sparc_f25", "sparc_f26", "sparc_f27", "sparc_f28", "sparc_f29", "sparc_f30", "sparc_f31" }; @@ -331,18 +331,18 @@ mono_arch_flush_register_windows (void) mono_sparc_flushw (); } -gboolean +gboolean mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) { return sparc_is_imm13 (imm); } -gboolean +gboolean mono_sparc_is_v9 (void) { return mono_hwcap_sparc_is_v9; } -gboolean +gboolean mono_sparc_is_sparc64 (void) { return v64; } @@ -461,7 +461,7 @@ add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean single) * get_call_info: * * Obtain information about a call according to the calling convention. - * For V8, see the "System V ABI, Sparc Processor Supplement" Sparc V8 version + * For V8, see the "System V ABI, Sparc Processor Supplement" Sparc V8 version * document for more information. * For V9, see the "Low Level System Information (64-bit psABI)" chapter in * the 'Sparc Compliance Definition 2.4' document. @@ -515,7 +515,7 @@ get_call_info (MonoCompile *cfg, MonoMethodSignature *sig, gboolean is_pinvoke) DEBUG(printf("param %d: ", i)); if (m_type_is_byref (sig->params [i])) { DEBUG(printf("byref\n")); - + add_general (&gr, &stack_size, ainfo, FALSE); continue; } @@ -699,7 +699,7 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg) GList *vars = NULL; int i; - /* + /* * FIXME: If an argument is allocated to a register, then load it from the * stack in the prolog. */ @@ -755,7 +755,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* * mono_arch_regalloc_cost: * - * Return the cost, in number of memory references, of the action of + * Return the cost, in number of memory references, of the action of * allocating the variable VMV into a register during global register * allocation. */ @@ -833,8 +833,8 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->frame_reg = sparc_fp; offset = 0; - /* - * Reserve a stack slot for holding information used during exception + /* + * Reserve a stack slot for holding information used during exception * handling. */ if (header->num_clauses) @@ -864,8 +864,8 @@ mono_arch_allocate_vars (MonoCompile *cfg) else size = mini_type_stack_size (inst->inst_vtype, &align); - /* - * This is needed since structures containing doubles must be doubleword + /* + * This is needed since structures containing doubles must be doubleword * aligned. * FIXME: Do this only if needed. */ @@ -905,7 +905,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) arg_type = sig->params [i - sig->hasthis]; #ifndef SPARCV9 - if (!m_type_is_byref (arg_type) && ((arg_type->type == MONO_TYPE_R4) + if (!m_type_is_byref (arg_type) && ((arg_type->type == MONO_TYPE_R4) || (arg_type->type == MONO_TYPE_R8))) /* * Since float arguments are passed in integer registers, we need to @@ -950,7 +950,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) break; case ArgInFloatReg: case ArgInDoubleReg: - /* + /* * Since float regs are volatile, we save the arguments to * the stack in the prolog. * FIXME: Avoid this if the method contains no calls. @@ -965,7 +965,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) inst->inst_offset = ainfo->offset + ARGS_OFFSET; if (!m_type_is_byref (arg_type) && (arg_type->type == MONO_TYPE_R8)) { - /* + /* * It is very hard to load doubles from non-doubleword aligned * memory locations. So if the offset is misaligned, we copy the * argument to a stack location in the prolog. @@ -1000,7 +1000,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) } } - /* + /* * spillvars are stored between the normal locals and the storage reserved * by the ABI. */ @@ -1163,7 +1163,7 @@ emit_pass_vtype (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo, ArgInfo else if (pinvoke) size = mono_type_native_stack_size (m_class_get_byval_arg (in->klass), &align); else { - /* + /* * Other backends use mono_type_stack_size (), but that * aligns the size to 8, which is larger than the size of * the source, leading to reads of invalid memory if the @@ -1182,7 +1182,7 @@ emit_pass_vtype (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo, ArgInfo cinfo->stack_usage += size; cinfo->stack_usage += pad; - /* + /* * We use OP_OUTARG_VT to copy the valuetype to a stack location, then * use the normal OUTARG opcodes to pass the address of the location to * the callee. @@ -1242,9 +1242,9 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) MonoMethodSignature *tmp_sig; /* - * mono_ArgIterator_Setup assumes the signature cookie is + * mono_ArgIterator_Setup assumes the signature cookie is * passed first and all the arguments which were before it are - * passed on the stack after the signature. So compensate by + * passed on the stack after the signature. So compensate by * passing a different signature. */ tmp_sig = mono_metadata_signature_dup (call->signature); @@ -1270,7 +1270,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) sig = call->signature; n = sig->param_count + sig->hasthis; - + cinfo = get_call_info (cfg, sig, sig->pinvoke); if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) { @@ -1483,7 +1483,7 @@ else { \ sparc_branch (code, 0, cond, 0); \ } \ if (filldelay) sparc_nop (code); \ - } while (0); + } while (0); #define EMIT_COND_SYSTEM_EXCEPTION(ins,cond,sexc_name) EMIT_COND_SYSTEM_EXCEPTION_GENERAL(ins,cond,sexc_name,TRUE,DEFAULT_ICC) @@ -1577,7 +1577,7 @@ emit_call (MonoCompile *cfg, guint32 *code, guint32 patch_type, gconstpointer da mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, patch_type, data); EMIT_CALL (); } - + return code; } @@ -1594,7 +1594,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) { switch (ins->opcode) { - case OP_MUL_IMM: + case OP_MUL_IMM: /* remove unnecessary multiplication with 1 */ if (ins->inst_imm == 1) { if (ins->dreg != ins->sreg1) { @@ -1608,11 +1608,11 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) #ifndef SPARCV9 case OP_LOAD_MEMBASE: case OP_LOADI4_MEMBASE: - /* - * OP_STORE_MEMBASE_REG reg, offset(basereg) + /* + * OP_STORE_MEMBASE_REG reg, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg */ - if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG + if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG || last_ins->opcode == OP_STORE_MEMBASE_REG) && ins->inst_basereg == last_ins->inst_destbasereg && ins->inst_offset == last_ins->inst_offset) { @@ -1625,7 +1625,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->sreg1 = last_ins->sreg1; } - /* + /* * Note: reg1 must be different from the basereg in the second load * OP_LOAD_MEMBASE offset(basereg), reg1 * OP_LOAD_MEMBASE offset(basereg), reg2 @@ -1650,11 +1650,11 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) //g_assert_not_reached (); #if 0 - /* - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + /* + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_LOAD_MEMBASE offset(basereg), reg * --> - * OP_STORE_MEMBASE_IMM imm, offset(basereg) + * OP_STORE_MEMBASE_IMM imm, offset(basereg) * OP_ICONST reg, imm */ } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM @@ -1702,7 +1702,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) /* Used when initializing temporaries */ /* We know sparc_fp is dword aligned */ if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM) && - (ins->inst_destbasereg == last_ins->inst_destbasereg) && + (ins->inst_destbasereg == last_ins->inst_destbasereg) && (ins->inst_destbasereg == sparc_fp) && (ins->inst_offset < 0) && ((ins->inst_offset % 8) == 0) && @@ -1732,13 +1732,13 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) /* * Convert compare with zero+branch to BRcc */ - /* + /* * This only works in 64 bit mode, since it examines all 64 * bits of the register. * Only do this if the method is small since BPr only has a 16bit * displacement. */ - if (v64 && (cfg->header->code_size < 10000) && last_ins && + if (v64 && (cfg->header->code_size < 10000) && last_ins && (last_ins->opcode == OP_COMPARE_IMM) && (last_ins->inst_imm == 0)) { switch (ins->opcode) { @@ -1788,15 +1788,15 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_MOVE: - /* - * OP_MOVE reg, reg + /* + * OP_MOVE reg, reg */ if (ins->dreg == ins->sreg1) { MONO_DELETE_INS (bb, ins); continue; } - /* - * OP_MOVE sreg, dreg + /* + * OP_MOVE sreg, dreg * OP_MOVE dreg, sreg */ if (last_ins && last_ins->opcode == OP_MOVE && @@ -1877,7 +1877,7 @@ sparc_patch (guint32 *code, const gpointer target) guint32 ins2 = code [1]; if (((ins2 >> 30) == 2) && (((ins2 >> 19) & 0x3f) == 2)) { - /* sethi followed by or */ + /* sethi followed by or */ guint32 *p = code; sparc_set (p, target8, rd); while (p <= (code + 1)) @@ -1900,7 +1900,7 @@ sparc_patch (guint32 *code, const gpointer target) *(code + 1) |= (t & 0x3ff); #endif } - else if (v64 && + else if (v64 && (sparc_inst_rd (ins) == sparc_g1) && (sparc_inst_op (c [1]) == 0) && (sparc_inst_op2 (c [1]) == 4) && (sparc_inst_op (c [2]) == 2) && (sparc_inst_op3 (c [2]) == 2) && @@ -1913,7 +1913,7 @@ sparc_patch (guint32 *code, const gpointer target) while (p < (c + 6)) sparc_nop (p); } - else if ((sparc_inst_op (ins2) == 2) && (sparc_inst_op3 (ins2) == 0x38) && + else if ((sparc_inst_op (ins2) == 2) && (sparc_inst_op3 (ins2) == 0x38) && (sparc_inst_imm (ins2))) { /* sethi followed by jmpl */ #ifndef SPARCV9 @@ -2012,7 +2012,7 @@ emit_vret_token (MonoInst *ins, guint32 *code) MonoCallInst *call = (MonoCallInst*)ins; guint32 size; - /* + /* * The sparc ABI requires that calls to functions which return a structure * contain an additional unimpl instruction which is checked by the callee. */ @@ -2045,7 +2045,7 @@ emit_move_return_value (MonoInst *ins, guint32 *code) case OP_LCALL: case OP_LCALL_REG: case OP_LCALL_MEMBASE: - /* + /* * ins->dreg is the least significant reg due to the lreg: LCALL rule * in inssel-long32.brg. */ @@ -2065,7 +2065,7 @@ emit_move_return_value (MonoInst *ins, guint32 *code) } else sparc_fmovd (code, sparc_f0, ins->dreg); -#else +#else sparc_fmovs (code, sparc_f0, ins->dreg); if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4) sparc_fstod (code, ins->dreg, ins->dreg); @@ -2107,7 +2107,7 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint32 *code) sig = mono_method_signature_internal (method); cinfo = get_call_info (cfg, sig, FALSE); - + /* This is the opposite of the code in emit_prolog */ for (i = 0; i < sig->param_count + sig->hasthis; ++i) { @@ -2215,7 +2215,7 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint32 *code) * * Determine whenever the instruction at CODE is a virtual call. */ -gboolean +gboolean mono_sparc_is_virtual_call (guint32 *code) { guint32 buf[1]; @@ -2225,7 +2225,7 @@ mono_sparc_is_virtual_call (guint32 *code) if ((sparc_inst_op (*code) == 0x2) && (sparc_inst_op3 (*code) == 0x38)) { /* - * Register indirect call. If it is a virtual call, then the + * Register indirect call. If it is a virtual call, then the * instruction in the delay slot is a special kind of nop. */ @@ -2540,8 +2540,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_BREAK: /* - * gdb does not like encountering 'ta 1' in the debugged code. So - * instead of emitting a trap, we emit a call a C function and place a + * gdb does not like encountering 'ta 1' in the debugged code. So + * instead of emitting a trap, we emit a call a C function and place a * breakpoint there. */ //sparc_ta (code, 1); @@ -2879,7 +2879,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) code = emit_save_sp_to_lmf (cfg, code); sparc_jmpl (code, ins->sreg1, sparc_g0, sparc_callsite); /* - * We emit a special kind of nop in the delay slot to tell the + * We emit a special kind of nop in the delay slot to tell the * trampoline code that this is a virtual call, thus an unbox * trampoline might need to be called. */ @@ -2989,7 +2989,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_LOCALLOC_IMM: { gint32 offset = ins->inst_imm; gint32 offset2; - + #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK /* Perform stack touching */ NOT_IMPLEMENTED; @@ -3058,11 +3058,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_START_HANDLER: { /* - * The START_HANDLER instruction marks the beginning of a handler - * block. It is called using a call instruction, so %o7 contains + * The START_HANDLER instruction marks the beginning of a handler + * block. It is called using a call instruction, so %o7 contains * the return address. Since the handler executes in the same stack - * frame as the method itself, we can't use save/restore to save - * the return address. Instead, we save it into a dedicated + * frame as the method itself, we can't use save/restore to save + * the return address. Instead, we save it into a dedicated * variable. */ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); @@ -3099,7 +3099,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_nop (code); break; } - case OP_CALL_HANDLER: + case OP_CALL_HANDLER: mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb); /* This is a jump inside the method, so call_simple works even on V9 */ sparc_call_simple (code, 0); @@ -3444,7 +3444,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1); #endif break; - case OP_LCONV_TO_R_UN: { + case OP_LCONV_TO_R_UN: { /* Emulated */ g_assert_not_reached (); break; @@ -3453,11 +3453,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_LCONV_TO_OVF_I4_2: { guint32 *br [3], *label [1]; - /* + /* * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */ sparc_cmp_imm (code, ins->sreg1, 0); - br [0] = code; + br [0] = code; sparc_branch (code, 1, sparc_bneg, 0); sparc_nop (code); @@ -3493,13 +3493,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FSUB: sparc_fsubd (code, ins->sreg1, ins->sreg2, ins->dreg); - break; + break; case OP_FMUL: sparc_fmuld (code, ins->sreg1, ins->sreg2, ins->dreg); - break; + break; case OP_FDIV: sparc_fdivd (code, ins->sreg1, ins->sreg2, ins->dreg); - break; + break; case OP_FNEG: #ifdef SPARCV9 sparc_fnegd (code, ins->sreg1, ins->dreg); @@ -3507,7 +3507,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* FIXME: why don't use fnegd ? */ sparc_fnegs (code, ins->sreg1, ins->dreg); #endif - break; + break; case OP_FREM: sparc_fdivd (code, ins->sreg1, ins->sreg2, FP_SCRATCH_REG); sparc_fmuld (code, ins->sreg2, FP_SCRATCH_REG, FP_SCRATCH_REG); @@ -3536,7 +3536,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) default: sparc_fbranch (code, 1, opcode_to_sparc_cond (ins->opcode), 2); /* delay slot */ - sparc_set (code, 1, ins->dreg); + sparc_set (code, 1, ins->dreg); } break; case OP_FBEQ: @@ -3644,7 +3644,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_inst_name (ins->opcode), max_len, ((guint8*)code) - code_start); g_assert_not_reached (); } - + cpos += max_len; last_ins = ins; @@ -3884,7 +3884,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) offset += 6 * sizeof (target_mgreg_t); else offset += cfg->param_area; - + /* align the stack size */ offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT); @@ -3950,7 +3950,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* Save the argument to a dword aligned stack location */ /* * stack_offset contains the offset of the argument on the stack. - * inst->inst_offset contains the dword aligned offset where the value + * inst->inst_offset contains the dword aligned offset where the value * should be stored. */ if (ainfo->storage == ArgInIRegPair) { @@ -3999,7 +3999,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) sparc_sth_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset); else if ((stack_offset - ARGS_OFFSET) & 0x4) - sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset); + sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset); else { if (v64) sparc_stx_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset); @@ -4016,7 +4016,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) if (!sparc_is_imm13 (inst->inst_offset + 4)) NOT_IMPLEMENTED; sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, inst->inst_offset); - sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4); + sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4); } else if ((ainfo->storage == ArgInFloatReg) && (inst->opcode != OP_REGVAR)) { if (!sparc_is_imm13 (stack_offset)) @@ -4027,7 +4027,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* The offset is guaranteed to be aligned by the ABI rules */ sparc_stdf_imm (code, ainfo->reg, inst->inst_basereg, inst->inst_offset); } - + if ((ainfo->storage == ArgInFloatReg) && (inst->opcode == OP_REGVAR)) { /* Need to move into the a double precision register */ sparc_fstod (code, ainfo->reg, ainfo->reg - 1); @@ -4080,10 +4080,10 @@ mono_arch_emit_epilog (MonoCompile *cfg) guint32 *code; int can_fold = 0; int max_epilog_size = 16 + 20 * 4; - + if (cfg->method->save_lmf) max_epilog_size += 128; - + if (mono_jit_trace_calls != NULL) max_epilog_size += 50; @@ -4099,7 +4099,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) code = mono_sparc_emit_restore_lmf (code, lmf_offset); } - /* + /* * The V8 ABI requires that calls to functions which return a structure * return to %i7+12 */ @@ -4113,8 +4113,8 @@ mono_arch_emit_epilog (MonoCompile *cfg) if (cfg->bb_exit->in_count == 1 && cfg->bb_exit->in_bb[0]->native_offset != cfg->bb_exit->native_offset) can_fold = 1; - /* - * FIXME: The last instruction might have a branch pointing into it like in + /* + * FIXME: The last instruction might have a branch pointing into it like in * int_ceq sparc_i0 <- */ can_fold = 0; @@ -4159,8 +4159,8 @@ mono_arch_emit_exceptions (MonoCompile *cfg) if (patch_info->type == MONO_PATCH_INFO_EXC) exc_count++; } - - /* + + /* * make sure we have enough space for exceptions */ #ifdef SPARCV9 @@ -4349,7 +4349,7 @@ mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMetho * @arg_info: an array to store the result infos * * Gathers information on parameters such as size, alignment and - * padding. arg_info should be large enought to hold param_count + 1 entries. + * padding. arg_info should be large enought to hold param_count + 1 entries. * * Returns the size of the activation frame. */ diff --git a/src/mono/mono/mini/mini-sparc.h b/src/mono/mono/mini/mini-sparc.h index 63be33284af89..1d96c2f0360ce 100644 --- a/src/mono/mono/mini/mini-sparc.h +++ b/src/mono/mono/mini/mini-sparc.h @@ -17,7 +17,7 @@ /* Parameters used by the register allocator */ -/* +/* * Use %o0..%o5 as local registers, plus %l7 since we need an extra register for * holding the sreg1 in call instructions. */ @@ -176,4 +176,4 @@ guint32* mono_sparc_emit_save_lmf (guint32* code, guint32 lmf_offset); guint32* mono_sparc_emit_restore_lmf (guint32 *code, guint32 lmf_offset); -#endif /* __MONO_MINI_SPARC_H__ */ +#endif /* __MONO_MINI_SPARC_H__ */ diff --git a/src/mono/mono/mini/mini-trampolines.c b/src/mono/mono/mini/mini-trampolines.c index 84aeee956586f..2b87e4bce2c55 100644 --- a/src/mono/mono/mini/mini-trampolines.c +++ b/src/mono/mono/mini/mini-trampolines.c @@ -317,7 +317,7 @@ mini_jit_info_is_gsharedvt (MonoJitInfo *ji) /** * mini_add_method_trampoline: - * @m: + * @m: * @compiled_method: * @add_static_rgctx_tramp: adds a static rgctx trampoline * @add_unbox_tramp: adds an unboxing trampoline @@ -658,7 +658,7 @@ common_call_trampoline (host_mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTa mini_patch_jump_sites (m, mono_get_addr_from_ftnptr (addr)); /* Patch the got entries pointing to this method */ - /* + /* * We do this here instead of in mono_codegen () to cover the case when m * was loaded from an aot image. */ @@ -729,7 +729,7 @@ common_call_trampoline (host_mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTa ji = mini_jit_info_table_find (code); if (ji && target_ji && generic_shared && ji->has_generic_jit_info && !target_ji->has_generic_jit_info) { - /* + /* * Can't patch the call as the caller is gshared, but the callee is not. Happens when * generic sharing fails. * FIXME: Performance problem. @@ -860,12 +860,12 @@ mono_vcall_trampoline (host_mgreg_t *regs, guint8 *code, int slot, guint8 *tramp /** * mono_aot_trampoline: * - * This trampoline handles calls made from AOT code. We try to bypass the + * This trampoline handles calls made from AOT code. We try to bypass the * normal JIT compilation logic to avoid loading the metadata for the method. */ #ifdef MONO_ARCH_AOT_SUPPORTED gpointer -mono_aot_trampoline (host_mgreg_t *regs, guint8 *code, guint8 *token_info, +mono_aot_trampoline (host_mgreg_t *regs, guint8 *code, guint8 *token_info, guint8* tramp) { MONO_REQ_GC_UNSAFE_MODE; @@ -912,7 +912,7 @@ mono_aot_trampoline (host_mgreg_t *regs, guint8 *code, guint8 *token_info, * This trampoline handles calls made from AOT code through the PLT table. */ gpointer -mono_aot_plt_trampoline (host_mgreg_t *regs, guint8 *code, guint8 *aot_module, +mono_aot_plt_trampoline (host_mgreg_t *regs, guint8 *code, guint8 *aot_module, guint8* tramp) { gpointer res; @@ -1002,8 +1002,8 @@ mono_delegate_trampoline (host_mgreg_t *regs, guint8 *code, gpointer *arg, guint method = delegate->method; /* - * delegate->method_ptr == NULL means the delegate was initialized by - * mini_delegate_ctor, while != NULL means it is initialized by + * delegate->method_ptr == NULL means the delegate was initialized by + * mini_delegate_ctor, while != NULL means it is initialized by * mono_delegate_ctor_with_method (). In both cases, we need to add wrappers * (ctor_with_method () does this, but it doesn't store the wrapper back into * delegate->method). @@ -1082,7 +1082,7 @@ mono_delegate_trampoline (host_mgreg_t *regs, guint8 *code, gpointer *arg, guint method = mono_object_get_virtual_method_internal (delegate->target, method); enable_caching = FALSE; } else if (delegate->target && - method->flags & METHOD_ATTRIBUTE_VIRTUAL && + method->flags & METHOD_ATTRIBUTE_VIRTUAL && method->flags & METHOD_ATTRIBUTE_ABSTRACT && mono_class_is_abstract (method->klass)) { method = mono_object_get_virtual_method_internal (delegate->target, method); @@ -1098,7 +1098,7 @@ mono_delegate_trampoline (host_mgreg_t *regs, guint8 *code, gpointer *arg, guint need_rgctx_tramp = TRUE; } - /* + /* * If the called address is a trampoline, replace it with the compiled method so * further calls don't have to go through the trampoline. */ @@ -1302,7 +1302,7 @@ mono_create_jump_trampoline (MonoMethod *method, gboolean add_sync_wrapper, Mono ji->d.method = method; /* - * mono_delegate_ctor needs to find the method metadata from the + * mono_delegate_ctor needs to find the method metadata from the * trampoline address, so we save it here. */ @@ -1335,7 +1335,7 @@ mono_create_jit_trampoline (MonoMethod *method, MonoError *error) /* Avoid creating trampolines if possible */ gpointer code = mono_jit_find_compiled_method (method); - + if (code) return code; if (mono_llvm_only) { @@ -1363,7 +1363,7 @@ mono_create_jit_trampoline (MonoMethod *method, MonoError *error) jit_mm_unlock (jit_mm); return tramp; -} +} gpointer mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token) @@ -1382,7 +1382,7 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token) UnlockedIncrement (&jit_trampolines); return tramp; -} +} /* diff --git a/src/mono/mono/mini/mini-unwind.h b/src/mono/mono/mini/mini-unwind.h index ff594c49937f2..3db2f45e9cb2b 100644 --- a/src/mono/mono/mini/mini-unwind.h +++ b/src/mono/mono/mini/mini-unwind.h @@ -19,7 +19,7 @@ #endif /* - * This is a platform-independent interface for unwinding through stack frames + * This is a platform-independent interface for unwinding through stack frames * based on the Dwarf unwinding interface. * See http://dwarfstd.org/Dwarf3.pdf, section "Call Frame Information". */ @@ -89,7 +89,7 @@ typedef struct { guint32 when; /* The offset _after_ the cpu instruction this unwind op belongs to */ } MonoUnwindOp; -/* +/* * Macros for emitting MonoUnwindOp structures. * These should be called _after_ emitting the cpu instruction the unwind op * belongs to. @@ -178,7 +178,7 @@ guint8* mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len); gboolean -mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, +mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations, mono_unwind_reg_t *regs, int nregs, host_mgreg_t **save_locations, int save_locations_len, diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index 82c8b1fcd6572..f341690dd7d59 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -535,7 +535,7 @@ gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) { g_error ("mono_chain_signal"); - + return FALSE; } @@ -784,7 +784,7 @@ mono_arch_load_function (MonoJitICallId jit_icall_id) return NULL; } -MONO_API void +MONO_API void mono_wasm_enable_debugging (int log_level) { mono_wasm_debug_level = log_level; diff --git a/src/mono/mono/mini/mini-wasm.h b/src/mono/mono/mini/mini-wasm.h index c98f7603828d5..d307077de1c33 100644 --- a/src/mono/mono/mini/mini-wasm.h +++ b/src/mono/mono/mini/mini-wasm.h @@ -45,7 +45,7 @@ #define MONO_ARCH_INST_SREG2_MASK(ins) 0 struct MonoLMF { - /* + /* * If the second lowest bit is set to 1, then this is a MonoLMFExt structure, and * the other fields are not valid. */ @@ -108,4 +108,4 @@ void mono_wasm_print_stack_trace (void); gboolean mini_wasm_is_scalar_vtype (MonoType *type); -#endif /* __MONO_MINI_WASM_H__ */ +#endif /* __MONO_MINI_WASM_H__ */ diff --git a/src/mono/mono/mini/mini-x86-gsharedvt.c b/src/mono/mono/mini/mini-x86-gsharedvt.c index d2d4b09d29834..93b86d8cc7afb 100644 --- a/src/mono/mono/mini/mini-x86-gsharedvt.c +++ b/src/mono/mono/mini/mini-x86-gsharedvt.c @@ -98,7 +98,7 @@ mono_arch_get_gsharedvt_call_info (MonoMemoryManager *mem_manager, gpointer addr * Map ret arg. * This handles the case when the method returns a normal vtype, and when it returns a type arg, and its instantiated * with a vtype. - */ + */ g_ptr_array_add (map, GUINT_TO_POINTER (caller_cinfo->vret_arg_offset / sizeof (target_mgreg_t))); g_ptr_array_add (map, GUINT_TO_POINTER (callee_cinfo->vret_arg_offset / sizeof (target_mgreg_t))); } diff --git a/src/mono/mono/mini/mini-x86.c b/src/mono/mono/mini/mini-x86.c index 53a83263399bc..e94494327c39c 100644 --- a/src/mono/mono/mini/mini-x86.c +++ b/src/mono/mono/mini/mini-x86.c @@ -80,7 +80,7 @@ mono_arch_regname (int reg) case X86_EBX: return "%ebx"; case X86_ECX: return "%ecx"; case X86_EDX: return "%edx"; - case X86_ESP: return "%esp"; + case X86_ESP: return "%esp"; case X86_EBP: return "%ebp"; case X86_EDI: return "%edi"; case X86_ESI: return "%esi"; @@ -318,7 +318,7 @@ add_valuetype (MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type, * get_call_info: * * Obtain information about a call according to the calling convention. - * For x86 ELF, see the "System V Application Binary Interface Intel386 + * For x86 ELF, see the "System V Application Binary Interface Intel386 * Architecture Processor Supplment, Fourth Edition" document for more * information. * For x86 win32, see https://msdn.microsoft.com/en-us/library/984x0h58.aspx. @@ -435,7 +435,7 @@ get_call_info_internal (CallInfo *cinfo, MonoMethodSignature *sig) if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) { fr = FLOAT_PARAM_REGS; - + /* Emit the signature cookie just before the implicit arguments */ add_general (&gr, param_regs, &stack_size, &cinfo->sig_cookie); } @@ -446,8 +446,8 @@ get_call_info_internal (CallInfo *cinfo, MonoMethodSignature *sig) if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) { /* We allways pass the sig cookie on the stack for simplicity */ - /* - * Prevent implicit arguments + the sig cookie from being passed + /* + * Prevent implicit arguments + the sig cookie from being passed * in registers. */ fr = FLOAT_PARAM_REGS; @@ -524,7 +524,7 @@ get_call_info_internal (CallInfo *cinfo, MonoMethodSignature *sig) if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) { fr = FLOAT_PARAM_REGS; - + /* Emit the signature cookie just before the implicit arguments */ add_general (&gr, param_regs, &stack_size, &cinfo->sig_cookie); } @@ -681,7 +681,7 @@ mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, Mo * @arg_info: an array to store the result infos * * Gathers information on parameters such as size, alignment and - * padding. arg_info should be large enought to hold param_count + 1 entries. + * padding. arg_info should be large enought to hold param_count + 1 entries. * * Returns the size of the argument area on the stack. * This should be signal safe, since it is called from @@ -738,7 +738,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit /* ignore alignment for now */ align = 1; - args_size += pad = (align - (args_size & (align - 1))) & (align - 1); + args_size += pad = (align - (args_size & (align - 1))) & (align - 1); arg_info [prev_stackarg].pad = pad; args_size += size; arg_info [k + 1].pad = 0; @@ -962,7 +962,7 @@ mono_arch_is_int_overflow (void *sigctx, void *info) if (reg == -1) return TRUE; } - + return FALSE; } @@ -980,11 +980,11 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg) if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos) continue; - if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || + if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG)) continue; - /* we dont allocate I1 to registers because there is no simply way to sign extend + /* we dont allocate I1 to registers because there is no simply way to sign extend * 8bit quantities in caller saved registers on x86 */ if (mono_is_regsize_var (ins->inst_vtype) && (ins->inst_vtype->type != MONO_TYPE_I1)) { g_assert (MONO_VARINFO (cfg, i)->reg == -1); @@ -1014,7 +1014,7 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /* * mono_arch_regalloc_cost: * - * Return the cost, in number of memory references, of the action of + * Return the cost, in number of memory references, of the action of * allocating the variable VMV into a register during global register * allocation. */ @@ -1219,7 +1219,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) switch (cinfo->ret.storage) { case ArgOnStack: if (cfg->vret_addr) { - /* + /* * In the new IR, the cfg->vret_addr variable represents the * vtype return value. */ @@ -1348,9 +1348,9 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) int sig_reg; /* - * mono_ArgIterator_Setup assumes the signature cookie is + * mono_ArgIterator_Setup assumes the signature cookie is * passed first and all the arguments which were before it are - * passed on the stack after the signature. So compensate by + * passed on the stack after the signature. So compensate by * passing a different signature. */ tmp_sig = mono_metadata_signature_dup (call->signature); @@ -1387,7 +1387,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) /* * LLVM always uses the native ABI while we use our own ABI, the * only difference is the handling of vtypes: - * - we only pass/receive them in registers in some cases, and only + * - we only pass/receive them in registers in some cases, and only * in 1 or 2 integer registers. */ if (cinfo->ret.storage == ArgValuetypeInReg) { @@ -1516,7 +1516,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) if (cinfo->ret.storage == ArgValuetypeInReg && cinfo->ret.pair_storage[0] != ArgNone ) { /* * Tell the JIT to use a more efficient calling convention: call using - * OP_CALL, compute the result location after the call, and save the + * OP_CALL, compute the result location after the call, and save the * result there. */ call->vret_in_reg = TRUE; @@ -1529,7 +1529,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) } } - // FIXME: Emit EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF everywhere + // FIXME: Emit EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF everywhere /* Handle the case where there are no implicit arguments */ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sentinelpos)) { @@ -1683,7 +1683,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) vtarg->sreg1 = call->inst.dreg; vtarg->dreg = mono_alloc_ireg (cfg); MONO_ADD_INS (cfg->cbb, vtarg); - + mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE); } else if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 0) { MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, cinfo->ret.offset, call->vret_var->dreg); @@ -1768,7 +1768,7 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) return; } } - + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg); } @@ -1784,9 +1784,9 @@ if (ins->inst_true_bb->native_offset) { \ x86_branch32 (code, cond, 0, sign); \ } -/* +/* * Emit an exception if condition is fail and - * if possible do a directly branch to target + * if possible do a directly branch to target */ #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name) \ do { \ @@ -1798,12 +1798,12 @@ if (ins->inst_true_bb->native_offset) { \ } else { \ EMIT_COND_BRANCH (tins, cond, signed); \ } \ - } while (0); + } while (0); #define EMIT_FPCOMPARE(code) do { \ x86_fcompp (code); \ x86_fnstsw (code); \ -} while (0); +} while (0); static guint8* x86_align_and_patch (MonoCompile *cfg, guint8 *code, guint32 patch_type, gconstpointer data) @@ -1862,7 +1862,7 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IADD_IMM: case OP_ADD_IMM: if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS)) { - /* + /* * X86_LEA is like ADD, but doesn't have the * sreg1==dreg restriction. */ @@ -1882,15 +1882,15 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_COMPARE_IMM: case OP_ICOMPARE_IMM: - /* OP_COMPARE_IMM (reg, 0) - * --> - * OP_X86_TEST_NULL (reg) + /* OP_COMPARE_IMM (reg, 0) + * --> + * OP_X86_TEST_NULL (reg) */ if (!ins->inst_imm) ins->opcode = OP_X86_TEST_NULL; break; case OP_X86_COMPARE_MEMBASE_IMM: - /* + /* * OP_STORE_MEMBASE_REG reg, offset(basereg) * OP_X86_COMPARE_MEMBASE_IMM offset(basereg), imm * --> @@ -1910,7 +1910,7 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) ins->opcode = OP_X86_TEST_NULL; } - break; + break; case OP_X86_PUSH_MEMBASE: if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG || last_ins->opcode == OP_STORE_MEMBASE_REG) && @@ -1943,8 +1943,8 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) ins->sreg1 = ins->dreg; ins->sreg2 = ins->dreg; - /* - * Convert succeeding STORE_MEMBASE_IMM 0 ins to STORE_MEMBASE_REG + /* + * Convert succeeding STORE_MEMBASE_IMM 0 ins to STORE_MEMBASE_REG * since it takes 3 bytes instead of 7. */ for (ins2 = mono_inst_next (ins, FILTER_IL_SEQ_POINT); ins2; ins2 = ins2->next) { @@ -1998,7 +1998,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) MonoInst *ins, *next; /* - * FIXME: Need to add more instructions, but the current machine + * FIXME: Need to add more instructions, but the current machine * description can't model some parts of the composite instructions like * cdq. */ @@ -2008,7 +2008,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) case OP_IDIV_IMM: case OP_IDIV_UN_IMM: case OP_IREM_UN_IMM: - /* + /* * Keep the cases where we could generated optimized code, otherwise convert * to the non-imm variant. */ @@ -2049,7 +2049,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) bb->max_vreg = cfg->next_vreg; } -static const int +static const int branch_cc_table [] = { X86_CC_EQ, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT, X86_CC_NE, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT, @@ -2099,7 +2099,7 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int size, gboolean x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8); x86_fist_pop_membase (code, X86_ESP, 0, TRUE); x86_pop_reg (code, dreg); - /* FIXME: need the high register + /* FIXME: need the high register * x86_pop_reg (code, dreg_high); */ } else { @@ -2151,7 +2151,7 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree) x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000); x86_test_membase_reg (code, X86_ESP, 0, X86_ESP); - /* + /* * By the end of the loop, sreg2 is smaller than 0x1000, so the init routine * that follows only initializes the last part of the area. */ @@ -2161,7 +2161,7 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree) x86_push_reg (code, X86_ECX); x86_push_reg (code, X86_EDI); x86_mov_reg_imm (code, X86_ECX, (0x1000 >> 2)); - x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX); + x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX); if (cfg->param_area) x86_lea_membase (code, X86_EDI, X86_ESP, 12 + ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); else @@ -2206,11 +2206,11 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree) x86_push_reg (code, X86_EDI); offset += 4; } - + x86_shift_reg_imm (code, X86_SHR, sreg, 2); x86_mov_reg_reg (code, X86_ECX, sreg); x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX); - + if (cfg->param_area) x86_lea_membase (code, X86_EDI, X86_ESP, offset + ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); else @@ -2218,7 +2218,7 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree) x86_cld (code); x86_prefix (code, X86_REP_PREFIX); x86_stosl (code); - + if (tree->dreg != X86_EDI && sreg != X86_EDI) x86_pop_reg (code, X86_EDI); if (tree->dreg != X86_ECX && sreg != X86_ECX) @@ -2641,7 +2641,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* Have to use ecx as a temp reg since this can occur after OP_SETRET */ - /* + /* * We do this _before_ the breakpoint, so single stepping after * a breakpoint is hit will step to the next IL offset. */ @@ -2680,7 +2680,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) int size = start + OP_SEQ_POINT_BP_OFFSET - code; x86_padding (code, size); } - /* + /* * A placeholder for a possible breakpoint inserted by * mono_arch_set_breakpoint (). */ @@ -2738,7 +2738,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_IDIV: case OP_IREM: - /* + /* * The code is the same for div/rem, the allocator will allocate dreg * to RAX/RDX as appropriate. */ @@ -2747,7 +2747,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_push_reg (code, ins->sreg2); x86_cdq (code); x86_div_membase (code, X86_ESP, 0, TRUE); - x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4); + x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4); } else { x86_cdq (code); x86_div_reg (code, ins->sreg2, TRUE); @@ -2759,7 +2759,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_push_reg (code, ins->sreg2); x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX); x86_div_membase (code, X86_ESP, 0, FALSE); - x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4); + x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4); } else { x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX); x86_div_reg (code, ins->sreg2, FALSE); @@ -2781,7 +2781,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* Based on http://compilers.iecc.com/comparch/article/93-04-079 */ x86_cdq (code); x86_alu_reg_imm (code, X86_AND, X86_EAX, 1); - /* + /* * If the divident is >= 0, this does not nothing. If it is positive, it * it transforms %eax=0 into %eax=0, and %eax=1 into %eax=-1. */ @@ -2854,7 +2854,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* handle shift over 32 bit */ x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1); x86_clear_reg (code, ins->sreg1); - + x86_patch (jump_to_end, code); } break; @@ -2871,7 +2871,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* handle shifts over 31 bits */ x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3); x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 31); - + x86_patch (jump_to_end, code); } break; @@ -2888,7 +2888,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* handle shifts over 31 bits */ x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3); x86_clear_reg (code, ins->backend.reg3); - + x86_patch (jump_to_end, code); } break; @@ -3128,7 +3128,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_mov_reg_membase (code, X86_EAX, X86_ESP, i, 4); x86_mov_membase_reg (code, X86_EBP, 8 + i, X86_EAX, 4); } - + /* restore ESP/EBP */ x86_leave (code); @@ -3315,13 +3315,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_BR: if (ins->inst_target_bb->native_offset) { - x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); + x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); } else { mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb); if ((cfg->opt & MONO_OPT_BRANCH) && x86_is_imm8 (ins->inst_target_bb->max_offset - cpos)) x86_jump8 (code, 0); - else + else x86_jump32 (code, 0); } break; @@ -3545,7 +3545,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_fld_membase (code, X86_ESP, 0, FALSE); x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8); break; - case OP_LCONV_TO_R_UN_2: { + case OP_LCONV_TO_R_UN_2: { static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 }; guint8 *br; @@ -3553,11 +3553,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_push_reg (code, ins->sreg2); x86_push_reg (code, ins->sreg1); x86_fild_membase (code, X86_ESP, 0, TRUE); - + /* test if lreg is negative */ x86_test_reg_reg (code, ins->sreg2, ins->sreg2); br = code; x86_branch8 (code, X86_CC_GEZ, 0, TRUE); - + /* add correction constant mn */ if (cfg->compile_aot) { x86_push_imm (code, (((guint32)mn [9]) << 24) | ((guint32)mn [8] << 16) | ((guint32)mn [7] << 8) | ((guint32)mn [6])); @@ -3585,7 +3585,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) guint8 *br [3], *label [1]; MonoInst *tins; - /* + /* * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */ x86_test_reg_reg (code, ins->sreg1, ins->sreg1); @@ -3609,12 +3609,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException"); x86_jump32 (code, 0); } - - + + x86_patch (br [0], code); /* our top bit is set, check that top word is 0xfffffff */ x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0xffffffff); - + x86_patch (br [1], code); /* nope, emit exception */ br [2] = code; x86_branch8 (code, X86_CC_NE, 0, TRUE); @@ -3639,23 +3639,23 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FSUB: x86_fp_op_reg (code, X86_FSUB, 1, TRUE); - break; + break; case OP_FMUL: x86_fp_op_reg (code, X86_FMUL, 1, TRUE); - break; + break; case OP_FDIV: x86_fp_op_reg (code, X86_FDIV, 1, TRUE); - break; + break; case OP_FNEG: x86_fchs (code); - break; + break; case OP_ABS: x86_fabs (code); - break; + break; case OP_TAN: { - /* + /* * it really doesn't make sense to inline all this code, - * it's here just to show that things may not be as simple + * it's here just to show that things may not be as simple * as they appear. */ guchar *check_pos, *end_tan, *pop_jump; @@ -3692,7 +3692,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_fpatan (code); x86_fldz (code); x86_fp_op_reg (code, X86_FADD, 1, TRUE); - break; + break; case OP_SQRT: x86_fsqrt (code); break; @@ -3736,7 +3736,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* we need to exchange ST(0) with ST(1) */ x86_fxch (code, 1); - /* this requires a loop, because fprem somtimes + /* this requires a loop, because fprem somtimes * returns a partial remainder */ l1 = code; /* looks like MS is using fprem instead of the IEEE compatible fprem1 */ @@ -3767,7 +3767,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCEQ: case OP_FCNEQ: if (cfg->opt & MONO_OPT_FCMOV) { - /* zeroing the register at the start results in + /* zeroing the register at the start results in * shorter and faster code (we can also remove the widening op) */ guchar *unordered_check; @@ -3791,7 +3791,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; } - if (ins->dreg != X86_EAX) + if (ins->dreg != X86_EAX) x86_push_reg (code, X86_EAX); EMIT_FPCOMPARE(code); @@ -3800,13 +3800,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_set_reg (code, ins->opcode == OP_FCEQ ? X86_CC_EQ : X86_CC_NE, ins->dreg, TRUE); x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE); - if (ins->dreg != X86_EAX) + if (ins->dreg != X86_EAX) x86_pop_reg (code, X86_EAX); break; case OP_FCLT: case OP_FCLT_UN: if (cfg->opt & MONO_OPT_FCMOV) { - /* zeroing the register at the start results in + /* zeroing the register at the start results in * shorter and faster code (we can also remove the widening op) */ x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg); @@ -3827,7 +3827,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; } - if (ins->dreg != X86_EAX) + if (ins->dreg != X86_EAX) x86_push_reg (code, X86_EAX); EMIT_FPCOMPARE(code); @@ -3846,7 +3846,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE); x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE); - if (ins->dreg != X86_EAX) + if (ins->dreg != X86_EAX) x86_pop_reg (code, X86_EAX); break; case OP_FCLE: { @@ -3890,7 +3890,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCGT: case OP_FCGT_UN: if (cfg->opt & MONO_OPT_FCMOV) { - /* zeroing the register at the start results in + /* zeroing the register at the start results in * shorter and faster code (we can also remove the widening op) */ guchar *unordered_check; @@ -3907,7 +3907,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; } - if (ins->dreg != X86_EAX) + if (ins->dreg != X86_EAX) x86_push_reg (code, X86_EAX); EMIT_FPCOMPARE(code); @@ -3921,13 +3921,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_jump8 (code, 0); x86_patch (is_not_zero_check, code); x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK); - + x86_patch (end_jump, code); } x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE); x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE); - if (ins->dreg != X86_EAX) + if (ins->dreg != X86_EAX) x86_pop_reg (code, X86_EAX); break; case OP_FCGE: { @@ -4114,7 +4114,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) br1 = code; x86_branch8 (code, X86_CC_NE, 0, FALSE); - x86_fstp (code, 0); + x86_fstp (code, 0); EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException"); x86_patch (br1, code); @@ -4172,7 +4172,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4); /* dreg contains the old value, add with sreg2 value */ x86_alu_reg_reg (code, X86_ADD, dreg, ins->sreg2); - + if (ins->dreg != dreg) { x86_mov_reg_reg (code, ins->dreg, dreg); x86_pop_reg (code, dreg); @@ -4188,11 +4188,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert (cfg->has_atomic_exchange_i4); /* cmpxchg uses eax as comperand, need to make sure we can use it - * hack to overcome limits in x86 reg allocator - * (req: dreg == eax and sreg2 != eax and breg != eax) + * hack to overcome limits in x86 reg allocator + * (req: dreg == eax and sreg2 != eax and breg != eax) */ g_assert (ins->dreg == X86_EAX); - + /* We need the EAX reg for the cmpxchg */ if (ins->sreg2 == X86_EAX) { sreg2 = (breg == X86_EDX) ? X86_EBX : X86_EDX; @@ -4417,11 +4417,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_SHUFPS: g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF); x86_sse_alu_reg_reg_imm8 (code, X86_SSE_SHUFP, ins->sreg1, ins->sreg2, ins->inst_c0); - break; + break; case OP_SHUFPD: g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0x3); x86_sse_alu_pd_reg_reg_imm8 (code, X86_SSE_SHUFP, ins->sreg1, ins->sreg2, ins->inst_c0); - break; + break; case OP_ADDPD: x86_sse_alu_pd_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2); @@ -4472,11 +4472,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_DUPPD: x86_sse_alu_sd_reg_reg (code, X86_SSE_MOVDDUP, ins->dreg, ins->sreg1); break; - + case OP_EXTRACT_MASK: x86_sse_alu_pd_reg_reg (code, X86_SSE_PMOVMSKB, ins->dreg, ins->sreg1); break; - + case OP_PAND: x86_sse_alu_pd_reg_reg (code, X86_SSE_PAND, ins->sreg1, ins->sreg2); break; @@ -4522,7 +4522,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_PMAXD_UN: x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUD, ins->sreg1, ins->sreg2); break; - + case OP_PMAXB: x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSB, ins->sreg1, ins->sreg2); break; @@ -4666,7 +4666,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_PSUBW_SAT: x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSW, ins->sreg1, ins->sreg2); break; - + case OP_PMULW: x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULLW, ins->sreg1, ins->sreg2); break; @@ -4737,8 +4737,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_PSHLQ_REG: x86_sse_shift_reg_reg (code, X86_SSE_PSLLQ_REG, ins->dreg, ins->sreg2); - break; - + break; + case OP_ICONV_TO_X: x86_movd_xreg_reg (code, ins->dreg, ins->sreg1); break; @@ -4831,7 +4831,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /*FIXME the peephole pass should have killed this*/ if (ins->dreg != ins->sreg1) x86_movaps_reg_reg (code, ins->dreg, ins->sreg1); - break; + break; case OP_XZERO: x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->dreg, ins->dreg); break; @@ -4859,7 +4859,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCONV_TO_U2: x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE); break; - } + } break; case OP_EXPAND_I2: @@ -4965,7 +4965,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset); g_assert_not_reached (); } - + cpos += max_len; } @@ -5275,7 +5275,7 @@ mono_arch_emit_epilog (MonoCompile *cfg) /* the code restoring the registers must be kept in sync with OP_TAILCALL */ pos = 0; - + if (method->save_lmf) { gint32 lmf_offset = cfg->lmf_var->inst_offset; @@ -5376,7 +5376,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg) exc_count++; } - /* + /* * make sure we have enough space for exceptions * 16 is the size of two push_imm instructions and a call */ @@ -5470,7 +5470,7 @@ mono_arch_flush_register_windows (void) { } -gboolean +gboolean mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) { return TRUE; @@ -5689,7 +5689,7 @@ mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMetho } else if (strcmp (cmethod->name, "Round") == 0 && fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R8) { opcode = OP_ROUND; } - + if (opcode && fsig->param_count == 1) { MONO_INST_NEW (cfg, ins, opcode); ins->type = STACK_R8; @@ -5707,7 +5707,7 @@ mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMetho } else if (strcmp (cmethod->name, "Max") == 0) { if (fsig->params [0]->type == MONO_TYPE_I4) opcode = OP_IMAX; - } + } if (opcode && fsig->param_count == 2) { MONO_INST_NEW (cfg, ins, opcode); @@ -5860,7 +5860,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par * and we need: * * - * + * * without unbalancing the stack. * So move each arg up a spot in the stack (overwriting un-needed 'this' arg) * and leaving original spot of first arg as placeholder in stack so @@ -6133,12 +6133,12 @@ get_float_to_x_spill_area (MonoCompile *cfg) if (!cfg->fconv_to_r8_x_var) { cfg->fconv_to_r8_x_var = mono_compile_create_var (cfg, m_class_get_byval_arg (mono_defaults.double_class), OP_LOCAL); cfg->fconv_to_r8_x_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/ - } + } return cfg->fconv_to_r8_x_var; } /* - * Convert all fconv opts that MONO_OPT_SSE2 would get wrong. + * Convert all fconv opts that MONO_OPT_SSE2 would get wrong. */ void mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) @@ -6203,12 +6203,12 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins) if (!(cfg->opt & MONO_OPT_SIMD)) return; - - /*TODO move this to simd-intrinsic.c once we support sse 4.1 dword extractors since we need the runtime caps info */ + + /*TODO move this to simd-intrinsic.c once we support sse 4.1 dword extractors since we need the runtime caps info */ switch (long_ins->opcode) { case OP_EXTRACT_I8: vreg = long_ins->sreg1; - + if (long_ins->inst_c0) { MONO_INST_NEW (cfg, ins, OP_PSHUFLED); ins->klass = long_ins->klass; @@ -6218,14 +6218,14 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins) ins->dreg = vreg = alloc_ireg (cfg); MONO_ADD_INS (cfg->cbb, ins); } - + MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4); ins->klass = mono_defaults.int32_class; ins->sreg1 = vreg; ins->type = STACK_I4; ins->dreg = MONO_LVREG_LS (long_ins->dreg); MONO_ADD_INS (cfg->cbb, ins); - + MONO_INST_NEW (cfg, ins, OP_PSHUFLED); ins->klass = long_ins->klass; ins->sreg1 = long_ins->sreg1; @@ -6233,14 +6233,14 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins) ins->type = STACK_VTYPE; ins->dreg = vreg = alloc_ireg (cfg); MONO_ADD_INS (cfg->cbb, ins); - + MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4); ins->klass = mono_defaults.int32_class; ins->sreg1 = vreg; ins->type = STACK_I4; ins->dreg = MONO_LVREG_MS (long_ins->dreg); MONO_ADD_INS (cfg->cbb, ins); - + long_ins->opcode = OP_NOP; break; case OP_INSERTX_I8_SLOW: @@ -6301,8 +6301,8 @@ guint8* mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji) { x86_call_imm (code, 0); - /* - * The patch needs to point to the pop, since the GOT offset needs + /* + * The patch needs to point to the pop, since the GOT offset needs * to be added to that address. */ if (cfg) @@ -6321,7 +6321,7 @@ mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, Mon * * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and * TARGET from the mscorlib GOT in full-aot code. - * On x86, the GOT address is assumed to be in EBX, and the result is placed into + * On x86, the GOT address is assumed to be in EBX, and the result is placed into * EAX. */ guint8* @@ -6385,7 +6385,7 @@ mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip) for (i = 0; i < 2; ++i) x86_nop (code); } - + /* * mono_arch_start_single_stepping: * @@ -6396,7 +6396,7 @@ mono_arch_start_single_stepping (void) { ss_trampoline = mini_get_single_step_trampoline (); } - + /* * mono_arch_stop_single_stepping: * diff --git a/src/mono/mono/mini/mini.c b/src/mono/mono/mini/mini.c index 2d6e3a22930f7..bf3a2d3282295 100644 --- a/src/mono/mono/mini/mini.c +++ b/src/mono/mono/mini/mini.c @@ -123,7 +123,7 @@ mono_emit_unwind_op (MonoCompile *cfg, int when, int tag, int reg, int val) op->reg = reg; op->val = val; op->when = when; - + cfg->unwind_ops = g_slist_append_mempool (cfg->mempool, cfg->unwind_ops, op); if (cfg->verbose_level > 1) { switch (tag) { @@ -219,7 +219,7 @@ mono_find_block_region_notry (MonoCompile *cfg, int offset) if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) && (offset < (clause->handler_offset))) return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags; - + if (MONO_OFFSET_IN_HANDLER (clause, offset)) { if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags; @@ -244,13 +244,13 @@ mono_get_block_region_notry (MonoCompile *cfg, int region) { if ((region & (0xf << 4)) == MONO_REGION_TRY) { MonoMethodHeader *header = cfg->header; - + /* * This can happen if a try clause is nested inside a finally clause. */ int clause_index = (region >> 8) - 1; g_assert (clause_index >= 0 && clause_index < header->num_clauses); - + region = mono_find_block_region_notry (cfg, header->clauses [clause_index].try_offset); } @@ -302,7 +302,7 @@ mono_reverse_branch_op (guint32 opcode) OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE, OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN }; - + if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) { opcode = reverse_map [opcode - CEE_BEQ]; } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) { @@ -342,7 +342,7 @@ mono_type_to_store_membase (MonoCompile *cfg, MonoType *type) case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: + case MONO_TYPE_ARRAY: return OP_STORE_MEMBASE_REG; case MONO_TYPE_I8: case MONO_TYPE_U8: @@ -403,7 +403,7 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type) case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: + case MONO_TYPE_ARRAY: return OP_LOAD_MEMBASE; case MONO_TYPE_I8: case MONO_TYPE_U8: @@ -674,7 +674,7 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, if (mini_type_is_reference (type)) mono_mark_vreg_as_ref (cfg, vreg); #endif - + cfg->varinfo [num] = inst; cfg->vars [num].idx = num; @@ -698,12 +698,12 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, if (regpair) { MonoInst *tree; - /* + /* * These two cannot be allocated using create_var_for_vreg since that would * put it into the cfg->varinfo array, confusing many parts of the JIT. */ - /* + /* * Set flags to VOLATILE so SSA skips it. */ @@ -802,7 +802,7 @@ mono_mark_vreg_as_ref (MonoCompile *cfg, int vreg) memcpy (cfg->vreg_is_ref, tmp, size * sizeof (gboolean)); } cfg->vreg_is_ref [vreg] = TRUE; -} +} void mono_mark_vreg_as_mp (MonoCompile *cfg, int vreg) @@ -818,7 +818,7 @@ mono_mark_vreg_as_mp (MonoCompile *cfg, int vreg) memcpy (cfg->vreg_is_mp, tmp, size * sizeof (gboolean)); } cfg->vreg_is_mp [vreg] = TRUE; -} +} static MonoType* type_from_stack_type (MonoInst *ins) @@ -829,7 +829,7 @@ type_from_stack_type (MonoInst *ins) case STACK_PTR: return mono_get_int_type (); case STACK_R8: return m_class_get_byval_arg (mono_defaults.double_class); case STACK_MP: - /* + /* * this if used to be commented without any specific reason, but * it breaks #80235 when commented */ @@ -915,7 +915,7 @@ mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst) mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst); } else { mono_bblock_insert_before_ins (bb, bb->last_ins, inst); - } + } } } else @@ -933,7 +933,7 @@ mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable)); table->table = bbs; table->table_size = num_blocks; - + ji->ip.label = label; ji->type = MONO_PATCH_INFO_SWITCH; ji->data.table = table; @@ -958,7 +958,7 @@ typedef struct { GSList *slots; } StackSlotInfo; -static gint +static gint compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b) { MonoMethodVar *v1 = (MonoMethodVar*)a; @@ -1199,11 +1199,11 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_ } } - /* + /* * This also handles the case when the variable is used in an * exception region, as liveness info is not computed there. */ - /* + /* * FIXME: All valuetypes are marked as INDIRECT because of LDADDR * opcodes. */ @@ -1438,7 +1438,7 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s slot = 0xffffff; if (cfg->comp_done & MONO_COMP_LIVENESS) { //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos); - + /* expire old intervals in active */ while (slot_info->active) { MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data; @@ -1452,11 +1452,11 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx])); } - /* + /* * This also handles the case when the variable is used in an * exception region, as liveness info is not computed there. */ - /* + /* * FIXME: All valuetypes are marked as INDIRECT because of LDADDR * opcodes. */ @@ -1507,7 +1507,7 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s if (MONO_TYPE_ISSTRUCT (t)) { align = MAX (align, sizeof (target_mgreg_t)); align = MAX (align, mono_class_min_align (mono_class_from_mono_type_internal (t))); - /* + /* * Align the size too so the code generated for passing vtypes in * registers doesn't overwrite random locals. */ @@ -1746,7 +1746,7 @@ mono_verify_cfg (MonoCompile *cfg) // This will free many fields in cfg to save // memory. Note that this must be safe to call -// multiple times. It must be idempotent. +// multiple times. It must be idempotent. void mono_empty_compile (MonoCompile *cfg) { @@ -1891,7 +1891,7 @@ mono_compile_create_vars (MonoCompile *cfg) header = cfg->header; sig = mono_method_signature_internal (cfg->method); - + if (!MONO_TYPE_IS_VOID (sig->ret)) { cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG); /* Inhibit optimizations */ @@ -1969,7 +1969,7 @@ void mono_print_code (MonoCompile *cfg, const char* msg) { MonoBasicBlock *bb; - + for (bb = cfg->bb_entry; bb; bb = bb->next_bb) mono_print_bb (bb, msg); } @@ -2145,7 +2145,7 @@ mono_codegen (MonoCompile *cfg) g_free (cfg->native_code); cfg->native_code = code; code = cfg->native_code + cfg->code_len; - + /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */ mono_postprocess_patches (cfg); @@ -2156,11 +2156,11 @@ mono_codegen (MonoCompile *cfg) g_free (nm); } #endif - + if (cfg->verbose_level > 0) { char* nm = mono_method_get_full_name (cfg->method); g_print ("Method %s emitted at %p to %p (code length %d)\n", - nm, + nm, cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len); g_free (nm); } @@ -2218,7 +2218,7 @@ mono_codegen (MonoCompile *cfg) mono_codeman_disable_write (); MONO_PROFILER_RAISE (jit_code_buffer, (cfg->native_code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method)); - + mono_arch_flush_icache (cfg->native_code, cfg->code_len); mono_debug_close_method (cfg); @@ -2263,7 +2263,7 @@ static void mono_bb_ordering (MonoCompile *cfg) cfg->num_bblocks = dfn + 1; - /* remove unreachable code, because the code in them may be + /* remove unreachable code, because the code in them may be * inconsistent (access to dead variables for example) */ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) bb->flags &= ~BB_VISITED; @@ -3313,7 +3313,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts cfg->method_to_register = method_to_register; ERROR_DECL (err); - sig = mono_method_signature_checked (cfg->method, err); + sig = mono_method_signature_checked (cfg->method, err); if (!sig) { cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD; cfg->exception_message = g_strdup (mono_error_get_message (err)); @@ -3344,7 +3344,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts if (!inited) inited = TRUE; - /* + /* * Check for methods which cannot be compiled by LLVM early, to avoid * the extra compilation pass. */ @@ -3382,7 +3382,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts if (mini_debug_options.mdb_optimizations || MONO_CFG_PROFILE_CALL_CONTEXT (cfg)) { cfg->disable_reuse_registers = TRUE; cfg->disable_reuse_stack_slots = TRUE; - /* + /* * This decreases the change the debugger will read registers/stack slots which are * not yet initialized. */ @@ -3426,18 +3426,18 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts char *env = g_getenv ("MONO_VERBOSE_METHOD"); if (env != NULL) verbose_method_names = g_strsplit (env, ";", -1); - + verbose_method_inited = TRUE; } if (verbose_method_names) { int i; - + for (i = 0; verbose_method_names [i] != NULL; i++){ const char *name = verbose_method_names [i]; if ((strchr (name, '.') > name) || strchr (name, ':') || strchr (name, '*')) { MonoMethodDesc *desc; - + desc = mono_method_desc_new (name, TRUE); if (desc) { if (mono_method_desc_full_match (desc, cfg->method)) { @@ -3558,9 +3558,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts cfg->after_method_to_ir = TRUE; /* todo: remove code when we have verified that the liveness for try/catch blocks - * works perfectly + * works perfectly */ - /* + /* * Currently, this can't be commented out since exception blocks are not * processed during liveness analysis. * It is also needed, because otherwise the local optimization passes would @@ -3650,9 +3650,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts mono_cfg_dump_ir (cfg, "bb_ordering"); if (((cfg->num_varinfo > 2000) || (cfg->num_bblocks > 1000)) && !cfg->compile_aot) { - /* + /* * we disable some optimizations if there are too many variables - * because JIT time may become too expensive. The actual number needs + * because JIT time may become too expensive. The actual number needs * to be tweaked and eventually the non-linear algorithms should be fixed. */ cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP); @@ -3696,7 +3696,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts mono_ssa_compute (cfg); #endif } -#else +#else if (cfg->opt & MONO_OPT_SSA) { if (!(cfg->comp_done & MONO_COMP_SSA) && !cfg->disable_ssa) { #ifndef DISABLE_SSA @@ -3797,11 +3797,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts g_assert (cfg->got_var_allocated); - /* + /* * Allways allocate the GOT var to a register, because keeping it * in memory will increase the number of live temporaries in some * code created by inssel.brg, leading to the well known spills+ - * branches problem. Testcase: mcs crash in + * branches problem. Testcase: mcs crash in * System.MonoCustomAttrs:GetCustomAttributes. */ #ifdef MONO_ARCH_GOT_REG @@ -3824,7 +3824,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts if (cfg->opt & MONO_OPT_LINEARS) { GList *vars, *regs, *l; - + /* fixme: maybe we can avoid to compute livenesss here if already computed ? */ cfg->comp_done &= ~MONO_COMP_LIVENESS; if (!(cfg->comp_done & MONO_COMP_LIVENESS)) @@ -3849,7 +3849,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts //mono_print_code (cfg, ""); //print_dfn (cfg); - + /* variables are allocated after decompose, since decompose could create temps */ if (!COMPILE_LLVM (cfg)) { MONO_TIME_TRACK (mono_jit_stats.jit_arch_allocate_vars, mono_arch_allocate_vars (cfg)); @@ -3917,7 +3917,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts if (cfg->verbose_level > 0 && !cfg->compile_aot) { nm = mono_method_get_full_name (cfg->method); g_print ("LLVM Method %s emitted at %p to %p (code length %d)\n", - nm, + nm, cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len); g_free (nm); } @@ -4466,7 +4466,7 @@ mini_get_cpu_features (MonoCompile* cfg) // This is a standard part of ARMv8-A; see A1.5 in "ARM // Architecture Reference Manual ARMv8, for ARMv8-A // architecture profile" - features |= MONO_CPU_ARM64_NEON; + features |= MONO_CPU_ARM64_NEON; #endif // apply parameters passed via -mattr diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 85f64cd67cc77..baa30d8bdcdb5 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -265,7 +265,7 @@ enum { NULLIFY_INS ((ins)); \ } while (0) -/* +/* * this is used to determine when some branch optimizations are possible: we exclude FP compares * because they have weird semantics with NaNs. */ @@ -454,7 +454,7 @@ typedef struct { int pc_offset; /* The basic block containing the call site */ MonoBasicBlock *bb; - /* + /* * The set of variables live at the call site. * Has length cfg->num_varinfo in bits. */ @@ -467,7 +467,7 @@ typedef struct { } GCCallSite; /* - * The IR-level extended basic block. + * The IR-level extended basic block. * * A basic block can have multiple exits just fine, as long as the point of * 'departure' is the last instruction in the basic block. Extended basic @@ -492,7 +492,7 @@ struct MonoBasicBlock { /* unique block number identification */ gint32 block_num; - + gint32 dfn; /* Basic blocks: incoming and outgoing counts and pointers */ @@ -529,13 +529,13 @@ struct MonoBasicBlock { /* fast dominator algorithm */ MonoBasicBlock *df_parent, *ancestor, *child, *label; int size, sdom, idomn; - + /* loop nesting and recognition */ GList *loop_blocks; gint8 nesting; gint8 loop_body_start; - /* + /* * Whenever the bblock is rarely executed so it should be emitted after * the function epilog. */ @@ -564,7 +564,7 @@ struct MonoBasicBlock { * call). */ guint extend_try_block : 1; - + /* use for liveness analysis */ MonoBitSet *gen_set; MonoBitSet *kill_set; @@ -583,7 +583,7 @@ struct MonoBasicBlock { // The MonoInst of the last sequence point for the current basic block. MonoInst *last_seq_point; - + // This will hold a list of last sequence points of incoming basic blocks MonoInst **pred_seq_points; guint num_pred_seq_points; @@ -609,7 +609,7 @@ struct MonoBasicBlock { * * Bits: | 0-3 | 4-7 | 8-31 * | | | - * | clause-flags | MONO_REGION | clause-index + * | clause-flags | MONO_REGION | clause-index * */ guint region; @@ -709,7 +709,7 @@ typedef struct { gboolean imt_arg; /* Whenever there is a dummy extra argument */ gboolean dummy_arg; - /* + /* * The position of the vret arg in the argument list. * Only if ret->storage == ArgVtypeRetAddr. * Should be 0 or 1. @@ -729,7 +729,7 @@ struct MonoInst { guint16 opcode; guint8 type; /* stack type */ guint8 flags; - + /* used by the register allocator */ gint32 dreg, sreg1, sreg2, sreg3; @@ -786,10 +786,10 @@ struct MonoInst { */ int memory_barrier_kind; } backend; - + MonoClass *klass; }; - + struct MonoCallInst { MonoInst inst; MonoMethodSignature *signature; @@ -845,7 +845,7 @@ struct MonoCallArgParm { gint32 offPrm; }; -/* +/* * flags for MonoInst * Note: some of the values overlap, because they can't appear * in the same MonoInst. @@ -869,7 +869,7 @@ enum { MONO_INST_NORANGECHECK = 16, /* On loads, the source address can be null */ MONO_INST_FAULT = 32, - /* + /* * On variables, identifies LMF variables. These variables have a dummy type (int), but * require stack space for a MonoLMF struct. */ @@ -957,7 +957,7 @@ typedef union { guint16 tid; /* tree number */ guint16 bid; /* block number */ } pos ; - guint32 abs_pos; + guint32 abs_pos; } MonoPosition; typedef struct { @@ -993,8 +993,8 @@ struct MonoMethodVar { char cpstate; /* used by SSA conditional constant propagation */ /* The native offsets corresponding to the live range of the variable */ gint32 live_range_start, live_range_end; - /* - * cfg->varinfo [idx]->dreg could be replaced for OP_REGVAR, this contains the + /* + * cfg->varinfo [idx]->dreg could be replaced for OP_REGVAR, this contains the * original vreg. */ gint32 vreg; @@ -1338,7 +1338,7 @@ typedef struct { MonoBackend *backend; - /* + /* * This variable represents the hidden argument holding the vtype * return address. If the method returns something other than a vtype, or * the vtype is returned in registers this is NULL. @@ -1349,7 +1349,7 @@ typedef struct { * This is used to initialize the cil_code field of MonoInst's. */ const unsigned char *ip; - + struct MonoAliasingInformation *aliasing_info; /* A hashtable of region ID-> SP var mappings */ @@ -1369,7 +1369,7 @@ typedef struct { GHashTable *exvars; GList *ldstr_list; /* used by AOT */ - + guint real_offset; GHashTable *cbb_hash; @@ -1542,7 +1542,7 @@ typedef struct { /* Size of above array */ guint32 vreg_is_mp_len; - /* + /* * The original method to compile, differs from 'method' when doing generic * sharing. */ @@ -1610,7 +1610,7 @@ typedef struct { GSList *interp_in_signatures; /* GC Maps */ - + /* The offsets of the locals area relative to the frame pointer */ gint locals_min_stack_offset, locals_max_stack_offset; @@ -1999,12 +1999,12 @@ enum { MONO_EXC_INTRINS_NUM }; - /* + /* * Information about a trampoline function. */ struct MonoTrampInfo { - /* + /* * The native code of the trampoline. Not owned by this structure. */ guint8 *code; @@ -2014,7 +2014,7 @@ struct MonoTrampInfo * structure. */ char *name; - /* + /* * Patches required by the trampoline when aot-ing. Owned by this structure. */ MonoJumpInfo *ji; @@ -2242,7 +2242,7 @@ mini_register_opcode_emulation (int opcode, MonoJitICallInfo *jit_icall_info, co void mono_trampolines_init (void); guint8 * mono_get_trampoline_code (MonoTrampolineType tramp_type); gpointer mono_create_specific_trampoline (MonoMemoryManager *mem_manager, gpointer arg1, MonoTrampolineType tramp_type, guint32 *code_len); -gpointer mono_create_jump_trampoline (MonoMethod *method, +gpointer mono_create_jump_trampoline (MonoMethod *method, gboolean add_sync_wrapper, MonoError *error); gpointer mono_create_jit_trampoline (MonoMethod *method, MonoError *error); @@ -2256,9 +2256,9 @@ gpointer mono_create_ftnptr_arg_trampoline (gpointer arg, gpointer addr guint32 mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr); gpointer mono_magic_trampoline (host_mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp); gpointer mono_delegate_trampoline (host_mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp); -gpointer mono_aot_trampoline (host_mgreg_t *regs, guint8 *code, guint8 *token_info, +gpointer mono_aot_trampoline (host_mgreg_t *regs, guint8 *code, guint8 *token_info, guint8* tramp); -gpointer mono_aot_plt_trampoline (host_mgreg_t *regs, guint8 *code, guint8 *token_info, +gpointer mono_aot_plt_trampoline (host_mgreg_t *regs, guint8 *code, guint8 *token_info, guint8* tramp); gconstpointer mono_get_trampoline_func (MonoTrampolineType tramp_type); gpointer mini_get_vtable_trampoline (MonoVTable *vt, int slot_index); @@ -2341,11 +2341,11 @@ CompRelation mono_negate_cond (CompRelation cond); int mono_op_imm_to_op (int opcode); void mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins); void mono_peephole_ins (MonoBasicBlock *bb, MonoInst *ins); -MonoUnwindOp *mono_create_unwind_op (int when, - int tag, int reg, +MonoUnwindOp *mono_create_unwind_op (int when, + int tag, int reg, int val); -void mono_emit_unwind_op (MonoCompile *cfg, int when, - int tag, int reg, +void mono_emit_unwind_op (MonoCompile *cfg, int when, + int tag, int reg, int val); MonoTrampInfo* mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops); void mono_tramp_info_free (MonoTrampInfo *info); @@ -2354,7 +2354,7 @@ void mono_tramp_info_register (MonoTrampInfo *info, MonoMemoryManag int mini_exception_id_by_name (const char *name); gboolean mini_type_is_hfa (MonoType *t, int *out_nfields, int *out_esize); -int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, +int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, MonoInst *return_var, MonoInst **inline_args, guint inline_offset, gboolean is_virtual_call); @@ -2475,7 +2475,7 @@ SeqPointInfo *mono_arch_get_seq_point_info (guint8 *code); gboolean mono_arch_unwind_frame (MonoJitTlsData *jit_tls, - MonoJitInfo *ji, MonoContext *ctx, + MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, StackFrameInfo *frame_info); @@ -2610,8 +2610,8 @@ ICALL_EXPORT MonoArray *ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info); ICALL_EXPORT -MonoBoolean ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, - MonoReflectionMethod **method, +MonoBoolean ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, + MonoReflectionMethod **method, gint32 *iloffset, gint32 *native_offset, MonoString **file, gint32 *line, gint32 *column); void mono_set_cast_details (MonoClass *from, MonoClass *to); @@ -2644,7 +2644,7 @@ void mono_debug_free_method (MonoCompile *cfg); void mono_debug_open_block (MonoCompile *cfg, MonoBasicBlock *bb, guint32 address); void mono_debug_record_line_number (MonoCompile *cfg, MonoInst *ins, guint32 address); void mono_debug_serialize_debug_info (MonoCompile *cfg, guint8 **out_buf, guint32 *buf_len); -void mono_debug_add_aot_method (MonoMethod *method, guint8 *code_start, +void mono_debug_add_aot_method (MonoMethod *method, guint8 *code_start, guint8 *debug_info, guint32 debug_info_len); MONO_API void mono_debug_print_vars (gpointer ip, gboolean only_arguments); MONO_API void mono_debugger_run_finally (MonoContext *start_ctx); @@ -2886,7 +2886,7 @@ typedef enum { MONO_CPU_X86_AVX_COMBINED = MONO_CPU_X86_SSE42_COMBINED | MONO_CPU_X86_AVX, MONO_CPU_X86_AVX2_COMBINED = MONO_CPU_X86_AVX_COMBINED | MONO_CPU_X86_AVX2, MONO_CPU_X86_FMA_COMBINED = MONO_CPU_X86_AVX_COMBINED | MONO_CPU_X86_FMA, - MONO_CPU_X86_FULL_SSEAVX_COMBINED = MONO_CPU_X86_FMA_COMBINED | MONO_CPU_X86_AVX2 | MONO_CPU_X86_PCLMUL + MONO_CPU_X86_FULL_SSEAVX_COMBINED = MONO_CPU_X86_FMA_COMBINED | MONO_CPU_X86_AVX2 | MONO_CPU_X86_PCLMUL | MONO_CPU_X86_AES | MONO_CPU_X86_POPCNT | MONO_CPU_X86_FMA, #endif #ifdef TARGET_WASM diff --git a/src/mono/mono/mini/mono-private-unstable.h b/src/mono/mono/mini/mono-private-unstable.h index 03f24a08ec917..fade778a39857 100644 --- a/src/mono/mono/mini/mono-private-unstable.h +++ b/src/mono/mono/mini/mono-private-unstable.h @@ -1,6 +1,6 @@ /** * \file - * + * * Private unstable APIs. * * WARNING: The declarations and behavior of functions in this header are NOT STABLE and can be modified or removed at @@ -64,7 +64,7 @@ mono_install_load_aot_data_hook (MonoLoadAotDataFunc load_func, MonoFreeAotDataF MONO_API int monovm_initialize (int propertyCount, const char **propertyKeys, const char **propertyValues); -MONO_API int +MONO_API int monovm_runtimeconfig_initialize (MonovmRuntimeConfigArguments *arg, MonovmRuntimeConfigArgumentsCleanup cleanup_fn, void *user_data); // The wrapper MonoCoreRuntimeProperties struct can be stack-allocated or freed, but the structs inside it _must_ be heap-allocated and never freed, as they are not copied to avoid extra allocations diff --git a/src/mono/mono/mini/monovm.c b/src/mono/mono/mini/monovm.c index e148596216599..a90b36ec3e3be 100644 --- a/src/mono/mono/mini/monovm.c +++ b/src/mono/mono/mini/monovm.c @@ -250,7 +250,7 @@ monovm_execute_assembly (int argc, const char **argv, const char *managedAssembl char **mono_argv = (char **) malloc (sizeof (char *) * (mono_argc + 1 /* null terminated */)); const char **ptr = (const char **) mono_argv; - + *ptr++ = NULL; // executable assembly @@ -280,7 +280,7 @@ monovm_shutdown (int *latchedExitCode) static int monovm_create_delegate_impl (const char* assemblyName, const char* typeName, const char *methodName, void **delegate); - + int monovm_create_delegate (const char *assemblyName, const char *typeName, const char *methodName, void **delegate) @@ -337,7 +337,7 @@ monovm_create_delegate_impl (const char* assemblyName, const char* typeName, con g_assert (t); MonoClass *klass = mono_class_from_mono_type_internal (t); - + MonoMethod *method = mono_class_get_method_from_name_checked (klass, methodName, -1, 0, error); goto_if_nok (error, fail); @@ -346,7 +346,7 @@ monovm_create_delegate_impl (const char* assemblyName, const char* typeName, con mono_error_set_not_supported (error, "MonoVM only supports UnmanagedCallersOnly implementations of hostfxr_get_runtime_delegate delegate types"); goto fail; } - + MonoClass *delegate_klass = NULL; MonoGCHandle target_handle = 0; MonoMethod *wrapper = mono_marshal_get_managed_wrapper (method, delegate_klass, target_handle, error); diff --git a/src/mono/mono/mini/regalloc.h b/src/mono/mono/mini/regalloc.h index c0aa5fdf64a8a..5ba2ee4bd0b02 100644 --- a/src/mono/mono/mini/regalloc.h +++ b/src/mono/mono/mini/regalloc.h @@ -14,7 +14,7 @@ enum { MONO_REG_SIMD }; - + #ifdef MONO_ARCH_NEED_SIMD_BANK #define MONO_NUM_REGBANKS 5 #else @@ -29,7 +29,7 @@ typedef struct { regmask_t free_mask [MONO_NUM_REGBANKS]; /* symbolic -> hard register assignment */ - /* + /* * If the register is spilled, then this contains -spill - 1, where 'spill' * is the index of the spill variable. */ diff --git a/src/mono/mono/mini/seq-points.c b/src/mono/mono/mini/seq-points.c index 257b408f192da..4a6c2dbb3710e 100644 --- a/src/mono/mono/mini/seq-points.c +++ b/src/mono/mono/mini/seq-points.c @@ -41,7 +41,7 @@ recursively_make_pred_seq_points (MonoCompile *cfg, MonoBasicBlock *bb) for (int i = 0; i < bb->in_count; ++i) { MonoBasicBlock *in_bb = bb->in_bb [i]; - + // This bb has the last seq point, append it and continue if (in_bb->last_seq_point != NULL) { predecessors = g_array_append_val (predecessors, in_bb->last_seq_point); @@ -54,7 +54,7 @@ recursively_make_pred_seq_points (MonoCompile *cfg, MonoBasicBlock *bb) continue; // Take sequence points from incoming basic blocks - + if (in_bb == cfg->bb_entry) continue; @@ -80,7 +80,7 @@ recursively_make_pred_seq_points (MonoCompile *cfg, MonoBasicBlock *bb) for (int newer = 0; newer < bb->num_pred_seq_points; newer++) { bb->pred_seq_points [newer] = g_array_index(predecessors, MonoInst*, newer); } - } + } g_array_free (predecessors, TRUE); } diff --git a/src/mono/mono/mini/seq-points.h b/src/mono/mono/mini/seq-points.h index a35584971c6c4..639b9ed60f09b 100644 --- a/src/mono/mono/mini/seq-points.h +++ b/src/mono/mono/mini/seq-points.h @@ -3,7 +3,7 @@ * Copyright 2014 Xamarin Inc * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ - + #ifndef __MONO_SEQ_POINTS_H__ #define __MONO_SEQ_POINTS_H__ diff --git a/src/mono/mono/mini/ssa.c b/src/mono/mono/mini/ssa.c index 47579c57e1285..df1ac7fb78ccf 100644 --- a/src/mono/mono/mini/ssa.c +++ b/src/mono/mono/mini/ssa.c @@ -38,7 +38,7 @@ typedef struct { MonoInst *inst; } MonoVarUsageInfo; -static void +static void unlink_target (MonoBasicBlock *bb, MonoBasicBlock *target) { int i; @@ -53,13 +53,13 @@ unlink_target (MonoBasicBlock *bb, MonoBasicBlock *target) if (target->in_bb [i] == bb) { target->in_bb [i] = target->in_bb [--target->in_count]; break; - + } } } static void -unlink_unused_bblocks (MonoCompile *cfg) +unlink_unused_bblocks (MonoCompile *cfg) { int i, j; MonoBasicBlock *bb; @@ -72,24 +72,24 @@ unlink_unused_bblocks (MonoCompile *cfg) for (bb = cfg->bb_entry; bb && bb->next_bb;) { if (!(bb->next_bb->flags & BB_REACHABLE)) { bb->next_bb = bb->next_bb->next_bb; - } else + } else bb = bb->next_bb; } for (i = 1; i < cfg->num_bblocks; i++) { bb = cfg->bblocks [i]; - + if (!(bb->flags & BB_REACHABLE)) { for (j = 0; j < bb->in_count; j++) { - unlink_target (bb->in_bb [j], bb); + unlink_target (bb->in_bb [j], bb); } for (j = 0; j < bb->out_count; j++) { - unlink_target (bb, bb->out_bb [j]); + unlink_target (bb, bb->out_bb [j]); } if (G_UNLIKELY (cfg->verbose_level > 1)) printf ("\tUnlinked BB%d\n", bb->block_num); } - + } } @@ -148,11 +148,11 @@ record_use (MonoCompile *cfg, MonoInst *var, MonoBasicBlock *bb, MonoInst *ins) MonoVarUsageInfo *ui = (MonoVarUsageInfo *)mono_mempool_alloc (cfg->mempool, sizeof (MonoVarUsageInfo)); info = MONO_VARINFO (cfg, var->inst_c0); - + ui->bb = bb; ui->inst = ins; info->uses = g_list_prepend_mempool (cfg->mempool, info->uses, ui); -} +} typedef struct { MonoInst *var; @@ -331,7 +331,7 @@ typedef struct { /** * mono_ssa_rename_vars: * Implement renaming of SSA variables. Also compute def-use information in parallel. - * \p stack_history points to an area of memory which can be used for storing changes + * \p stack_history points to an area of memory which can be used for storing changes * made to the stack, so they can be reverted later. */ static void @@ -476,7 +476,7 @@ mono_ssa_compute (MonoCompile *cfg) mono_blockset_print (cfg, set, "", -1); } } - + mono_bitset_foreach_bit (set, idx, cfg->num_bblocks) { MonoBasicBlock *bb = cfg->bblocks [idx]; @@ -675,7 +675,7 @@ mono_ssa_remove (MonoCompile *cfg) } /* - * Removal of SSA form introduces many copies. To avoid this, we tyry to coalesce + * Removal of SSA form introduces many copies. To avoid this, we tyry to coalesce * the variables if possible. Since the newly introduced SSA variables don't * have overlapping live ranges (because we don't do agressive optimization), we * can coalesce them into the original variable. @@ -697,14 +697,14 @@ mono_ssa_remove (MonoCompile *cfg) if (var) { MonoMethodVar *vmv = MONO_VARINFO (cfg, var->inst_c0); - - /* + + /* * The third condition avoids coalescing with variables eliminated * during deadce. */ if ((vmv->reg != -1) && (vmv->idx != vmv->reg) && (MONO_VARINFO (cfg, vmv->reg)->reg != -1)) { printf ("COALESCE: R%d -> R%d\n", ins->dreg, cfg->varinfo [vmv->reg]->dreg); - ins->dreg = cfg->varinfo [vmv->reg]->dreg; + ins->dreg = cfg->varinfo [vmv->reg]->dreg; } } } @@ -739,7 +739,7 @@ mono_ssa_remove (MonoCompile *cfg) } static void -mono_ssa_create_def_use (MonoCompile *cfg) +mono_ssa_create_def_use (MonoCompile *cfg) { MonoBasicBlock *bb; MonoInst *ins; @@ -999,7 +999,7 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, GList **cvars, change_varstate (cfg, cvars, info, 2, NULL, carray); break; } - + if (mv->cpstate == 0) continue; @@ -1007,7 +1007,7 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, GList **cvars, if (!c0) c0 = carray [var->dreg]; - + /* FIXME: */ if (c0->opcode != OP_ICONST) { change_varstate (cfg, cvars, info, 2, NULL, carray); @@ -1019,7 +1019,7 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, GList **cvars, break; } } - + if (c0 && info->cpstate < 1) { change_varstate (cfg, cvars, info, 1, c0, carray); @@ -1050,7 +1050,7 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, GList **cvars, } else if (!var && (ins->dreg != -1)) { /* - * We don't record def-use information for local vregs since it would be + * We don't record def-use information for local vregs since it would be * expensive. Instead, we depend on the fact that all uses of the vreg are in * the same bblock, so they will be examined after the definition. * FIXME: This isn't true if the ins is visited through an SSA edge. @@ -1059,7 +1059,7 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, GList **cvars, carray [ins->dreg] = c0; } else { if (carray [ins->dreg]) { - /* + /* * The state of the vreg changed from constant to non-constant * -> need to rescan the whole bblock. */ @@ -1255,7 +1255,7 @@ fold_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **carray NULLIFY_INS (ins->next->next); } } - } + } else if (MONO_IS_COND_BRANCH_OP (ins)) { if (ins->flags & MONO_INST_CFOLD_TAKEN) { remove_bb_from_phis (cfg, bb, ins->inst_false_bb); @@ -1272,7 +1272,7 @@ fold_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **carray } void -mono_ssa_cprop (MonoCompile *cfg) +mono_ssa_cprop (MonoCompile *cfg) { MonoInst **carray; MonoBasicBlock *bb; @@ -1317,7 +1317,7 @@ mono_ssa_cprop (MonoCompile *cfg) g_assert (bb->flags & BB_REACHABLE); - /* + /* * Some bblocks are linked to 2 others even through they fall through to the * next bblock. */ @@ -1334,7 +1334,7 @@ mono_ssa_cprop (MonoCompile *cfg) } while (cvars) { - MonoMethodVar *info = (MonoMethodVar *)cvars->data; + MonoMethodVar *info = (MonoMethodVar *)cvars->data; cvars = g_list_delete_link (cvars, cvars); for (tmp = info->uses; tmp; tmp = tmp->next) { @@ -1380,11 +1380,11 @@ add_to_dce_worklist (MonoCompile *cfg, MonoMethodVar *var, MonoMethodVar *use, G use->uses = g_list_remove_link (use->uses, tmp); break; } - } + } } void -mono_ssa_deadce (MonoCompile *cfg) +mono_ssa_deadce (MonoCompile *cfg) { int i; GList *work_list; @@ -1408,7 +1408,7 @@ mono_ssa_deadce (MonoCompile *cfg) MonoMethodVar *info = (MonoMethodVar *)work_list->data; work_list = g_list_remove_link (work_list, work_list); - /* + /* * The second part of the condition happens often when PHI nodes have their dreg * as one of their arguments due to the fact that we use the original vars. */ @@ -1466,7 +1466,7 @@ mono_ssa_strength_reduction (MonoCompile *cfg) for (i = 0; i < cfg->num_varinfo; i++) { MonoMethodVar *info = MONO_VARINFO (cfg, i); - + if (info->def && info->def->ssa_op == MONO_SSA_STORE && info->def->inst_i0->opcode == OP_LOCAL && g_list_find (lp, info->def_bb)) { MonoInst *v = info->def->inst_i1; diff --git a/src/mono/mono/mini/trace.h b/src/mono/mono/mini/trace.h index f973d10fbd1fa..a286e574e1f4b 100644 --- a/src/mono/mono/mini/trace.h +++ b/src/mono/mono/mini/trace.h @@ -13,11 +13,11 @@ void mono_trace_enter_method (MonoMethod *method, MonoJitInfo *ji, MonoProfilerCallContext *ctx); ICALL_EXPORT -void +void mono_trace_leave_method (MonoMethod *method, MonoJitInfo *ji, MonoProfilerCallContext *ctx); ICALL_EXPORT -void +void mono_trace_tail_method (MonoMethod *method, MonoJitInfo *ji, MonoMethod *target); void mono_trace_enable (gboolean enable); diff --git a/src/mono/mono/mini/tramp-amd64-gsharedvt.c b/src/mono/mono/mini/tramp-amd64-gsharedvt.c index 0d564fbeefe45..b8f45e7afe907 100644 --- a/src/mono/mono/mini/tramp-amd64-gsharedvt.c +++ b/src/mono/mono/mini/tramp-amd64-gsharedvt.c @@ -252,7 +252,7 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) /* setup the frame */ amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize); - + /* save stuff */ /* save info */ @@ -294,7 +294,7 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) /* arg1 == info */ amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, AMD64_RAX, sizeof (target_mgreg_t)); /* arg2 = caller stack area */ - amd64_lea_membase (code, MONO_AMD64_ARG_REG2, AMD64_RBP, -(framesize - caller_reg_area_offset)); + amd64_lea_membase (code, MONO_AMD64_ARG_REG2, AMD64_RBP, -(framesize - caller_reg_area_offset)); /* arg3 == callee stack area */ amd64_lea_membase (code, MONO_AMD64_ARG_REG3, AMD64_RSP, callee_reg_area_offset); diff --git a/src/mono/mono/mini/tramp-amd64.c b/src/mono/mono/mini/tramp-amd64.c index ad749405c1511..6c4557a4da971 100644 --- a/src/mono/mono/mini/tramp-amd64.c +++ b/src/mono/mono/mini/tramp-amd64.c @@ -159,7 +159,7 @@ mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) gboolean disp_32bit = ((((gint64)addr - (gint64)orig_code)) < (1 << 30)) && ((((gint64)addr - (gint64)orig_code)) > -(1 << 30)); if ((((guint64)(addr)) >> 32) != 0 && !disp_32bit) { - /* + /* * This might happen with LLVM or when calling AOTed code. Create a thunk. */ guint8 *thunk_start, *thunk_code; @@ -290,7 +290,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf cfa_offset -= sizeof (target_mgreg_t); mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset); - /* + /* * Allocate a new stack frame */ amd64_push_reg (code, AMD64_RBP); @@ -473,7 +473,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMFTramp, lmf_addr), sizeof (target_mgreg_t)); amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RCX, sizeof (target_mgreg_t)); - /* + /* * Save rax to the stack, after the leave instruction, this will become part of * the red zone. */ @@ -482,7 +482,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Check for thread interruption */ /* This is not perf critical code so no need to check the interrupt flag */ - /* + /* * Have to call the _force_ variant, since there could be a protected wrapper on the top of the stack. */ if (aot) { @@ -626,7 +626,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type))); return buf; -} +} gpointer mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot) @@ -966,7 +966,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo amd64_mov_reg_imm (code, AMD64_R11, mono_component_debugger ()->single_step_from_context); else amd64_mov_reg_imm (code, AMD64_R11, mono_component_debugger ()->breakpoint_from_context); - } + } amd64_call_reg (code, AMD64_R11); /* Restore registers from ctx */ diff --git a/src/mono/mono/mini/tramp-arm.c b/src/mono/mono/mini/tramp-arm.c index 0834f106505e3..4b12b2aab0bda 100644 --- a/src/mono/mono/mini/tramp-arm.c +++ b/src/mono/mono/mini/tramp-arm.c @@ -40,7 +40,7 @@ mono_arch_patch_callsite (guint8 *method_start, guint8 *code_ptr, guint8 *addr) /* This is the 'bl' or the 'mov pc' instruction */ --code; - + /* * Note that methods are called also with the bl opcode. */ @@ -70,10 +70,10 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, host_mgreg_t *regs, guin if (*(guint32*)code == 0xe59fc000) { /* ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0); */ guint32 offset = ((guint32*)code)[2]; - + jump_entry = code + offset + 12; } else if (*(guint16*)(code - 4) == 0xf8df) { - /* + /* * Thumb PLT entry, begins with ldr.w ip, [pc, #8], code points to entry + 4, see * mono_arm_get_thumb_plt_entry (). */ @@ -178,9 +178,9 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_R4 + i, -regsave_size + ((4 + i) * 4)); if (aot) { - /* + /* * For page trampolines the data is in r1, so just move it, otherwise use the got slot as below. - * The trampoline contains a pc-relative offset to the got slot + * The trampoline contains a pc-relative offset to the got slot * preceeding the got slot where the value is stored. The offset can be * found at [lr + 0]. */ @@ -209,7 +209,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf code = mono_arm_emit_load_imm (code, ARMREG_R2, STACK - MONO_ABI_SIZEOF (MonoLMF)); ARM_ADD_REG_REG (code, ARMREG_V1, ARMREG_SP, ARMREG_R2); - /* ok, now we can continue with the MonoLMF setup, mostly untouched + /* ok, now we can continue with the MonoLMF setup, mostly untouched * from emit_prolog in mini-arm.c * This is a synthetized call to mono_get_lmf_addr () */ @@ -286,7 +286,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf } else { ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_V3); } - + /* Arg 3: the specific argument, stored in v2 */ ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_V2); @@ -1146,7 +1146,7 @@ mono_arm_get_thumb_plt_entry (guint8 *code) g_assert (((guint16*)target) [0] == 0xf8df); g_assert (((guint16*)target) [1] == 0xc008); - /* + /* * The PLT info offset is at offset 16, but mono_arch_get_plt_entry_offset () returns * the 3rd word, so compensate by returning a different value. */ diff --git a/src/mono/mono/mini/tramp-arm64.c b/src/mono/mono/mini/tramp-arm64.c index e0ea4f11e787e..e437bc2480333 100644 --- a/src/mono/mono/mini/tramp-arm64.c +++ b/src/mono/mono/mini/tramp-arm64.c @@ -5,7 +5,7 @@ * Copyright 2013 Xamarin Inc * * Based on tramp-arm.c: - * + * * Authors: * Paolo Molaro (lupus@ximian.com) * @@ -43,7 +43,7 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, host_mgreg_t *regs, guin guint64 slot_addr; int disp; - /* + /* * Decode the address loaded by the PLT entry emitted by arch_emit_plt_entry () in * aot-compiler.c */ diff --git a/src/mono/mono/mini/tramp-mips.c b/src/mono/mono/mini/tramp-mips.c index fdd9e546bebd8..edfdbe2b405bd 100644 --- a/src/mono/mono/mini/tramp-mips.c +++ b/src/mono/mono/mini/tramp-mips.c @@ -41,7 +41,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) { guint8 *code, *start; MonoMemoryManager *mem_manager = m_method_get_mem_manager (m); - + start = code = mono_mem_manager_code_reserve (mem_manager, 20); mips_load (code, mips_t9, addr); @@ -81,7 +81,7 @@ mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) On entry, 'code' points just after one of the above sequences. */ - + /* The jal case */ if ((code[-2] >> 26) == 0x03) { //g_print ("direct patching\n"); @@ -107,7 +107,7 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, host_mgreg_t *regs, guin g_assert_not_reached (); } -/* Stack size for trampoline function +/* Stack size for trampoline function * MIPS_MINIMAL_STACK_SIZE + 16 (args + alignment to mips_magic_trampoline) * + MonoLMF + 14 fp regs + 13 gregs + alignment * #define STACK (MIPS_MINIMAL_STACK_SIZE + 4 * sizeof (gulong) + sizeof (MonoLMF) + 14 * sizeof (double) + 13 * (sizeof (gulong))) @@ -219,13 +219,13 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Arg 4: Trampoline */ mips_move (code, mips_a3, mips_zero); - + /* Now go to the trampoline */ tramp = (guint8*)mono_get_trampoline_func (tramp_type); mips_load (code, mips_t9, (guint32)tramp); mips_jalr (code, mips_t9, mips_ra); mips_nop (code); - + /* Code address is now in v0, move it to at */ mips_move (code, mips_at, mips_v0); @@ -290,7 +290,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty * mono_arch_create_trampoline_code() knows we're putting this in t8 */ mips_load (code, mips_t8, arg1); - + /* Now jump to the generic trampoline code */ mips_load (code, mips_at, tramp); mips_jr (code, mips_at); diff --git a/src/mono/mono/mini/tramp-ppc.c b/src/mono/mono/mini/tramp-ppc.c index 67eb7c24db3ba..7d3c286a95af7 100644 --- a/src/mono/mono/mini/tramp-ppc.c +++ b/src/mono/mono/mini/tramp-ppc.c @@ -166,7 +166,7 @@ mono_arch_patch_callsite (guint8 *method_start, guint8 *code_ptr, guint8 *addr) /* This is the 'blrl' instruction */ --code; - + /* * Note that methods are called also with the bl opcode. */ @@ -176,7 +176,7 @@ mono_arch_patch_callsite (guint8 *method_start, guint8 *code_ptr, guint8 *addr) mono_arch_flush_icache ((guint8*)code, 4); return; } - + /* Sanity check */ g_assert (mono_ppc_is_direct_call_sequence (code)); @@ -203,7 +203,7 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, host_mgreg_t *regs, guin *(guint8**)((guint8*)got + offset) = addr; } -/* Stack size for trampoline function +/* Stack size for trampoline function * PPC_MINIMAL_STACK_SIZE + 16 (args + alignment to ppc_magic_trampoline) * + MonoLMF + 14 fp regs + 13 gregs + alignment */ @@ -260,7 +260,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf ppc_stfd (code, i, offset, ppc_r1); offset += sizeof (double); } - /* + /* * now the integer registers. */ offset = STACK - sizeof (MonoLMF) + G_STRUCT_OFFSET (MonoLMF, iregs); @@ -291,7 +291,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf ppc_mflr (code, ppc_r0); ppc_str (code, ppc_r0, STACK + PPC_RET_ADDR_OFFSET, ppc_r1); - /* ok, now we can continue with the MonoLMF setup, mostly untouched + /* ok, now we can continue with the MonoLMF setup, mostly untouched * from emit_prolog in mini-ppc.c */ if (aot) { @@ -342,7 +342,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf */ /* Arg 1: a pointer to the registers */ ppc_addi (code, ppc_r3, ppc_r1, GREGS_OFFSET); - + /* Arg 2: code (next address to the instruction that called us) */ if (tramp_type == MONO_TRAMPOLINE_JUMP) ppc_li (code, ppc_r4, 0); @@ -366,7 +366,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf ppc_mtlr (code, PPC_CALL_REG); ppc_blrl (code); } - + /* OK, code address is now on r3, move it to r14 for now. */ if (!MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) { #ifdef PPC_USES_FUNCTION_DESCRIPTOR @@ -510,12 +510,12 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty /* Prepare the jump to the generic trampoline code.*/ ppc_load_ptr (code, ppc_r0, tramp); ppc_mtctr (code, ppc_r0); - + /* And finally put 'arg1' in r0 and fly! */ ppc_load_ptr (code, ppc_r0, arg1); ppc_bcctr (code, 20, 0); } - + /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (buf, code - buf); MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type))); diff --git a/src/mono/mono/mini/tramp-s390x.c b/src/mono/mono/mini/tramp-s390x.c index d301a3777eacf..64497d163baae 100644 --- a/src/mono/mono/mini/tramp-s390x.c +++ b/src/mono/mono/mini/tramp-s390x.c @@ -25,7 +25,7 @@ #define LMFReg s390_r13 /* - * Method-specific trampoline code fragment sizes + * Method-specific trampoline code fragment sizes */ #define SPECIFIC_TRAMPOLINE_SIZE 96 @@ -83,17 +83,17 @@ typedef struct { /*====================== End of Global Variables ===================*/ /** - * + * * @brief Build the unbox trampoline * * @param[in] Method pointer * @param[in] Pointer to native code for method * - * Return a pointer to a trampoline which does the unboxing before + * Return a pointer to a trampoline which does the unboxing before * calling the method. * - * When value type methods are called through the - * vtable we need to unbox the 'this' argument. + * When value type methods are called through the + * vtable we need to unbox the 'this' argument. */ gpointer @@ -125,7 +125,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) /*========================= End of Function ========================*/ /** - * + * * @brief Build the SDB trampoline * * @param[in] Type of trampoline (ss or bp) @@ -141,7 +141,7 @@ guint8 * mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot) { int tramp_size = 512; - int i, framesize, ctx_offset, + int i, framesize, ctx_offset, gr_offset, fp_offset, ip_offset, sp_offset; guint8 *code, *buf; @@ -158,7 +158,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT); - /** + /** * Create unwind information - On entry s390_r1 has value of method's frame reg */ s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); @@ -168,7 +168,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo mono_add_unwind_op_offset (unwind_ops, code, buf, i, gr_offset); gr_offset += sizeof(uintptr_t); } - + s390_lgr (code, s390_r0, STK_BASE); s390_aghi (code, STK_BASE, -framesize); mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, framesize + S390_CFA_OFFSET); @@ -182,20 +182,20 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo s390_stmg (code, s390_r0, s390_r14, STK_BASE, gr_offset); s390_stg (code, s390_r1, 0, STK_BASE, sp_offset); s390_stg (code, s390_r14, 0, STK_BASE, ip_offset); - + fp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs); for (i = s390_f0; i < s390_f15; ++i) { s390_std (code, i, 0, STK_BASE, fp_offset); fp_offset += sizeof(double); } - /* + /* * Call the single step/breakpoint function in sdb using * the context address as the parameter */ s390_la (code, s390_r2, 0, STK_BASE, ctx_offset); - if (single_step) + if (single_step) ep = (mono_component_debugger ())->single_step_from_context; else ep = (mono_component_debugger ())->breakpoint_from_context; @@ -205,12 +205,12 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo /* * Restore volatiles - */ + */ s390_lmg (code, s390_r0, s390_r5, STK_BASE, gr_offset); /* * Restore FP registers - */ + */ fp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs); for (i = s390_f0; i < s390_f15; ++i) { s390_ld (code, i, 0, STK_BASE, fp_offset); @@ -219,12 +219,12 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo /* * Load the IP from the context to pick up any SET_IP command results - */ + */ s390_lg (code, s390_r14, 0, STK_BASE, ip_offset); /* * Restore everything else from the on-entry values - */ + */ s390_aghi (code, STK_BASE, framesize); mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, S390_CFA_OFFSET); mono_add_unwind_op_same_value (unwind_ops, code, buf, STK_BASE); @@ -349,10 +349,10 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Now we'll create in 'buf' the S/390 trampoline code. This is the trampoline code common to all methods */ - + code = buf = (guint8 *) mono_global_codeman_reserve(512); - - if (tramp_type == MONO_TRAMPOLINE_JUMP) + + if (tramp_type == MONO_TRAMPOLINE_JUMP) has_caller = 0; else has_caller = 1; @@ -361,7 +361,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf STEP 0: First create a non-standard function prologue with a stack size big enough to save our registers. -----------------------------------------------------------*/ - + mono_add_unwind_op_def_cfa (unwind_ops, buf, code, STK_BASE, S390_CFA_OFFSET); s390_stmg (buf, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); offset = S390_REG_SAVE_OFFSET - S390_CFA_OFFSET; @@ -369,7 +369,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf mono_add_unwind_op_offset (unwind_ops, buf, code, i, offset); offset += sizeof(uintptr_t); } - + s390_lgr (buf, s390_r11, s390_r15); s390_aghi (buf, STK_BASE, -sizeof(trampStack_t)); mono_add_unwind_op_def_cfa_offset (unwind_ops, buf, code, sizeof(trampStack_t) + S390_CFA_OFFSET); @@ -379,13 +379,13 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* we build the MonoLMF structure on the stack - see mini-s390.h */ /* Keep in sync with the code in mono_arch_emit_prolog */ /*---------------------------------------------------------------*/ - + s390_lgr (buf, LMFReg, STK_BASE); s390_aghi (buf, LMFReg, G_STRUCT_OFFSET(trampStack_t, LMF)); - - /*---------------------------------------------------------------*/ - /* Save general and floating point registers in LMF */ - /*---------------------------------------------------------------*/ + + /*---------------------------------------------------------------*/ + /* Save general and floating point registers in LMF */ + /*---------------------------------------------------------------*/ s390_stmg (buf, s390_r0, s390_r1, LMFReg, G_STRUCT_OFFSET(MonoLMF, gregs[0])); s390_stmg (buf, s390_r2, s390_r5, LMFReg, G_STRUCT_OFFSET(MonoLMF, gregs[2])); s390_mvc (buf, 10*sizeof(gulong), LMFReg, G_STRUCT_OFFSET(MonoLMF, gregs[6]), @@ -403,63 +403,63 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf 's390_magic_trampoline' and before the call to the native method. ----------------------------------------------------------*/ - + S390_SET (buf, s390_r1, mono_get_lmf_addr); s390_basr (buf, s390_r14, s390_r1); - - /*---------------------------------------------------------------*/ - /* Set lmf.lmf_addr = jit_tls->lmf */ - /*---------------------------------------------------------------*/ - s390_stg (buf, s390_r2, 0, LMFReg, - G_STRUCT_OFFSET(MonoLMF, lmf_addr)); - - /*---------------------------------------------------------------*/ - /* Get current lmf */ - /*---------------------------------------------------------------*/ - s390_lg (buf, s390_r0, 0, s390_r2, 0); - - /*---------------------------------------------------------------*/ - /* Set our lmf as the current lmf */ - /*---------------------------------------------------------------*/ - s390_stg (buf, LMFReg, 0, s390_r2, 0); - - /*---------------------------------------------------------------*/ - /* Have our lmf.previous_lmf point to the last lmf */ - /*---------------------------------------------------------------*/ - s390_stg (buf, s390_r0, 0, LMFReg, - G_STRUCT_OFFSET(MonoLMF, previous_lmf)); - - /*---------------------------------------------------------------*/ - /* save method info */ - /*---------------------------------------------------------------*/ + + /*---------------------------------------------------------------*/ + /* Set lmf.lmf_addr = jit_tls->lmf */ + /*---------------------------------------------------------------*/ + s390_stg (buf, s390_r2, 0, LMFReg, + G_STRUCT_OFFSET(MonoLMF, lmf_addr)); + + /*---------------------------------------------------------------*/ + /* Get current lmf */ + /*---------------------------------------------------------------*/ + s390_lg (buf, s390_r0, 0, s390_r2, 0); + + /*---------------------------------------------------------------*/ + /* Set our lmf as the current lmf */ + /*---------------------------------------------------------------*/ + s390_stg (buf, LMFReg, 0, s390_r2, 0); + + /*---------------------------------------------------------------*/ + /* Have our lmf.previous_lmf point to the last lmf */ + /*---------------------------------------------------------------*/ + s390_stg (buf, s390_r0, 0, LMFReg, + G_STRUCT_OFFSET(MonoLMF, previous_lmf)); + + /*---------------------------------------------------------------*/ + /* save method info */ + /*---------------------------------------------------------------*/ s390_lg (buf, s390_r1, 0, LMFReg, G_STRUCT_OFFSET(MonoLMF, gregs[0])); - s390_stg (buf, s390_r1, 0, LMFReg, G_STRUCT_OFFSET(MonoLMF, method)); - - /*---------------------------------------------------------------*/ - /* save the current SP */ - /*---------------------------------------------------------------*/ + s390_stg (buf, s390_r1, 0, LMFReg, G_STRUCT_OFFSET(MonoLMF, method)); + + /*---------------------------------------------------------------*/ + /* save the current SP */ + /*---------------------------------------------------------------*/ s390_lg (buf, s390_r1, 0, STK_BASE, 0); - s390_stg (buf, s390_r1, 0, LMFReg, G_STRUCT_OFFSET(MonoLMF, ebp)); - - /*---------------------------------------------------------------*/ - /* save the current IP */ - /*---------------------------------------------------------------*/ + s390_stg (buf, s390_r1, 0, LMFReg, G_STRUCT_OFFSET(MonoLMF, ebp)); + + /*---------------------------------------------------------------*/ + /* save the current IP */ + /*---------------------------------------------------------------*/ if (has_caller) { s390_lg (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET); } else { s390_lghi (buf, s390_r1, 0); } - s390_stg (buf, s390_r1, 0, LMFReg, G_STRUCT_OFFSET(MonoLMF, eip)); - + s390_stg (buf, s390_r1, 0, LMFReg, G_STRUCT_OFFSET(MonoLMF, eip)); + /*---------------------------------------------------------------*/ /* STEP 2: call the C trampoline function */ /*---------------------------------------------------------------*/ - + /* Set arguments */ /* Arg 1: host_mgreg_t *regs */ s390_la (buf, s390_r2, 0, LMFReg, G_STRUCT_OFFSET(MonoLMF, gregs[0])); - + /* Arg 2: code (next address to the instruction that called us) */ if (has_caller) { s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET); @@ -472,12 +472,12 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Arg 4: trampoline address. */ S390_SET (buf, s390_r5, buf); - + /* Calculate call address and call the C trampoline. Return value will be in r2 */ tramp = (guint8*)mono_get_trampoline_func (tramp_type); S390_SET (buf, s390_r1, tramp); s390_basr (buf, s390_r14, s390_r1); - + /* OK, code address is now on r2. Save it, so that we can restore r2 and use it later */ s390_stg (buf, s390_r2, 0, STK_BASE, G_STRUCT_OFFSET(trampStack_t, saveFn)); @@ -486,7 +486,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf STEP 3: Restore the LMF ----------------------------------------------------------*/ restoreLMF(buf, STK_BASE, sizeof(trampStack_t)); - + /* Check for thread interruption */ S390_SET (buf, s390_r1, (guint8 *)mono_thread_force_interruption_checkpoint_noraise); s390_basr (buf, s390_r14, s390_r1); @@ -496,11 +496,11 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* * Exception case: * We have an exception we want to throw in the caller's frame, so pop - * the trampoline frame and throw from the caller. + * the trampoline frame and throw from the caller. */ S390_SET (buf, s390_r1, (guint *)mono_get_rethrow_preserve_exception_addr ()); s390_aghi (buf, STK_BASE, sizeof(trampStack_t)); - s390_lg (buf, s390_r1, 0, s390_r1, 0); + s390_lg (buf, s390_r1, 0, s390_r1, 0); s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); s390_br (buf, s390_r1); PTRSLOT (buf, o[0]); @@ -511,10 +511,10 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /*---------------------------------------------------------- STEP 4: call the compiled method ----------------------------------------------------------*/ - + /* Restore parameter registers */ s390_lmg (buf, s390_r2, s390_r5, LMFReg, G_STRUCT_OFFSET(MonoLMF, gregs[2])); - + /* Restore the FP registers */ offset = G_STRUCT_OFFSET(MonoLMF, fregs[0]); for (i = s390_f0; i <= s390_f15; ++i) { @@ -523,7 +523,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf } /* Restore stack pointer and jump to the code - - * R14 contains the return address to our caller + * R14 contains the return address to our caller */ s390_lgr (buf, STK_BASE, s390_r11); mono_add_unwind_op_def_cfa_offset (unwind_ops, buf, code, S390_CFA_OFFSET); @@ -542,7 +542,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (code, buf - code); MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); - + g_assert (info); tramp_name = mono_get_generic_trampoline_name (tramp_type); *info = mono_tramp_info_create (tramp_name, code, buf - code, ji, unwind_ops); @@ -628,9 +628,9 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty if (code_len) *code_len = buf - code; - + return code; -} +} /*========================= End of Function ========================*/ @@ -654,8 +654,8 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info guint8 **rgctx_null_jumps; gint64 displace; int tramp_size, - depth, - index, + depth, + index, iPatch = 0, i; gboolean mrgctx; @@ -757,7 +757,7 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info g_free (name); return(buf); -} +} /*========================= End of Function ========================*/ @@ -799,6 +799,6 @@ mono_arch_get_static_rgctx_trampoline (MonoMemoryManager *mem_manager, gpointer mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), mem_manager); return(start); -} +} /*========================= End of Function ========================*/ diff --git a/src/mono/mono/mini/tramp-sparc.c b/src/mono/mono/mini/tramp-sparc.c index 47b8010ce7d15..230198cb5b0b0 100644 --- a/src/mono/mono/mini/tramp-sparc.c +++ b/src/mono/mono/mini/tramp-sparc.c @@ -104,7 +104,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Save r1 needed by the IMT code */ sparc_sti_imm (code, sparc_g1, sparc_sp, regs_offset + (sparc_g1 * sizeof (target_mgreg_t))); - /* + /* * sparc_g5 contains the return address, the trampoline argument is stored in the * instruction stream after the call. */ @@ -114,7 +114,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Save fp regs since they are not preserved by calls */ for (i = 0; i < 16; i ++) sparc_stdf_imm (code, sparc_f0 + (i * 2), sparc_sp, MONO_SPARC_STACK_BIAS + 320 + (i * 8)); -#endif +#endif /* We receive the method address in %r1, so save it here */ sparc_sti_imm (code, method_reg, sparc_sp, MONO_SPARC_STACK_BIAS + 200); @@ -186,7 +186,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Reload fp regs */ for (i = 0; i < 16; i ++) sparc_lddf_imm (code, sparc_sp, MONO_SPARC_STACK_BIAS + 320 + (i * 8), sparc_f0 + (i * 2)); -#endif +#endif sparc_jmpl (code, sparc_o0, sparc_g0, sparc_g0); @@ -253,7 +253,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type))); return buf; -} +} gpointer mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot) diff --git a/src/mono/mono/mini/tramp-x86-gsharedvt.c b/src/mono/mono/mini/tramp-x86-gsharedvt.c index 83f55eb11586c..58eb280388ae1 100644 --- a/src/mono/mono/mini/tramp-x86-gsharedvt.c +++ b/src/mono/mono/mini/tramp-x86-gsharedvt.c @@ -177,7 +177,7 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) x86_mov_reg_membase (code, X86_ECX, X86_EBP, info_offset, 4); /* Branch to the in/out handling code */ - x86_alu_membase_imm (code, X86_CMP, X86_ECX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in), 1); + x86_alu_membase_imm (code, X86_CMP, X86_ECX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in), 1); br_out = code; x86_branch32 (code, X86_CC_NE, 0, TRUE); diff --git a/src/mono/mono/mini/tramp-x86.c b/src/mono/mono/mini/tramp-x86.c index 582628105b1d5..b109c4f09bbf1 100644 --- a/src/mono/mono/mini/tramp-x86.c +++ b/src/mono/mono/mini/tramp-x86.c @@ -397,7 +397,7 @@ gpointer mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoMemoryManager *mem_manager, guint32 *code_len) { guint8 *code, *buf, *tramp; - + tramp = mono_get_trampoline_code (tramp_type); const int size = TRAMPOLINE_SIZE; @@ -538,7 +538,7 @@ mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboo code = buf = mono_global_codeman_reserve (tramp_size); // FIXME: Currently, we always go to the slow path. - + /* Load trampoline addr */ x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_RGCTX_REG, 4, 4); /* Load mrgctx/vtable */ diff --git a/src/mono/mono/mini/type-checking.c b/src/mono/mono/mini/type-checking.c index b623c603741af..1d279e86b8d22 100644 --- a/src/mono/mono/mini/type-checking.c +++ b/src/mono/mono/mini/type-checking.c @@ -169,7 +169,7 @@ mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_r #endif } -/* +/* * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass * stored in "klass_reg" implements the interface "klass". */ @@ -179,7 +179,7 @@ mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, m_class_offsetof_interface_bitmap (), klass); } -/* +/* * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable * stored in "vtable_reg" implements the interface "klass". */ @@ -189,7 +189,7 @@ mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtab mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass); } -/* +/* * Emit code which checks whenever the interface id of @klass is smaller than * than the value given by max_iid_reg. */ @@ -216,7 +216,7 @@ mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *kla MonoBasicBlock *false_target) { int max_iid_reg = alloc_preg (cfg); - + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id)); mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target); } @@ -263,7 +263,7 @@ mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBa if (true_target) MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target); else - MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException"); + MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException"); } /* @@ -286,7 +286,7 @@ mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, M static void mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null); - + static void mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null) { @@ -564,7 +564,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb); } else if (m_class_get_cast_class (klass) == m_class_get_parent (mono_defaults.enum_class)) { mini_emit_class_check_branch (cfg, eclass_reg, m_class_get_parent (mono_defaults.enum_class), OP_PBEQ, is_null_bb); - mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb); + mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb); } else if (m_class_get_cast_class (klass) == mono_defaults.enum_class) { mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb); @@ -665,7 +665,7 @@ mono_decompose_typechecks (MonoCompile *cfg) } if ((cfg->verbose_level > 2) && found_typetest) mono_print_code (cfg, "AFTER DECOMPOSE TYPE_CHECKS"); - + } diff --git a/src/mono/mono/mini/unwind.c b/src/mono/mono/mini/unwind.c index bdcfe78604b7c..5b78f6ea25a54 100644 --- a/src/mono/mono/mini/unwind.c +++ b/src/mono/mono/mini/unwind.c @@ -97,7 +97,7 @@ static int map_hw_reg_to_dwarf_reg [ppc_lr + 1] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, * 0-15 = GR0-15 * 16-31 = FP0-15 (f0, f2, f4, f6, f1, f3, f5, f7, f8, f10, f12, f14, f9, f11, f13, f15) */ -static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, +static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 17, 21, 18, 22, 19, 23, 24, 28, 25, 29, 26, 30, 27, 31}; @@ -449,7 +449,7 @@ mono_unwind_ops_encode_full (GSList *unwind_ops, guint32 *out_len, gboolean enab *p ++ = DW_CFA_advance_loc | (30); loc += 30; } - } + } switch (op->op) { case DW_CFA_def_cfa: @@ -502,7 +502,7 @@ mono_unwind_ops_encode_full (GSList *unwind_ops, guint32 *out_len, gboolean enab break; } } - + g_assert (p - buf < 4096); *out_len = p - buf; res = (guint8 *)g_malloc (p - buf); @@ -540,8 +540,8 @@ typedef struct { } UnwindState; /* - * Given the state of the current frame as stored in REGS, execute the unwind - * operations in unwind_info until the location counter reaches POS. The result is + * Given the state of the current frame as stored in REGS, execute the unwind + * operations in unwind_info until the location counter reaches POS. The result is * stored back into REGS. OUT_CFA will receive the value of the CFA. * If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN. * On return, the nth entry will point to the address of the stack slot where register @@ -552,7 +552,7 @@ typedef struct { * It returns FALSE on failure */ gboolean -mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, +mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations, mono_unwind_reg_t *regs, int nregs, host_mgreg_t **save_locations, int save_locations_len, @@ -1037,7 +1037,7 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi guint8 *buf; gboolean has_fde_augmentation = FALSE; - /* + /* * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html */ @@ -1105,7 +1105,7 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi break; } } - + p = cie_aug; p += cie_aug_len; } diff --git a/src/mono/mono/sgen/sgen-alloc.c b/src/mono/mono/sgen/sgen-alloc.c index 3e7959b85c563..6638a943341a6 100644 --- a/src/mono/mono/sgen/sgen-alloc.c +++ b/src/mono/mono/sgen/sgen-alloc.c @@ -52,7 +52,7 @@ static guint64 stat_bytes_alloced_los = 0; * This is not constantly syncrhonized, but only updated on each GC. */ static guint64 bytes_allocated_attached = 0; -/* Total bytes allocated so far in program execution by detached threads */ +/* Total bytes allocated so far in program execution by detached threads */ static guint64 bytes_allocated_detached = 0; /* @@ -532,7 +532,7 @@ sgen_clear_tlabs (void) } FOREACH_THREAD_END sgen_set_bytes_allocated_attached (total_bytes_allocated_globally); -} +} void sgen_update_allocation_count (void) { @@ -553,7 +553,7 @@ sgen_set_bytes_allocated_attached (guint64 bytes) } void -sgen_increment_bytes_allocated_detached (guint64 bytes) +sgen_increment_bytes_allocated_detached (guint64 bytes) { bytes_allocated_detached += bytes; } @@ -561,16 +561,16 @@ sgen_increment_bytes_allocated_detached (guint64 bytes) guint64 sgen_get_total_allocated_bytes (MonoBoolean precise) { - if (precise) { + if (precise) { LOCK_GC; sgen_stop_world (0, FALSE); sgen_update_allocation_count (); - + sgen_restart_world (0, FALSE); UNLOCK_GC; } - + return bytes_allocated_attached + bytes_allocated_detached; } diff --git a/src/mono/mono/sgen/sgen-cardtable.c b/src/mono/mono/sgen/sgen-cardtable.c index 31a25f47fd8fd..a79924fa8eeca 100644 --- a/src/mono/mono/sgen/sgen-cardtable.c +++ b/src/mono/mono/sgen/sgen-cardtable.c @@ -95,7 +95,7 @@ sgen_card_table_wbarrier_arrayref_copy (gpointer dest_ptr, gconstpointer src_ptr sgen_card_table_mark_address ((mword)dest); sgen_dummy_use (value); } - } + } } static void @@ -130,7 +130,7 @@ sgen_card_table_wbarrier_object_copy (GCObject* obj, GCObject *src) static void sgen_card_table_wbarrier_generic_nostore (gpointer ptr) { - sgen_card_table_mark_address ((mword)ptr); + sgen_card_table_mark_address ((mword)ptr); } static void diff --git a/src/mono/mono/sgen/sgen-conf.h b/src/mono/mono/sgen/sgen-conf.h index fc6ee088dbf5e..9962dffb34c93 100644 --- a/src/mono/mono/sgen/sgen-conf.h +++ b/src/mono/mono/sgen/sgen-conf.h @@ -175,7 +175,7 @@ typedef target_mword SgenDescriptor; * * Increasing this value speeds up allocation but will cause more frequent nursery collections as less space will be used. * Descreasing this value will cause allocation to be slower since we'll have to cycle thru more fragments. - * 512 annedoctally keeps wastage under control and doesn't impact allocation performance too much. + * 512 annedoctally keeps wastage under control and doesn't impact allocation performance too much. */ #define SGEN_MAX_NURSERY_WASTE 512 diff --git a/src/mono/mono/sgen/sgen-descriptor.c b/src/mono/mono/sgen/sgen-descriptor.c index df72b4e692ed2..195b13349bf52 100644 --- a/src/mono/mono/sgen/sgen-descriptor.c +++ b/src/mono/mono/sgen/sgen-descriptor.c @@ -213,7 +213,7 @@ mono_gc_get_bitmap_for_descr (SgenDescriptor descr, int *numbits) gsize *bitmap; switch (d & DESC_TYPE_MASK) { - case DESC_TYPE_RUN_LENGTH: { + case DESC_TYPE_RUN_LENGTH: { int first_set = (d >> 16) & 0xff; int num_set = (d >> 24) & 0xff; int i; @@ -295,7 +295,7 @@ mono_gc_make_root_descr_all_refs (int numbits) gc_bitmap = (gsize *)g_malloc0 (ALIGN_TO (ALIGN_TO (numbits, 8) + 1, sizeof (gsize))); memset (gc_bitmap, 0xff, num_bytes); - if (numbits < ((sizeof (*gc_bitmap) * 8) - ROOT_DESC_TYPE_SHIFT)) + if (numbits < ((sizeof (*gc_bitmap) * 8) - ROOT_DESC_TYPE_SHIFT)) gc_bitmap[0] = GUINT64_TO_LE(gc_bitmap[0]); else if (numbits && num_bytes % (sizeof (*gc_bitmap))) gc_bitmap[num_bytes / 8] = GUINT64_TO_LE(gc_bitmap [num_bytes / 8]); diff --git a/src/mono/mono/sgen/sgen-descriptor.h b/src/mono/mono/sgen/sgen-descriptor.h index f10ebf6a5104a..faa9abb8a1dd1 100644 --- a/src/mono/mono/sgen/sgen-descriptor.h +++ b/src/mono/mono/sgen/sgen-descriptor.h @@ -113,7 +113,7 @@ enum { enum { ROOT_DESC_CONSERVATIVE, /* 0, so matches NULL value */ ROOT_DESC_BITMAP, - ROOT_DESC_RUN_LEN, + ROOT_DESC_RUN_LEN, ROOT_DESC_COMPLEX, ROOT_DESC_VECTOR, ROOT_DESC_USER, diff --git a/src/mono/mono/sgen/sgen-fin-weak-hash.c b/src/mono/mono/sgen/sgen-fin-weak-hash.c index 055963affe70d..e1a85926950c1 100644 --- a/src/mono/mono/sgen/sgen-fin-weak-hash.c +++ b/src/mono/mono/sgen/sgen-fin-weak-hash.c @@ -34,7 +34,7 @@ typedef SgenGrayQueue GrayQueue; static int no_finalize = 0; /* - * The finalizable hash has the object as the key, the + * The finalizable hash has the object as the key, the * disappearing_link hash, has the link address as key. * * Copyright 2011 Xamarin Inc. @@ -136,7 +136,7 @@ sgen_collect_bridge_objects (int generation, ScanCopyContext ctx) copy_func (©, queue); sgen_client_bridge_register_finalized_object (copy); - + if (hash_table == &minor_finalizable_hash && !ptr_in_nursery (copy)) { /* remove from the list */ SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE); @@ -623,7 +623,7 @@ sgen_remove_finalizers_if (SgenObjectPredicateFunc predicate, void *user_data, i SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE); continue; } - } SGEN_HASH_TABLE_FOREACH_END; + } SGEN_HASH_TABLE_FOREACH_END; } void diff --git a/src/mono/mono/sgen/sgen-gc.c b/src/mono/mono/sgen/sgen-gc.c index b91cef311aeb1..8ae0ded31a080 100644 --- a/src/mono/mono/sgen/sgen-gc.c +++ b/src/mono/mono/sgen/sgen-gc.c @@ -397,7 +397,7 @@ static SgenPointerQueue fin_ready_queue = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_ static SgenPointerQueue critical_fin_queue = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_FINALIZE_READY); /* registered roots: the key to the hash is the root start address */ -/* +/* * Different kinds of roots are kept separate to speed up pin_from_roots () for example. */ SgenHashTable sgen_roots_hash [ROOT_TYPE_NUM] = { @@ -408,7 +408,7 @@ SgenHashTable sgen_roots_hash [ROOT_TYPE_NUM] = { static mword roots_size = 0; /* amount of memory in the root set */ /* The size of a TLAB */ -/* The bigger the value, the less often we have to go to the slow path to allocate a new +/* The bigger the value, the less often we have to go to the slow path to allocate a new * one, but the more space is wasted by threads not allocating much memory. * FIXME: Tune this. * FIXME: Make this self-tuning for each thread. @@ -829,7 +829,7 @@ sgen_sort_addresses (void **array, size_t size) } } -/* +/* * Scan the memory between start and end and queue values which could be pointers * to the area between start_nursery and end_nursery for later consideration. * Typically used for thread stacks. @@ -1134,7 +1134,7 @@ finish_gray_stack (int generation, ScanCopyContext ctx) * We need to walk the LO list as well in search of marked big objects * (use a flag since this is needed only on major collections). We need to loop * here as well, so keep a counter of marked LO (increasing it in copy_object). - * To achieve better cache locality and cache usage, we drain the gray stack + * To achieve better cache locality and cache usage, we drain the gray stack * frequently, after each object is copied, and just finish the work here. */ sgen_drain_gray_stack (ctx); @@ -1231,7 +1231,7 @@ finish_gray_stack (int generation, ScanCopyContext ctx) sgen_client_clear_unreachable_ephemerons (ctx); /* - * We clear togglerefs only after all possible chances of revival are done. + * We clear togglerefs only after all possible chances of revival are done. * This is semantically more inline with what users expect and it allows for * user finalizers to correctly interact with TR objects. */ @@ -2606,7 +2606,7 @@ sgen_ensure_free_space (size_t size, int generation) generation_to_collect = GENERATION_OLD; } else { generation_to_collect = GENERATION_NURSERY; - reason = "Nursery full"; + reason = "Nursery full"; } } @@ -2643,7 +2643,7 @@ sgen_perform_collection_inner (size_t requested_size, int generation_to_collect, sgen_stop_world (generation_to_collect, forced_serial || !sgen_major_collector.is_concurrent); else SGEN_ASSERT (0, sgen_is_world_stopped (), "We can only collect if the world is stopped"); - + TV_GETTIME (gc_total_start); diff --git a/src/mono/mono/sgen/sgen-gc.h b/src/mono/mono/sgen/sgen-gc.h index b5b91c9a2eec7..ef7569f4fe980 100644 --- a/src/mono/mono/sgen/sgen-gc.h +++ b/src/mono/mono/sgen/sgen-gc.h @@ -293,7 +293,7 @@ sgen_get_nursery_end (void) #define SGEN_LOAD_VTABLE(obj) ((GCVTable)(SGEN_POINTER_UNTAG_ALL (SGEN_LOAD_VTABLE_UNCHECKED ((GCObject *)(obj))))) /* -List of what each bit on of the vtable gc bits means. +List of what each bit on of the vtable gc bits means. */ enum { // When the Java bridge has determined an object is "bridged", it uses these two bits to cache that information. @@ -1038,7 +1038,7 @@ sgen_major_is_object_alive (GCObject *object) /* - * If the object has been forwarded it means it's still referenced from a root. + * If the object has been forwarded it means it's still referenced from a root. * If it is pinned it's still alive as well. * A LOS object is only alive if we have pinned it. * Return TRUE if @obj is ready to be finalized. @@ -1190,7 +1190,7 @@ gint64 sgen_timestamp (void); * - CANARY_SIZE must be multiple of word size in bytes * - Canary space is not included on checks against SGEN_MAX_SMALL_OBJ_SIZE */ - + gboolean sgen_nursery_canaries_enabled (void); #define CANARY_SIZE 8 diff --git a/src/mono/mono/sgen/sgen-gray.h b/src/mono/mono/sgen/sgen-gray.h index 7da84ba07359a..19e9b90f3bf4b 100644 --- a/src/mono/mono/sgen/sgen-gray.h +++ b/src/mono/mono/sgen/sgen-gray.h @@ -16,24 +16,24 @@ * This gray queue has to be as optimized as possible, because it is in the core of * the mark/copy phase of the garbage collector. The memory access has then to be as * cache friendly as possible. That's why we use a cursor based implementation. - * + * * This simply consist in maintaining a pointer to the current element in the * queue. In addition to using this cursor, we use a simple linked list of arrays, * called sections, so that we have the cache friendliness of arrays without having * the cost of memory reallocation of a dynaic array, not the cost of memory * indirection of a linked list. - * + * * This implementation also allows the dequeuing of a whole section at a time. This is - * for example used in the parallel GC because it would be too costly to take one element + * for example used in the parallel GC because it would be too costly to take one element * at a time. This imply the main constraint that, because we don't carry the cursor - * with the section, we still have to store the index of the last element. This is done + * with the section, we still have to store the index of the last element. This is done * through the 'size' field on the section, which default value is it's maximum value * SGEN_GRAY_QUEUE_SECTION_SIZE. This field is updated in multiple cases : * - section allocation : default value * - object push : default value if we fill the current queue first * - section dequeue : position of the cursor in the dequeued section * - section enqueue : position of the cursor in the previously first section in the queue - * + * * The previous implementation was an index based access where we would store the index * of the last element in the section. This was less efficient because we would have * to make 1 memory access for the index value, 1 for the base address of the objects diff --git a/src/mono/mono/sgen/sgen-hash-table.c b/src/mono/mono/sgen/sgen-hash-table.c index e9c921588a4d5..01a45ed3d8154 100644 --- a/src/mono/mono/sgen/sgen-hash-table.c +++ b/src/mono/mono/sgen/sgen-hash-table.c @@ -8,10 +8,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/src/mono/mono/sgen/sgen-marksweep-drain-gray-stack.h b/src/mono/mono/sgen/sgen-marksweep-drain-gray-stack.h index 889fa6077f141..6bf3dc0a9ae3c 100644 --- a/src/mono/mono/sgen/sgen-marksweep-drain-gray-stack.h +++ b/src/mono/mono/sgen/sgen-marksweep-drain-gray-stack.h @@ -285,7 +285,7 @@ SCAN_OBJECT_FUNCTION_NAME (GCObject *full_object, SgenDescriptor desc, SgenGrayQ #include "sgen-scan-object.h" } -#ifdef SCAN_VTYPE_FUNCTION_NAME +#ifdef SCAN_VTYPE_FUNCTION_NAME static void SCAN_VTYPE_FUNCTION_NAME (GCObject *full_object, char *start, SgenDescriptor desc, SgenGrayQueue *queue BINARY_PROTOCOL_ARG (size_t size)) { diff --git a/src/mono/mono/sgen/sgen-marksweep.c b/src/mono/mono/sgen/sgen-marksweep.c index f767431c1699e..24eaf1fd9ad9b 100644 --- a/src/mono/mono/sgen/sgen-marksweep.c +++ b/src/mono/mono/sgen/sgen-marksweep.c @@ -712,7 +712,7 @@ alloc_obj (GCVTable vtable, size_t size, gboolean pinned, gboolean has_reference /* FIXME: assumes object layout */ *(GCVTable*)obj = vtable; - sgen_total_allocated_major += block_obj_sizes [size_index]; + sgen_total_allocated_major += block_obj_sizes [size_index]; return (GCObject *)obj; } @@ -767,7 +767,7 @@ major_alloc_object_par (GCVTable vtable, size_t size, gboolean has_references) *(GCVTable*)obj = vtable; /* FIXME is it worth CAS-ing here */ - sgen_total_allocated_major += block_obj_sizes [size_index]; + sgen_total_allocated_major += block_obj_sizes [size_index]; return (GCObject *)obj; } diff --git a/src/mono/mono/sgen/sgen-memory-governor.c b/src/mono/mono/sgen/sgen-memory-governor.c index ac801a24a92f0..a2eb08ae7f288 100644 --- a/src/mono/mono/sgen/sgen-memory-governor.c +++ b/src/mono/mono/sgen/sgen-memory-governor.c @@ -165,7 +165,7 @@ sgen_need_major_collection (mword space_needed, gboolean *forced) heap_size = get_heap_size (); if (heap_size <= major_collection_trigger_size) - return FALSE; + return FALSE; /* * The more the heap grows, the more we need to decrease the allowance above, diff --git a/src/mono/mono/sgen/sgen-minor-copy-object.h b/src/mono/mono/sgen/sgen-minor-copy-object.h index 5597ab41bb06c..7e498482f50b8 100644 --- a/src/mono/mono/sgen/sgen-minor-copy-object.h +++ b/src/mono/mono/sgen/sgen-minor-copy-object.h @@ -74,7 +74,7 @@ extern guint64 stat_nursery_copy_object_failed_to_space; /* from sgen-gc.c */ */ static MONO_ALWAYS_INLINE void -SERIAL_COPY_OBJECT (GCObject **obj_slot, SgenGrayQueue *queue) +SERIAL_COPY_OBJECT (GCObject **obj_slot, SgenGrayQueue *queue) { GCObject *forwarded; GCObject *copy; @@ -115,7 +115,7 @@ SERIAL_COPY_OBJECT (GCObject **obj_slot, SgenGrayQueue *queue) if (sgen_nursery_is_to_space (obj)) { SGEN_ASSERT (9, sgen_vtable_get_descriptor (SGEN_LOAD_VTABLE(obj)), "to space object %p has no gc descriptor", obj); SGEN_LOG (9, " (tospace, no change)"); - HEAVY_STAT (++stat_nursery_copy_object_failed_to_space); + HEAVY_STAT (++stat_nursery_copy_object_failed_to_space); return; } #endif @@ -188,7 +188,7 @@ SERIAL_COPY_OBJECT_FROM_OBJ (GCObject **obj_slot, SgenGrayQueue *queue) /* FIXME: all of these could just use `sgen_obj_get_descriptor_safe()` */ SGEN_ASSERT (9, sgen_vtable_get_descriptor (SGEN_LOAD_VTABLE(obj)), "to space object %p has no gc descriptor", obj); SGEN_LOG (9, " (tospace, no change)"); - HEAVY_STAT (++stat_nursery_copy_object_failed_to_space); + HEAVY_STAT (++stat_nursery_copy_object_failed_to_space); /* * FIXME: diff --git a/src/mono/mono/sgen/sgen-nursery-allocator.c b/src/mono/mono/sgen/sgen-nursery-allocator.c index c4ac6b2c67381..731dfcccbd1d4 100644 --- a/src/mono/mono/sgen/sgen-nursery-allocator.c +++ b/src/mono/mono/sgen/sgen-nursery-allocator.c @@ -4,7 +4,7 @@ * * Copyright 2009-2010 Novell, Inc. * 2011 Rodrigo Kumpera - * + * * Copyright 2011 Xamarin Inc (http://www.xamarin.com) * Copyright (C) 2012 Xamarin Inc * @@ -23,7 +23,7 @@ * We should start assigning threads very small fragments: if there are many * threads the nursery will be full of reserved space that the threads may not * use at all, slowing down allocation speed. - * Thread local allocation is done from areas of memory Hotspot calls Thread Local + * Thread local allocation is done from areas of memory Hotspot calls Thread Local * Allocation Buffers (TLABs). */ #include "config.h" @@ -360,7 +360,7 @@ par_alloc_from_fragment (SgenFragmentAllocator *allocator, SgenFragment *frag, s if (frag->fragment_end - end < SGEN_MAX_NURSERY_WASTE) { SgenFragment *next, **prev_ptr; - + /* * Before we clean the remaining nursery, we must claim the remaining space * as it could end up been used by the range allocator since it can end up @@ -422,7 +422,7 @@ serial_alloc_from_fragment (SgenFragment **previous, SgenFragment *frag, size_t if (frag->fragment_end - end < SGEN_MAX_NURSERY_WASTE) { *previous = frag->next; - + /* Clear the remaining space, pinning depends on this. FIXME move this to use phony arrays */ memset (end, 0, frag->fragment_end - end); @@ -598,7 +598,7 @@ sgen_clear_allocator_fragments (SgenFragmentAllocator *allocator) #ifdef NALLOC_DEBUG add_alloc_record (frag->fragment_next, frag->fragment_end - frag->fragment_next, CLEAR_NURSERY_FRAGS); #endif - } + } } /* Clear all remaining nursery fragments */ diff --git a/src/mono/mono/sgen/sgen-pinning-stats.c b/src/mono/mono/sgen/sgen-pinning-stats.c index c8f0e0e22c29d..34fea4f836e22 100644 --- a/src/mono/mono/sgen/sgen-pinning-stats.c +++ b/src/mono/mono/sgen/sgen-pinning-stats.c @@ -3,7 +3,7 @@ * Copyright 2001-2003 Ximian, Inc * Copyright 2003-2010 Novell, Inc. * Copyright 2011 Xamarin Inc (http://www.xamarin.com) - * + * * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ diff --git a/src/mono/mono/sgen/sgen-pinning.c b/src/mono/mono/sgen/sgen-pinning.c index 6776c576372e1..9c53416e82498 100644 --- a/src/mono/mono/sgen/sgen-pinning.c +++ b/src/mono/mono/sgen/sgen-pinning.c @@ -89,7 +89,7 @@ sgen_scan_pin_queue_objects (ScanCopyContext ctx) void sgen_pin_stage_ptr (void *ptr) { - /*very simple multiplicative hash function, tons better than simple and'ng */ + /*very simple multiplicative hash function, tons better than simple and'ng */ int hash_idx = ((mword)ptr * 1737350767) & (PIN_HASH_SIZE - 1); if (pin_hash_filter [hash_idx] == ptr) return; diff --git a/src/mono/mono/sgen/sgen-simple-nursery.c b/src/mono/mono/sgen/sgen-simple-nursery.c index 1db3b081f1952..18a771d0abafc 100644 --- a/src/mono/mono/sgen/sgen-simple-nursery.c +++ b/src/mono/mono/sgen/sgen-simple-nursery.c @@ -66,7 +66,7 @@ prepare_to_space (char *to_space_bitmap, size_t space_bitmap_size) static void clear_fragments (void) -{ +{ } static void @@ -154,7 +154,7 @@ sgen_simple_nursery_init (SgenMinorCollector *collector, gboolean parallel) #ifdef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC g_assert (parallel == FALSE); #endif - + collector->is_split = FALSE; collector->is_parallel = parallel; diff --git a/src/mono/mono/sgen/sgen-split-nursery.c b/src/mono/mono/sgen/sgen-split-nursery.c index 4afd1ff8d246c..5c73a1ced752e 100644 --- a/src/mono/mono/sgen/sgen-split-nursery.c +++ b/src/mono/mono/sgen/sgen-split-nursery.c @@ -46,7 +46,7 @@ The Allocator Space takes the botton part of the nursery. The Survivor spaces are intermingled in the top part of the nursery. It's done this way since the required size for the To Space depends on the survivor rate -of objects from the Allocator Space. +of objects from the Allocator Space. During a collection when the object scan function see a nursery object it must determine if the object needs to be evacuated or left in place. Originally, this diff --git a/src/mono/mono/tests/metadata-verifier/gen-md-tests.c b/src/mono/mono/tests/metadata-verifier/gen-md-tests.c index 869ac8b60ea8f..0f1efd15849b5 100644 --- a/src/mono/mono/tests/metadata-verifier/gen-md-tests.c +++ b/src/mono/mono/tests/metadata-verifier/gen-md-tests.c @@ -29,7 +29,7 @@ tokens: comment ::= '#.* - identifier ::= ([a-z] | [A-Z]) ([a-z] | [A-Z] | [0-9] | [_-.])* + identifier ::= ([a-z] | [A-Z]) ([a-z] | [A-Z] | [0-9] | [_-.])* hexa_digit = [0-9] | [a-f] | [A-F] number ::= hexadecimal | decimal hexadecimal ::= (+-)?('0' [xX])? hexa_digit+ @@ -44,7 +44,7 @@ identifier '{' assembly_directive test_entry* '}' assembly_directive: - 'assembly' identifier + 'assembly' identifier test_entry: validity patch (',' patch)* @@ -277,7 +277,7 @@ init_test_set (test_set_t *test_set) printf ("Could not parse image %s\n", test_set->assembly); exit (INVALID_BAD_FILE); } - + test_set->init = 1; } @@ -293,7 +293,7 @@ make_test_name (test_entry_t *entry, test_set_t *test_set) #define READ_BIT(PTR,OFF) ((((guint8*)(PTR))[(OFF / 8)] & (1 << ((OFF) % 8))) != 0) #define SET_BIT(PTR,OFF) do { ((guint8*)(PTR))[(OFF / 8)] |= (1 << ((OFF) % 8)); } while (0) -static guint32 +static guint32 get_pe_header (test_entry_t *entry) { return READ_VAR (guint32, entry->data + 0x3c) + 4; @@ -363,7 +363,7 @@ get_metadata_stream_header (test_entry_t *entry, guint32 idx) } offset = pad4 (offset); } - return offset; + return offset; } static guint32 @@ -374,14 +374,14 @@ lookup_var (test_entry_t *entry, const char *name) if (!strcmp ("pe-signature", name)) return get_pe_header (entry) - 4; if (!strcmp ("pe-header", name)) - return get_pe_header (entry); + return get_pe_header (entry); if (!strcmp ("pe-optional-header", name)) - return get_pe_header (entry) + 20; + return get_pe_header (entry) + 20; if (!strcmp ("section-table", name)) - return get_pe_header (entry) + 244; + return get_pe_header (entry) + 244; if (!strcmp ("cli-header", name)) return get_cli_header (entry); - if (!strcmp ("cli-metadata", name)) + if (!strcmp ("cli-metadata", name)) return get_cli_metadata_root (entry); if (!strcmp ("tables-header", name)) { guint32 metadata_root = get_cli_metadata_root (entry); @@ -597,7 +597,7 @@ process_test_entry (test_set_t *test_set, test_entry_t *entry) fclose (f); g_free (file_name); -} +} /*******************************************************************************************************/ @@ -685,7 +685,7 @@ static char* token_text_dup (scanner_t *scanner, token_t *token) { int len = token->end - token->start; - + char *str = g_memdup (scanner->input + token->start, len + 1); str [len] = 0; return str; @@ -696,7 +696,7 @@ static void dump_token (scanner_t *scanner, token_t *token) { char *str = token_text_dup (scanner, token); - + printf ("token '%s' of type '%s' at line %d\n", str, token_type_name (token->type), token->line); free (str); } @@ -965,13 +965,13 @@ parse_effect (scanner_t *scanner) CONSUME_IDENTIFIER(name); if (!strcmp ("set-byte", name)) - type = EFFECT_SET_BYTE; + type = EFFECT_SET_BYTE; else if (!strcmp ("set-ushort", name)) - type = EFFECT_SET_USHORT; + type = EFFECT_SET_USHORT; else if (!strcmp ("set-uint", name)) - type = EFFECT_SET_UINT; + type = EFFECT_SET_UINT; else if (!strcmp ("set-bit", name)) - type = EFFECT_SET_BIT; + type = EFFECT_SET_BIT; else if (!strcmp ("truncate", name)) type = EFFECT_SET_TRUNC; else if (!strcmp ("or-byte", name)) @@ -980,7 +980,7 @@ parse_effect (scanner_t *scanner) type = EFFECT_OR_USHORT; else if (!strcmp ("or-uint", name)) type = EFFECT_OR_UINT; - else + else FAIL(g_strdup_printf ("Invalid effect kind, expected one of: (set-byte set-ushort set-uint set-bit or-byte or-ushort or-uint truncate) but got %s",name), INVALID_ID_TEXT); effect = g_new0 (patch_effect_t, 1); @@ -1027,7 +1027,7 @@ static void parse_test_entry (scanner_t *scanner, test_set_t *test_set) { test_entry_t entry = { 0 }; - + entry.validity = parse_validity (scanner); do { @@ -1073,7 +1073,7 @@ parse_program (scanner_t *scanner) static void digest_file (const char *file) { - scanner_t *scanner = scanner_new (file); + scanner_t *scanner = scanner_new (file); parse_program (scanner); scanner_free (scanner); } diff --git a/src/mono/mono/utils/atomic.c b/src/mono/mono/utils/atomic.c index eac6be32557ec..215fe6ccce73f 100644 --- a/src/mono/mono/utils/atomic.c +++ b/src/mono/mono/utils/atomic.c @@ -34,20 +34,20 @@ gint32 mono_atomic_cas_i32(volatile gint32 *dest, gint32 exch, { gint32 old; int ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); ret = pthread_mutex_lock(&spin); g_assert (ret == 0); - + old= *dest; if(old==comp) { *dest=exch; } - + ret = pthread_mutex_unlock(&spin); g_assert (ret == 0); - + pthread_cleanup_pop (0); return(old); @@ -58,20 +58,20 @@ gpointer mono_atomic_cas_ptr(volatile gpointer *dest, { gpointer old; int ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); ret = pthread_mutex_lock(&spin); g_assert (ret == 0); - + old= *dest; if(old==comp) { *dest=exch; } - + ret = pthread_mutex_unlock(&spin); g_assert (ret == 0); - + pthread_cleanup_pop (0); return(old); @@ -123,7 +123,7 @@ gint32 mono_atomic_inc_i32(volatile gint32 *dest) { gint32 ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); @@ -131,12 +131,12 @@ gint32 mono_atomic_inc_i32(volatile gint32 *dest) (*dest)++; ret= *dest; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); - + pthread_cleanup_pop (0); - + return(ret); } @@ -165,20 +165,20 @@ gint32 mono_atomic_dec_i32(volatile gint32 *dest) { gint32 ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); - + (*dest)--; ret= *dest; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); - + pthread_cleanup_pop (0); - + return(ret); } @@ -207,7 +207,7 @@ gint32 mono_atomic_xchg_i32(volatile gint32 *dest, gint32 exch) { gint32 ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); @@ -215,12 +215,12 @@ gint32 mono_atomic_xchg_i32(volatile gint32 *dest, gint32 exch) ret=*dest; *dest=exch; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); - + pthread_cleanup_pop (0); - + return(ret); } @@ -249,20 +249,20 @@ gpointer mono_atomic_xchg_ptr(volatile gpointer *dest, gpointer exch) { gpointer ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); - + ret=*dest; *dest=exch; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); - + pthread_cleanup_pop (0); - + return(ret); } @@ -270,7 +270,7 @@ gint32 mono_atomic_fetch_add_i32(volatile gint32 *dest, gint32 add) { gint32 ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); @@ -278,7 +278,7 @@ gint32 mono_atomic_fetch_add_i32(volatile gint32 *dest, gint32 add) ret= *dest; *dest+=add; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); @@ -291,7 +291,7 @@ gint64 mono_atomic_fetch_add_i64(volatile gint64 *dest, gint64 add) { gint64 ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); @@ -299,7 +299,7 @@ gint64 mono_atomic_fetch_add_i64(volatile gint64 *dest, gint64 add) ret= *dest; *dest+=add; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); @@ -312,14 +312,14 @@ gint8 mono_atomic_load_i8(volatile gint8 *src) { gint8 ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); ret= *src; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); @@ -332,14 +332,14 @@ gint16 mono_atomic_load_i16(volatile gint16 *src) { gint16 ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); ret= *src; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); @@ -352,14 +352,14 @@ gint32 mono_atomic_load_i32(volatile gint32 *src) { gint32 ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); ret= *src; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); @@ -372,14 +372,14 @@ gint64 mono_atomic_load_i64(volatile gint64 *src) { gint64 ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); ret= *src; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); @@ -392,14 +392,14 @@ gpointer mono_atomic_load_ptr(volatile gpointer *src) { gpointer ret; int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); ret= *src; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); @@ -411,85 +411,85 @@ gpointer mono_atomic_load_ptr(volatile gpointer *src) void mono_atomic_store_i8(volatile gint8 *dst, gint8 val) { int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); *dst=val; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); - + pthread_cleanup_pop (0); } void mono_atomic_store_i16(volatile gint16 *dst, gint16 val) { int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); *dst=val; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); - + pthread_cleanup_pop (0); } void mono_atomic_store_i32(volatile gint32 *dst, gint32 val) { int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); *dst=val; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); - + pthread_cleanup_pop (0); } void mono_atomic_store_i64(volatile gint64 *dst, gint64 val) { int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); *dst=val; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); - + pthread_cleanup_pop (0); } void mono_atomic_store_ptr(volatile gpointer *dst, gpointer val) { int thr_ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); thr_ret = pthread_mutex_lock(&spin); g_assert (thr_ret == 0); *dst=val; - + thr_ret = pthread_mutex_unlock(&spin); g_assert (thr_ret == 0); - + pthread_cleanup_pop (0); } @@ -578,20 +578,20 @@ mono_atomic_cas_i64(volatile gint64 *dest, gint64 exch, gint64 comp) { gint64 old; int ret; - + pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock, (void *)&spin); ret = pthread_mutex_lock(&spin); g_assert (ret == 0); - + old= *dest; if(old==comp) { *dest=exch; } - + ret = pthread_mutex_unlock(&spin); g_assert (ret == 0); - + pthread_cleanup_pop (0); return(old); diff --git a/src/mono/mono/utils/dlmalloc.c b/src/mono/mono/utils/dlmalloc.c index ed68e4103be5c..48ed19153e748 100644 --- a/src/mono/mono/utils/dlmalloc.c +++ b/src/mono/mono/utils/dlmalloc.c @@ -382,9 +382,9 @@ MALLINFO_FIELD_TYPE default: size_t size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set REALLOC_ZERO_BYTES_FREES default: not defined - This should be set if a call to realloc with zero bytes should - be the same as a call to free. Some people think it should. Otherwise, - since this malloc returns a unique pointer for malloc(0), so does + This should be set if a call to realloc with zero bytes should + be the same as a call to free. Some people think it should. Otherwise, + since this malloc returns a unique pointer for malloc(0), so does realloc(p, 0). LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H @@ -3485,7 +3485,7 @@ static void* sys_alloc(mstate m, size_t nb) { m->seg.sflags = mmap_flag; m->magic = mparams.magic; init_bins(m); - if (is_global(m)) + if (is_global(m)) init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); else { /* Offset top by embedded malloc_state */ @@ -3636,7 +3636,7 @@ static int sys_trim(mstate m, size_t pad) { } /* Unmap any unused mmapped segments */ - if (HAVE_MMAP) + if (HAVE_MMAP) released += release_unused_segments(m); /* On failure, disable autotrim to avoid repeated failed future calls */ @@ -3848,7 +3848,7 @@ static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { while (a < alignment) a <<= 1; alignment = a; } - + if (bytes >= MAX_REQUEST - alignment) { if (m != 0) { /* Test isn't needed but avoids compiler warning */ MALLOC_FAILURE_ACTION; @@ -5103,5 +5103,5 @@ int mspace_mallopt(int param_number, int value) { Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) * Based loosely on libg++-1.2X malloc. (It retains some of the overall structure of old version, but most details differ.) - + */ diff --git a/src/mono/mono/utils/dlmalloc.h b/src/mono/mono/utils/dlmalloc.h index 327cc4c0c14d0..e382b994af1e7 100644 --- a/src/mono/mono/utils/dlmalloc.h +++ b/src/mono/mono/utils/dlmalloc.h @@ -1,14 +1,14 @@ /* Default header file for malloc-2.8.x, written by Doug Lea and released to the public domain, as explained at - http://creativecommons.org/licenses/publicdomain. - + http://creativecommons.org/licenses/publicdomain. + last update: Mon Aug 15 08:55:52 2005 Doug Lea (dl at gee) This header is for ANSI C/C++ only. You can set any of the following #defines before including: - * If USE_DL_PREFIX is defined, it is assumed that malloc.c + * If USE_DL_PREFIX is defined, it is assumed that malloc.c was also compiled with this option, so all routines have names starting with "dl". diff --git a/src/mono/mono/utils/dtrace.h b/src/mono/mono/utils/dtrace.h index 883d1affa6188..c1f1e01121173 100644 --- a/src/mono/mono/utils/dtrace.h +++ b/src/mono/mono/utils/dtrace.h @@ -1,10 +1,10 @@ /* * * \file * DTrace probes - * + * * Authors: * Andreas Faerber - * + * */ #ifndef __UTILS_DTRACE_H__ diff --git a/src/mono/mono/utils/freebsd-elf_common.h b/src/mono/mono/utils/freebsd-elf_common.h index 658119fdbc51f..b3520edda1f98 100644 --- a/src/mono/mono/utils/freebsd-elf_common.h +++ b/src/mono/mono/utils/freebsd-elf_common.h @@ -196,12 +196,12 @@ typedef struct { #define SHT_STRTAB 3 /* string table section */ #define SHT_RELA 4 /* relocation section with addends */ #define SHT_HASH 5 /* symbol hash table section */ -#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_DYNAMIC 6 /* dynamic section */ #define SHT_NOTE 7 /* note section */ #define SHT_NOBITS 8 /* no space section */ #define SHT_REL 9 /* relocation section - no addends */ #define SHT_SHLIB 10 /* reserved - purpose unknown */ -#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ #define SHT_INIT_ARRAY 14 /* Initialization function pointers. */ #define SHT_FINI_ARRAY 15 /* Termination function pointers. */ #define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */ diff --git a/src/mono/mono/utils/gc_wrapper.h b/src/mono/mono/utils/gc_wrapper.h index 00ab7fb6c5501..3881d88ef7141 100644 --- a/src/mono/mono/utils/gc_wrapper.h +++ b/src/mono/mono/utils/gc_wrapper.h @@ -28,10 +28,10 @@ */ #ifndef HOST_WIN32 // FIXME? # if defined(MONO_KEYWORD_THREAD) && !defined(__powerpc__) - + /* The local alloc stuff is in pthread_support.c, but solaris uses solaris_threads.c */ /* It is also disabled on solaris/x86 by libgc/configure.ac */ - /* + /* * ARM has no definition for some atomic functions in gc_locks.h and * support is also disabled in libgc/configure.ac. */ diff --git a/src/mono/mono/utils/lock-free-alloc.h b/src/mono/mono/utils/lock-free-alloc.h index c05610fabc154..cca1d83eb6614 100644 --- a/src/mono/mono/utils/lock-free-alloc.h +++ b/src/mono/mono/utils/lock-free-alloc.h @@ -11,10 +11,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/src/mono/mono/utils/lock-free-queue.c b/src/mono/mono/utils/lock-free-queue.c index b1e1725cbe26b..02ce5b1745a77 100644 --- a/src/mono/mono/utils/lock-free-queue.c +++ b/src/mono/mono/utils/lock-free-queue.c @@ -11,10 +11,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/src/mono/mono/utils/lock-free-queue.h b/src/mono/mono/utils/lock-free-queue.h index abb16d287b896..76a8e98decc2d 100644 --- a/src/mono/mono/utils/lock-free-queue.h +++ b/src/mono/mono/utils/lock-free-queue.h @@ -12,10 +12,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/src/mono/mono/utils/mach-support-arm.c b/src/mono/mono/utils/mach-support-arm.c index 004b03cfd7c93..f877fa7050020 100644 --- a/src/mono/mono/utils/mach-support-arm.c +++ b/src/mono/mono/utils/mach-support-arm.c @@ -80,7 +80,7 @@ mono_mach_arch_get_thread_states (thread_port_t thread, thread_state_t state, ma { #if defined(HOST_WATCHOS) g_error ("thread_get_state() is not supported by this platform"); -#else +#else arm_thread_state_t *arch_state = (arm_thread_state_t *) state; kern_return_t ret; diff --git a/src/mono/mono/utils/mach-support-x86.c b/src/mono/mono/utils/mach-support-x86.c index e28ee66f9e0fe..6dd775d2c0860 100644 --- a/src/mono/mono/utils/mach-support-x86.c +++ b/src/mono/mono/utils/mach-support-x86.c @@ -116,7 +116,7 @@ mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, ma return ret; ret = thread_set_state (thread, x86_FLOAT_STATE32, fpstate, fpcount); return ret; -#endif +#endif } #endif diff --git a/src/mono/mono/utils/memcheck.h b/src/mono/mono/utils/memcheck.h index 2740578f1dc53..960bed5f7abcb 100644 --- a/src/mono/mono/utils/memcheck.h +++ b/src/mono/mono/utils/memcheck.h @@ -22,16 +22,16 @@ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS @@ -53,7 +53,7 @@ the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. - ---------------------------------------------------------------- + ---------------------------------------------------------------- */ @@ -71,12 +71,12 @@ #include "valgrind.h" -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! +/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ typedef - enum { + enum { VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'), VG_USERREQ__MAKE_MEM_UNDEFINED, VG_USERREQ__MAKE_MEM_DEFINED, @@ -100,7 +100,7 @@ typedef VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE, /* This is just for memcheck's internal use - don't use it */ - _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR + _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR = VG_USERREQ_TOOL_BASE('M','C') + 256 } Vg_MemCheckClientRequest; @@ -113,7 +113,7 @@ typedef VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ VG_USERREQ__MAKE_MEM_NOACCESS, \ (_qzz_addr), (_qzz_len), 0, 0, 0) - + /* Similarly, mark memory at _qzz_addr as addressable but undefined for _qzz_len bytes. */ #define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) \ diff --git a/src/mono/mono/utils/memfuncs.c b/src/mono/mono/utils/memfuncs.c index 5ffb16b25912e..4fc78079626ab 100644 --- a/src/mono/mono/utils/memfuncs.c +++ b/src/mono/mono/utils/memfuncs.c @@ -44,7 +44,7 @@ #if defined(TARGET_WIN32) #include -#endif +#endif #include "memfuncs.h" diff --git a/src/mono/mono/utils/mono-codeman.c b/src/mono/mono/utils/mono-codeman.c index c7ff9326ed710..3d1fa4ac82325 100644 --- a/src/mono/mono/utils/mono-codeman.c +++ b/src/mono/mono/utils/mono-codeman.c @@ -36,9 +36,9 @@ static size_t dynamic_code_frees_count; static const MonoCodeManagerCallbacks *code_manager_callbacks; /* - * AMD64 processors maintain icache coherency only for pages which are + * AMD64 processors maintain icache coherency only for pages which are * marked executable. Also, windows DEP requires us to obtain executable memory from - * malloc when using dynamic code managers. The system malloc can't do this so we use a + * malloc when using dynamic code managers. The system malloc can't do this so we use a * slighly modified version of Doug Lea's Malloc package for this purpose: * http://g.oswego.edu/dl/html/malloc.html * @@ -51,7 +51,7 @@ static const MonoCodeManagerCallbacks *code_manager_callbacks; #define MIN_ALIGN MEMORY_ALLOCATION_ALIGNMENT #elif defined(__x86_64__) /* - * We require 16 byte alignment on amd64 so the fp literals embedded in the code are + * We require 16 byte alignment on amd64 so the fp literals embedded in the code are * properly aligned for SSE2. */ #define MIN_ALIGN 16 @@ -157,7 +157,7 @@ codechunk_vfree (void *ptr, guint32 size) mono_vfree (ptr, size, MONO_MEM_ACCOUNT_CODE); } mono_os_mutex_unlock (&valloc_mutex); -} +} static void codechunk_cleanup (void) @@ -303,7 +303,7 @@ mono_code_manager_new_internal (int codeman_type) * * Returns: the new code manager */ -MonoCodeManager* +MonoCodeManager* mono_code_manager_new (void) { return mono_code_manager_new_internal (MONO_CODEMAN_TYPE_JIT); @@ -318,7 +318,7 @@ mono_code_manager_new (void) * * Returns: the new code manager */ -MonoCodeManager* +MonoCodeManager* mono_code_manager_new_dynamic (void) { return mono_code_manager_new_internal (MONO_CODEMAN_TYPE_DYNAMIC); @@ -373,12 +373,12 @@ static void free_chunklist (MonoCodeManager *cman, CodeChunk *chunk) { CodeChunk *dead; - + #if defined(HAVE_VALGRIND_MEMCHECK_H) && defined (VALGRIND_JIT_UNREGISTER_MAP) int valgrind_unregister = 0; if (RUNNING_ON_VALGRIND) valgrind_unregister = 1; -#define valgrind_unregister(x) do { if (valgrind_unregister) { VALGRIND_JIT_UNREGISTER_MAP(NULL,x); } } while (0) +#define valgrind_unregister(x) do { if (valgrind_unregister) { VALGRIND_JIT_UNREGISTER_MAP(NULL,x); } } while (0) #else #define valgrind_unregister(x) #endif @@ -631,8 +631,8 @@ mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment) return ptr; } } - /* - * no room found, move one filled chunk to cman->full + /* + * no room found, move one filled chunk to cman->full * to keep cman->current from growing too much */ prev = NULL; diff --git a/src/mono/mono/utils/mono-conc-hashtable.c b/src/mono/mono/utils/mono-conc-hashtable.c index c7050a2a5a327..0b4bd7bb0a0c8 100644 --- a/src/mono/mono/utils/mono-conc-hashtable.c +++ b/src/mono/mono/utils/mono-conc-hashtable.c @@ -356,7 +356,7 @@ mono_conc_hashtable_insert (MonoConcurrentHashTable *hash_table, gpointer key, g if (kvs [i].key == TOMBSTONE) --hash_table->tombstone_count; else - ++hash_table->element_count; + ++hash_table->element_count; kvs [i].key = key; return NULL; } diff --git a/src/mono/mono/utils/mono-context.h b/src/mono/mono/utils/mono-context.h index bd1a3cd0104c2..57d98ee52b430 100644 --- a/src/mono/mono/utils/mono-context.h +++ b/src/mono/mono/utils/mono-context.h @@ -596,7 +596,7 @@ typedef struct { #ifdef __mono_ppc64__ typedef struct { - gulong sc_ir; // pc + gulong sc_ir; // pc gulong sc_sp; // r1 host_mgreg_t regs [32]; double fregs [32]; @@ -787,9 +787,9 @@ typedef struct MonoContext { gpointer *fp; } MonoContext; -#define MONO_CONTEXT_SET_IP(ctx,eip) do { (ctx)->ip = (gpointer)(eip); } while (0); -#define MONO_CONTEXT_SET_BP(ctx,ebp) do { (ctx)->fp = (gpointer*)(ebp); } while (0); -#define MONO_CONTEXT_SET_SP(ctx,esp) do { (ctx)->sp = (gpointer*)(esp); } while (0); +#define MONO_CONTEXT_SET_IP(ctx,eip) do { (ctx)->ip = (gpointer)(eip); } while (0); +#define MONO_CONTEXT_SET_BP(ctx,ebp) do { (ctx)->fp = (gpointer*)(ebp); } while (0); +#define MONO_CONTEXT_SET_SP(ctx,esp) do { (ctx)->sp = (gpointer*)(esp); } while (0); #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->ip)) #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->fp)) @@ -917,13 +917,13 @@ typedef struct ucontext MonoContext; do { \ (ctx)->uc_mcontext.gregs[14] = (unsigned long)ip; \ (ctx)->uc_mcontext.psw.addr = (unsigned long)ip; \ - } while (0); + } while (0); #define MONO_CONTEXT_SET_SP(ctx,bp) MONO_CONTEXT_SET_BP((ctx),(bp)) #define MONO_CONTEXT_SET_BP(ctx,bp) \ do { \ (ctx)->uc_mcontext.gregs[15] = (unsigned long)bp; \ - } while (0) + } while (0) #define MONO_CONTEXT_GET_IP(ctx) (gpointer) (ctx)->uc_mcontext.psw.addr #define MONO_CONTEXT_GET_SP(ctx) ((gpointer)((ctx)->uc_mcontext.gregs[15])) diff --git a/src/mono/mono/utils/mono-counters.c b/src/mono/mono/utils/mono-counters.c index 5acf772cca9c6..9e93493dec282 100644 --- a/src/mono/mono/utils/mono-counters.c +++ b/src/mono/mono/utils/mono-counters.c @@ -211,7 +211,7 @@ register_internal (const char *name, int type, void *addr, int size) * It may be a function pointer if \c MONO_COUNTER_CALLBACK is specified: * the function should return the value and take no arguments. */ -void +void mono_counters_register (const char* name, int type, void *addr) { int size; @@ -620,7 +620,7 @@ mono_counters_dump_section (int section, int variance, FILE *outfile) * mono_counters_dump: * \param section_mask The sections to dump counters for * \param outfile a FILE to dump the results to; NULL will default to g_print - * Displays the counts of all the enabled counters registered. + * Displays the counts of all the enabled counters registered. * To filter by variance, you can OR one or more variance with the specific section you want. * Use \c MONO_COUNTER_SECTION_MASK to dump all categories of a specific variance. */ @@ -799,7 +799,7 @@ mono_counters_init (void) { } -void +void mono_counters_register (const char* name, int type, void *addr) { } diff --git a/src/mono/mono/utils/mono-counters.h b/src/mono/mono/utils/mono-counters.h index 77175b35f49a8..c5da782c7faac 100644 --- a/src/mono/mono/utils/mono-counters.h +++ b/src/mono/mono/utils/mono-counters.h @@ -57,7 +57,7 @@ typedef struct _MonoCounter MonoCounter; MONO_API void mono_counters_enable (int section_mask); MONO_API void mono_counters_init (void); -/* +/* * register addr as the address of a counter of type type. * It may be a function pointer if MONO_COUNTER_CALLBACK is specified: * the function should return the value and take no arguments. @@ -68,7 +68,7 @@ MONO_API void mono_counters_register_with_size (const char *name, int type, void typedef void (*MonoCounterRegisterCallback) (MonoCounter*); MONO_API void mono_counters_on_register (MonoCounterRegisterCallback callback); -/* +/* * Create a readable dump of the counters for section_mask sections (ORed section values) */ MONO_API void mono_counters_dump (int section_mask, FILE *outfile); diff --git a/src/mono/mono/utils/mono-embed.c b/src/mono/mono/utils/mono-embed.c index 1e535cca26fd6..fa89d37166e6a 100644 --- a/src/mono/mono/utils/mono-embed.c +++ b/src/mono/mono/utils/mono-embed.c @@ -29,12 +29,12 @@ static void * dl_mapping_open (const char *file, int flags, char **err, void *user_data) { MonoDlMapping *mappings; - + if (mono_dls == NULL){ *err = g_strdup ("Library not registered"); return NULL; } - + mappings = (MonoDlMapping *) g_hash_table_lookup (mono_dls, file); *err = g_strdup (mappings == NULL ? "File not registered" : ""); return mappings; @@ -44,7 +44,7 @@ static void * dl_mapping_symbol (void *handle, const char *symbol, char **err, void *user_data) { MonoDlMapping *mappings = (MonoDlMapping *) handle; - + for (;mappings->name; mappings++){ if (strcmp (symbol, mappings->name) == 0){ *err = g_strdup (""); @@ -60,11 +60,11 @@ dl_mapping_symbol (void *handle, const char *symbol, char **err, void *user_data * \param name Library name, this is the name used by the DllImport as the external library name * \param mappings the mappings to register for P/Invoke. * - * The mappings registered using this function are used as fallbacks if the dynamic linker + * The mappings registered using this function are used as fallbacks if the dynamic linker * fails, or if the platform doesn't have a dynamic linker. * * \p mappings is a pointer to the first element of an array of - * \c MonoDlMapping values. The list must be terminated with both + * \c MonoDlMapping values. The list must be terminated with both * the \c name and \c addr fields set to NULL. * * This is typically used like this: @@ -93,7 +93,7 @@ mono_dl_register_library (const char *name, MonoDlMapping *mappings) mono_dls = g_hash_table_new (g_str_hash, g_str_equal); mono_dl_fallback_register (dl_mapping_open, dl_mapping_symbol, NULL, NULL); } - + g_hash_table_insert (mono_dls, g_strdup (name), mappings); } diff --git a/src/mono/mono/utils/mono-embed.h b/src/mono/mono/utils/mono-embed.h index 9a81e788c5982..f4934a47a2de7 100644 --- a/src/mono/mono/utils/mono-embed.h +++ b/src/mono/mono/utils/mono-embed.h @@ -7,11 +7,11 @@ #include -/* +/* * This is a fallback for platform symbol loading functionality. */ typedef struct { - const char *name; + const char *name; void *addr; } MonoDlMapping; diff --git a/src/mono/mono/utils/mono-error-internals.h b/src/mono/mono/utils/mono-error-internals.h index f43727dde76bf..6d55b5a7f81a1 100644 --- a/src/mono/mono/utils/mono-error-internals.h +++ b/src/mono/mono/utils/mono-error-internals.h @@ -164,7 +164,7 @@ void mono_error_dup_strings (MonoError *error, gboolean dup_strings); /* This function is not very useful as you can't provide any details beyond the message.*/ -MONO_COMPONENT_API +MONO_COMPONENT_API void mono_error_set_error (MonoError *error, int error_code, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4); @@ -210,7 +210,7 @@ MONO_COMPONENT_API void mono_error_set_not_supported (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3); -void +void mono_error_set_ambiguous_implementation (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3); MONO_COMPONENT_API diff --git a/src/mono/mono/utils/mono-error.c b/src/mono/mono/utils/mono-error.c index 6d02df6968dc2..0f422502de118 100644 --- a/src/mono/mono/utils/mono-error.c +++ b/src/mono/mono/utils/mono-error.c @@ -311,7 +311,7 @@ mono_error_set_class (MonoError *oerror, MonoClass *klass) if (is_managed_exception (error)) return; - error->exn.klass = klass; + error->exn.klass = klass; } static void @@ -716,9 +716,9 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) case MONO_ERROR_ARGUMENT_NULL: exception = mono_exception_new_argument_null (error->first_argument, error_out); break; - - case MONO_ERROR_ARGUMENT_OUT_OF_RANGE: - exception = mono_exception_new_argument_out_of_range(error->first_argument, error->full_message, error_out); + + case MONO_ERROR_ARGUMENT_OUT_OF_RANGE: + exception = mono_exception_new_argument_out_of_range(error->first_argument, error->full_message, error_out); break; case MONO_ERROR_NOT_VERIFIABLE: @@ -852,7 +852,7 @@ mono_error_box (const MonoError *ierror, MonoImage *image) to->exn.klass = from->exn.klass; #undef DUP_STR - + return box; } @@ -896,7 +896,7 @@ mono_error_set_from_boxed (MonoError *oerror, const MonoErrorBoxed *box) DUP_STR (full_message_with_fields); DUP_STR (first_argument); to->exn.klass = from->exn.klass; - + #undef DUP_STR return (to->flags & MONO_ERROR_INCOMPLETE) == 0 ; } diff --git a/src/mono/mono/utils/mono-error.h b/src/mono/mono/utils/mono-error.h index 69bfb8a47346f..297412b3d5a15 100644 --- a/src/mono/mono/utils/mono-error.h +++ b/src/mono/mono/utils/mono-error.h @@ -40,7 +40,7 @@ enum { /* * This is a generic error mechanism is you need to raise an arbitrary corlib exception. - * You must pass the exception name otherwise prepare_exception will fail with internal execution. + * You must pass the exception name otherwise prepare_exception will fail with internal execution. */ MONO_ERROR_GENERIC = 9, /* This one encapsulates a managed exception instance */ diff --git a/src/mono/mono/utils/mono-filemap.c b/src/mono/mono/utils/mono-filemap.c index 3fe31d7776f76..0c4ac46a5b497 100644 --- a/src/mono/mono/utils/mono-filemap.c +++ b/src/mono/mono/utils/mono-filemap.c @@ -44,7 +44,7 @@ mono_file_map_open (const char* name) #endif } -guint64 +guint64 mono_file_map_size (MonoFileMap *fmap) { struct stat stat_buf; @@ -63,7 +63,7 @@ mono_file_map_fd (MonoFileMap *fmap) #endif } -int +int mono_file_map_close (MonoFileMap *fmap) { #ifdef WIN32 diff --git a/src/mono/mono/utils/mono-flight-recorder.c b/src/mono/mono/utils/mono-flight-recorder.c index 7ff4b59d737da..ab14f4fe57848 100644 --- a/src/mono/mono/utils/mono-flight-recorder.c +++ b/src/mono/mono/utils/mono-flight-recorder.c @@ -26,14 +26,14 @@ // Mutex has to be held when called void -mono_flight_recorder_iter_init (MonoFlightRecorder *recorder, MonoFlightRecorderIter *iter) +mono_flight_recorder_iter_init (MonoFlightRecorder *recorder, MonoFlightRecorderIter *iter) { // Make sure we are initialized g_assert (recorder->max_count > 0); iter->recorder = recorder; if (recorder->cursor == MONO_FLIGHT_RECORDER_SENTINEL) { - iter->lowest_index = MONO_FLIGHT_RECORDER_SENTINEL; + iter->lowest_index = MONO_FLIGHT_RECORDER_SENTINEL; iter->highest_index = MONO_FLIGHT_RECORDER_SENTINEL; } else if (recorder->cursor >= recorder->max_count) { // Ring buffer has wrapped around diff --git a/src/mono/mono/utils/mono-hwcap-arm.c b/src/mono/mono/utils/mono-hwcap-arm.c index b4de27ee1de98..c6a30854a3918 100644 --- a/src/mono/mono/utils/mono-hwcap-arm.c +++ b/src/mono/mono/utils/mono-hwcap-arm.c @@ -95,21 +95,21 @@ mono_hwcap_arch_init (void) /* TODO: Find a way to detect features like Thumb and VFP. */ #elif defined (_WIN32) - /* From MSDN: - * Windows on ARM presumes that it is running on an ARMv7 architecture at all times. + /* From MSDN: + * Windows on ARM presumes that it is running on an ARMv7 architecture at all times. * Floating-point support in the form of VFPv3-D32 or later must be present in hardware. - * The VFP must support both single-precision and double-precision floating-point in hardware. + * The VFP must support both single-precision and double-precision floating-point in hardware. * * The Windows runtime does not support emulation of floating-point to enable running on non-VFP hardware. - * Advanced SIMD Extensions (NEON) support—this includes both integer and floating-point operations—must also be present in hardware. + * Advanced SIMD Extensions (NEON) support—this includes both integer and floating-point operations—must also be present in hardware. * No run-time support for emulation is provided. * * Integer divide support (UDIV/SDIV) is strongly recommended but not required. * Platforms that lack integer divide support may incur a performance penalty because * these operations have to be trapped and possibly patched. * - * The instruction set for Windows on ARM is strictly limited to Thumb-2. - * All code executed on this platform is expected to start and remain in Thumb mode at all times. + * The instruction set for Windows on ARM is strictly limited to Thumb-2. + * All code executed on this platform is expected to start and remain in Thumb mode at all times. */ mono_hwcap_arm_is_v5 = TRUE; mono_hwcap_arm_is_v6 = TRUE; diff --git a/src/mono/mono/utils/mono-jemalloc.c b/src/mono/mono/utils/mono-jemalloc.c index 4b0f5baa05c6d..16b4c1d7c6207 100644 --- a/src/mono/mono/utils/mono-jemalloc.c +++ b/src/mono/mono/utils/mono-jemalloc.c @@ -9,7 +9,7 @@ #ifdef MONO_JEMALLOC_ENABLED -void +void mono_init_jemalloc (void) { GMemVTable g_mem_vtable = { MONO_JEMALLOC_MALLOC, MONO_JEMALLOC_REALLOC, MONO_JEMALLOC_FREE, MONO_JEMALLOC_CALLOC}; diff --git a/src/mono/mono/utils/mono-jemalloc.h b/src/mono/mono/utils/mono-jemalloc.h index 6721877f51428..73d869bbb36d0 100644 --- a/src/mono/mono/utils/mono-jemalloc.h +++ b/src/mono/mono/utils/mono-jemalloc.h @@ -16,11 +16,11 @@ * 2. You can use it as a global malloc replacement * 3. You can use it with a prefix. If you use it with a prefix, you have to explicitly name the malloc function. * - * In order to make this feature able to be toggled at run-time, I chose to use a prefix of mono_je. + * In order to make this feature able to be toggled at run-time, I chose to use a prefix of mono_je. * This mapping is captured below in the header, in the spirit of "no magic constants". * * The place that configures jemalloc and sets this prefix is in the Makefile in - * mono/jemalloc/Makefile.am + * mono/jemalloc/Makefile.am * */ #define MONO_JEMALLOC_MALLOC mono_jemalloc diff --git a/src/mono/mono/utils/mono-linked-list-set.c b/src/mono/mono/utils/mono-linked-list-set.c index ee43dfdf7a3af..a3a2b7f548cad 100644 --- a/src/mono/mono/utils/mono-linked-list-set.c +++ b/src/mono/mono/utils/mono-linked-list-set.c @@ -139,7 +139,7 @@ gboolean mono_lls_insert (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value) { MonoLinkedListSetNode *cur, **prev; - /*We must do a store barrier before inserting + /*We must do a store barrier before inserting to make sure all values in @node are globally visible.*/ mono_memory_barrier (); diff --git a/src/mono/mono/utils/mono-log-android.c b/src/mono/mono/utils/mono-log-android.c index 6a86ce1c8fba6..4a4c4b1932fd5 100644 --- a/src/mono/mono/utils/mono-log-android.c +++ b/src/mono/mono/utils/mono-log-android.c @@ -20,7 +20,7 @@ * \param path Unused * \param userData Unused * Open access to Android logcat (no-op) - */ + */ void mono_log_open_logcat (const char *path, void *userData) { diff --git a/src/mono/mono/utils/mono-log-common.c b/src/mono/mono/utils/mono-log-common.c index 74cfd6adba2e6..6ad11e378cca2 100644 --- a/src/mono/mono/utils/mono-log-common.c +++ b/src/mono/mono/utils/mono-log-common.c @@ -35,7 +35,7 @@ static void *logUserData = NULL; /** * mapSyslogLevel: - * + * * @level - GLogLevelFlags value * @returns The equivalent character identifier */ @@ -80,7 +80,7 @@ mono_log_open_logfile(const char *path, void *userData) } #endif if (logFile == NULL) { - g_warning("opening of log file %s failed with %s - defaulting to stdout", + g_warning("opening of log file %s failed with %s - defaulting to stdout", path, strerror(errno)); logFile = stdout; } diff --git a/src/mono/mono/utils/mono-log-flight-recorder.c b/src/mono/mono/utils/mono-log-flight-recorder.c index ff76d6d43346e..c083391038f1b 100644 --- a/src/mono/mono/utils/mono-log-flight-recorder.c +++ b/src/mono/mono/utils/mono-log-flight-recorder.c @@ -63,7 +63,7 @@ handle_command (gpointer state, gpointer payload, gboolean at_shutdown) #if 0 // Dump all messages on each append. This is an aggressive, slow - // debugging method. + // debugging method. LogMessage messages [MAX_RECORDER_LOG_LEN]; LogQueueDumpRequest dump; @@ -100,8 +100,8 @@ static MonoUtilityThread *logger_thread; * mono_log_open_recorder: * \param path Unused * \param userData Unused - * Open access to recorder - */ + * Open access to recorder + */ void mono_log_open_recorder (const char *path, void *userData) { @@ -150,7 +150,7 @@ mono_log_write_recorder (const char *log_domain, GLogLevelFlags level, mono_bool /** * mono_log_close_recorder * - * Close access to recorder + * Close access to recorder */ void mono_log_close_recorder (void) diff --git a/src/mono/mono/utils/mono-log-posix.c b/src/mono/mono/utils/mono-log-posix.c index 454bf021356e1..094a9f1a5bd25 100644 --- a/src/mono/mono/utils/mono-log-posix.c +++ b/src/mono/mono/utils/mono-log-posix.c @@ -32,12 +32,12 @@ static void *logUserData = NULL; /** * mapSyslogLevel: - * + * * @level - GLogLevelFlags value * @returns The equivalent syslog priority value */ static __inline__ int -mapSyslogLevel(GLogLevelFlags level) +mapSyslogLevel(GLogLevelFlags level) { if (level & G_LOG_LEVEL_ERROR) return (LOG_ERR); @@ -58,7 +58,7 @@ mapSyslogLevel(GLogLevelFlags level) * mono_log_open_syslog: * \param ident Identifier: ignored * \param userData Not used - * Open the syslog interface specifying that we want our PID recorded + * Open the syslog interface specifying that we want our PID recorded * and that we're using the \c LOG_USER facility. */ void diff --git a/src/mono/mono/utils/mono-log-windows.c b/src/mono/mono/utils/mono-log-windows.c index b7d328cf33e02..cd6e8922d76d5 100644 --- a/src/mono/mono/utils/mono-log-windows.c +++ b/src/mono/mono/utils/mono-log-windows.c @@ -34,7 +34,7 @@ static const wchar_t *logFileName = L".//mono.log"; // FIXME double slash /** * mapSyslogLevel: - * + * * @level - GLogLevelFlags value * @returns The equivalent character identifier */ @@ -60,7 +60,7 @@ mapLogFileLevel (GLogLevelFlags level) * mono_log_open_syslog: * \param ident Identifier: ignored * \param userData Not used - * Open the syslog file. If the open fails issue a warning and + * Open the syslog file. If the open fails issue a warning and * use stdout as the log file destination. */ void diff --git a/src/mono/mono/utils/mono-logger-internals.h b/src/mono/mono/utils/mono-logger-internals.h index bff13285fb6d9..4100ddaa105f2 100644 --- a/src/mono/mono/utils/mono-logger-internals.h +++ b/src/mono/mono/utils/mono-logger-internals.h @@ -45,16 +45,16 @@ mono_trace_init (void); MONO_API void mono_tracev_inner (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args); -void +void mono_trace_set_level (GLogLevelFlags level); -void +void mono_trace_set_mask (MonoTraceMask mask); -void +void mono_trace_push (GLogLevelFlags level, MonoTraceMask mask); -void +void mono_trace_pop (void); MONO_COMPONENT_API diff --git a/src/mono/mono/utils/mono-logger.c b/src/mono/mono/utils/mono-logger.c index b5870ac3b2515..83a97b326ea14 100644 --- a/src/mono/mono/utils/mono-logger.c +++ b/src/mono/mono/utils/mono-logger.c @@ -37,7 +37,7 @@ typedef struct { * * Initializes the mono tracer. */ -void +void mono_trace_init (void) { if(level_stack == NULL) { @@ -68,7 +68,7 @@ mono_trace_init (void) * Traces a new message, depending on the current logging level * and trace mask. */ -void +void mono_tracev_inner (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args) { char *log_message; @@ -93,7 +93,7 @@ mono_tracev_inner (GLogLevelFlags level, MonoTraceMask mask, const char *format, * \c mono_trace will check the visibility of a message against this * value. */ -void +void mono_trace_set_level (GLogLevelFlags level) { if(level_stack == NULL) @@ -109,7 +109,7 @@ mono_trace_set_level (GLogLevelFlags level) * \c mono_trace will check the visibility of a message against this * value. */ -void +void mono_trace_set_mask (MonoTraceMask mask) { if(level_stack == NULL) @@ -124,7 +124,7 @@ mono_trace_set_mask (MonoTraceMask mask) * Sets the current logging destination. This can be a file or, if supported, * syslog. */ -void +void mono_trace_set_logdest_string (const char *dest) { MonoLogCallParm logger; @@ -179,7 +179,7 @@ mono_trace_set_logdest_string (const char *dest) * \param head Whether we want pid/date/time header on log messages * Sets the current logging header option. */ -void +void mono_trace_set_logheader_string(const char *head) { if (head == NULL) { @@ -196,7 +196,7 @@ mono_trace_set_logheader_string(const char *head) * Saves the current values of level and mask then calls \c mono_trace_set * with the specified new values. */ -void +void mono_trace_push (GLogLevelFlags level, MonoTraceMask mask) { if(level_stack == NULL) @@ -220,7 +220,7 @@ mono_trace_push (GLogLevelFlags level, MonoTraceMask mask) * * Restores level and mask values saved from a previous call to mono_trace_push. */ -void +void mono_trace_pop (void) { if(level_stack == NULL) @@ -240,7 +240,7 @@ mono_trace_pop (void) } -void +void mono_trace_set_level_string (const char *value) { int i = 0; @@ -263,7 +263,7 @@ mono_trace_set_level_string (const char *value) g_print("Unknown trace loglevel: %s\n", value); } -void +void mono_trace_set_mask_string (const char *value) { int i; @@ -368,7 +368,7 @@ log_level_get_name (GLogLevelFlags log_level) /** * callback_adapter - * + * * @log_domain Message prefix * @log_level Severity * @message Message to be written @@ -415,7 +415,7 @@ legacy_closer(void) { if (logCallback.user_data != NULL) { g_free (logCallback.user_data); /* This is a UserSuppliedLoggerUserData struct */ - logCallback.opener = NULL; + logCallback.opener = NULL; logCallback.writer = NULL; logCallback.closer = NULL; logCallback.user_data = NULL; @@ -425,10 +425,10 @@ legacy_closer(void) /** * mono_trace_set_log_handler: - * + * * @callback The callback that will replace the default logging handler * @user_data Argument passed to @callback - * + * * The log handler replaces the default runtime logger. All logging requests with be routed to it. * If the fatal argument in the callback is true, the callback must abort the current process. The runtime expects that * execution will not resume after a fatal error. diff --git a/src/mono/mono/utils/mono-logger.h b/src/mono/mono/utils/mono-logger.h index a90e6c54cf365..e3ef20475485c 100644 --- a/src/mono/mono/utils/mono-logger.h +++ b/src/mono/mono/utils/mono-logger.h @@ -8,10 +8,10 @@ #include MONO_BEGIN_DECLS -MONO_API void +MONO_API void mono_trace_set_level_string (const char *value); -MONO_API void +MONO_API void mono_trace_set_mask_string (const char *value); typedef void (*MonoPrintCallback) (const char *string, mono_bool is_stdout); diff --git a/src/mono/mono/utils/mono-md5.c b/src/mono/mono/utils/mono-md5.c index 165e42a564f92..b239cd1782cef 100644 --- a/src/mono/mono/utils/mono-md5.c +++ b/src/mono/mono/utils/mono-md5.c @@ -86,7 +86,7 @@ static union _endian { gint i; gchar b[4]; } *_endian = (union _endian *)&_ie; /* * Note: this code is harmless on little-endian machines. */ -static void +static void _byte_reverse (guchar *buf, guint32 longs) { guint32 t; @@ -100,26 +100,26 @@ _byte_reverse (guchar *buf, guint32 longs) /** * mono_md5_init: Initialise an md5 context object - * @ctx: md5 context - * - * Initialise an md5 buffer. + * @ctx: md5 context + * + * Initialise an md5 buffer. * **/ -void +void mono_md5_init (MonoMD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; - + ctx->bits[0] = 0; ctx->bits[1] = 0; - - if (IS_BIG_ENDIAN()) - ctx->doByteReverse = 1; - else - ctx->doByteReverse = 0; + + if (IS_BIG_ENDIAN()) + ctx->doByteReverse = 1; + else + ctx->doByteReverse = 0; } @@ -129,29 +129,29 @@ mono_md5_init (MonoMD5Context *ctx) * @ctx: conetxt object used for md5 computaion * @buf: buffer to add * @len: buffer length - * + * * Update context to reflect the concatenation of another buffer full * of bytes. Use this to progressively construct an md5 hash. **/ -void +void mono_md5_update (MonoMD5Context *ctx, const guchar *buf, guint32 len) { guint32 t; - + /* Update bitcount */ - + t = ctx->bits[0]; if ((ctx->bits[0] = t + ((guint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; - + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - + /* Handle any leading odd-sized chunks */ - + if (t) { guchar *p = (guchar *) ctx->in + t; - + t = 64 - t; if (len < t) { memcpy (p, buf, len); @@ -165,7 +165,7 @@ mono_md5_update (MonoMD5Context *ctx, const guchar *buf, guint32 len) len -= t; } /* Process data in 64-byte chunks */ - + while (len >= 64) { memcpy (ctx->in, buf, 64); if (ctx->doByteReverse) @@ -174,9 +174,9 @@ mono_md5_update (MonoMD5Context *ctx, const guchar *buf, guint32 len) buf += 64; len -= 64; } - + /* Handle any remaining bytes of data. */ - + memcpy (ctx->in, buf, len); } @@ -185,33 +185,33 @@ mono_md5_update (MonoMD5Context *ctx, const guchar *buf, guint32 len) /* - * Final wrapup - pad to 64-byte boundary with the bit pattern + * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ /** * mono_md5_final: copy the final md5 hash to a bufer * @digest: 16 bytes buffer * @ctx: context containing the calculated md5 - * + * * copy the final md5 hash to a bufer **/ -void +void mono_md5_final (MonoMD5Context *ctx, guchar digest[16]) { guint32 count; guchar *p; - + /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; - + /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; - + /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; - + /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ @@ -219,7 +219,7 @@ mono_md5_final (MonoMD5Context *ctx, guchar digest[16]) if (ctx->doByteReverse) _byte_reverse (ctx->in, 16); md5_transform (ctx->buf, (guint32 *) ctx->in); - + /* Now fill the next block with 56 bytes */ memset (ctx->in, 0, 56); } else { @@ -228,11 +228,11 @@ mono_md5_final (MonoMD5Context *ctx, guchar digest[16]) } if (ctx->doByteReverse) _byte_reverse (ctx->in, 14); - + /* Append length in bits and transform */ ((guint32 *) ctx->in)[14] = ctx->bits[0]; ((guint32 *) ctx->in)[15] = ctx->bits[1]; - + md5_transform (ctx->buf, (guint32 *) ctx->in); if (ctx->doByteReverse) _byte_reverse ((guchar *) ctx->buf, 4); @@ -265,16 +265,16 @@ mono_md5_ctx_byte_length (MonoMD5Context *ctx) * reflect the addition of 16 longwords of new data. md5_Update blocks * the data and converts bytes into longwords for this routine. */ -static void +static void md5_transform (guint32 buf[4], const guint32 in[16]) { guint32 a, b, c, d; - + a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; - + MD5STEP (F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP (F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP (F1, c, d, a, b, in[2] + 0x242070db, 17); @@ -291,7 +291,7 @@ md5_transform (guint32 buf[4], const guint32 in[16]) MD5STEP (F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP (F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP (F1, b, c, d, a, in[15] + 0x49b40821, 22); - + MD5STEP (F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP (F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP (F2, c, d, a, b, in[11] + 0x265e5a51, 14); @@ -308,7 +308,7 @@ md5_transform (guint32 buf[4], const guint32 in[16]) MD5STEP (F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP (F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP (F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - + MD5STEP (F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP (F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP (F3, c, d, a, b, in[11] + 0x6d9d6122, 16); @@ -325,7 +325,7 @@ md5_transform (guint32 buf[4], const guint32 in[16]) MD5STEP (F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP (F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP (F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - + MD5STEP (F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP (F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP (F4, c, d, a, b, in[14] + 0xab9423a7, 15); @@ -342,7 +342,7 @@ md5_transform (guint32 buf[4], const guint32 in[16]) MD5STEP (F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP (F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP (F4, b, c, d, a, in[9] + 0xeb86d391, 21); - + buf[0] += a; buf[1] += b; buf[2] += c; @@ -357,19 +357,19 @@ md5_transform (guint32 buf[4], const guint32 in[16]) * \param buffer byte buffer * \param buffer_size buffer size (in bytes) * \param digest 16-byte buffer receiving the hash code. - * - * Get the MD5 hash of a buffer. The result is put in + * + * Get the MD5 hash of a buffer. The result is put in * the 16-byte buffer \p digest. */ void mono_md5_get_digest (const guchar *buffer, gint buffer_size, guchar digest[16]) -{ +{ MonoMD5Context ctx; mono_md5_init (&ctx); mono_md5_update (&ctx, buffer, buffer_size); mono_md5_final (&ctx, digest); - + } @@ -377,15 +377,15 @@ mono_md5_get_digest (const guchar *buffer, gint buffer_size, guchar digest[16]) * mono_md5_get_digest_from_file: * \param filename file name * \param digest 16-byte buffer receiving the hash code. - * - * Get the MD5 hash of a file. The result is put in + * + * Get the MD5 hash of a file. The result is put in * the 16-byte buffer \p digest. - * + * * If an IO error happens the value in \p digest is not updated. */ void mono_md5_get_digest_from_file (const gchar *filename, guchar digest[16]) -{ +{ MonoMD5Context ctx; guchar tmp_buf[1024]; gint nb_bytes_read; @@ -396,10 +396,10 @@ mono_md5_get_digest_from_file (const gchar *filename, guchar digest[16]) if (!fp) { return; } - + while ((nb_bytes_read = fread (tmp_buf, sizeof (guchar), 1024, fp)) > 0) mono_md5_update (&ctx, tmp_buf, nb_bytes_read); - + if (ferror(fp)) { fclose(fp); return; diff --git a/src/mono/mono/utils/mono-memory-model.h b/src/mono/mono/utils/mono-memory-model.h index a35433fd023dd..863ee77d61563 100644 --- a/src/mono/mono/utils/mono-memory-model.h +++ b/src/mono/mono/utils/mono-memory-model.h @@ -22,7 +22,7 @@ On the other hand, we can't use arm's weak model on targets such as x86 that hav a stronger model that requires much much less fencing. The idea of exposing each arch memory model is to avoid fencing whenever possible -but at the same time make all required ordering explicit. +but at the same time make all required ordering explicit. There are four kinds of barriers, LoadLoad, LoadStore, StoreLoad and StoreStore. Each arch must define which ones needs fencing. @@ -109,19 +109,19 @@ LDR R3, [R4, R0] #ifndef STORE_STORE_FENCE #define STORE_STORE_FENCE mono_compiler_barrier () -#endif +#endif #ifndef LOAD_LOAD_FENCE #define LOAD_LOAD_FENCE mono_compiler_barrier () -#endif +#endif #ifndef STORE_LOAD_FENCE #define STORE_LOAD_FENCE mono_compiler_barrier () -#endif +#endif #ifndef LOAD_STORE_FENCE #define LOAD_STORE_FENCE mono_compiler_barrier () -#endif +#endif #ifndef STORE_RELEASE_FENCE #define STORE_RELEASE_FENCE mono_compiler_barrier () diff --git a/src/mono/mono/utils/mono-mmap-wasm.c b/src/mono/mono/utils/mono-mmap-wasm.c index 82f117b728c79..3364ec4fed939 100644 --- a/src/mono/mono/utils/mono-mmap-wasm.c +++ b/src/mono/mono/utils/mono-mmap-wasm.c @@ -63,7 +63,7 @@ mono_valloc_granule (void) static int prot_from_flags (int flags) -{ +{ #if HOST_WASI // The mmap in wasi-sdk rejects PROT_NONE, but otherwise disregards the flags // We just need to pass an acceptable value diff --git a/src/mono/mono/utils/mono-networkinterfaces.c b/src/mono/mono/utils/mono-networkinterfaces.c index f86bd651ee74b..c93ce63db77cd 100644 --- a/src/mono/mono/utils/mono-networkinterfaces.c +++ b/src/mono/mono/utils/mono-networkinterfaces.c @@ -27,7 +27,7 @@ mono_networkinterface_list (int *size) char name [256]; f = fopen ("/proc/net/dev", "r"); - if (!f) + if (!f) return NULL; if (!fgets (buf, sizeof (buf) / sizeof (char), f)) @@ -86,7 +86,7 @@ mono_network_get_data (char* name, MonoNetworkData data, MonoNetworkError *error *error = MONO_NETWORK_ERROR_OTHER; f = fopen ("/proc/net/dev", "r"); - if (!f) + if (!f) return -1; if (!fgets (buf, sizeof (buf) / sizeof (char), f)) @@ -109,7 +109,7 @@ mono_network_get_data (char* name, MonoNetworkData data, MonoNetworkError *error &rx_bytes, &rx_packets, &rx_errs, &rx_drops, &rx_fifo, &rx_frame, &rx_multi, &tx_bytes, &tx_packets, &tx_errs, &tx_drops, - &tx_fifo, &tx_colls, &tx_carrier) != 14) + &tx_fifo, &tx_colls, &tx_carrier) != 14) goto out; switch (data) { diff --git a/src/mono/mono/utils/mono-path.c b/src/mono/mono/utils/mono-path.c index 2f4790666a428..5e4f117272206 100644 --- a/src/mono/mono/utils/mono-path.c +++ b/src/mono/mono/utils/mono-path.c @@ -1,7 +1,7 @@ /** * \file * Routines for handling path names. - * + * * Authors: * Gonzalo Paniagua Javier (gonzalo@novell.com) * Miguel de Icaza (miguel@novell.com) @@ -69,7 +69,7 @@ mono_path_canonicalize (const char *path) if (backc > 0) { backc--; } else { - if (dest != lastpos) + if (dest != lastpos) /* The two strings can overlap */ memmove (dest, lastpos, len + 1); dest += len + 1; @@ -86,9 +86,9 @@ mono_path_canonicalize (const char *path) if (*(lastpos-1) == G_DIR_SEPARATOR && *(lastpos-2) == G_DIR_SEPARATOR && *lastpos == 0) lastpos = lastpos-1; #endif - + if (dest != lastpos) strcpy (dest, lastpos); - + g_strreverse (abspath); /* We strip away all trailing dir separators. This is not correct for the root directory, @@ -126,7 +126,7 @@ resolve_symlink (const char *path) g_free (copy); return p; } - + buffer [n] = 0; if (!g_path_is_absolute (buffer)) { dir = g_path_get_dirname (p); diff --git a/src/mono/mono/utils/mono-poll.c b/src/mono/mono/utils/mono-poll.c index 022cabc24b4be..20091c34e6dc9 100644 --- a/src/mono/mono/utils/mono-poll.c +++ b/src/mono/mono/utils/mono-poll.c @@ -108,7 +108,7 @@ mono_poll (mono_pollfd *ufds, unsigned int nfds, int timeout) nexc++; if (fd > maxfd) maxfd = fd; - + } affected = select (maxfd + 1, &rfds, &wfds, &efds, tvptr); diff --git a/src/mono/mono/utils/mono-private-unstable.h b/src/mono/mono/utils/mono-private-unstable.h index 241a723447957..489c3451b49b0 100644 --- a/src/mono/mono/utils/mono-private-unstable.h +++ b/src/mono/mono/utils/mono-private-unstable.h @@ -1,6 +1,6 @@ /** * \file - * + * * Private unstable APIs. * * WARNING: The declarations and behavior of functions in this header are NOT STABLE and can be modified or removed at diff --git a/src/mono/mono/utils/mono-property-hash.c b/src/mono/mono/utils/mono-property-hash.c index 0703b8b977778..65b257d2e16f7 100644 --- a/src/mono/mono/utils/mono-property-hash.c +++ b/src/mono/mono/utils/mono-property-hash.c @@ -56,7 +56,7 @@ mono_property_hash_insert (MonoPropertyHash *hash, gpointer object, guint32 prop } g_hash_table_insert (prop_hash, object, value); -} +} static void remove_object (gpointer key, gpointer value, gpointer user_data) @@ -82,4 +82,4 @@ mono_property_hash_lookup (MonoPropertyHash *hash, gpointer object, guint32 prop return NULL; return g_hash_table_lookup (prop_hash, object); } - + diff --git a/src/mono/mono/utils/mono-publib.h b/src/mono/mono/utils/mono-publib.h index b01438e52cf1c..24346ccf1c578 100644 --- a/src/mono/mono/utils/mono-publib.h +++ b/src/mono/mono/utils/mono-publib.h @@ -5,7 +5,7 @@ #ifndef __MONO_PUBLIB_H__ #define __MONO_PUBLIB_H__ -/* +/* * Minimal general purpose header for use in public mono header files. * We can't include config.h, so we use compiler-specific preprocessor * directives where needed. diff --git a/src/mono/mono/utils/mono-rand.c b/src/mono/mono/utils/mono-rand.c index ae6e795169562..52b1e2807fdb8 100644 --- a/src/mono/mono/utils/mono-rand.c +++ b/src/mono/mono/utils/mono-rand.c @@ -131,7 +131,7 @@ get_entropy_from_egd (const char *path, guchar *buffer, gssize buffer_size, Mono gint ret; guint offset = 0; int err = 0; - + socket_fd = socket (PF_UNIX, SOCK_STREAM, 0); if (socket_fd < 0) { ret = -1; @@ -325,7 +325,7 @@ mono_rand_try_get_bytes (gpointer *handle, guchar *buffer, gssize buffer_size, M error_init (error); g_static_assert (RAND_MAX >= 0xFF); - + while (buffer_size > 0) { int const i = rand (); int j; diff --git a/src/mono/mono/utils/mono-sha1.c b/src/mono/mono/utils/mono-sha1.c index bfcf6cf4031b5..7b6d6dd4d273e 100644 --- a/src/mono/mono/utils/mono-sha1.c +++ b/src/mono/mono/utils/mono-sha1.c @@ -5,7 +5,7 @@ By Steve Reid 100% Public Domain ----------------- -Modified 7/98 +Modified 7/98 By James H. Brown Still 100% Public Domain @@ -27,7 +27,7 @@ Since the file IO in main() reads 16K at a time, any file 8K or larger would be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million "a"s). -I also changed the declaration of variables i & j in mono_sha1_update to +I also changed the declaration of variables i & j in mono_sha1_update to unsigned long from unsigned int for the same reason. These changes should make no difference to any 32 bit implementations since @@ -54,7 +54,7 @@ Still 100% public domain Modified 4/01 By Saul Kravitz Still 100% PD -Modified to run on Compaq Alpha hardware. +Modified to run on Compaq Alpha hardware. */ @@ -137,7 +137,7 @@ static void SHA1Transform(guint32 state[5], const guchar buffer[64]); static void SHAPrintContext(MonoSHA1Context *context, char *msg){ printf("%s (%d,%d) %x %x %x %x %x\n", msg, - context->count[0], context->count[1], + context->count[0], context->count[1], context->state[0], context->state[1], context->state[2], @@ -287,28 +287,28 @@ unsigned char finalcount[8]; */ void mono_sha1_get_digest (const guchar *buffer, gint buffer_size, guchar digest [20]) -{ +{ MonoSHA1Context ctx; mono_sha1_init (&ctx); mono_sha1_update (&ctx, buffer, buffer_size); mono_sha1_final (&ctx, digest); - + } /** * mono_sha1_get_digest_from_file: * \param filename file name * \param digest 20-byte buffer receiving the hash code. - * - * Get the SHA-1 hash of a file. The result is put in + * + * Get the SHA-1 hash of a file. The result is put in * the 20-byte buffer \p digest. - * + * * If an IO error happens the value in \p digest is not updated. */ void mono_sha1_get_digest_from_file (const gchar *filename, guchar digest [20]) -{ +{ MonoSHA1Context ctx; guchar tmp_buf[1024]; gint nb_bytes_read; @@ -319,10 +319,10 @@ mono_sha1_get_digest_from_file (const gchar *filename, guchar digest [20]) if (!fp) { return; } - + while ((nb_bytes_read = fread (tmp_buf, sizeof (guchar), 1024, fp)) > 0) mono_sha1_update (&ctx, tmp_buf, nb_bytes_read); - + if (ferror(fp)) { fclose(fp); return; @@ -339,7 +339,7 @@ mono_sha1_get_digest_from_file (const gchar *filename, guchar digest [20]) * Get the public token from public key data. * \p token must point to at least 8 bytes of storage. */ -void +void mono_digest_get_public_token (guchar* token, const guchar *pubkey, guint32 len) { guchar digest [20]; diff --git a/src/mono/mono/utils/mono-stack-unwinding.h b/src/mono/mono/utils/mono-stack-unwinding.h index b3109a9b0e61f..66931c6defc04 100644 --- a/src/mono/mono/utils/mono-stack-unwinding.h +++ b/src/mono/mono/utils/mono-stack-unwinding.h @@ -55,7 +55,7 @@ typedef enum { typedef struct { MonoStackFrameType type; - /* + /* * For FRAME_TYPE_MANAGED, otherwise NULL. */ MonoJitInfo *ji; @@ -79,7 +79,7 @@ typedef struct { int native_offset; /* * IL offset of this frame. - * Only available if the runtime have debugging enabled (--debug switch) and + * Only available if the runtime have debugging enabled (--debug switch) and * il offset resultion was requested (MONO_UNWIND_LOOKUP_IL_OFFSET) */ int il_offset; @@ -114,7 +114,7 @@ typedef struct { enum { MONO_UNWIND_DATA_DOMAIN, MONO_UNWIND_DATA_LMF, - MONO_UNWIND_DATA_JIT_TLS, + MONO_UNWIND_DATA_JIT_TLS, }; /* diff --git a/src/mono/mono/utils/mono-stdlib.c b/src/mono/mono/utils/mono-stdlib.c index 5f679b15fafdf..3c94f06aa1d48 100644 --- a/src/mono/mono/utils/mono-stdlib.c +++ b/src/mono/mono/utils/mono-stdlib.c @@ -1,7 +1,7 @@ /** * \file * stdlib replacement functions. - * + * * Authors: * Gonzalo Paniagua Javier (gonzalo@novell.com) * diff --git a/src/mono/mono/utils/mono-threads-aix.c b/src/mono/mono/utils/mono-threads-aix.c index 28cae9b44abec..5ce0e25561930 100644 --- a/src/mono/mono/utils/mono-threads-aix.c +++ b/src/mono/mono/utils/mono-threads-aix.c @@ -12,7 +12,7 @@ void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize) { - /* see GC_push_all_stacks in libgc/aix_irix_threads.c + /* see GC_push_all_stacks in libgc/aix_irix_threads.c for why we do this; pthread_getattr_np exists only on some versions of AIX and not on PASE, so use a legacy way to get the stack information */ diff --git a/src/mono/mono/utils/mono-threads-coop.c b/src/mono/mono/utils/mono-threads-coop.c index 970a7099e9ecf..602a607439c0f 100644 --- a/src/mono/mono/utils/mono-threads-coop.c +++ b/src/mono/mono/utils/mono-threads-coop.c @@ -41,7 +41,7 @@ #elif defined (HOST_WASM) //TODO: figure out wasm stack scanning #define SAVE_REGS_ON_STACK do {} while (0) -#else +#else #define SAVE_REGS_ON_STACK __builtin_unwind_init (); #endif diff --git a/src/mono/mono/utils/mono-threads-mach-helper.c b/src/mono/mono/utils/mono-threads-mach-helper.c index 7b4f140b619ef..498d9ff069d65 100644 --- a/src/mono/mono/utils/mono-threads-mach-helper.c +++ b/src/mono/mono/utils/mono-threads-mach-helper.c @@ -49,7 +49,7 @@ static id mono_dead_letter_key; * due to duplicate entries. * * So what do we do here? - * + * * Experimentation showns that threadDictionary is destroied after the * problematic keys, so we add our dead letter object as an aditional * way to be notified of thread death. @@ -115,7 +115,7 @@ mono_threads_init_dead_letter (void) alloc = sel_registerName ("alloc"); release = sel_registerName ("release"); dealloc = sel_registerName ("dealloc"); - + currentThread = sel_registerName ("currentThread"); threadDictionary = sel_registerName ("threadDictionary"); diff --git a/src/mono/mono/utils/mono-threads-state-machine.c b/src/mono/mono/utils/mono-threads-state-machine.c index 927d86d619f23..8b863f8371349 100644 --- a/src/mono/mono/utils/mono-threads-state-machine.c +++ b/src/mono/mono/utils/mono-threads-state-machine.c @@ -315,7 +315,7 @@ mono_threads_transition_request_suspension (MonoThreadInfo *info) goto retry_state_change; trace_state_change ("SUSPEND_INIT_REQUESTED", info, raw_state, cur_state, no_safepoints, 1); return ReqSuspendAlreadySuspendedBlocking; - + /* [1] It's questionable on what to do if we hit the beginning of a self suspend. @@ -435,7 +435,7 @@ Try to resume a suspended thread. Returns one of the following values: - Sucess: The thread was resumed. - Error: The thread was not suspended in the first place. [2] -- InitSelfResume: The thread is blocked on self suspend and should be resumed +- InitSelfResume: The thread is blocked on self suspend and should be resumed - InitAsyncResume: The thread is blocked on async suspend and should be resumed - ResumeInitBlockingResume: The thread was suspended on the exit path of blocking state and should be resumed FIXME: ResumeInitBlockingResume is just InitSelfResume by a different name. diff --git a/src/mono/mono/utils/mono-threads.h b/src/mono/mono/utils/mono-threads.h index 4a29ab561e7f6..d0efd7d77c1c6 100644 --- a/src/mono/mono/utils/mono-threads.h +++ b/src/mono/mono/utils/mono-threads.h @@ -407,7 +407,7 @@ mono_thread_info_set_tid (THREAD_INFO_TYPE *info, MonoNativeThreadId tid) /* * @thread_info_size is sizeof (GcThreadInfo), a struct the GC defines to make it possible to have - * a single block with info from both camps. + * a single block with info from both camps. */ void mono_thread_info_init (size_t thread_info_size); @@ -647,8 +647,8 @@ mono_native_thread_id_main_thread_known (MonoNativeThreadId *main_thread_tid); /* * This does _not_ return the same value as mono_native_thread_id_get, except on Windows. * On POSIX, mono_native_thread_id_get returns the value from pthread_self, which is then - * passed around as an identifier to other pthread functions. However this function, where - * possible, returns the OS-unique thread id value, fetched in a platform-specific manner. + * passed around as an identifier to other pthread functions. However this function, where + * possible, returns the OS-unique thread id value, fetched in a platform-specific manner. * It will not work with the various pthread functions, should never be used as a * MonoNativeThreadId, and is intended solely to match the output of various diagonistic tools. */ diff --git a/src/mono/mono/utils/mono-uri.c b/src/mono/mono/utils/mono-uri.c index a39f6be3f0819..ed49c4c96bdb4 100644 --- a/src/mono/mono/utils/mono-uri.c +++ b/src/mono/mono/utils/mono-uri.c @@ -39,7 +39,7 @@ int main () { char *s = g_malloc (256); int i = 0; - + s [255] = 0; for (i = 1; i < 256; i++) diff --git a/src/mono/mono/utils/mono-utility-thread.c b/src/mono/mono/utils/mono-utility-thread.c index ce248018d1171..1c88040df35d3 100644 --- a/src/mono/mono/utils/mono-utility-thread.c +++ b/src/mono/mono/utils/mono-utility-thread.c @@ -22,7 +22,7 @@ typedef struct { MonoSemType *response_sem; // Variably-sized, size is thread->payload_size - gpointer payload [MONO_ZERO_LEN_ARRAY]; + gpointer payload [MONO_ZERO_LEN_ARRAY]; } UtilityThreadQueueEntry; static void @@ -38,7 +38,7 @@ utility_thread_handle_inbox (MonoUtilityThread *thread, gboolean at_shutdown) UtilityThreadQueueEntry *entry = (UtilityThreadQueueEntry *) mono_lock_free_queue_dequeue (&thread->work_queue); if (!entry) return FALSE; - + thread->callbacks.command (thread->state_ptr, &entry->payload, at_shutdown); if (entry->response_sem) { *entry->finished = TRUE; diff --git a/src/mono/mono/utils/mono-value-hash.c b/src/mono/mono/utils/mono-value-hash.c index 351df65443a69..42e2a9b6b3647 100644 --- a/src/mono/mono/utils/mono-value-hash.c +++ b/src/mono/mono/utils/mono-value-hash.c @@ -133,7 +133,7 @@ mono_value_hash_table_new (GHashFunc hash_func, GEqualFunc key_equal_func, MonoV mono_value_hash_table_set_shift (hash, HASH_TABLE_MIN_SHIFT); hash->table = g_new0 (Slot, hash->table_size); - + return hash; } @@ -146,10 +146,10 @@ mono_value_hash_table_new_full (GHashFunc hash_func, GEqualFunc key_equal_func, MonoValueHashTable *hash = mono_value_hash_table_new (hash_func, key_equal_func); if (hash == NULL) return NULL; - + hash->key_destroy_func = key_destroy_func; hash->value_destroy_func = value_destroy_func; - + return hash; } @@ -169,7 +169,7 @@ do_rehash (MonoValueHashTable *hash) /* printf ("New size: %d\n", hash->table_size); */ hash->table = g_new0 (Slot, hash->table_size); - + for (i = 0; i < old_size; i++){ Slot *s = &old_table [i]; Slot *new_s; @@ -222,7 +222,7 @@ mono_value_hash_table_insert_replace (MonoValueHashTable *hash, gpointer key, gp g_assert (value); g_assert (hash->key_extract_func (value) == key); - + g_return_if_fail (hash != NULL); hashcode = HASH (hash, key); @@ -282,7 +282,7 @@ lookup_internal (MonoValueHashTable *hash, gconstpointer key) guint hashcode; guint s_index; guint step = 0; - + hashcode = HASH (hash, key); s_index = hashcode & hash->table_mask; @@ -321,7 +321,7 @@ void mono_value_hash_table_destroy (MonoValueHashTable *hash) { int i; - + g_return_if_fail (hash != NULL); for (i = 0; i < hash->table_size; i++){ @@ -335,6 +335,6 @@ mono_value_hash_table_destroy (MonoValueHashTable *hash) } } g_free (hash->table); - + g_free (hash); } diff --git a/src/mono/mono/utils/mono-value-hash.h b/src/mono/mono/utils/mono-value-hash.h index 7702844ad9eea..27b9d95d4c262 100644 --- a/src/mono/mono/utils/mono-value-hash.h +++ b/src/mono/mono/utils/mono-value-hash.h @@ -17,7 +17,7 @@ /* * This is a hash table with the following features/restrictions: - * - Keys are not stored in the table, instead a function must be supplied which + * - Keys are not stored in the table, instead a function must be supplied which * computes them from the value. * - Values are assumed to be normal pointers, i.e. their lowest 2-3 bits should be * zero. @@ -27,7 +27,7 @@ * hash tables which store the key (or even the key hash) in the hash nodes. But * it also means that each hash node has a size of one machine word, instead of * 4 in GHashTable. - * - Removal of entries is not supported, as it is not needed by the runtime right + * - Removal of entries is not supported, as it is not needed by the runtime right * now. */ diff --git a/src/mono/mono/utils/monobitset.c b/src/mono/mono/utils/monobitset.c index ecbe76cd54f9c..db163b6a820bf 100644 --- a/src/mono/mono/utils/monobitset.c +++ b/src/mono/mono/utils/monobitset.c @@ -115,7 +115,7 @@ mono_bitset_test (const MonoBitSet *set, guint32 pos) { * mono_bitset_test_bulk: * \param set bitset ptr * \param pos test bit at this pos - * \returns 32/64 bits from the bitset, starting from \p pos, which must be + * \returns 32/64 bits from the bitset, starting from \p pos, which must be * divisible with 32/64. */ gsize @@ -190,7 +190,7 @@ mono_bitset_size (const MonoBitSet *set) { return set->size; } -/* +/* * should test wich version is faster. */ #if 1 @@ -251,7 +251,7 @@ mono_bitset_count (const MonoBitSet *set) { #endif #if 0 -const static int +const static int bitstart_mask [] = { 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8, 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, @@ -283,7 +283,7 @@ my_g_bit_nth_lsf (gsize mask, gint nth_bit) int r; /* This depends on mask != 0 */ __asm__("bsfl %1,%0\n\t" - : "=r" (r) : "g" (mask)); + : "=r" (r) : "g" (mask)); return nth_bit + r; } #elif defined(__x86_64) && defined(__GNUC__) @@ -445,7 +445,7 @@ mono_bitset_find_last (const MonoBitSet *set, gint pos) { if (pos < 0) pos = set->size - 1; - + j = pos / BITS_PER_CHUNK; bit = pos % BITS_PER_CHUNK; @@ -656,10 +656,10 @@ mono_bitset_test_safe (const MonoBitSet *set, guint32 pos) #ifdef TEST_BITSET /* - * Compile with: + * Compile with: * gcc -g -Wall -DTEST_BITSET -o monobitset monobitset.c `pkg-config --cflags --libs glib-2.0` */ -int +int main() { MonoBitSet *set1, *set2, *set3, *set4; int error = 1; @@ -671,14 +671,14 @@ main() { if (mono_bitset_count (set1) != 0) return error; error++; - + mono_bitset_set (set1, 33); if (mono_bitset_count (set1) != 1) return error; error++; /* g_print("should be 33: %d\n", mono_bitset_find_first (set1, 0)); */ - + if (mono_bitset_find_first (set1, 0) != 33) return error; error++; @@ -804,7 +804,7 @@ main() { mono_bitset_free (set4); g_print ("total tests passed: %d\n", error - 1); - + return 0; } diff --git a/src/mono/mono/utils/monobitset.h b/src/mono/mono/utils/monobitset.h index 3e89eac3bc535..5a71dcb4a146b 100644 --- a/src/mono/mono/utils/monobitset.h +++ b/src/mono/mono/utils/monobitset.h @@ -75,7 +75,7 @@ MONO_API MonoBitSet* mono_bitset_new (guint32 max_size, guint32 flags); MONO_API MonoBitSet* mono_bitset_mem_new (gpointer mem, guint32 max_size, guint32 flags); -MONO_API void mono_bitset_free (MonoBitSet *set); +MONO_API void mono_bitset_free (MonoBitSet *set); MONO_API void mono_bitset_set (MonoBitSet *set, guint32 pos); diff --git a/src/mono/mono/utils/networking-fallback.c b/src/mono/mono/utils/networking-fallback.c index 1b31ae503c695..0c3b47adaf340 100644 --- a/src/mono/mono/utils/networking-fallback.c +++ b/src/mono/mono/utils/networking-fallback.c @@ -16,7 +16,7 @@ #include #endif -#if !defined (HAVE_GETADDRINFO) +#if !defined (HAVE_GETADDRINFO) #if defined (HAVE_GETHOSTBYNAME) || defined (HAVE_GETHOSTBYNAME2) @@ -71,7 +71,7 @@ mono_get_address_info (const char *hostname, int port, int flags, MonoAddressInf if (!addr_info->entries) { *result = NULL; mono_free_address_info (addr_info); - return 1; + return 1; } *result = addr_info; diff --git a/src/mono/mono/utils/networking-missing.c b/src/mono/mono/utils/networking-missing.c index 45ccf518a7db1..1f16b4121d7fe 100644 --- a/src/mono/mono/utils/networking-missing.c +++ b/src/mono/mono/utils/networking-missing.c @@ -25,17 +25,17 @@ inet_pton (int family, const char *address, void *inaddrp) if (family == AF_INET) { #ifdef HAVE_INET_ATON struct in_addr inaddr; - + if (!inet_aton (address, &inaddr)) return 0; - + memcpy (inaddrp, &inaddr, sizeof (struct in_addr)); return 1; #else /* assume the system has inet_addr(), if it doesn't have that we're pretty much screwed... */ guint32 inaddr; - + if (!strcmp (address, "255.255.255.255")) { /* special-case hack */ inaddr = 0xffffffff; @@ -47,12 +47,12 @@ inet_pton (int family, const char *address, void *inaddrp) if (inaddr == INADDR_NONE) return 0; } - + memcpy (inaddrp, &inaddr, sizeof (guint32)); return 1; #endif /* HAVE_INET_ATON */ } - + return -1; } diff --git a/src/mono/mono/utils/networking-posix.c b/src/mono/mono/utils/networking-posix.c index 8d79cc637f7bc..64d7a5d8a8d67 100644 --- a/src/mono/mono/utils/networking-posix.c +++ b/src/mono/mono/utils/networking-posix.c @@ -112,7 +112,7 @@ mono_get_address_info (const char *hostname, int port, int flags, MonoAddressInf if (cur->family == PF_INET) { cur->address_len = sizeof (struct in_addr); cur->address.v4 = ((struct sockaddr_in*)res->ai_addr)->sin_addr; -#ifdef HAVE_STRUCT_SOCKADDR_IN6 +#ifdef HAVE_STRUCT_SOCKADDR_IN6 } else if (cur->family == PF_INET6) { cur->address_len = sizeof (struct in6_addr); cur->address.v6 = ((struct sockaddr_in6*)res->ai_addr)->sin6_addr; @@ -131,7 +131,7 @@ mono_get_address_info (const char *hostname, int port, int flags, MonoAddressInf prev->next = cur; else addr_info->entries = cur; - + prev = cur; res = res->ai_next; } diff --git a/src/mono/mono/utils/strenc.c b/src/mono/mono/utils/strenc.c index bb383e10eca2f..f6eb0f4b898c8 100644 --- a/src/mono/mono/utils/strenc.c +++ b/src/mono/mono/utils/strenc.c @@ -50,16 +50,16 @@ gunichar2 *mono_unicode_from_external (const gchar *in, gsize *bytes) gchar *encoding_list; int i; glong lbytes; - + if(in==NULL) { return(NULL); } - + encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS"); if(encoding_list==NULL) { encoding_list = g_strdup(""); } - + encodings=g_strsplit (encoding_list, ":", 0); g_free (encoding_list); for(i=0;encodings[i]!=NULL; i++) { @@ -88,9 +88,9 @@ gunichar2 *mono_unicode_from_external (const gchar *in, gsize *bytes) return((gunichar2 *)res); } } - + g_strfreev (encodings); - + if(g_utf8_validate (in, -1, NULL)) { glong items_written; gunichar2 *unires=g_utf8_to_utf16 (in, -1, NULL, &items_written, NULL); @@ -125,20 +125,20 @@ gchar *mono_utf8_from_external (const gchar *in) gchar **encodings; gchar *encoding_list; int i; - + if(in==NULL) { return(NULL); } - + encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS"); if(encoding_list==NULL) { encoding_list = g_strdup(""); } - + encodings=g_strsplit (encoding_list, ":", 0); g_free (encoding_list); for(i=0;encodings[i]!=NULL; i++) { - + /* "default_locale" is a special case encoding */ if(!strcmp (encodings[i], "default_locale")) { res=g_locale_to_utf8 (in, -1, NULL, NULL, NULL); @@ -156,9 +156,9 @@ gchar *mono_utf8_from_external (const gchar *in) return(res); } } - + g_strfreev (encodings); - + if(g_utf8_validate (in, -1, NULL)) { return(g_strdup (in)); } @@ -184,7 +184,7 @@ gchar *mono_unicode_to_external_checked (const gunichar2 *uni, MonoError *err) gchar *utf8; gchar *encoding_list; GError *gerr = NULL; - + /* Turn the unicode into utf8 to start with, because its * easier to work with gchar * than gunichar2 * */ @@ -194,7 +194,7 @@ gchar *mono_unicode_to_external_checked (const gunichar2 *uni, MonoError *err) g_error_free (gerr); return utf8; } - + encoding_list=g_getenv ("MONO_EXTERNAL_ENCODINGS"); if(encoding_list==NULL) { /* Do UTF8 */ @@ -202,7 +202,7 @@ gchar *mono_unicode_to_external_checked (const gunichar2 *uni, MonoError *err) } else { gchar *res, **encodings; int i; - + encodings=g_strsplit (encoding_list, ":", 0); g_free (encoding_list); for(i=0; encodings[i]!=NULL; i++) { @@ -217,14 +217,14 @@ gchar *mono_unicode_to_external_checked (const gunichar2 *uni, MonoError *err) if(res!=NULL) { g_free (utf8); g_strfreev (encodings); - + return(res); } } - + g_strfreev (encodings); } - + /* Nothing else worked, so just return the utf8 */ return(utf8); } @@ -333,7 +333,7 @@ mono_utf8_validate_and_len_with_bounds (const gchar *source, glong max_bytes, gl while (*ptr != 0) { length = trailingBytesForUTF8 [*ptr] + 1; srcPtr = (guchar*) ptr + length; - + /* since *ptr is not zero we must ensure that we can decode the current char + the byte after srcPtr points to the first byte after the current char.*/ if (srcPtr >= end) { diff --git a/src/mono/mono/utils/valgrind.h b/src/mono/mono/utils/valgrind.h index 0829ac748b7c6..070617915864c 100644 --- a/src/mono/mono/utils/valgrind.h +++ b/src/mono/mono/utils/valgrind.h @@ -21,16 +21,16 @@ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS @@ -52,13 +52,13 @@ the terms of the GNU General Public License, version 2. See the COPYING file in the source distribution for details. - ---------------------------------------------------------------- + ---------------------------------------------------------------- */ /* This file is for inclusion into client (your!) code. - You can use these macros to manipulate and query Valgrind's + You can use these macros to manipulate and query Valgrind's execution inside your own programs. The resulting executables will still run without Valgrind, just a @@ -222,8 +222,8 @@ this is executed not under Valgrind. Args are passed in a memory block, and so there's no intrinsic limit to the number that could be passed, but it's currently five. - - The macro args are: + + The macro args are: _zzq_rlval result lvalue _zzq_default default value (result returned when running on real CPU) _zzq_request request code @@ -250,7 +250,7 @@ || (defined(PLAT_x86_win32) && defined(__GNUC__)) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -314,7 +314,7 @@ typedef #if defined(PLAT_x86_win32) && !defined(__GNUC__) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -388,7 +388,7 @@ valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, || (defined(PLAT_amd64_win64) && defined(__GNUC__)) typedef - struct { + struct { unsigned long long int nraddr; /* where's the code? */ } OrigFn; @@ -460,7 +460,7 @@ typedef #if defined(PLAT_ppc32_linux) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -529,7 +529,7 @@ typedef #if defined(PLAT_ppc64be_linux) typedef - struct { + struct { unsigned long long int nraddr; /* where's the code? */ unsigned long long int r2; /* what tocptr do we need? */ } @@ -685,7 +685,7 @@ typedef #if defined(PLAT_arm_linux) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -753,7 +753,7 @@ typedef #if defined(PLAT_arm64_linux) typedef - struct { + struct { unsigned long long int nraddr; /* where's the code? */ } OrigFn; @@ -898,7 +898,7 @@ typedef #if defined(PLAT_mips32_linux) typedef - struct { + struct { unsigned int nraddr; /* where's the code? */ } OrigFn; @@ -912,7 +912,7 @@ typedef "srl $0, $0, 29\n\t" \ "srl $0, $0, 3\n\t" \ "srl $0, $0, 19\n\t" - + #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ @@ -2161,7 +2161,7 @@ typedef #define VALGRIND_RESTORE_STACK \ "mr 1,28\n\t" -/* These CALL_FN_ macros assume that on ppc32-linux, +/* These CALL_FN_ macros assume that on ppc32-linux, sizeof(unsigned long) == 4. */ #define CALL_FN_W_v(lval, orig) \ @@ -4678,7 +4678,7 @@ typedef #define __CALLER_SAVED_REGS "0","1","2","3","4","5","14", \ "f0","f1","f2","f3","f4","f5","f6","f7" -/* Nb: Although r11 is modified in the asm snippets below (inside +/* Nb: Although r11 is modified in the asm snippets below (inside VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for two reasons: (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not @@ -5128,7 +5128,7 @@ typedef #endif /* PLAT_s390x_linux */ /* ------------------------- mips32-linux ----------------------- */ - + #if defined(PLAT_mips32_linux) /* These regs are trashed by the hidden call. */ @@ -6104,7 +6104,7 @@ typedef #define VG_IS_TOOL_USERREQ(a, b, v) \ (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! +/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! This enum comprises an ABI exported by Valgrind to programs which use client requests. DO NOT CHANGE THE ORDER OF THESE ENTRIES, NOR DELETE ANY -- add new ones at the end. */ @@ -6242,7 +6242,7 @@ VALGRIND_PRINTF(const char *format, ...) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_VALIST_BY_REF, (unsigned long)format, - (unsigned long)&vargs, + (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); @@ -6280,7 +6280,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...) _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, (unsigned long)format, - (unsigned long)&vargs, + (unsigned long)&vargs, 0, 0, 0); #endif va_end(vargs); @@ -6291,7 +6291,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...) /* These requests allow control to move from the simulated CPU to the real CPU, calling an arbitary function. - + Note that the current ThreadId is inserted as the first argument. So this call: @@ -6377,7 +6377,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...) - It marks the block as being addressable and undefined (if 'is_zeroed' is not set), or addressable and defined (if 'is_zeroed' is set). This controls how accesses to the block by the program are handled. - + 'addr' is the start of the usable block (ie. after any redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator can apply redzones -- these are blocks of padding at the start and end of @@ -6385,7 +6385,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...) Valgrind will spot block overruns. `is_zeroed' indicates if the memory is zeroed (or filled with another predictable value), as is the case for calloc(). - + VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a heap block -- that will be used by the client program -- is allocated. It's best to put it at the outermost level of the allocator if possible; From 455551b2ff8f854a3e05a0c1eeb86c71dc849f8f Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Sat, 22 Jan 2022 02:24:10 +0300 Subject: [PATCH 136/308] Delete `GT_DYN_BLK` (#63026) * Import GT_STORE_DYN_BLK directly * Delete GT_DYN_BLK * DynBlk -> StoreDynBlk * Add some tests * Mark tests Pri-1 * Rebase and fix build * Bring back the odd early return --- src/coreclr/jit/assertionprop.cpp | 3 +- src/coreclr/jit/codegenlinear.cpp | 4 +- src/coreclr/jit/compiler.cpp | 3 +- src/coreclr/jit/compiler.h | 31 +--- src/coreclr/jit/compiler.hpp | 13 +- src/coreclr/jit/flowgraph.cpp | 32 +--- src/coreclr/jit/gentree.cpp | 167 +++++------------- src/coreclr/jit/gentree.h | 74 +++----- src/coreclr/jit/gtlist.h | 3 +- src/coreclr/jit/gtstructs.h | 6 +- src/coreclr/jit/importer.cpp | 45 +++-- src/coreclr/jit/lclmorph.cpp | 31 +--- src/coreclr/jit/liveness.cpp | 1 - src/coreclr/jit/lsraarm64.cpp | 1 - src/coreclr/jit/lsraarmarch.cpp | 2 +- src/coreclr/jit/lsraxarch.cpp | 3 +- src/coreclr/jit/morph.cpp | 19 +- src/coreclr/jit/morphblock.cpp | 128 +++++++------- src/coreclr/jit/optimizer.cpp | 1 + src/coreclr/jit/rationalize.cpp | 4 - src/coreclr/jit/ssabuilder.cpp | 2 +- src/coreclr/jit/valuenum.cpp | 38 ++-- .../JIT/Methodical/xxblk/dynblk_order.il | 114 ++++++++++++ .../Methodical/xxblk/dynblk_order_d.ilproj | 12 ++ .../Methodical/xxblk/dynblk_order_ro.ilproj | 13 ++ .../DynBlkNullAssertions.cs | 42 +++++ .../DynBlkNullAssertions.csproj | 13 ++ 27 files changed, 407 insertions(+), 398 deletions(-) create mode 100644 src/tests/JIT/Methodical/xxblk/dynblk_order.il create mode 100644 src/tests/JIT/Methodical/xxblk/dynblk_order_d.ilproj create mode 100644 src/tests/JIT/Methodical/xxblk/dynblk_order_ro.ilproj create mode 100644 src/tests/JIT/opt/AssertionPropagation/DynBlkNullAssertions.cs create mode 100644 src/tests/JIT/opt/AssertionPropagation/DynBlkNullAssertions.csproj diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 51fad24772b47..4e0e708be326c 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2576,7 +2576,6 @@ void Compiler::optAssertionGen(GenTree* tree) case GT_OBJ: case GT_BLK: - case GT_DYN_BLK: case GT_IND: // R-value indirections create non-null assertions, but not all indirections are R-values. // Those under ADDR nodes or on the LHS of ASGs are "locations", and will not end up @@ -4626,9 +4625,9 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, case GT_OBJ: case GT_BLK: - case GT_DYN_BLK: case GT_IND: case GT_NULLCHECK: + case GT_STORE_DYN_BLK: return optAssertionProp_Ind(assertions, tree, stmt); case GT_BOUNDS_CHECK: diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index ff4e0b2d3c285..009c0d9ad41dd 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1912,7 +1912,7 @@ void CodeGen::genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg) } else { - GenTree* sizeNode = blkNode->AsDynBlk()->gtDynamicSize; + GenTree* sizeNode = blkNode->AsStoreDynBlk()->gtDynamicSize; inst_Mov(sizeNode->TypeGet(), sizeReg, sizeNode->GetRegNum(), /* canSkip */ true); } } @@ -2022,7 +2022,7 @@ void CodeGen::genConsumeBlockOp(GenTreeBlk* blkNode, regNumber dstReg, regNumber // in the case where the size is a constant (i.e. it is not GT_STORE_DYN_BLK). if (blkNode->OperGet() == GT_STORE_DYN_BLK) { - genConsumeReg(blkNode->AsDynBlk()->gtDynamicSize); + genConsumeReg(blkNode->AsStoreDynBlk()->gtDynamicSize); } // Next, perform any necessary moves. diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 56701ceb08fad..be0c4393cab8b 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -9389,7 +9389,6 @@ void cTreeFlags(Compiler* comp, GenTree* tree) FALLTHROUGH; case GT_BLK: - case GT_DYN_BLK: case GT_STORE_BLK: case GT_STORE_DYN_BLK: @@ -9742,7 +9741,7 @@ bool Compiler::lvaIsOSRLocal(unsigned varNum) // void Compiler::gtChangeOperToNullCheck(GenTree* tree, BasicBlock* block) { - assert(tree->OperIs(GT_FIELD, GT_IND, GT_OBJ, GT_BLK, GT_DYN_BLK)); + assert(tree->OperIs(GT_FIELD, GT_IND, GT_OBJ, GT_BLK)); tree->ChangeOper(GT_NULLCHECK); tree->ChangeType(TYP_INT); block->bbFlags |= BBF_HAS_NULLCHECK; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index cfee3b00519f5..0d4a9398481fd 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6404,6 +6404,7 @@ class Compiler GenTree* fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE clsHnd, bool isRValue = false); GenTree* fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigned blockWidth, bool isBlkReqd); GenTree* fgMorphCopyBlock(GenTree* tree); + GenTree* fgMorphStoreDynBlock(GenTreeStoreDynBlk* tree); GenTree* fgMorphForRegisterFP(GenTree* tree); GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr); GenTree* fgOptimizeCast(GenTreeCast* cast); @@ -11501,42 +11502,14 @@ class GenTreeVisitor break; } - case GT_DYN_BLK: - { - GenTreeDynBlk* const dynBlock = node->AsDynBlk(); - - GenTree** op1Use = &dynBlock->gtOp1; - GenTree** op2Use = &dynBlock->gtDynamicSize; - - result = WalkTree(op1Use, dynBlock); - if (result == fgWalkResult::WALK_ABORT) - { - return result; - } - result = WalkTree(op2Use, dynBlock); - if (result == fgWalkResult::WALK_ABORT) - { - return result; - } - break; - } - case GT_STORE_DYN_BLK: { - GenTreeDynBlk* const dynBlock = node->AsDynBlk(); + GenTreeStoreDynBlk* const dynBlock = node->AsStoreDynBlk(); GenTree** op1Use = &dynBlock->gtOp1; GenTree** op2Use = &dynBlock->gtOp2; GenTree** op3Use = &dynBlock->gtDynamicSize; - if (TVisitor::UseExecutionOrder) - { - if (dynBlock->IsReverseOp()) - { - std::swap(op1Use, op2Use); - } - } - result = WalkTree(op1Use, dynBlock); if (result == fgWalkResult::WALK_ABORT) { diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 2379c0e0ac6ac..5a7b17f776f2c 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -4347,20 +4347,9 @@ void GenTree::VisitOperands(TVisitor visitor) return; } - case GT_DYN_BLK: - { - GenTreeDynBlk* const dynBlock = this->AsDynBlk(); - if (visitor(dynBlock->gtOp1) == VisitResult::Abort) - { - return; - } - visitor(dynBlock->gtDynamicSize); - return; - } - case GT_STORE_DYN_BLK: { - GenTreeDynBlk* const dynBlock = this->AsDynBlk(); + GenTreeStoreDynBlk* const dynBlock = this->AsStoreDynBlk(); if (visitor(dynBlock->gtOp1) == VisitResult::Abort) { return; diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index ba032045e74b7..21f0f583340a8 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -3910,33 +3910,6 @@ void Compiler::fgSetTreeSeqHelper(GenTree* tree, bool isLIR) return; } - // Special handling for dynamic block ops. - if (tree->OperIs(GT_DYN_BLK, GT_STORE_DYN_BLK)) - { - GenTreeDynBlk* dynBlk = tree->AsDynBlk(); - GenTree* sizeNode = dynBlk->gtDynamicSize; - GenTree* dstAddr = dynBlk->Addr(); - GenTree* src = dynBlk->Data(); - bool isReverse = dynBlk->IsReverseOp(); - - // We either have a DYN_BLK or a STORE_DYN_BLK. If the latter, we have a - // src (the Data to be stored), and isReverse tells us whether to evaluate - // that before dstAddr. - if (isReverse && (src != nullptr)) - { - fgSetTreeSeqHelper(src, isLIR); - } - fgSetTreeSeqHelper(dstAddr, isLIR); - if (!isReverse && (src != nullptr)) - { - fgSetTreeSeqHelper(src, isLIR); - } - fgSetTreeSeqHelper(sizeNode, isLIR); - - fgSetTreeSeqFinish(dynBlk, isLIR); - return; - } - /* Is it a 'simple' unary/binary operator? */ if (kind & GTK_SMPOP) @@ -4108,8 +4081,9 @@ void Compiler::fgSetTreeSeqHelper(GenTree* tree, bool isLIR) break; case GT_STORE_DYN_BLK: - case GT_DYN_BLK: - noway_assert(!"DYN_BLK nodes should be sequenced as a special case"); + fgSetTreeSeqHelper(tree->AsStoreDynBlk()->Addr(), isLIR); + fgSetTreeSeqHelper(tree->AsStoreDynBlk()->Data(), isLIR); + fgSetTreeSeqHelper(tree->AsStoreDynBlk()->gtDynamicSize, isLIR); break; default: diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index ead4be3295769..678a2a60409db 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -258,7 +258,6 @@ void GenTree::InitNodeSize() GenTree::s_gtNodeSizes[GT_FIELD] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_CMPXCHG] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_QMARK] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_DYN_BLK] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_STORE_DYN_BLK] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_INTRINSIC] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_ALLOCOBJ] = TREE_NODE_SZ_LARGE; @@ -320,7 +319,7 @@ void GenTree::InitNodeSize() static_assert_no_msg(sizeof(GenTreeAddrMode) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeObj) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeBlk) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeDynBlk) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeStoreDynBlk) <= TREE_NODE_SZ_LARGE); // *** large node static_assert_no_msg(sizeof(GenTreeRetExpr) <= TREE_NODE_SZ_LARGE); // *** large node static_assert_no_msg(sizeof(GenTreeILOffset) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeClsVar) <= TREE_NODE_SZ_SMALL); @@ -1609,10 +1608,9 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK) Compare(op1->AsCmpXchg()->gtOpComparand, op2->AsCmpXchg()->gtOpComparand); case GT_STORE_DYN_BLK: - case GT_DYN_BLK: - return Compare(op1->AsDynBlk()->Addr(), op2->AsDynBlk()->Addr()) && - Compare(op1->AsDynBlk()->Data(), op2->AsDynBlk()->Data()) && - Compare(op1->AsDynBlk()->gtDynamicSize, op2->AsDynBlk()->gtDynamicSize); + return Compare(op1->AsStoreDynBlk()->Addr(), op2->AsStoreDynBlk()->Addr()) && + Compare(op1->AsStoreDynBlk()->Data(), op2->AsStoreDynBlk()->Data()) && + Compare(op1->AsStoreDynBlk()->gtDynamicSize, op2->AsStoreDynBlk()->gtDynamicSize); default: assert(!"unexpected operator"); @@ -2073,11 +2071,9 @@ unsigned Compiler::gtHashValue(GenTree* tree) break; case GT_STORE_DYN_BLK: - hash = genTreeHashAdd(hash, gtHashValue(tree->AsDynBlk()->Data())); - FALLTHROUGH; - case GT_DYN_BLK: - hash = genTreeHashAdd(hash, gtHashValue(tree->AsDynBlk()->Addr())); - hash = genTreeHashAdd(hash, gtHashValue(tree->AsDynBlk()->gtDynamicSize)); + hash = genTreeHashAdd(hash, gtHashValue(tree->AsStoreDynBlk()->Data())); + hash = genTreeHashAdd(hash, gtHashValue(tree->AsStoreDynBlk()->Addr())); + hash = genTreeHashAdd(hash, gtHashValue(tree->AsStoreDynBlk()->gtDynamicSize)); break; default: @@ -4136,7 +4132,6 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) case GT_IND: case GT_BLK: case GT_OBJ: - case GT_DYN_BLK: // In an indirection, the destination address is evaluated prior to the source. // If we have any side effects on the target indirection, @@ -4645,23 +4640,19 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) break; case GT_STORE_DYN_BLK: - case GT_DYN_BLK: - level = gtSetEvalOrder(tree->AsDynBlk()->Addr()); - costEx = tree->AsDynBlk()->Addr()->GetCostEx(); - costSz = tree->AsDynBlk()->Addr()->GetCostSz(); + level = gtSetEvalOrder(tree->AsStoreDynBlk()->Addr()); + costEx = tree->AsStoreDynBlk()->Addr()->GetCostEx(); + costSz = tree->AsStoreDynBlk()->Addr()->GetCostSz(); - if (oper == GT_STORE_DYN_BLK) - { - lvl2 = gtSetEvalOrder(tree->AsDynBlk()->Data()); - level = max(level, lvl2); - costEx += tree->AsDynBlk()->Data()->GetCostEx(); - costSz += tree->AsDynBlk()->Data()->GetCostSz(); - } + lvl2 = gtSetEvalOrder(tree->AsStoreDynBlk()->Data()); + level = max(level, lvl2); + costEx += tree->AsStoreDynBlk()->Data()->GetCostEx(); + costSz += tree->AsStoreDynBlk()->Data()->GetCostSz(); - lvl2 = gtSetEvalOrder(tree->AsDynBlk()->gtDynamicSize); + lvl2 = gtSetEvalOrder(tree->AsStoreDynBlk()->gtDynamicSize); level = max(level, lvl2); - costEx += tree->AsDynBlk()->gtDynamicSize->GetCostEx(); - costSz += tree->AsDynBlk()->gtDynamicSize->GetCostSz(); + costEx += tree->AsStoreDynBlk()->gtDynamicSize->GetCostEx(); + costSz += tree->AsStoreDynBlk()->gtDynamicSize->GetCostSz(); break; default: @@ -4965,25 +4956,9 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) return false; } - case GT_DYN_BLK: - { - GenTreeDynBlk* const dynBlock = this->AsDynBlk(); - if (operand == dynBlock->gtOp1) - { - *pUse = &dynBlock->gtOp1; - return true; - } - if (operand == dynBlock->gtDynamicSize) - { - *pUse = &dynBlock->gtDynamicSize; - return true; - } - return false; - } - case GT_STORE_DYN_BLK: { - GenTreeDynBlk* const dynBlock = this->AsDynBlk(); + GenTreeStoreDynBlk* const dynBlock = this->AsStoreDynBlk(); if (operand == dynBlock->gtOp1) { *pUse = &dynBlock->gtOp1; @@ -5184,7 +5159,8 @@ GenTree* GenTree::gtRetExprVal(BasicBlockFlags* pbbFlags /* = nullptr */) bool GenTree::OperRequiresAsgFlag() { - if (OperIs(GT_ASG) || OperIs(GT_XADD, GT_XORR, GT_XAND, GT_XCHG, GT_LOCKADD, GT_CMPXCHG, GT_MEMORYBARRIER)) + if (OperIs(GT_ASG, GT_STORE_DYN_BLK) || + OperIs(GT_XADD, GT_XORR, GT_XAND, GT_XCHG, GT_LOCKADD, GT_CMPXCHG, GT_MEMORYBARRIER)) { return true; } @@ -5266,7 +5242,6 @@ bool GenTree::OperIsImplicitIndir() const case GT_CMPXCHG: case GT_BLK: case GT_OBJ: - case GT_DYN_BLK: case GT_STORE_BLK: case GT_STORE_OBJ: case GT_STORE_DYN_BLK: @@ -5353,9 +5328,9 @@ bool GenTree::OperMayThrow(Compiler* comp) case GT_IND: case GT_BLK: case GT_OBJ: - case GT_DYN_BLK: - case GT_STORE_BLK: case GT_NULLCHECK: + case GT_STORE_BLK: + case GT_STORE_DYN_BLK: return (((this->gtFlags & GTF_IND_NONFAULTING) == 0) && comp->fgAddrCouldBeNull(this->AsIndir()->Addr())); case GT_ARR_LENGTH: @@ -7430,10 +7405,6 @@ GenTree* Compiler::gtCloneExpr( GenTreeBlk(GT_BLK, tree->TypeGet(), tree->AsBlk()->Addr(), tree->AsBlk()->GetLayout()); break; - case GT_DYN_BLK: - copy = new (this, GT_DYN_BLK) GenTreeDynBlk(tree->AsOp()->gtGetOp1(), tree->AsDynBlk()->gtDynamicSize); - break; - case GT_FIELD: copy = new (this, GT_FIELD) GenTreeField(tree->TypeGet(), tree->AsField()->GetFldObj(), tree->AsField()->gtFldHnd, tree->AsField()->gtFldOffset); @@ -7661,10 +7632,10 @@ GenTree* Compiler::gtCloneExpr( break; case GT_STORE_DYN_BLK: - case GT_DYN_BLK: copy = new (this, oper) - GenTreeDynBlk(gtCloneExpr(tree->AsDynBlk()->Addr(), addFlags, deepVarNum, deepVarVal), - gtCloneExpr(tree->AsDynBlk()->gtDynamicSize, addFlags, deepVarNum, deepVarVal)); + GenTreeStoreDynBlk(gtCloneExpr(tree->AsStoreDynBlk()->Addr(), addFlags, deepVarNum, deepVarVal), + gtCloneExpr(tree->AsStoreDynBlk()->Data(), addFlags, deepVarNum, deepVarVal), + gtCloneExpr(tree->AsStoreDynBlk()->gtDynamicSize, addFlags, deepVarNum, deepVarVal)); break; default: @@ -8348,20 +8319,10 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node) m_advance = &GenTreeUseEdgeIterator::AdvanceArrOffset; return; - case GT_DYN_BLK: - m_edge = &m_node->AsDynBlk()->Addr(); - assert(*m_edge != nullptr); - m_advance = &GenTreeUseEdgeIterator::AdvanceDynBlk; - return; - case GT_STORE_DYN_BLK: - { - GenTreeDynBlk* const dynBlock = m_node->AsDynBlk(); - m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1; + m_edge = &m_node->AsStoreDynBlk()->Addr(); assert(*m_edge != nullptr); - m_advance = &GenTreeUseEdgeIterator::AdvanceStoreDynBlk; - } return; case GT_CALL: @@ -8439,28 +8400,16 @@ void GenTreeUseEdgeIterator::AdvanceArrOffset() assert(*m_edge != nullptr); } -//------------------------------------------------------------------------ -// GenTreeUseEdgeIterator::AdvanceDynBlk: produces the next operand of a DynBlk node and advances the state. -// -void GenTreeUseEdgeIterator::AdvanceDynBlk() -{ - GenTreeDynBlk* const dynBlock = m_node->AsDynBlk(); - - m_edge = &dynBlock->gtDynamicSize; - assert(*m_edge != nullptr); - m_advance = &GenTreeUseEdgeIterator::Terminate; -} - //------------------------------------------------------------------------ // GenTreeUseEdgeIterator::AdvanceStoreDynBlk: produces the next operand of a StoreDynBlk node and advances the state. // void GenTreeUseEdgeIterator::AdvanceStoreDynBlk() { - GenTreeDynBlk* const dynBlock = m_node->AsDynBlk(); + GenTreeStoreDynBlk* const dynBlock = m_node->AsStoreDynBlk(); switch (m_state) { case 0: - m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2; + m_edge = &dynBlock->Data(); m_state = 1; break; case 1: @@ -9252,7 +9201,6 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, _In_ _In_opt_ case GT_LEA: case GT_BLK: case GT_OBJ: - case GT_DYN_BLK: case GT_STORE_BLK: case GT_STORE_OBJ: case GT_STORE_DYN_BLK: @@ -11071,7 +11019,6 @@ void Compiler::gtDispTree(GenTree* tree, break; case GT_STORE_DYN_BLK: - case GT_DYN_BLK: if (tree->OperIsCopyBlkOp()) { printf(" (copy)"); @@ -11084,12 +11031,12 @@ void Compiler::gtDispTree(GenTree* tree, if (!topOnly) { - if (tree->AsDynBlk()->Data() != nullptr) + gtDispChild(tree->AsStoreDynBlk()->Addr(), indentStack, IIArc, nullptr, topOnly); + if (tree->AsStoreDynBlk()->Data() != nullptr) { - gtDispChild(tree->AsDynBlk()->Data(), indentStack, IIArc, nullptr, topOnly); + gtDispChild(tree->AsStoreDynBlk()->Data(), indentStack, IIArc, nullptr, topOnly); } - gtDispChild(tree->AsDynBlk()->Addr(), indentStack, IIArc, nullptr, topOnly); - gtDispChild(tree->AsDynBlk()->gtDynamicSize, indentStack, IIArcBottom, nullptr, topOnly); + gtDispChild(tree->AsStoreDynBlk()->gtDynamicSize, indentStack, IIArcBottom, nullptr, topOnly); } break; @@ -11482,7 +11429,7 @@ void Compiler::gtDispLIRNode(GenTree* node, const char* prefixMsg /* = nullptr * displayOperand(operand, buf, operandArc, indentStack, prefixIndent); } } - else if (node->OperIsDynBlkOp()) + else if (node->OperIs(GT_STORE_DYN_BLK)) { if (operand == node->AsBlk()->Addr()) { @@ -11494,19 +11441,7 @@ void Compiler::gtDispLIRNode(GenTree* node, const char* prefixMsg /* = nullptr * } else { - assert(operand == node->AsDynBlk()->gtDynamicSize); - displayOperand(operand, "size", operandArc, indentStack, prefixIndent); - } - } - else if (node->OperGet() == GT_DYN_BLK) - { - if (operand == node->AsBlk()->Addr()) - { - displayOperand(operand, "lhs", operandArc, indentStack, prefixIndent); - } - else - { - assert(operand == node->AsDynBlk()->gtDynamicSize); + assert(operand == node->AsStoreDynBlk()->gtDynamicSize); displayOperand(operand, "size", operandArc, indentStack, prefixIndent); } } @@ -14539,14 +14474,14 @@ bool Compiler::gtNodeHasSideEffects(GenTree* tree, GenTreeFlags flags) { if (flags & GTF_ASG) { - // TODO-Cleanup: This only checks for GT_ASG but according to OperRequiresAsgFlag there - // are many more opers that are considered to have an assignment side effect: atomic ops + // TODO-Bug: This only checks for GT_ASG/GT_STORE_DYN_BLK but according to OperRequiresAsgFlag + // there are many more opers that are considered to have an assignment side effect: atomic ops // (GT_CMPXCHG & co.), GT_MEMORYBARRIER (not classified as an atomic op) and HW intrinsic // memory stores. Atomic ops have special handling in gtExtractSideEffList but the others // will simply be dropped is they are ever subject to an "extract side effects" operation. // It is possible that the reason no bugs have yet been observed in this area is that the // other nodes are likely to always be tree roots. - if (tree->OperIs(GT_ASG)) + if (tree->OperIs(GT_ASG, GT_STORE_DYN_BLK)) { return true; } @@ -15272,33 +15207,21 @@ bool GenTree::DefinesLocal(Compiler* comp, GenTreeLclVarCommon** pLclVarTree, bo GenTree* destAddr = blkNode->Addr(); unsigned width = blkNode->Size(); // Do we care about whether this assigns the entire variable? - if (pIsEntire != nullptr && blkNode->OperIs(GT_DYN_BLK)) + if (pIsEntire != nullptr && blkNode->OperIs(GT_STORE_DYN_BLK)) { - GenTree* blockWidth = blkNode->AsDynBlk()->gtDynamicSize; + GenTree* blockWidth = blkNode->AsStoreDynBlk()->gtDynamicSize; if (blockWidth->IsCnsIntOrI()) { - if (blockWidth->IsIconHandle()) - { - // If it's a handle, it must be a class handle. We only create such block operations - // for initialization of struct types, so the type of the argument(s) will match this - // type, by construction, and be "entire". - assert(blockWidth->IsIconHandle(GTF_ICON_CLASS_HDL)); - width = comp->info.compCompHnd->getClassSize( - CORINFO_CLASS_HANDLE(blockWidth->AsIntConCommon()->IconValue())); - } - else + assert(blockWidth->AsIntConCommon()->FitsInI32()); + width = static_cast(blockWidth->AsIntConCommon()->IconValue()); + + if (width == 0) { - ssize_t swidth = blockWidth->AsIntConCommon()->IconValue(); - assert(swidth >= 0); - // cpblk of size zero exists in the wild (in yacc-generated code in SQL) and is valid IL. - if (swidth == 0) - { - return false; - } - width = unsigned(swidth); + return false; } } } + return destAddr->DefinesLocalAddr(comp, width, pLclVarTree, pIsEntire); } // Otherwise... diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 992a2cb1c0f38..085bc17a1e510 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1235,12 +1235,10 @@ struct GenTree bool OperIsBlkOp(); bool OperIsCopyBlkOp(); bool OperIsInitBlkOp(); - bool OperIsDynBlkOp(); static bool OperIsBlk(genTreeOps gtOper) { - return ((gtOper == GT_BLK) || (gtOper == GT_OBJ) || (gtOper == GT_DYN_BLK) || (gtOper == GT_STORE_BLK) || - (gtOper == GT_STORE_OBJ) || (gtOper == GT_STORE_DYN_BLK)); + return (gtOper == GT_BLK) || (gtOper == GT_OBJ) || OperIsStoreBlk(gtOper); } bool OperIsBlk() const @@ -1248,19 +1246,9 @@ struct GenTree return OperIsBlk(OperGet()); } - static bool OperIsDynBlk(genTreeOps gtOper) - { - return ((gtOper == GT_DYN_BLK) || (gtOper == GT_STORE_DYN_BLK)); - } - - bool OperIsDynBlk() const - { - return OperIsDynBlk(OperGet()); - } - static bool OperIsStoreBlk(genTreeOps gtOper) { - return ((gtOper == GT_STORE_BLK) || (gtOper == GT_STORE_OBJ) || (gtOper == GT_STORE_DYN_BLK)); + return StaticOperIs(gtOper, GT_STORE_BLK, GT_STORE_OBJ, GT_STORE_DYN_BLK); } bool OperIsStoreBlk() const @@ -2078,9 +2066,14 @@ struct GenTree SetAllEffectsFlags(source->gtFlags & GTF_ALL_EFFECT); } - void SetAllEffectsFlags(GenTree* source, GenTree* otherSource) + void SetAllEffectsFlags(GenTree* firstSource, GenTree* secondSource) { - SetAllEffectsFlags((source->gtFlags | otherSource->gtFlags) & GTF_ALL_EFFECT); + SetAllEffectsFlags((firstSource->gtFlags | secondSource->gtFlags) & GTF_ALL_EFFECT); + } + + void SetAllEffectsFlags(GenTree* firstSource, GenTree* secondSource, GenTree* thirdSouce) + { + SetAllEffectsFlags((firstSource->gtFlags | secondSource->gtFlags | thirdSouce->gtFlags) & GTF_ALL_EFFECT); } void SetAllEffectsFlags(GenTreeFlags sourceFlags) @@ -2745,7 +2738,6 @@ class GenTreeUseEdgeIterator final void AdvanceCmpXchg(); void AdvanceArrElem(); void AdvanceArrOffset(); - void AdvanceDynBlk(); void AdvanceStoreDynBlk(); void AdvanceFieldList(); void AdvancePhi(); @@ -5985,8 +5977,6 @@ struct GenTreeAddrMode : public GenTreeOp struct GenTreeIndir : public GenTreeOp { // The address for the indirection. - // Since GenTreeDynBlk derives from this, but is an "EXOP" (i.e. it has extra fields), - // we can't access Op1 and Op2 in the normal manner if we may have a DynBlk. GenTree*& Addr() { return gtOp1; @@ -6053,7 +6043,7 @@ struct GenTreeBlk : public GenTreeIndir void SetLayout(ClassLayout* layout) { - assert((layout != nullptr) || OperIs(GT_DYN_BLK, GT_STORE_DYN_BLK)); + assert((layout != nullptr) || OperIs(GT_STORE_DYN_BLK)); m_layout = layout; } @@ -6070,7 +6060,7 @@ struct GenTreeBlk : public GenTreeIndir // The size of the buffer to be copied. unsigned Size() const { - assert((m_layout != nullptr) || OperIs(GT_DYN_BLK, GT_STORE_DYN_BLK)); + assert((m_layout != nullptr) || OperIs(GT_STORE_DYN_BLK)); return (m_layout != nullptr) ? m_layout->GetSize() : 0; } @@ -6108,7 +6098,7 @@ struct GenTreeBlk : public GenTreeIndir #endif { assert(OperIsBlk(oper)); - assert((layout != nullptr) || OperIs(GT_DYN_BLK, GT_STORE_DYN_BLK)); + assert((layout != nullptr) || OperIs(GT_STORE_DYN_BLK)); gtFlags |= (addr->gtFlags & GTF_ALL_EFFECT); } @@ -6121,7 +6111,7 @@ struct GenTreeBlk : public GenTreeIndir #endif { assert(OperIsBlk(oper)); - assert((layout != nullptr) || OperIs(GT_DYN_BLK, GT_STORE_DYN_BLK)); + assert((layout != nullptr) || OperIs(GT_STORE_DYN_BLK)); gtFlags |= (addr->gtFlags & GTF_ALL_EFFECT); gtFlags |= (data->gtFlags & GTF_ALL_EFFECT); } @@ -6170,28 +6160,33 @@ struct GenTreeObj : public GenTreeBlk #endif }; -// gtDynBlk -- 'dynamic block' (GT_DYN_BLK). +// GenTreeStoreDynBlk -- 'dynamic block store' (GT_STORE_DYN_BLK). // -// This node is used for block values that have a dynamic size. -// Note that such a value can never have GC pointers. - -struct GenTreeDynBlk : public GenTreeBlk +// This node is used to represent stores that have a dynamic size - the "cpblk" and "initblk" +// IL instructions are implemented with it. Note that such stores assume the input has no GC +// pointers in it, and as such do not ever use write barriers. +// +// The "Data()" member of this node will either be a "dummy" IND(struct) node, for "cpblk", or +// the zero constant/INIT_VAL for "initblk". +// +struct GenTreeStoreDynBlk : public GenTreeBlk { public: GenTree* gtDynamicSize; - GenTreeDynBlk(GenTree* addr, GenTree* dynamicSize) - : GenTreeBlk(GT_DYN_BLK, TYP_STRUCT, addr, nullptr), gtDynamicSize(dynamicSize) + GenTreeStoreDynBlk(GenTree* dstAddr, GenTree* data, GenTree* dynamicSize) + : GenTreeBlk(GT_STORE_DYN_BLK, TYP_VOID, dstAddr, data, nullptr), gtDynamicSize(dynamicSize) { - // Conservatively the 'addr' could be null or point into the global heap. - gtFlags |= GTF_EXCEPT | GTF_GLOB_REF; + // Conservatively the 'dstAddr' could be null or point into the global heap. + // Likewise, this is a store and so must be marked with the GTF_ASG flag. + gtFlags |= (GTF_ASG | GTF_EXCEPT | GTF_GLOB_REF); gtFlags |= (dynamicSize->gtFlags & GTF_ALL_EFFECT); } #if DEBUGGABLE_GENTREE protected: friend GenTree; - GenTreeDynBlk() : GenTreeBlk() + GenTreeStoreDynBlk() : GenTreeBlk() { } #endif // DEBUGGABLE_GENTREE @@ -7493,19 +7488,6 @@ inline bool GenTree::OperIsBlkOp() return ((gtOper == GT_ASG) && varTypeIsStruct(AsOp()->gtOp1)) || OperIsStoreBlk(); } -inline bool GenTree::OperIsDynBlkOp() -{ - if (gtOper == GT_ASG) - { - return gtGetOp1()->OperGet() == GT_DYN_BLK; - } - else if (gtOper == GT_STORE_DYN_BLK) - { - return true; - } - return false; -} - inline bool GenTree::OperIsInitBlkOp() { if (!OperIsBlkOp()) diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h index 5a5afe6aad050..9b40861fef0fd 100644 --- a/src/coreclr/jit/gtlist.h +++ b/src/coreclr/jit/gtlist.h @@ -90,8 +90,7 @@ GTNODE(OBJ , GenTreeObj ,0,(GTK_UNOP|GTK_EXOP)) GTNODE(STORE_OBJ , GenTreeObj ,0,(GTK_BINOP|GTK_EXOP|GTK_NOVALUE)) // Object that MAY have gc pointers, and thus includes the relevant gc layout info. GTNODE(BLK , GenTreeBlk ,0,(GTK_UNOP|GTK_EXOP)) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) GTNODE(STORE_BLK , GenTreeBlk ,0,(GTK_BINOP|GTK_EXOP|GTK_NOVALUE)) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) -GTNODE(DYN_BLK , GenTreeDynBlk ,0,GTK_SPECIAL) // Dynamically sized block object -GTNODE(STORE_DYN_BLK , GenTreeDynBlk ,0,(GTK_SPECIAL|GTK_NOVALUE)) // Dynamically sized block object +GTNODE(STORE_DYN_BLK , GenTreeStoreDynBlk ,0,(GTK_SPECIAL|GTK_NOVALUE)) // Dynamically sized block store GTNODE(BOX , GenTreeBox ,0,(GTK_UNOP|GTK_EXOP|GTK_NOTLIR)) GTNODE(FIELD , GenTreeField ,0,(GTK_UNOP|GTK_EXOP)) // Member-field diff --git a/src/coreclr/jit/gtstructs.h b/src/coreclr/jit/gtstructs.h index 591753837fe89..6373011779020 100644 --- a/src/coreclr/jit/gtstructs.h +++ b/src/coreclr/jit/gtstructs.h @@ -92,14 +92,14 @@ GTSTRUCT_2(ClsVar , GT_CLS_VAR, GT_CLS_VAR_ADDR) GTSTRUCT_1(ArgPlace , GT_ARGPLACE) GTSTRUCT_1(CmpXchg , GT_CMPXCHG) GTSTRUCT_1(AddrMode , GT_LEA) -GTSTRUCT_N(Blk , GT_BLK, GT_STORE_BLK, GT_OBJ, GT_STORE_OBJ, GT_DYN_BLK, GT_STORE_DYN_BLK) +GTSTRUCT_N(Blk , GT_BLK, GT_STORE_BLK, GT_OBJ, GT_STORE_OBJ, GT_STORE_DYN_BLK) GTSTRUCT_2(Obj , GT_OBJ, GT_STORE_OBJ) -GTSTRUCT_2(DynBlk , GT_DYN_BLK, GT_STORE_DYN_BLK) +GTSTRUCT_1(StoreDynBlk , GT_STORE_DYN_BLK) GTSTRUCT_1(Qmark , GT_QMARK) GTSTRUCT_1(PhiArg , GT_PHI_ARG) GTSTRUCT_1(Phi , GT_PHI) GTSTRUCT_1(StoreInd , GT_STOREIND) -GTSTRUCT_N(Indir , GT_STOREIND, GT_IND, GT_NULLCHECK, GT_BLK, GT_STORE_BLK, GT_OBJ, GT_STORE_OBJ, GT_DYN_BLK, GT_STORE_DYN_BLK) +GTSTRUCT_N(Indir , GT_STOREIND, GT_IND, GT_NULLCHECK, GT_BLK, GT_STORE_BLK, GT_OBJ, GT_STORE_OBJ, GT_STORE_DYN_BLK) #if FEATURE_ARG_SPLIT GTSTRUCT_2_SPECIAL(PutArgStk, GT_PUTARG_STK, GT_PUTARG_SPLIT) GTSTRUCT_1(PutArgSplit , GT_PUTARG_SPLIT) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 08597695cf2d4..648b4a8493d2f 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1864,7 +1864,6 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, case GT_OBJ: case GT_BLK: - case GT_DYN_BLK: case GT_ASG: // These should already have the appropriate type. assert(structVal->gtType == structType); @@ -17070,19 +17069,29 @@ void Compiler::impImportBlockCode(BasicBlock* block) op3 = impPopStack().val; // Size op2 = impPopStack().val; // Value - op1 = impPopStack().val; // Dest + op1 = impPopStack().val; // Dst addr if (op3->IsCnsIntOrI()) { size = (unsigned)op3->AsIntConCommon()->IconValue(); op1 = new (this, GT_BLK) GenTreeBlk(GT_BLK, TYP_STRUCT, op1, typGetBlkLayout(size)); + op1 = gtNewBlkOpNode(op1, op2, (prefixFlags & PREFIX_VOLATILE) != 0, false); } else { - op1 = new (this, GT_DYN_BLK) GenTreeDynBlk(op1, op3); + if (!op2->IsIntegralConst(0)) + { + op2 = gtNewOperNode(GT_INIT_VAL, TYP_INT, op2); + } + + op1 = new (this, GT_STORE_DYN_BLK) GenTreeStoreDynBlk(op1, op2, op3); size = 0; + + if ((prefixFlags & PREFIX_VOLATILE) != 0) + { + op1->gtFlags |= GTF_BLK_VOLATILE; + } } - op1 = gtNewBlkOpNode(op1, op2, (prefixFlags & PREFIX_VOLATILE) != 0, false); goto SPILL_APPEND; @@ -17093,29 +17102,35 @@ void Compiler::impImportBlockCode(BasicBlock* block) Verify(false, "bad opcode"); } op3 = impPopStack().val; // Size - op2 = impPopStack().val; // Src - op1 = impPopStack().val; // Dest + op2 = impPopStack().val; // Src addr + op1 = impPopStack().val; // Dst addr - if (op3->IsCnsIntOrI()) + if (op2->OperGet() == GT_ADDR) { - size = (unsigned)op3->AsIntConCommon()->IconValue(); - op1 = new (this, GT_BLK) GenTreeBlk(GT_BLK, TYP_STRUCT, op1, typGetBlkLayout(size)); + op2 = op2->AsOp()->gtOp1; } else { - op1 = new (this, GT_DYN_BLK) GenTreeDynBlk(op1, op3); - size = 0; + op2 = gtNewOperNode(GT_IND, TYP_STRUCT, op2); } - if (op2->OperGet() == GT_ADDR) + + if (op3->IsCnsIntOrI()) { - op2 = op2->AsOp()->gtOp1; + size = (unsigned)op3->AsIntConCommon()->IconValue(); + op1 = new (this, GT_BLK) GenTreeBlk(GT_BLK, TYP_STRUCT, op1, typGetBlkLayout(size)); + op1 = gtNewBlkOpNode(op1, op2, (prefixFlags & PREFIX_VOLATILE) != 0, true); } else { - op2 = gtNewOperNode(GT_IND, TYP_STRUCT, op2); + op1 = new (this, GT_STORE_DYN_BLK) GenTreeStoreDynBlk(op1, op2, op3); + size = 0; + + if ((prefixFlags & PREFIX_VOLATILE) != 0) + { + op1->gtFlags |= GTF_BLK_VOLATILE; + } } - op1 = gtNewBlkOpNode(op1, op2, (prefixFlags & PREFIX_VOLATILE) != 0, true); goto SPILL_APPEND; case CEE_CPOBJ: diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 84d7965d395bf..66684e38e1a3b 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -567,26 +567,6 @@ class LocalAddressVisitor final : public GenTreeVisitor PopValue(); break; - case GT_DYN_BLK: - assert(TopValue(2).Node() == node); - assert(TopValue(1).Node() == node->AsDynBlk()->Addr()); - assert(TopValue(0).Node() == node->AsDynBlk()->gtDynamicSize); - - // The block size may be the result of an indirection so we need - // to escape the location that may be associated with it. - EscapeValue(TopValue(0), node); - - if (!TopValue(2).Indir(TopValue(1))) - { - // If the address comes from another indirection (e.g. DYN_BLK(IND(...)) - // then we need to escape the location. - EscapeLocation(TopValue(1), node); - } - - PopValue(); - PopValue(); - break; - case GT_RETURN: if (TopValue(0).Node() != node) { @@ -829,14 +809,13 @@ class LocalAddressVisitor final : public GenTreeVisitor // user - the node that uses the indirection // // Notes: - // This returns 0 for indirection of unknown size, typically GT_DYN_BLK. - // GT_IND nodes that have type TYP_STRUCT are expected to only appears - // on the RHS of an assignment, in which case the LHS size will be used instead. - // Otherwise 0 is returned as well. + // This returns 0 for indirection of unknown size. GT_IND nodes that have type + // TYP_STRUCT are expected to only appears on the RHS of an assignment, in which + // case the LHS size will be used instead. Otherwise 0 is returned as well. // unsigned GetIndirSize(GenTree* indir, GenTree* user) { - assert(indir->OperIs(GT_IND, GT_OBJ, GT_BLK, GT_DYN_BLK, GT_FIELD)); + assert(indir->OperIs(GT_IND, GT_OBJ, GT_BLK, GT_FIELD)); if (indir->TypeGet() != TYP_STRUCT) { @@ -883,7 +862,7 @@ class LocalAddressVisitor final : public GenTreeVisitor case GT_OBJ: return indir->AsBlk()->GetLayout()->GetSize(); default: - assert(indir->OperIs(GT_IND, GT_DYN_BLK)); + assert(indir->OperIs(GT_IND)); return 0; } } diff --git a/src/coreclr/jit/liveness.cpp b/src/coreclr/jit/liveness.cpp index 4f8d9334249cf..d9592683db798 100644 --- a/src/coreclr/jit/liveness.cpp +++ b/src/coreclr/jit/liveness.cpp @@ -2090,7 +2090,6 @@ void Compiler::fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALAR case GT_BLK: case GT_OBJ: - case GT_DYN_BLK: { bool removed = fgTryRemoveNonLocal(node, &blockRange); if (!removed && node->IsUnusedValue()) diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index 796a9e8126e6f..f18099f4f573e 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -522,7 +522,6 @@ int LinearScan::BuildNode(GenTree* tree) break; case GT_BLK: - case GT_DYN_BLK: // These should all be eliminated prior to Lowering. assert(!"Non-store block node in Lowering"); srcCount = 0; diff --git a/src/coreclr/jit/lsraarmarch.cpp b/src/coreclr/jit/lsraarmarch.cpp index f85cb81d9e8c3..a8db1264b64af 100644 --- a/src/coreclr/jit/lsraarmarch.cpp +++ b/src/coreclr/jit/lsraarmarch.cpp @@ -785,7 +785,7 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) if (blkNode->OperIs(GT_STORE_DYN_BLK)) { useCount++; - BuildUse(blkNode->AsDynBlk()->gtDynamicSize, sizeRegMask); + BuildUse(blkNode->AsStoreDynBlk()->gtDynamicSize, sizeRegMask); } buildInternalRegisterUses(); diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index ce1de0b6f4fde..e679f00b3bca3 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -496,7 +496,6 @@ int LinearScan::BuildNode(GenTree* tree) case GT_OBJ: #endif case GT_BLK: - case GT_DYN_BLK: // These should all be eliminated prior to Lowering. assert(!"Non-store block node in Lowering"); srcCount = 0; @@ -1438,7 +1437,7 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) if (blkNode->OperIs(GT_STORE_DYN_BLK)) { useCount++; - BuildUse(blkNode->AsDynBlk()->gtDynamicSize, sizeRegMask); + BuildUse(blkNode->AsStoreDynBlk()->gtDynamicSize, sizeRegMask); } #ifdef TARGET_X86 diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 48007f56ca860..e7a3db4e80afd 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -11601,7 +11601,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) break; case GT_OBJ: case GT_BLK: - case GT_DYN_BLK: case GT_IND: // A non-null mac here implies this node is part of an address computation (the tree parent is // GT_ADDR). @@ -14971,23 +14970,7 @@ GenTree* Compiler::fgMorphTree(GenTree* tree, MorphAddrContext* mac) break; case GT_STORE_DYN_BLK: - case GT_DYN_BLK: - if (tree->OperGet() == GT_STORE_DYN_BLK) - { - tree->AsDynBlk()->Data() = fgMorphTree(tree->AsDynBlk()->Data()); - } - tree->AsDynBlk()->Addr() = fgMorphTree(tree->AsDynBlk()->Addr()); - tree->AsDynBlk()->gtDynamicSize = fgMorphTree(tree->AsDynBlk()->gtDynamicSize); - - tree->gtFlags &= ~GTF_CALL; - tree->SetIndirExceptionFlags(this); - - if (tree->OperGet() == GT_STORE_DYN_BLK) - { - tree->gtFlags |= tree->AsDynBlk()->Data()->gtFlags & GTF_ALL_EFFECT; - } - tree->gtFlags |= tree->AsDynBlk()->Addr()->gtFlags & GTF_ALL_EFFECT; - tree->gtFlags |= tree->AsDynBlk()->gtDynamicSize->gtFlags & GTF_ALL_EFFECT; + tree = fgMorphStoreDynBlock(tree->AsStoreDynBlk()); break; default: diff --git a/src/coreclr/jit/morphblock.cpp b/src/coreclr/jit/morphblock.cpp index 4dd0325c480f6..d725923478433 100644 --- a/src/coreclr/jit/morphblock.cpp +++ b/src/coreclr/jit/morphblock.cpp @@ -26,7 +26,6 @@ class MorphInitBlockHelper static GenTree* MorphBlock(Compiler* comp, GenTree* tree, bool isDest); static GenTree* MorphCommaBlock(Compiler* comp, GenTreeOp* firstComma); - static GenTreeBlk* MorphDynamicBlock(Compiler* comp, GenTreeDynBlk* dynBlock); protected: Compiler* m_comp; @@ -36,9 +35,7 @@ class MorphInitBlockHelper GenTree* m_dst = nullptr; GenTree* m_src = nullptr; - unsigned m_blockSize = 0; - bool m_blockSizeIsConst = false; - + unsigned m_blockSize = 0; unsigned m_dstLclNum = BAD_VAR_NUM; GenTreeLclVarCommon* m_dstLclNode = nullptr; LclVarDsc* m_dstVarDsc = nullptr; @@ -212,9 +209,8 @@ void MorphInitBlockHelper::PrepareDst() if (m_dst->IsLocal()) { - m_dstLclNode = m_dst->AsLclVarCommon(); - m_dstVarDsc = m_comp->lvaGetDesc(m_dstLclNode); - m_blockSizeIsConst = true; + m_dstLclNode = m_dst->AsLclVarCommon(); + m_dstVarDsc = m_comp->lvaGetDesc(m_dstLclNode); if (m_dst->OperIs(GT_LCL_VAR)) { @@ -248,21 +244,19 @@ void MorphInitBlockHelper::PrepareDst() else { assert(m_dst == m_dst->gtEffectiveVal() && "the commas were skipped in MorphBlock"); - assert(m_dst->OperIs(GT_IND, GT_BLK, GT_OBJ, GT_DYN_BLK)); + assert(m_dst->OperIs(GT_IND, GT_BLK, GT_OBJ)); GenTree* dstAddr = m_dst->AsIndir()->Addr(); if (m_dst->OperGet() == GT_IND) { assert(m_dst->TypeGet() != TYP_STRUCT); - m_blockSize = genTypeSize(m_dst); - m_blockSizeIsConst = true; + m_blockSize = genTypeSize(m_dst); } else { assert(m_dst->OperIsBlk()); - GenTreeBlk* blk = m_dst->AsBlk(); - m_blockSize = blk->Size(); - m_blockSizeIsConst = !blk->OperIs(GT_DYN_BLK); + GenTreeBlk* blk = m_dst->AsBlk(); + m_blockSize = blk->Size(); } noway_assert(dstAddr->TypeIs(TYP_BYREF, TYP_I_IMPL)); @@ -444,22 +438,10 @@ GenTree* MorphInitBlockHelper::MorphBlock(Compiler* comp, GenTree* tree, bool is return tree; } - GenTreeBlk* blkNode = tree->AsBlk(); - if (blkNode->OperIs(GT_DYN_BLK)) - { - blkNode = MorphDynamicBlock(comp, blkNode->AsDynBlk()); - if (blkNode->OperIs(GT_DYN_BLK)) - { - JITDUMP("MorphBlock after:\n"); - DISPTREE(blkNode); - return blkNode; - } - } - - GenTree* blkAddr = blkNode->Addr(); + GenTree* blkAddr = tree->AsBlk()->Addr(); assert(blkAddr != nullptr); assert(blkAddr->TypeIs(TYP_I_IMPL, TYP_BYREF, TYP_REF)); - // GT_ADDR, GT_LCL_VAR/FLD, GT_ADD, GT_COMMA, GT_CALL, GT_CNST_INT, GT_LCL_VAR/FLD_ADDR + // GT_ADDR, GT_LCL_VAR/FLD, GT_ADD, GT_COMMA, GT_CALL, GT_CNS_INT, GT_LCL_VAR/FLD_ADDR JITDUMP("MorphBlock after:\n"); DISPTREE(tree); @@ -539,41 +521,6 @@ GenTree* MorphInitBlockHelper::MorphCommaBlock(Compiler* comp, GenTreeOp* firstC return res; } -//------------------------------------------------------------------------ -// MorphDynamicBlock: tries to transform a dynamic block as a const block. -// -// static -GenTreeBlk* MorphInitBlockHelper::MorphDynamicBlock(Compiler* comp, GenTreeDynBlk* dynBlock) -{ - if (dynBlock->gtDynamicSize->IsCnsIntOrI()) - { - GenTreeIntCon* dynSize = dynBlock->gtDynamicSize->AsIntCon(); - assert(dynSize->FitsInI32()); - unsigned size = static_cast(dynSize->IconValue()); - // A GT_BLK with size of zero is not supported, - // so if we encounter such a thing we just leave it as a GT_DYN_BLK - if (size != 0) - { - dynBlock->gtDynamicSize = nullptr; - GenTreeBlk* blkNode = dynBlock; - blkNode->ChangeOper(GT_BLK); - blkNode->SetLayout(comp->typGetBlkLayout(size)); - JITDUMP("MorphDynamicBlock: DYN_BLK was morphed into BLK:\n"); - return blkNode; - } - else - { - JITDUMP("MorphDynamicBlock: DYN_BLK with zero size can't be morphed:\n"); - return dynBlock; - } - } - else - { - JITDUMP("MorphDynamicBlock: DYN_BLK with non-const size can't be morphed:\n"); - return dynBlock; - } -} - class MorphCopyBlockHelper : public MorphInitBlockHelper { public: @@ -745,7 +692,7 @@ void MorphCopyBlockHelper::MorphStructCases() if (m_dstVarDsc != nullptr) { - if (m_dstVarDsc->lvPromoted && m_blockSizeIsConst) + if (m_dstVarDsc->lvPromoted) { noway_assert(varTypeIsStruct(m_dstVarDsc)); noway_assert(!m_comp->opts.MinOpts()); @@ -765,7 +712,7 @@ void MorphCopyBlockHelper::MorphStructCases() if (m_srcVarDsc != nullptr) { - if (m_srcVarDsc->lvPromoted && m_blockSizeIsConst) + if (m_srcVarDsc->lvPromoted) { noway_assert(varTypeIsStruct(m_srcVarDsc)); noway_assert(!m_comp->opts.MinOpts()); @@ -912,7 +859,7 @@ void MorphCopyBlockHelper::MorphStructCases() // [000085] -A---------- = long // [000083] D------N---- lclVar long V17 tmp9 // - if (m_blockSizeIsConst && (m_dstVarDsc->lvFieldCnt == 1) && (m_srcVarDsc != nullptr) && + if ((m_dstVarDsc->lvFieldCnt == 1) && (m_srcVarDsc != nullptr) && (m_blockSize == genTypeSize(m_srcVarDsc->TypeGet()))) { // Reject the following tree: @@ -950,7 +897,7 @@ void MorphCopyBlockHelper::MorphStructCases() // [000243] -----+------ \--* addr byref // [000242] D----+-N---- \--* lclVar byref V28 tmp19 // - if (m_blockSizeIsConst && (m_srcVarDsc->lvFieldCnt == 1) && (m_dstVarDsc != nullptr) && + if ((m_srcVarDsc->lvFieldCnt == 1) && (m_dstVarDsc != nullptr) && (m_blockSize == genTypeSize(m_dstVarDsc->TypeGet()))) { // Check for type agreement @@ -1259,7 +1206,7 @@ GenTree* MorphCopyBlockHelper::CopyFieldByField() // Is the address of a local? GenTreeLclVarCommon* lclVarTree = nullptr; bool isEntire = false; - bool* pIsEntire = (m_blockSizeIsConst ? &isEntire : nullptr); + bool* pIsEntire = &isEntire; if (dstAddrClone->DefinesLocalAddr(m_comp, m_blockSize, &lclVarTree, pIsEntire)) { lclVarTree->gtFlags |= GTF_VAR_DEF; @@ -1532,3 +1479,50 @@ GenTree* Compiler::fgMorphInitBlock(GenTree* tree) { return MorphInitBlockHelper::MorphInitBlock(this, tree); } + +//------------------------------------------------------------------------ +// fgMorphStoreDynBlock: Morph a dynamic block store (GT_STORE_DYN_BLK). +// +// Performs full (pre-order and post-order) morphing for a STORE_DYN_BLK. +// +// Arguments: +// tree - The GT_STORE_DYN_BLK tree to morph. +// +// Return Value: +// In case the size turns into a constant - the store, transformed +// into an "ordinary" ASG(BLK, Data()) one, and further morphed by +// "fgMorphInitBlock"/"fgMorphCopyBlock". Otherwise, the original +// tree (fully morphed). +// +GenTree* Compiler::fgMorphStoreDynBlock(GenTreeStoreDynBlk* tree) +{ + tree->Addr() = fgMorphTree(tree->Addr()); + tree->Data() = fgMorphTree(tree->Data()); + tree->gtDynamicSize = fgMorphTree(tree->gtDynamicSize); + + if (tree->gtDynamicSize->IsIntegralConst()) + { + int64_t size = tree->gtDynamicSize->AsIntConCommon()->IntegralValue(); + assert(FitsIn(size)); + + if (size != 0) + { + GenTree* lhs = gtNewBlockVal(tree->Addr(), static_cast(size)); + lhs->SetIndirExceptionFlags(this); + + GenTree* asg = gtNewAssignNode(lhs, tree->Data()); + asg->gtFlags |= (tree->gtFlags & (GTF_ALL_EFFECT | GTF_BLK_VOLATILE | GTF_BLK_UNALIGNED)); + INDEBUG(asg->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); + + JITDUMP("MorphStoreDynBlock: trasformed STORE_DYN_BLK into ASG(BLK, Data())\n"); + + return tree->OperIsCopyBlkOp() ? fgMorphCopyBlock(asg) : fgMorphInitBlock(asg); + } + } + + tree->SetAllEffectsFlags(tree->Addr(), tree->Data(), tree->gtDynamicSize); + tree->SetIndirExceptionFlags(this); + tree->gtFlags |= GTF_ASG; + + return tree; +} diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index a6c9ea4d85c68..d633a6d84aecd 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -7965,6 +7965,7 @@ bool Compiler::optComputeLoopSideEffectsOfBlock(BasicBlock* blk) case GT_XCHG: case GT_CMPXCHG: case GT_MEMORYBARRIER: + case GT_STORE_DYN_BLK: { memoryHavoc |= memoryKindSet(GcHeap, ByrefExposed); } diff --git a/src/coreclr/jit/rationalize.cpp b/src/coreclr/jit/rationalize.cpp index 18503a4ce3c53..72c1591c6d425 100644 --- a/src/coreclr/jit/rationalize.cpp +++ b/src/coreclr/jit/rationalize.cpp @@ -465,7 +465,6 @@ void Rationalizer::RewriteAssignment(LIR::Use& use) case GT_BLK: case GT_OBJ: - case GT_DYN_BLK: { assert(varTypeIsStruct(location)); GenTreeBlk* storeBlk = location->AsBlk(); @@ -478,9 +477,6 @@ void Rationalizer::RewriteAssignment(LIR::Use& use) case GT_OBJ: storeOper = GT_STORE_OBJ; break; - case GT_DYN_BLK: - storeOper = GT_STORE_DYN_BLK; - break; default: unreached(); } diff --git a/src/coreclr/jit/ssabuilder.cpp b/src/coreclr/jit/ssabuilder.cpp index 4646769263d37..48fe4d84d9aec 100644 --- a/src/coreclr/jit/ssabuilder.cpp +++ b/src/coreclr/jit/ssabuilder.cpp @@ -732,7 +732,7 @@ void SsaBuilder::RenameDef(GenTreeOp* asgNode, BasicBlock* block) // This is perhaps temporary -- maybe should be done elsewhere. Label GT_INDs on LHS of assignments, so we // can skip these during (at least) value numbering. GenTree* lhs = asgNode->gtGetOp1()->gtEffectiveVal(/*commaOnly*/ true); - if (lhs->OperIs(GT_IND, GT_OBJ, GT_BLK, GT_DYN_BLK)) + if (lhs->OperIs(GT_IND, GT_OBJ, GT_BLK)) { lhs->gtFlags |= GTF_IND_ASG_LHS; } diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 9fc0cefa30089..356124ab00e5c 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -6208,7 +6208,7 @@ void ValueNumStore::vnDumpZeroObj(Compiler* comp, VNFuncApp* zeroObj) static UINT8 vnfOpAttribs[VNF_COUNT]; static genTreeOps genTreeOpsIllegalAsVNFunc[] = {GT_IND, // When we do heap memory. GT_NULLCHECK, GT_QMARK, GT_COLON, GT_LOCKADD, GT_XADD, GT_XCHG, - GT_CMPXCHG, GT_LCLHEAP, GT_BOX, GT_XORR, GT_XAND, + GT_CMPXCHG, GT_LCLHEAP, GT_BOX, GT_XORR, GT_XAND, GT_STORE_DYN_BLK, // These need special semantics: GT_COMMA, // == second argument (but with exception(s) from first). @@ -9297,6 +9297,30 @@ void Compiler::fgValueNumberTree(GenTree* tree) break; #endif // FEATURE_HW_INTRINSICS + case GT_STORE_DYN_BLK: + { + // Conservatively, mutate the heaps - we don't analyze these rare stores. + // Likewise, any locals possibly defined by them we mark as address-exposed. + fgMutateGcHeap(tree DEBUGARG("dynamic block store")); + + GenTreeStoreDynBlk* store = tree->AsStoreDynBlk(); + ValueNumPair vnpExcSet = ValueNumStore::VNPForEmptyExcSet(); + + // Propagate the exceptions... + vnpExcSet = vnStore->VNPUnionExcSet(store->Addr()->gtVNPair, vnpExcSet); + vnpExcSet = vnStore->VNPUnionExcSet(store->Data()->gtVNPair, vnpExcSet); + vnpExcSet = vnStore->VNPUnionExcSet(store->gtDynamicSize->gtVNPair, vnpExcSet); + + // This is a store, it produces no value. Thus we use VNPForVoid(). + store->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), vnpExcSet); + + // Note that we are only adding the exception for the destination address. + // Currently, "Data()" is an explicit indirection in case this is a "cpblk". + assert(store->Data()->gtEffectiveVal()->OperIsIndir() || store->OperIsInitBlkOp()); + fgValueNumberAddExceptionSetForIndirection(store, store->Addr()); + break; + } + case GT_CMPXCHG: // Specialop { // For CMPXCHG and other intrinsics add an arbitrary side effect on GcHeap/ByrefExposed. @@ -9349,17 +9373,6 @@ void Compiler::fgValueNumberTree(GenTree* tree) } break; - // DYN_BLK is always an L-value. - case GT_DYN_BLK: - assert(!tree->CanCSE()); - tree->gtVNPair = vnStore->VNPForVoid(); - tree->gtVNPair = - vnStore->VNPWithExc(tree->gtVNPair, vnStore->VNPExceptionSet(tree->AsDynBlk()->Addr()->gtVNPair)); - tree->gtVNPair = - vnStore->VNPWithExc(tree->gtVNPair, - vnStore->VNPExceptionSet(tree->AsDynBlk()->gtDynamicSize->gtVNPair)); - break; - // FIELD_LIST is an R-value that we currently don't model. case GT_FIELD_LIST: tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet())); @@ -10985,7 +10998,6 @@ void Compiler::fgValueNumberAddExceptionSet(GenTree* tree) case GT_IND: case GT_BLK: case GT_OBJ: - case GT_DYN_BLK: case GT_NULLCHECK: fgValueNumberAddExceptionSetForIndirection(tree, tree->AsIndir()->Addr()); break; diff --git a/src/tests/JIT/Methodical/xxblk/dynblk_order.il b/src/tests/JIT/Methodical/xxblk/dynblk_order.il new file mode 100644 index 0000000000000..f4d24714c31ad --- /dev/null +++ b/src/tests/JIT/Methodical/xxblk/dynblk_order.il @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Tests that cpblk/initblk importation sastifies ordering constraints. + +.assembly extern System.Runtime { } +.assembly extern System.Console { } +.assembly extern xunit.core {} + +.assembly DynBlkOrder {} + +.typedef [System.Runtime]System.OverflowException as OverflowException +.typedef [System.Runtime]System.IndexOutOfRangeException as IndexOutOfRangeException + +.class DynBlkOrder extends [System.Runtime]System.Object +{ + .method static int32 Main() + { + .custom instance void [xunit.core]Xunit.FactAttribute::.ctor() = ( + 01 00 00 00 + ) + .entrypoint + .locals (void* dst, void*[] srcArr, int32 srcIdx, int32 size) + + ldloca dst + ldloca srcArr + ldloca srcIdx + ldloca size + call void DynBlkOrder::InitValues(void*&, void*[]&, int32&, int32&) + + .try + { + ldloc dst + ldloc srcArr + ldloc srcIdx + ldelem.i + ldloc size + conv.ovf.u + cpblk + + leave FAIL + } + catch IndexOutOfRangeException + { + leave INITBLK + } + catch OverflowException + { + leave FAIL1 + } + + INITBLK: + .try + { + ldloc dst + ldloc srcArr + ldloc srcIdx + ldelem.i + conv.i4 + ldloc size + conv.ovf.u + initblk + + leave FAIL + } + catch IndexOutOfRangeException + { + leave SUCCESS + } + catch OverflowException + { + leave FAIL2 + } + + SUCCESS: + ldc.i4 100 + ret + + FAIL: + ldc.i4 99 + ret + + FAIL1: + ldc.i4 101 + ret + + FAIL2: + ldc.i4 102 + ret + } + + .method static void InitValues(void*& pSrc, void*[]& pSrcArr, int32& pSrcIdx, int32& pSize) noinlining + { + ldarg pSrc + ldc.i4 0 + conv.u + stind.i + + ldarg pSrcArr + ldc.i4 0 + newarr int32 + stind.ref + + ldarg pSrcIdx + ldc.i4 1 + stind.i4 + + ldarg pSize + ldc.i4 -1 + stind.i4 + + ret + } +} diff --git a/src/tests/JIT/Methodical/xxblk/dynblk_order_d.ilproj b/src/tests/JIT/Methodical/xxblk/dynblk_order_d.ilproj new file mode 100644 index 0000000000000..7a8255ed9d1e6 --- /dev/null +++ b/src/tests/JIT/Methodical/xxblk/dynblk_order_d.ilproj @@ -0,0 +1,12 @@ + + + Exe + 1 + + + Full + + + + + diff --git a/src/tests/JIT/Methodical/xxblk/dynblk_order_ro.ilproj b/src/tests/JIT/Methodical/xxblk/dynblk_order_ro.ilproj new file mode 100644 index 0000000000000..1a281b5960752 --- /dev/null +++ b/src/tests/JIT/Methodical/xxblk/dynblk_order_ro.ilproj @@ -0,0 +1,13 @@ + + + Exe + 1 + + + PdbOnly + True + + + + + diff --git a/src/tests/JIT/opt/AssertionPropagation/DynBlkNullAssertions.cs b/src/tests/JIT/opt/AssertionPropagation/DynBlkNullAssertions.cs new file mode 100644 index 0000000000000..22b7c3b94e693 --- /dev/null +++ b/src/tests/JIT/opt/AssertionPropagation/DynBlkNullAssertions.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. + +// "cpblk/initblk" should not generate non-null assertions because the +// indirections they represent may not be realized (in case the "size" +// was zero). + +using System; +using System.Runtime.CompilerServices; + +public class DynBlkNullAssertions +{ + public static int Main() + { + if (!TestCpBlk(ref Unsafe.NullRef(), ref Unsafe.NullRef(), 0)) + { + return 101; + } + if (!TestInitBlk(ref Unsafe.NullRef(), 0, 0)) + { + return 102; + } + + return 100; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestCpBlk(ref byte dst, ref byte src, uint size) + { + Unsafe.CopyBlock(ref dst, ref src, size); + + return Unsafe.AreSame(ref dst, ref Unsafe.NullRef()); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestInitBlk(ref byte dst, byte value, uint size) + { + Unsafe.InitBlock(ref dst, value, size); + + return Unsafe.AreSame(ref dst, ref Unsafe.NullRef()); + } +} diff --git a/src/tests/JIT/opt/AssertionPropagation/DynBlkNullAssertions.csproj b/src/tests/JIT/opt/AssertionPropagation/DynBlkNullAssertions.csproj new file mode 100644 index 0000000000000..5d8fe22529764 --- /dev/null +++ b/src/tests/JIT/opt/AssertionPropagation/DynBlkNullAssertions.csproj @@ -0,0 +1,13 @@ + + + Exe + 1 + + + None + True + + + + + From 5851430104caa7114f1841a69d655c3409b03cd9 Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Sat, 22 Jan 2022 04:39:21 +0500 Subject: [PATCH 137/308] Ignore conversion exceptions during dictionary construction (#63792) --- .../src/ConfigurationBinder.cs | 34 +++++++++++-------- .../ConfigurationCollectionBindingTests.cs | 17 ++++++++++ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs index bec1c6d44e34e..09d4f271aba72 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs @@ -461,24 +461,30 @@ private static void BindDictionary( PropertyInfo setter = dictionaryType.GetProperty("Item", DeclaredOnlyLookup)!; foreach (IConfigurationSection child in config.GetChildren()) { - object? item = BindInstance( - type: valueType, - instance: null, - config: child, - options: options); - if (item != null) + try { - if (keyType == typeof(string)) - { - string key = child.Key; - setter.SetValue(dictionary, item, new object[] { key }); - } - else if (keyTypeIsEnum) + object? item = BindInstance( + type: valueType, + instance: null, + config: child, + options: options); + if (item != null) { - object key = Enum.Parse(keyType, child.Key); - setter.SetValue(dictionary, item, new object[] { key }); + if (keyType == typeof(string)) + { + string key = child.Key; + setter.SetValue(dictionary, item, new object[] { key }); + } + else if (keyTypeIsEnum) + { + object key = Enum.Parse(keyType, child.Key); + setter.SetValue(dictionary, item, new object[] { key }); + } } } + catch + { + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs index 140aedc7eee35..38ab7766d391d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationCollectionBindingTests.cs @@ -74,6 +74,23 @@ public void GetListInvalidValues() Assert.True(list[0]); } + [Fact] + public void GetDictionaryInvalidValues() + { + var input = new Dictionary + { + {"InvalidDictionary:0", "true"}, + {"InvalidDictionary:1", "invalid"}, + }; + var config = new ConfigurationBuilder().AddInMemoryCollection(input).Build(); + var dict = new Dictionary(); + + config.Bind("InvalidDictionary", dict); + + Assert.Single(dict); + Assert.True(dict["0"]); + } + [Fact] public void BindList() { From 66a4f235e9f82acdc5b94e49b47be6d873088fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Sat, 22 Jan 2022 08:55:56 +0900 Subject: [PATCH 138/308] Extract SuperPMI into a separate component (#64035) Allows building the runtime without SPMI. `build.cmd clr` will still build SPMI. `build.cmd clr.native` will still build SPMI. `build.cmd clr.runtime` will no longer build SPMI. This is mostly motivated by NativeAOT subset builds where SPMI contributes to 10% of the native build time (nativeaot CorecLR subset builds pretty quickly compared to full CoreCLR). --- eng/Subsets.props | 7 ++++++- eng/pipelines/coreclr/templates/build-jit-job.yml | 4 ++-- eng/pipelines/coreclr/templates/build-job.yml | 4 ++-- src/coreclr/build-runtime.cmd | 5 ++++- src/coreclr/build-runtime.sh | 2 +- src/coreclr/components.cmake | 1 + src/coreclr/runtime.proj | 1 + src/coreclr/tools/superpmi/mcs/CMakeLists.txt | 2 +- .../tools/superpmi/superpmi-shim-collector/CMakeLists.txt | 2 +- .../tools/superpmi/superpmi-shim-counter/CMakeLists.txt | 2 +- .../tools/superpmi/superpmi-shim-simple/CMakeLists.txt | 2 +- src/coreclr/tools/superpmi/superpmi/CMakeLists.txt | 2 +- 12 files changed, 22 insertions(+), 12 deletions(-) diff --git a/eng/Subsets.props b/eng/Subsets.props index 772fbfcb99532..5ce5417445136 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -58,7 +58,7 @@ - clr.native+linuxdac+clr.corelib+clr.tools+clr.nativecorelib+clr.packages+clr.nativeaotlibs + clr.native+linuxdac+clr.corelib+clr.tools+clr.nativecorelib+clr.packages+clr.nativeaotlibs+clr.spmi clr.iltools+clr.packages @@ -112,6 +112,7 @@ + @@ -206,6 +207,10 @@ $(ClrRuntimeBuildSubsets);ClrNativeAotSubset=true + + $(ClrRuntimeBuildSubsets);ClrSpmiSubset=true + + diff --git a/eng/pipelines/coreclr/templates/build-jit-job.yml b/eng/pipelines/coreclr/templates/build-jit-job.yml index c251c06f28679..2022a8c53a24f 100644 --- a/eng/pipelines/coreclr/templates/build-jit-job.yml +++ b/eng/pipelines/coreclr/templates/build-jit-job.yml @@ -107,10 +107,10 @@ jobs: # Build CoreCLR JIT - ${{ if ne(parameters.osGroup, 'windows') }}: - - script: $(Build.SourcesDirectory)/src/coreclr/build-runtime$(scriptExt) $(buildConfig) $(archType) $(crossArg) -ci $(compilerArg) -component alljits + - script: $(Build.SourcesDirectory)/src/coreclr/build-runtime$(scriptExt) $(buildConfig) $(archType) $(crossArg) -ci $(compilerArg) -component alljits -component spmi displayName: Build CoreCLR JIT - ${{ if eq(parameters.osGroup, 'windows') }}: - - script: set __TestIntermediateDir=int&&$(Build.SourcesDirectory)/src/coreclr/build-runtime$(scriptExt) $(buildConfig) $(archType) -ci -component alljits + - script: set __TestIntermediateDir=int&&$(Build.SourcesDirectory)/src/coreclr/build-runtime$(scriptExt) $(buildConfig) $(archType) -ci -component alljits -component spmi displayName: Build CoreCLR JIT - ${{ if eq(parameters.uploadAs, 'azureBlob') }}: diff --git a/eng/pipelines/coreclr/templates/build-job.yml b/eng/pipelines/coreclr/templates/build-job.yml index b89cd621eda1e..713882250e627 100644 --- a/eng/pipelines/coreclr/templates/build-job.yml +++ b/eng/pipelines/coreclr/templates/build-job.yml @@ -132,10 +132,10 @@ jobs: value: '' - ${{ if ne(parameters.testGroup, 'innerloop') }}: - name: clrRuntimeComponentsBuildArg - value: '-component runtime -component alljits -component paltests -component nativeaot ' + value: '-component runtime -component alljits -component paltests -component nativeaot -component spmi ' - ${{ if and(eq(parameters.osGroup, 'Linux'), eq(parameters.archType, 'x86')) }}: - name: clrRuntimeComponentsBuildArg - value: '-component runtime -component jit -component iltools ' + value: '-component runtime -component jit -component iltools -component spmi ' - name: pgoInstrumentArg value: '' diff --git a/src/coreclr/build-runtime.cmd b/src/coreclr/build-runtime.cmd index ed9d735a7d428..30cd7d2785267 100644 --- a/src/coreclr/build-runtime.cmd +++ b/src/coreclr/build-runtime.cmd @@ -345,6 +345,9 @@ for /f "delims=" %%a in ("-%__RequestedBuildComponents%-") do ( if not "!string:-nativeaot-=!"=="!string!" ( set __CMakeTarget=!__CMakeTarget! nativeaot ) + if not "!string:-spmi-=!"=="!string!" ( + set __CMakeTarget=!__CMakeTarget! spmi + ) ) if [!__CMakeTarget!] == [] ( set __CMakeTarget=install @@ -745,7 +748,7 @@ echo -all: Builds all configurations and platforms. echo Build architecture: one of -x64, -x86, -arm, -arm64 ^(default: -x64^). echo Build type: one of -Debug, -Checked, -Release ^(default: -Debug^). echo -component ^ : specify this option one or more times to limit components built to those specified. -echo Allowed ^: hosts jit alljits runtime paltests iltools +echo Allowed ^: hosts jit alljits runtime paltests iltools nativeaot spmi echo -enforcepgo: verify after the build that PGO was used for key DLLs, and fail the build if not echo -pgoinstrument: generate instrumented code for profile guided optimization enabled binaries. echo -cmakeargs: user-settable additional arguments passed to CMake. diff --git a/src/coreclr/build-runtime.sh b/src/coreclr/build-runtime.sh index 8d42b92ce95c0..a1e03198ac6df 100755 --- a/src/coreclr/build-runtime.sh +++ b/src/coreclr/build-runtime.sh @@ -22,7 +22,7 @@ usage_list+=("-pgodatapath: path to profile guided optimization data.") usage_list+=("-pgoinstrument: generate instrumented code for profile guided optimization enabled binaries.") usage_list+=("-skipcrossarchnative: Skip building cross-architecture native binaries.") usage_list+=("-staticanalyzer: use scan_build static analyzer.") -usage_list+=("-component: Build individual components instead of the full project. Available options are 'hosts', 'jit', 'runtime', 'paltests', 'alljits', 'iltools', and 'nativeaot'. Can be specified multiple times.") +usage_list+=("-component: Build individual components instead of the full project. Available options are 'hosts', 'jit', 'runtime', 'paltests', 'alljits', 'iltools', 'nativeaot', and 'spmi'. Can be specified multiple times.") setup_dirs_local() { diff --git a/src/coreclr/components.cmake b/src/coreclr/components.cmake index c23a38539247e..3eaa2c966bf32 100644 --- a/src/coreclr/components.cmake +++ b/src/coreclr/components.cmake @@ -6,6 +6,7 @@ add_component(runtime) add_component(paltests paltests_install) add_component(iltools) add_component(nativeaot) +add_component(spmi) # Define coreclr_all as the fallback component and make every component depend on this component. # iltools and paltests should be minimal subsets, so don't add a dependency on coreclr_misc diff --git a/src/coreclr/runtime.proj b/src/coreclr/runtime.proj index 5f062c9af2f40..26801ea8c198c 100644 --- a/src/coreclr/runtime.proj +++ b/src/coreclr/runtime.proj @@ -48,6 +48,7 @@ <_CoreClrBuildArg Condition="'$(ClrAllJitsSubset)' == 'true'" Include="-component alljits" /> <_CoreClrBuildArg Condition="'$(ClrILToolsSubset)' == 'true'" Include="-component iltools" /> <_CoreClrBuildArg Condition="'$(ClrNativeAotSubset)' == 'true'" Include="-component nativeaot" /> + <_CoreClrBuildArg Condition="'$(ClrSpmiSubset)' == 'true'" Include="-component spmi" /> diff --git a/src/coreclr/tools/superpmi/mcs/CMakeLists.txt b/src/coreclr/tools/superpmi/mcs/CMakeLists.txt index 56dcaff658cc5..8ce4c19725082 100644 --- a/src/coreclr/tools/superpmi/mcs/CMakeLists.txt +++ b/src/coreclr/tools/superpmi/mcs/CMakeLists.txt @@ -68,4 +68,4 @@ else() endif(CLR_CMAKE_HOST_UNIX) -install_clr(TARGETS mcs DESTINATIONS .) +install_clr(TARGETS mcs DESTINATIONS . COMPONENT spmi) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt index 1eb640c4cb9c0..5090fd411dfc9 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt @@ -61,4 +61,4 @@ else() ) endif(CLR_CMAKE_HOST_UNIX) -install_clr(TARGETS superpmi-shim-collector DESTINATIONS .) +install_clr(TARGETS superpmi-shim-collector DESTINATIONS . COMPONENT spmi) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt index 602a6751b02da..403841d95c8ed 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt @@ -63,4 +63,4 @@ else() ) endif(CLR_CMAKE_HOST_UNIX) -install_clr(TARGETS superpmi-shim-counter DESTINATIONS .) +install_clr(TARGETS superpmi-shim-counter DESTINATIONS . COMPONENT spmi) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt index b6f4d52ea4cab..e1c168ef9d9dd 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt @@ -62,4 +62,4 @@ else() ) endif(CLR_CMAKE_HOST_UNIX) -install_clr(TARGETS superpmi-shim-simple DESTINATIONS .) +install_clr(TARGETS superpmi-shim-simple DESTINATIONS . COMPONENT spmi) diff --git a/src/coreclr/tools/superpmi/superpmi/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi/CMakeLists.txt index 4827c195dc299..63237450898e3 100644 --- a/src/coreclr/tools/superpmi/superpmi/CMakeLists.txt +++ b/src/coreclr/tools/superpmi/superpmi/CMakeLists.txt @@ -64,4 +64,4 @@ else() ) endif(CLR_CMAKE_HOST_UNIX) -install_clr(TARGETS superpmi DESTINATIONS .) +install_clr(TARGETS superpmi DESTINATIONS . COMPONENT spmi) From fdf6485c800ec580656d7491795e10881d493afb Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Fri, 21 Jan 2022 22:59:57 -0800 Subject: [PATCH 139/308] Add COMWrappers to crossgen (#63969) --- .../ILCompiler.Diagnostics.csproj | 1 + .../ILCompilerComWrappers.cs | 32 ++++ .../ILCompiler.Diagnostics/ISymNGenWriter.cs | 75 ++++++++- .../aot/ILCompiler.Diagnostics/PdbWriter.cs | 37 ++--- .../SymNgenWriterWrapper.cs | 149 ++++++++++++++++++ 5 files changed, 268 insertions(+), 26 deletions(-) create mode 100644 src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompilerComWrappers.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Diagnostics/SymNgenWriterWrapper.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj index 97c97bb7de720..0d1b23ad73b3c 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj @@ -15,6 +15,7 @@ binaries are up to date and which are stale. --> false Debug;Release;Checked + true diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompilerComWrappers.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompilerComWrappers.cs new file mode 100644 index 0000000000000..d9972da41f76c --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompilerComWrappers.cs @@ -0,0 +1,32 @@ + +using System; +using System.Collections; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Microsoft.DiaSymReader +{ + internal unsafe sealed class ILCompilerComWrappers : ComWrappers + { + protected override unsafe ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) + { + // passing the managed object to COM is not currently supported + throw new NotImplementedException(); + } + + protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flags) + { + // Assert use of the UniqueInstance flag since the returned Native Object Wrapper always + // supports IDisposable and its Dispose will always release and suppress finalization. + // If the wrapper doesn't always support IDisposable the assert can be relaxed. + Debug.Assert(flags.HasFlag(CreateObjectFlags.UniqueInstance)); + + // Throw an exception if the type is not supported by the implementation. + // Null can be returned as well, but an ArgumentNullException will be thrown for + // the consumer of this ComWrappers instance. + return SymNgenWriterWrapper.CreateIfSupported(externalComObject) ?? throw new NotSupportedException(); + } + + protected override void ReleaseObjects(IEnumerable objects) => throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ISymNGenWriter.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ISymNGenWriter.cs index 4c4b6b97d60a9..40702fd187a75 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ISymNGenWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ISymNGenWriter.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#pragma warning disable 436 // SuppressUnmanagedCodeSecurityAttribute defined in source and mscorlib +#pragma warning disable 436 // SuppressUnmanagedCodeSecurityAttribute defined in source and mscorlib using System; using System.Collections.Generic; @@ -11,9 +11,39 @@ namespace Microsoft.DiaSymReader { - [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D682FD12-43dE-411C-811B-BE8404CEA126"), SuppressUnmanagedCodeSecurity] + /// + /// IUnknown COM type for writing NGen PDBs + /// + /// + /// + /// [ + /// object, + /// uuid(d682fd12-43de-411c-811b-be8404cea126), + /// pointer_default(unique) + /// ] + /// interface ISymNGenWriter : IUnknown + /// { + /// /* + /// * Add a new public symbol to the NGEN PDB. + /// */ + /// HRESULT AddSymbol([in] BSTR pSymbol, + /// [in] USHORT iSection, + /// [in] ULONGLONG rva); + /// + /// /* + /// * Adds a new section to the NGEN PDB. + /// */ + /// HRESULT AddSection([in] USHORT iSection, + /// [in] USHORT flags, + /// [in] long offset, + /// [in] long cb); + /// }; + /// + /// internal interface ISymNGenWriter { + public static readonly Guid IID = new Guid("D682FD12-43dE-411C-811B-BE8404CEA126"); + // Add a new public symbol to the NGEN PDB. void AddSymbol([MarshalAs(UnmanagedType.BStr)] string pSymbol, ushort iSection, @@ -46,9 +76,46 @@ internal enum OMF : ushort } - [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B029E51B-4C55-4fe2-B993-9F7BC1F10DB4"), SuppressUnmanagedCodeSecurity] + /// + /// IUnknown COM type for writing NGen PDBs + /// + /// + /// + /// [ + /// object, + /// local, + /// uuid(B029E51B-4C55-4fe2-B993-9F7BC1F10DB4), + /// pointer_default(unique) + /// ] + /// interface ISymNGenWriter2 : ISymNGenWriter + /// { + /// HRESULT OpenModW([in] const wchar_t* wszModule, + /// [in] const wchar_t* wszObjFile, + /// [out] BYTE** ppmod); + /// + /// HRESULT CloseMod([in] BYTE* pmod); + /// + /// HRESULT ModAddSymbols([in] BYTE* pmod, [in] BYTE* pbSym, [in] long cb); + /// + /// HRESULT ModAddSecContribEx( + /// [in] BYTE* pmod, + /// [in] USHORT isect, + /// [in] long off, + /// [in] long cb, + /// [in] ULONG dwCharacteristics, + /// [in] DWORD dwDataCrc, + /// [in] DWORD dwRelocCrc); + /// + /// HRESULT QueryPDBNameExW( + /// [out, size_is(cchMax)] wchar_t wszPDB[], + /// [in] SIZE_T cchMax); + /// }; + /// + /// internal interface ISymNGenWriter2 : ISymNGenWriter { + public readonly static new Guid IID = new Guid("B029E51B-4C55-4fe2-B993-9F7BC1F10DB4"); + // Add a new public symbol to the NGEN PDB. new void AddSymbol([MarshalAs(UnmanagedType.BStr)] string pSymbol, ushort iSection, @@ -78,7 +145,7 @@ void ModAddSecContribEx( uint dwRelocCrc); void QueryPDBNameExW( - [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pdb, + [MarshalAs(UnmanagedType.LPWStr)] char[] pdb, IntPtr cchMax); } } diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs index a16d5bf19a8e6..be0d8af909f72 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs @@ -89,7 +89,7 @@ public class PdbWriter Dictionary _documentToChecksumOffsetMapping; UIntPtr _pdbMod; - ISymNGenWriter2 _ngenWriter; + SymNgenWriterWrapper _ngenWriter; static PdbWriter() { @@ -116,7 +116,7 @@ private static IntPtr DllImportResolver(string libraryName, Assembly assembly, D private extern static void CreateNGenPdbWriter( [MarshalAs(UnmanagedType.LPWStr)] string ngenImagePath, [MarshalAs(UnmanagedType.LPWStr)] string pdbPath, - [MarshalAs(UnmanagedType.Interface)] out ISymNGenWriter2 ngenPdbWriter); + out IntPtr ngenPdbWriterPtr); public PdbWriter(string pdbPath, PDBExtraData pdbExtraData, TargetDetails target) { @@ -138,23 +138,14 @@ public void WritePDBData(string dllPath, IEnumerable methods) { try { - try - { - WritePDBDataHelper(dllPath, methods); - } - finally - { - if ((_ngenWriter != null) && (_pdbMod != UIntPtr.Zero)) - { - _ngenWriter.CloseMod(_pdbMod); - } - } + WritePDBDataHelper(dllPath, methods); } finally { - if (_ngenWriter != null) + if ((_ngenWriter != null) && (_pdbMod != UIntPtr.Zero)) { - Marshal.FinalReleaseComObject(_ngenWriter); + _ngenWriter.CloseMod(_pdbMod); + _ngenWriter?.Dispose(); } } @@ -217,14 +208,16 @@ private void WritePDBDataHelper(string dllPath, IEnumerable methods) // Delete any preexisting PDB file upfront, otherwise CreateNGenPdbWriter silently opens it File.Delete(_pdbFilePath); - CreateNGenPdbWriter(dllPath, _pdbFilePath, out _ngenWriter); + var comWrapper = new ILCompilerComWrappers(); + CreateNGenPdbWriter(dllPath, _pdbFilePath, out var pdbWriterInst); + _ngenWriter = (SymNgenWriterWrapper)comWrapper.GetOrCreateObjectForComInstance(pdbWriterInst, CreateObjectFlags.UniqueInstance); { // PDB file is now created. Get its path and update _pdbFilePath so the PDB file // can be deleted if we don't make it successfully to the end. - StringBuilder pdbFilePathBuilder = new StringBuilder(); - pdbFilePathBuilder.Capacity = 1024; - _ngenWriter.QueryPDBNameExW(pdbFilePathBuilder, new IntPtr(pdbFilePathBuilder.Capacity)); + const int capacity = 1024; + var pdbFilePathBuilder = new char[capacity]; + _ngenWriter.QueryPDBNameExW(pdbFilePathBuilder, new IntPtr(capacity - 1) /* remove 1 byte for null */); _pdbFilePath = pdbFilePathBuilder.ToString(); } @@ -428,9 +421,9 @@ private void WriteCompilerVersion() byte iLanguage = (byte)CV_CFL_LANG.CV_CFL_MSIL; writer.Write(iLanguage); // Write rest of flags - writer.Write((byte)0); - writer.Write((byte)0); - writer.Write((byte)0); + writer.Write((byte)0); + writer.Write((byte)0); + writer.Write((byte)0); switch (_target.Architecture) { diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/SymNgenWriterWrapper.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/SymNgenWriterWrapper.cs new file mode 100644 index 0000000000000..8a1166f43a39b --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/SymNgenWriterWrapper.cs @@ -0,0 +1,149 @@ + +using System; +using System.Runtime.InteropServices; +using System.Text; + +#nullable enable + +namespace Microsoft.DiaSymReader +{ + internal class SymNgenWriterWrapper : ISymNGenWriter2, IDisposable + { + private bool _isDisposed = false; + public IntPtr ISymNGenWriter2Inst { get; } + + private SymNgenWriterWrapper(IntPtr writer2Inst) + { + ISymNGenWriter2Inst = writer2Inst; + } + + public static SymNgenWriterWrapper? CreateIfSupported(IntPtr ptr) + { + var iid = ISymNGenWriter2.IID; + int hr = Marshal.QueryInterface(ptr, ref iid, out IntPtr ngenWriterInst); + if (hr != 0) + { + return null; + } + + return new SymNgenWriterWrapper(ngenWriterInst); + } + + ~SymNgenWriterWrapper() + { + DisposeInternal(); + } + + public void Dispose() + { + DisposeInternal(); + GC.SuppressFinalize(this); + } + + private void DisposeInternal() + { + if (_isDisposed) + { + return; + } + Marshal.Release(ISymNGenWriter2Inst); + _isDisposed = true; + } + + public unsafe void AddSymbol(string pSymbol, ushort iSection, ulong rva) + { + IntPtr strLocal = Marshal.StringToBSTR(pSymbol); + var inst = ISymNGenWriter2Inst; + var func = (delegate* unmanaged)(*(*(void***)inst + 3 /* ISymNGenWriter2.AddSymbol slot */)); + int hr = func(inst, strLocal, iSection, rva); + Marshal.FreeBSTR(strLocal); + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + } + + public unsafe void AddSection(ushort iSection, OMF flags, int offset, int cb) + { + var inst = ISymNGenWriter2Inst; + var func = (delegate* unmanaged)(*(*(void***)inst + 4)); + int hr = func(inst, iSection, flags, offset, cb); + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + } + + public unsafe void OpenModW(string wszModule, string wszObjFile, out UIntPtr ppmod) + { + var inst = ISymNGenWriter2Inst; + fixed (char* wszModulePtr = wszModule) + fixed (char* wszObjFilePtr = wszObjFile) + { + UIntPtr ppmodPtr; + var func = (delegate* unmanaged)(*(*(void***)inst + 5)); + int hr = func(inst, wszModulePtr, wszObjFilePtr, &ppmodPtr); + ppmod = ppmodPtr; + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + } + } + + public unsafe void CloseMod(UIntPtr pmod) + { + var inst = ISymNGenWriter2Inst; + var func = (delegate* unmanaged)(*(*(void***)inst + 6)); + int hr = func(inst, pmod); + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + } + + public unsafe void ModAddSymbols(UIntPtr pmod, byte[] pbSym, int cb) + { + fixed (byte* pbSymPtr = pbSym) + { + var pbSymLocal = (IntPtr)pbSymPtr; + var inst = ISymNGenWriter2Inst; + var func = (delegate* unmanaged)(*(*(void***)inst + 7)); + int hr = func(inst, pmod, pbSymLocal, cb); + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + } + } + + public unsafe void ModAddSecContribEx(UIntPtr pmod, ushort isect, int off, int cb, uint dwCharacteristics, uint dwDataCrc, uint dwRelocCrc) + { + var inst = ISymNGenWriter2Inst; + var func = (delegate* unmanaged)(*(*(void***)inst + 8)); + int hr = func(inst, pmod, isect, off, cb, dwCharacteristics, dwDataCrc, dwRelocCrc); + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + } + + public unsafe void QueryPDBNameExW(char[] pdb, IntPtr cchMax) + { + fixed (char* pdbPtr = pdb) + { + var pdbLocal = (IntPtr)pdbPtr; + var inst = ISymNGenWriter2Inst; + var func = (delegate* unmanaged)(*(*(void***)inst + 9)); + int hr = func(inst, pdbPtr, cchMax); + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + } + } + + void ISymNGenWriter.AddSymbol(string pSymbol, ushort iSection, ulong rva) => AddSymbol(pSymbol, iSection, rva); + void ISymNGenWriter.AddSection(ushort iSection, OMF flags, int offset, int cb) => AddSection(iSection, flags, offset, cb); + } +} From 068295b281070c1efaa4b11522d7d8ce96244b42 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Sat, 22 Jan 2022 02:10:06 -0500 Subject: [PATCH 140/308] pipelines: Add wasm jobs (#64109) --- eng/pipelines/runtime-extra-platforms.yml | 45 +----- eng/pipelines/runtime-staging.yml | 174 ++++++++++++++++++++++ eng/pipelines/runtime.yml | 45 +++++- src/tests/issues.targets | 3 + 4 files changed, 222 insertions(+), 45 deletions(-) diff --git a/eng/pipelines/runtime-extra-platforms.yml b/eng/pipelines/runtime-extra-platforms.yml index d9121f4b8027a..a0642f4ab521c 100644 --- a/eng/pipelines/runtime-extra-platforms.yml +++ b/eng/pipelines/runtime-extra-platforms.yml @@ -177,7 +177,7 @@ jobs: value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: testGroup: innerloop - nameSuffix: ConsoleBrowserTests + nameSuffix: LibraryTests buildArgs: -subset mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows timeoutInMinutes: 180 condition: >- @@ -221,7 +221,7 @@ jobs: jobParameters: isExtraPlatforms: ${{ variables.isExtraPlatformsBuild }} testGroup: innerloop - nameSuffix: AllSubsets_Mono_EAT + nameSuffix: LibraryTests_EAT buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=false timeoutInMinutes: 180 condition: >- @@ -265,7 +265,7 @@ jobs: jobParameters: isExtraPlatforms: ${{ variables.isExtraPlatformsBuild }} testGroup: innerloop - nameSuffix: AllSubsets_Mono_AOT + nameSuffix: LibraryTests_AOT buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true /p:BrowserHost=$(_hostedOs) timeoutInMinutes: 180 condition: >- @@ -288,43 +288,6 @@ jobs: eq(variables['monoContainsChange'], true), eq(variables['isRollingBuild'], true)) -# -# Build the whole product using Mono and run runtime tests -# -- template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml - buildConfig: Release - runtimeFlavor: mono - platforms: - - Browser_wasm - variables: - - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: pr/dotnet/runtime/$(Build.SourceBranch) - - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: - - name: _HelixSource - value: ci/dotnet/runtime/$(Build.SourceBranch) - - name: timeoutPerTestInMinutes - value: 10 - - name: timeoutPerTestCollectionInMinutes - value: 200 - jobParameters: - testGroup: innerloop - nameSuffix: AllSubsets_Mono_RuntimeTests - buildArgs: -s mono+libs -c $(_BuildConfig) - timeoutInMinutes: 180 - condition: >- - or( - eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), - eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), - eq(variables['isRollingBuild'], true)) - extraStepsTemplate: /eng/pipelines/common/templates/runtimes/wasm-runtime-and-send-to-helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - # # Build the whole product using Mono and run libraries tests # @@ -562,7 +525,7 @@ jobs: value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'] ] jobParameters: testGroup: innerloop - nameSuffix: Windows_wasm_DebuggerTests + nameSuffix: Mono_DebuggerTests buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmDebuggerTests=true /p:TestAssemblies=false /p:BrowserHost=windows timeoutInMinutes: 180 condition: >- diff --git a/eng/pipelines/runtime-staging.yml b/eng/pipelines/runtime-staging.yml index 42803677d0037..d49ceeed3ef53 100644 --- a/eng/pipelines/runtime-staging.yml +++ b/eng/pipelines/runtime-staging.yml @@ -273,6 +273,180 @@ jobs: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) +# +# Build the whole product using Mono and run libraries tests, for Wasm.Build.Tests +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - Browser_wasm_win + variables: + # map dependencies variables to local variables + - name: wasmbuildtestsContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'] ] + jobParameters: + isExtraPlatforms: ${{ variables.isExtraPlatformsBuild }} + testGroup: innerloop + nameSuffix: WasmBuildTests + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmBuildTests=true /p:TestAssemblies=false /p:BrowserHost=$(_hostedOs) + timeoutInMinutes: 180 + condition: >- + eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'], true) + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Mono_$(_BuildConfig)_$(_hostedOs) + extraHelixArguments: /p:BrowserHost=$(_hostedOs) + scenarios: + - buildwasmapps + condition: >- + eq(variables['wasmbuildtestsContainsChange'], true) + +# +# Build Browser_wasm, on windows, run console and browser tests +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: release + runtimeFlavor: mono + platforms: + - Browser_wasm_win + variables: + # map dependencies variables to local variables + - name: librariesContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: monoContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] + jobParameters: + testGroup: innerloop + nameSuffix: LibraryTests + buildArgs: -subset mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows + timeoutInMinutes: 180 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true)) + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Windows_wasm_$(_BuildConfig) + extraHelixArguments: /p:BrowserHost=windows + scenarios: + - normal + - wasmtestonbrowser + condition: >- + or( + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true), + eq(variables['isRollingBuild'], true)) + +# +# Build for Browser/wasm with RunAOTCompilation=true +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - Browser_wasm_win + variables: + # map dependencies variables to local variables + - name: librariesContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: monoContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] + jobParameters: + isExtraPlatforms: ${{ variables.isExtraPlatformsBuild }} + testGroup: innerloop + nameSuffix: LibraryTests_AOT + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true /p:BrowserHost=$(_hostedOs) + timeoutInMinutes: 180 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true)) + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Mono_AOT_$(_BuildConfig)_$(_hostedOs) + extraHelixArguments: /p:NeedsToBuildWasmAppsOnHelix=true $(_runSmokeTestsOnlyArg) /p:BrowserHost=$(_hostedOs) + scenarios: + - normal + condition: >- + or( + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true)) + +# Wasm debugger tests - windows +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - Browser_wasm_win + variables: + # map dependencies variables to local variables + - name: wasmdebuggertestsContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'] ] + jobParameters: + testGroup: innerloop + nameSuffix: Mono_DebuggerTests + buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmDebuggerTests=true /p:TestAssemblies=false /p:BrowserHost=windows + timeoutInMinutes: 180 + condition: >- + eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'], true) + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Mono_$(_BuildConfig) + extraHelixArguments: /p:BrowserHost=windows + scenarios: + - wasmdebuggertests + +# Wasm debugger tests +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - Browser_wasm + variables: + # map dependencies variables to local variables + - name: wasmdebuggertestsContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'] ] + jobParameters: + testGroup: innerloop + nameSuffix: Mono_DebuggerTests + buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmDebuggerTests=true /p:TestAssemblies=false + timeoutInMinutes: 180 + condition: >- + eq(dependencies.evaluate_paths.outputs['SetPathVars_wasmdebuggertests.containsChange'], true) + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Mono_$(_BuildConfig) + scenarios: + - wasmdebuggertests + # # Build the whole product using Mono for Android and run runtime tests with Android devices # diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index cfc899e8d808d..7fb2493bac479 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -364,7 +364,7 @@ jobs: value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono + nameSuffix: LibraryTests buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true timeoutInMinutes: 180 condition: >- @@ -404,7 +404,7 @@ jobs: value: $[ dependencies.evaluate_paths.outputs['SetPathVars_wasmbuildtests.containsChange'] ] jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono_WasmBuildTests + nameSuffix: WasmBuildTests buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmBuildTests=true /p:TestAssemblies=false timeoutInMinutes: 180 condition: >- @@ -442,7 +442,7 @@ jobs: value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono_EAT + nameSuffix: LibraryTests_EAT buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=false timeoutInMinutes: 180 condition: >- @@ -484,7 +484,7 @@ jobs: value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] jobParameters: testGroup: innerloop - nameSuffix: AllSubsets_Mono_AOT + nameSuffix: LibraryTests_AOT buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true timeoutInMinutes: 180 condition: >- @@ -507,6 +507,43 @@ jobs: eq(variables['monoContainsChange'], true), eq(variables['isRollingBuild'], true)) +# +# Build the whole product using Mono and run runtime tests +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - Browser_wasm + variables: + - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: + - name: _HelixSource + value: pr/dotnet/runtime/$(Build.SourceBranch) + - ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: + - name: _HelixSource + value: ci/dotnet/runtime/$(Build.SourceBranch) + - name: timeoutPerTestInMinutes + value: 10 + - name: timeoutPerTestCollectionInMinutes + value: 200 + jobParameters: + testGroup: innerloop + nameSuffix: AllSubsets_Mono_RuntimeTests + buildArgs: -s mono+libs -c $(_BuildConfig) + timeoutInMinutes: 180 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(variables['isRollingBuild'], true)) + extraStepsTemplate: /eng/pipelines/common/templates/runtimes/wasm-runtime-and-send-to-helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Mono_$(_BuildConfig) + # Build and test libraries under single-file publishing - template: /eng/pipelines/common/platform-matrix.yml parameters: diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 3269c33f9bd46..7b718aa15617d 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1985,6 +1985,9 @@ Tests coreclr JIT's debug info generation + + https://github.com/dotnet/runtime/issues/64127 + From 71a6433a44f55d140115cd8da678e2cbb18c55aa Mon Sep 17 00:00:00 2001 From: Floris Westerman Date: Sat, 22 Jan 2022 08:31:21 +0100 Subject: [PATCH 141/308] Fixing update issue with multivalued properties #34267 (#56696) * Add custom attribute test * Adding test demonstrating issue #34267 * Solution for issue #34267 Replacing all values in property with the new collection, instead of just appending new values, leaving old values in place. * Incorporate review feedback Changing the variable name --- .../AD/ADStoreCtx_LoadStore.cs | 11 +- .../tests/AccountManagementTests.cs | 147 ++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/AD/ADStoreCtx_LoadStore.cs b/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/AD/ADStoreCtx_LoadStore.cs index 709ccb1601f73..2d8eebfc84ee7 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/AD/ADStoreCtx_LoadStore.cs +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/AD/ADStoreCtx_LoadStore.cs @@ -1357,6 +1357,12 @@ protected static void ExtensionCacheToLdapConverter(Principal p, string property valueCollection = (ICollection)kvp.Value.Value; } + // We make a local copy of all elements to set, instead of adding them to the real property + // directly. This allows us to override all existing elements without using Clear() and then Add(), + // as that order sends a Clear operation and then a number of Append operations, which will fail. + // Instead, setting the new list all at once will send a Clear operation and then an Update operation. + var propertyValueList = new List(); + foreach (object oVal in valueCollection) { if (null != oVal) @@ -1373,8 +1379,11 @@ protected static void ExtensionCacheToLdapConverter(Principal p, string property if (p.unpersisted && null == oVal) continue; - de.Properties[kvp.Key].Add(oVal); + propertyValueList.Add(oVal); } + + de.Properties[kvp.Key].Value = propertyValueList.ToArray(); + GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADStoreCtx", "ExtensionCacheToLdapConverter - Collection complete"); } else diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/AccountManagementTests.cs b/src/libraries/System.DirectoryServices.AccountManagement/tests/AccountManagementTests.cs index 4796aa4451558..10dde4837cc6d 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/AccountManagementTests.cs +++ b/src/libraries/System.DirectoryServices.AccountManagement/tests/AccountManagementTests.cs @@ -7,6 +7,7 @@ using System.DirectoryServices.Tests; using System.Linq; using Xunit; +using System.Collections.Generic; namespace System.DirectoryServices.AccountManagement.Tests { @@ -325,6 +326,7 @@ public void TestUpdateUserAndGroupData() using (GroupPrincipal gp = FindGroup(g1.Name, context)) { Assert.Equal(group.DisplayName, gp.DisplayName); } user.DisplayName = "Updated CoreFx Test Child User 4"; + user.Save(); group.DisplayName = "Updated CoreFX Test Group Container 4"; group.Save(); @@ -365,6 +367,91 @@ public void TestCredentials() } } + [ConditionalFact(nameof(IsActiveDirectoryServer))] + public void TestCustomUserAttributes() + { + var userData = CustomUserData.GenerateUserData("CustomCoreFxUser1"); + + DeleteUser(userData.Name); + + try + { + using var context = DomainContext; + using (var principal = CreateCustomUser(context, userData)) + { + Assert.NotNull(principal); + ValidateRecentAddedUser(context, userData); + ValidateUserUsingPrincipal(context, principal); + + using var foundPrincipal = FindCustomUser(userData.Name, context); + Assert.NotNull(foundPrincipal); + + Assert.Equal(userData.PostalCode, foundPrincipal.PostalCode); + Assert.Equal(principal.PostalCode, foundPrincipal.PostalCode); + + Assert.Equal(userData.PostalAddress, foundPrincipal.PostalAddress); + Assert.Equal(principal.PostalAddress, foundPrincipal.PostalAddress); + } + } + finally + { + DeleteUser(userData.Name); + } + } + + [ConditionalFact(nameof(IsActiveDirectoryServer))] + public void TestMultiValueCustomAttributes() + { + var userData = CustomUserData.GenerateUserData("CustomCoreFxUser2"); + userData.PostalAddress.Add("Second address"); + + DeleteUser(userData.Name); + + // Check whether directory-data is equivalent to expected data + void CheckAddressWithDirectory(PrincipalContext context, List address) + { + using var foundPrincipal = FindCustomUser(userData.Name, context); + Assert.NotNull(foundPrincipal); + Assert.Equal(address.ToHashSet(), foundPrincipal.PostalAddress.ToHashSet()); + }; + + // Helper to update list + void UpdateAddressList(CustomUserPrincipal principal, Action> update) + { + var localCopy = principal.PostalAddress; + update(localCopy); + principal.PostalAddress = localCopy; + principal.Save(); + } + + try + { + // Initial setup + using var context = DomainContext; + using var principal = CreateCustomUser(context, userData); + Assert.NotNull(principal); + Assert.Equal(userData.PostalAddress, principal.PostalAddress); + + CheckAddressWithDirectory(context, principal.PostalAddress); + + // Add address + UpdateAddressList(principal, addresses => addresses.Add("Third address")); + CheckAddressWithDirectory(context, principal.PostalAddress); + + // Remove address + UpdateAddressList(principal, addresses => addresses.Remove("Second address")); + CheckAddressWithDirectory(context, principal.PostalAddress); + + // Remove address so we have one remaining + UpdateAddressList(principal, addresses => addresses.Remove("Third address")); + CheckAddressWithDirectory(context, principal.PostalAddress); + } + finally + { + DeleteUser(userData.Name); + } + } + private void ValidateRecentAddedUser(PrincipalContext context, UserData userData) { using (UserPrincipal p = FindUser(userData.Name, context)) @@ -440,6 +527,20 @@ private UserPrincipal CreateUser(PrincipalContext context, UserData userData) return user; } + private CustomUserPrincipal CreateCustomUser(PrincipalContext context, CustomUserData userData) + { + CustomUserPrincipal user = new CustomUserPrincipal(context, userData.Name, userData.Password, true); + + // assign some properties to the custom user principal + user.GivenName = userData.FirstName; + user.Surname = userData.LastName; + user.DisplayName = userData.DisplayName; + user.PostalCode = userData.PostalCode; + user.PostalAddress = userData.PostalAddress; + user.Save(); + return user; + } + private GroupPrincipal CreateGroup(PrincipalContext context, GroupData groupData) { GroupPrincipal group = new GroupPrincipal(context, groupData.Name); @@ -493,6 +594,11 @@ private UserPrincipal FindUser(string userName, PrincipalContext context) return UserPrincipal.FindByIdentity(context, IdentityType.Name, userName); } + private CustomUserPrincipal FindCustomUser(string userName, PrincipalContext context) + { + return CustomUserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, userName); + } + private UserPrincipal FindUserUsingFilter(string userName, PrincipalContext context) { CustomUserPrincipal userPrincipal = new CustomUserPrincipal(context); @@ -528,6 +634,23 @@ internal static UserData GenerateUserData(string name) internal string DisplayName { get; set; } } + internal class CustomUserData : UserData + { + internal static new CustomUserData GenerateUserData(string name) => new CustomUserData + { + Name = name, + Password = Guid.NewGuid().ToString() + "#1aZ", + FirstName = "First " + name, + LastName = "Last " + name, + DisplayName = "Display " + name, + PostalAddress = new List { "Postal Address " + name }, + PostalCode = "Code " + name + }; + + internal string PostalCode { get; set; } + internal List PostalAddress { get; set; } + } + internal class GroupData { internal static GroupData GenerateGroupData(string name) @@ -545,11 +668,14 @@ internal static GroupData GenerateGroupData(string name) } [DirectoryObjectClass("user")] + [DirectoryRdnPrefix("CN")] public class CustomUserPrincipal : UserPrincipal { private CustomFilter _customFilter; public CustomUserPrincipal(PrincipalContext context) : base(context) { } + public CustomUserPrincipal(PrincipalContext context, string samAccountName, string password, bool enabled) + : base(context, samAccountName, password, enabled) { } public void SetUserNameFilter(string name) { @@ -568,6 +694,27 @@ public override AdvancedFilters AdvancedSearchFilter return _customFilter; } } + + // Custom properties + [DirectoryProperty("postalCode")] + public string PostalCode + { + get => ExtensionGet("postalCode").FirstOrDefault() as string; + set => ExtensionSet("postalCode", value); + } + + [DirectoryProperty("postalAddress")] + public List PostalAddress + { + get => ExtensionGet("postalAddress").OfType().ToList(); + set => ExtensionSet("postalAddress", value == null || value?.Count == 0 ? null : value.ToArray()); + } + + // Method overrides + public new static CustomUserPrincipal FindByIdentity(PrincipalContext context, IdentityType identityType, string identityValue) + { + return FindByIdentityWithType(context, typeof(CustomUserPrincipal), identityType, identityValue) as CustomUserPrincipal; + } } public class CustomFilter : AdvancedFilters From 64245ab3966abde394767fbd6531e7edbea2802e Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 21 Jan 2022 23:56:14 -0800 Subject: [PATCH 142/308] Relax assert in ApplyEditAndContinue (#64132) Fixes #64070 --- src/coreclr/md/enc/metamodelrw.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreclr/md/enc/metamodelrw.cpp b/src/coreclr/md/enc/metamodelrw.cpp index 34fe8b84e95c8..3fde673faa5c4 100644 --- a/src/coreclr/md/enc/metamodelrw.cpp +++ b/src/coreclr/md/enc/metamodelrw.cpp @@ -309,16 +309,15 @@ ULONG CMiniMdRW::m_TruncatedEncTables[] = ULONG CMiniMdRW::GetTableForToken( // Table index, or -1. mdToken tkn) // Token to find. { - ULONG ixTbl; // Loop control. ULONG type = TypeFromToken(tkn); // Get the type -- if a string, no associated table. if (type >= mdtString) return (ULONG) -1; // Table number is same as high-byte of token. - ixTbl = type >> 24; + ULONG ixTbl = type >> 24; // Make sure. - _ASSERTE(g_TblIndex[ixTbl].m_Token == type); + _ASSERTE(ixTbl < TBL_COUNT); return ixTbl; } // CMiniMdRW::GetTableForToken From fe622eb8981361d13b4821db66a4326b8daa5138 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 22 Jan 2022 09:19:39 -0500 Subject: [PATCH 143/308] Disable NJulianRuleTest test crashing in CI (#64142) --- src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs index b352a529d6b00..fb7b8292b03f9 100644 --- a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs +++ b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs @@ -2489,6 +2489,7 @@ public static void GetSystemTimeZones_AllTimeZonesHaveOffsetInValidRange() // 0x3E, 0x2C, 0x30, 0x2F, 0x30, 0x2C, 0x4A, 0x33, 0x36, 0x35, 0x2F, 0x32, 0x35, 0x0A }; + [ActiveIssue("https://github.com/dotnet/runtime/issues/64134")] [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [PlatformSpecific(TestPlatforms.AnyUnix)] [InlineData("<+00>0<+01>,0/0,J365/25", 1, 1, true)] From 8c1b48040db83aa3c24e654cf3dd9c22fa68d376 Mon Sep 17 00:00:00 2001 From: Floris Westerman Date: Sat, 22 Jan 2022 16:44:23 +0100 Subject: [PATCH 144/308] Updating unit tests for DirectoryServices.AccountManagement (#56670) Removing old, redundant unit tests that were actually never executed Migrating old tests to new test infrastructure with configurable LDAP/AD connections --- .../tests/AccountManagementTests.cs | 73 ++++++++- .../tests/ComputerPrincipalTest.cs | 83 ---------- .../tests/ExtendedUserPrincipal.cs | 36 ----- .../tests/GroupPrincipalTest.cs | 68 --------- .../tests/PrincipalTest.cs | 143 ------------------ ...oryServices.AccountManagement.Tests.csproj | 8 +- .../tests/UserPrincipalTest.cs | 32 ---- 7 files changed, 70 insertions(+), 373 deletions(-) delete mode 100644 src/libraries/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs delete mode 100644 src/libraries/System.DirectoryServices.AccountManagement/tests/ExtendedUserPrincipal.cs delete mode 100644 src/libraries/System.DirectoryServices.AccountManagement/tests/GroupPrincipalTest.cs delete mode 100644 src/libraries/System.DirectoryServices.AccountManagement/tests/PrincipalTest.cs delete mode 100644 src/libraries/System.DirectoryServices.AccountManagement/tests/UserPrincipalTest.cs diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/AccountManagementTests.cs b/src/libraries/System.DirectoryServices.AccountManagement/tests/AccountManagementTests.cs index 10dde4837cc6d..33de32cb836c0 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/AccountManagementTests.cs +++ b/src/libraries/System.DirectoryServices.AccountManagement/tests/AccountManagementTests.cs @@ -17,6 +17,42 @@ public class AccountManagementTests internal static bool IsActiveDirectoryServer => IsLdapConfigurationExist && LdapConfiguration.Configuration.IsActiveDirectoryServer; internal static bool IsDomainJoinedClient => !Environment.MachineName.Equals(Environment.UserDomainName, StringComparison.OrdinalIgnoreCase); + [Fact] + public void TestConstructors() + { + using var context = new PrincipalContext(ContextType.Machine); + + using (var principal = new ComputerPrincipal(context)) + { + Assert.Same(context, principal.Context); + Assert.Empty(principal.ServicePrincipalNames); + Assert.Equal(ContextType.Machine, principal.ContextType); + } + Assert.Throws(() => new ComputerPrincipal(null)); + Assert.Throws(() => new ComputerPrincipal(null, "samAccountName", "password", true)); + Assert.Throws(() => new ComputerPrincipal(context, null, "password", true)); + Assert.Throws(() => new ComputerPrincipal(context, "samAccountName", null, true)); + + using (var principal = new UserPrincipal(context)) + { + Assert.Same(context, principal.Context); + Assert.Equal(ContextType.Machine, principal.ContextType); + } + Assert.Throws(() => new UserPrincipal(null)); + Assert.Throws(() => new UserPrincipal(null, "samAccountName", "password", true)); + Assert.Throws(() => new UserPrincipal(context, null, "password", true)); + Assert.Throws(() => new UserPrincipal(context, "samAccountName", null, true)); + + using (var principal = new GroupPrincipal(context)) + { + Assert.Same(context, principal.Context); + Assert.Equal(ContextType.Machine, principal.ContextType); + } + Assert.Throws(() => new GroupPrincipal(null)); + Assert.Throws(() => new GroupPrincipal(null, "samAccountName")); + Assert.Throws(() => new GroupPrincipal(context, null)); + } + [ConditionalFact(nameof(IsActiveDirectoryServer))] public void TestCurrentUser() { @@ -24,7 +60,7 @@ public void TestCurrentUser() using (UserPrincipal p = FindUser(LdapConfiguration.Configuration.UserNameWithNoDomain, context)) { Assert.NotNull(p); - Assert.Equal(LdapConfiguration.Configuration.UserNameWithNoDomain, p.Name); + Assert.Equal(LdapConfiguration.Configuration.UserNameWithNoDomain, p.SamAccountName); } } @@ -35,6 +71,7 @@ public void TestCurrentUserContext() using (UserPrincipal p = FindUser(LdapConfiguration.Configuration.UserNameWithNoDomain, context)) using (UserPrincipal cu = UserPrincipal.Current) { + Assert.NotNull(cu); Assert.NotEqual(cu.Context.Name, p.Context.Name); } } @@ -46,7 +83,7 @@ public void TestCurrentUserUsingSearchFilter() using (UserPrincipal p = FindUserUsingFilter(LdapConfiguration.Configuration.UserNameWithNoDomain, context)) { Assert.NotNull(p); - Assert.Equal(LdapConfiguration.Configuration.UserNameWithNoDomain, p.Name); + Assert.Equal(LdapConfiguration.Configuration.UserNameWithNoDomain, p.SamAccountName); } } @@ -279,6 +316,27 @@ public void TestNegativeCases() } } + [ConditionalFact(nameof(IsActiveDirectoryServer))] + public void TestInvalidSaves() + { + UserData u1 = UserData.GenerateUserData("CoreFxUser9"); + + DeleteUser(u1.Name); + + try + { + using var context = DomainContext; + using var user = new UserPrincipal(context, u1.Name, u1.Password, true); + + Assert.Throws(() => user.Save(null)); + Assert.Throws(() => user.Save(new PrincipalContext(ContextType.Machine))); + } + finally + { + DeleteUser(u1.Name); + } + } + [ConditionalFact(nameof(IsActiveDirectoryServer))] public void TestComputerContext() { @@ -307,6 +365,13 @@ public void TestComputerContext() } } + [ConditionalFact(nameof(IsActiveDirectoryServer))] + public void TestComputerNegativeCases() + { + using var context = DomainContext; + + } + [ConditionalFact(nameof(IsActiveDirectoryServer))] public void TestUpdateUserAndGroupData() { @@ -591,7 +656,7 @@ private GroupPrincipal FindGroup(string groupName, PrincipalContext context) private UserPrincipal FindUser(string userName, PrincipalContext context) { - return UserPrincipal.FindByIdentity(context, IdentityType.Name, userName); + return UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, userName); } private CustomUserPrincipal FindCustomUser(string userName, PrincipalContext context) @@ -723,7 +788,7 @@ public CustomFilter(Principal p) : base(p) { } public void SetFilter(string userName) { - this.AdvancedFilterSet("cn", userName, typeof(string), MatchType.Equals); + this.AdvancedFilterSet("samAccountName", userName, typeof(string), MatchType.Equals); } } } diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs b/src/libraries/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs deleted file mode 100644 index ce6b8cf70565b..0000000000000 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Xunit; - -namespace System.DirectoryServices.AccountManagement.Tests -{ - public class ComputerPrincipalTest : PrincipalTest - { - [Fact] - public void Ctor_Context() - { - var context = new PrincipalContext(ContextType.Machine); - var principal = new ComputerPrincipal(context); - Assert.Same(context, principal.Context); - Assert.Empty(principal.ServicePrincipalNames); - } - - [Fact] - public void Ctor_NullContext_ThrowsArgumentException() - { - AssertExtensions.Throws(null, () => new ComputerPrincipal(null)); - AssertExtensions.Throws(null, () => new ComputerPrincipal(null, "samAccountName", "password", enabled: true)); - } - - [Fact] - public void Ctor_NullSamAccountName_ThrowsArgumentException() - { - var context = new PrincipalContext(ContextType.Machine); - AssertExtensions.Throws(null, () => new ComputerPrincipal(context, null, "password", enabled: true)); - } - - [Fact] - public void Ctor_EmptySamAccountName_ThrowsArgumentNullException() - { - var context = new PrincipalContext(ContextType.Machine); - AssertExtensions.Throws("value", null, () => new ComputerPrincipal(context, string.Empty, "password", enabled: true)); - } - - [Fact] - public void Ctor_NullPassword_ThrowsArgumentException() - { - var context = new PrincipalContext(ContextType.Machine); - AssertExtensions.Throws(null, () => new ComputerPrincipal(context, "samAccountName", null, enabled: true)); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoNorServerCore), nameof(PlatformDetection.IsNotWindowsIoTCore))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/34442", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] - public void Ctor_MachineContext_NoException() - { - var context = new PrincipalContext(ContextType.Machine); - var principal = new ComputerPrincipal(context, "samAccountName", "password", enabled: true); - Assert.Equal(ContextType.Machine, principal.ContextType); - } - - [Fact] - public void ComputerPrincipalConstructorTest() - { - if (DomainContext == null) - { - return; - } - - ComputerPrincipal computer = new ComputerPrincipal(DomainContext); - computer.Dispose(); - } - - public override Principal CreatePrincipal(PrincipalContext context, string name) - { - return new ComputerPrincipal(context) { Name = name }; - } - - public override Principal CreateExtendedPrincipal(PrincipalContext context, string name) - { - throw new NotImplementedException(); - } - - public override Principal FindExtendedPrincipal(PrincipalContext context, string name) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/ExtendedUserPrincipal.cs b/src/libraries/System.DirectoryServices.AccountManagement/tests/ExtendedUserPrincipal.cs deleted file mode 100644 index 7f378a13acf43..0000000000000 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/ExtendedUserPrincipal.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.DirectoryServices.AccountManagement.Tests -{ - [DirectoryRdnPrefix("CN")] - [DirectoryObjectClass("User")] - public class ExtendedUserPrincipal : UserPrincipal, IExtendedPrincipalTest - { - public ExtendedUserPrincipal(PrincipalContext context) : base(context) { } - - public static new ExtendedUserPrincipal FindByIdentity(PrincipalContext context,string identityValue) - { - return (ExtendedUserPrincipal)FindByIdentityWithType(context, typeof(ExtendedUserPrincipal), identityValue); - } - - [DirectoryProperty("jpegPhoto")] - public byte[] ByteArrayExtension - { - get => (byte[])ExtensionGet("jpegPhoto")[0]; - set => ExtensionSet("jpegPhoto", value); - } - - public object ObjectExtension - { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); - } - - public object[] ObjectArrayExtension - { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); - } - } -} diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/GroupPrincipalTest.cs b/src/libraries/System.DirectoryServices.AccountManagement/tests/GroupPrincipalTest.cs deleted file mode 100644 index 8817afbddd186..0000000000000 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/GroupPrincipalTest.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Xunit; - -namespace System.DirectoryServices.AccountManagement.Tests -{ - public class GroupPrincipalTest : PrincipalTest - { - [Fact] - public void GroupPrincipalConstructorTest() - { - if (DomainContext == null) - { - return; - } - - GroupPrincipal group = new GroupPrincipal(DomainContext); - group.Dispose(); - } - - public override Principal CreatePrincipal(PrincipalContext context, string name) - { - return new GroupPrincipal(context, name); - } - - [Fact] - public void IsMemberOfTest() - { - if (DomainContext == null) - { - return; - } - - using (GroupPrincipal group = GroupPrincipal.FindByIdentity(DomainContext, "TestLargeGroup")) - { - Assert.True(UserPrincipal.FindByIdentity(DomainContext, "user1499-LargeGroup").IsMemberOf(group)); - Assert.True(UserPrincipal.FindByIdentity(DomainContext, "user1500-LargeGroup").IsMemberOf(group)); - Assert.True(UserPrincipal.FindByIdentity(DomainContext, "user1501-LargeGroup").IsMemberOf(group)); - Assert.True(UserPrincipal.FindByIdentity(DomainContext, "user3000-LargeGroup").IsMemberOf(group)); - Assert.True(UserPrincipal.FindByIdentity(DomainContext, "user3001-LargeGroup").IsMemberOf(group)); - Assert.False(UserPrincipal.FindByIdentity(DomainContext, "userNotInLargeGroup").IsMemberOf(group)); - } - } - - private void CreateManyUsersInGroup(GroupPrincipal group) - { - for (int i = 1; i < 3002; i++) - { - string name = $"user{i:0000}-LargeGroup"; - UserPrincipal user = new UserPrincipal(DomainContext, name, "Adrumble@6", false); - user.Save(); - group.Members.Add(user); - } - group.Save(); - } - - public override Principal CreateExtendedPrincipal(PrincipalContext context, string name) - { - throw new NotImplementedException(); - } - - public override Principal FindExtendedPrincipal(PrincipalContext context, string name) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/PrincipalTest.cs b/src/libraries/System.DirectoryServices.AccountManagement/tests/PrincipalTest.cs deleted file mode 100644 index a0078001f74f4..0000000000000 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/PrincipalTest.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Security.Principal; -using Xunit; - -namespace System.DirectoryServices.AccountManagement.Tests -{ - public abstract class PrincipalTest : IDisposable - { - public PrincipalContext DomainContext { get; private set; } - - public PrincipalTest() => RefreshContext(); - - private void RefreshContext() - { - string username = "Administrator"; - string password = Environment.GetEnvironmentVariable("TESTPASSWORD"); - string OU = "Tests"; - string baseDomain = WindowsIdentity.GetCurrent().Name.Split(new char[] { '\\' })[1] + "-TEST"; - string domain = $"{baseDomain}.nttest.microsoft.com"; - string container = $"ou={OU},dc={baseDomain},dc=nttest,dc=microsoft,dc=com"; - DomainContext?.Dispose(); - try - { - DomainContext = new PrincipalContext(ContextType.Domain, domain, container, username, password); - } - catch - { - } - } - - public void Dispose() => DomainContext?.Dispose(); - - [Fact] - public void AddExistingPrincipal() - { - if (DomainContext == null) - { - return; - } - - // use new GUID for the user name so we be sure this user does not exist yet - string name = Guid.NewGuid().ToString(); - using (Principal principal = CreatePrincipal(DomainContext, name)) - { - principal.Save(); - } - - Assert.NotNull(Principal.FindByIdentity(DomainContext, name)); - - // this previously caused the user to be deleted. it is still expected to throw an exception, but not delete the user - bool exceptionThrown = false; - try - { - using (Principal principal = CreatePrincipal(DomainContext, name)) - { - principal.Save(); - } - } - catch (PrincipalExistsException) - { - exceptionThrown = true; - } - - // validate that we correctly throw an exception when trying to add an existing principal - Assert.True(exceptionThrown); - - // validate that we did not delete incorrectly delete the first principal - using (Principal principal2 = Principal.FindByIdentity(DomainContext, name)) - { - Assert.NotNull(principal2); - - // explicitly delete the user and check it was really deleted - principal2.Delete(); - } - - // ensure we cleaned up the test principal - Assert.Null(Principal.FindByIdentity(DomainContext, name)); - } - - [Fact] - public void TestExtendedPrincipal() - { - if (DomainContext == null) - { - return; - } - - string name = Guid.NewGuid().ToString(); - byte[] writtenArray = new byte[] { 10, 20, 30 }; - using (Principal principal = CreateExtendedPrincipal(DomainContext, name)) - { - IExtendedPrincipalTest extendedPrincipal = (IExtendedPrincipalTest)principal; - extendedPrincipal.ByteArrayExtension = writtenArray; - principal.Save(); - } - - RefreshContext(); - using (Principal principal = FindExtendedPrincipal(DomainContext, name)) - { - IExtendedPrincipalTest extendedPrincipal = (IExtendedPrincipalTest)principal; - byte[] readArray = extendedPrincipal.ByteArrayExtension; - principal.Delete(); - } - } - - [Theory] - [MemberData(nameof(TestDebuggerAttributes_Inputs))] - public void Save_ThrowsInvalidOperationException(PrincipalContext context) - { - if (DomainContext == null) - { - return; - } - - using (Principal principal = CreateExtendedPrincipal(DomainContext, Guid.NewGuid().ToString())) - { - Assert.Throws(() => principal.Save(context)); - } - } - - public static IEnumerable TestDebuggerAttributes_Inputs() - { - yield return new object[] { null }; - yield return new object[] { new PrincipalContext(ContextType.Machine) }; - } - - public abstract Principal CreatePrincipal(PrincipalContext context, string name); - - public abstract Principal CreateExtendedPrincipal(PrincipalContext context, string name); - - public abstract Principal FindExtendedPrincipal(PrincipalContext context, string name); - } - - public interface IExtendedPrincipalTest - { - object ObjectExtension { get; set; } - byte[] ByteArrayExtension { get; set; } - object[] ObjectArrayExtension { get; set; } - } -} diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj b/src/libraries/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj index 6ee1a6b7217ba..0bb24c8eadd87 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj +++ b/src/libraries/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj @@ -3,15 +3,9 @@ $(NetCoreAppCurrent)-windows;net48 - - - - - - + diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/UserPrincipalTest.cs b/src/libraries/System.DirectoryServices.AccountManagement/tests/UserPrincipalTest.cs deleted file mode 100644 index 53b99ab5c939c..0000000000000 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/UserPrincipalTest.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Security.Principal; -using Xunit; - -namespace System.DirectoryServices.AccountManagement.Tests -{ - public class UserPrincipalTest : PrincipalTest - { - public override Principal CreatePrincipal(PrincipalContext context, string name) - { - return new UserPrincipal(context) { Name = name }; - } - - public override Principal CreateExtendedPrincipal(PrincipalContext context, string name) - { - return new ExtendedUserPrincipal(context) { Name = name }; - } - - public override Principal FindExtendedPrincipal(PrincipalContext context, string name) - { - return ExtendedUserPrincipal.FindByIdentity(context, name); - } - - public void UserPrincipalConstructorTest() - { - UserPrincipal user = new UserPrincipal(DomainContext); - user.Dispose(); - } - } -} From feb25b01385242beb804b48f4954dbda62d3d54f Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Sat, 22 Jan 2022 22:24:54 +0200 Subject: [PATCH 145/308] Fix MultiByteToWideChar call in pal (#64146) --- src/coreclr/pal/src/init/pal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp index 5469b4bebd483..951680114d886 100644 --- a/src/coreclr/pal/src/init/pal.cpp +++ b/src/coreclr/pal/src/init/pal.cpp @@ -1242,7 +1242,7 @@ static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv) return NULL; } - if(!MultiByteToWideChar(CP_ACP, 0,command_line, i, retval, i)) + if(!MultiByteToWideChar(CP_ACP, 0,command_line, -1, retval, i)) { ASSERT("MultiByteToWideChar failure\n"); free(retval); From 8d2268a5323f261d63b4b288fc96c2daa34fc6cf Mon Sep 17 00:00:00 2001 From: Vladimir Sadov Date: Sat, 22 Jan 2022 14:57:43 -0800 Subject: [PATCH 146/308] Extra tests for assembly name parser. (#64022) * Dead code in native assembly name parsing * disallow `\u` escaping in assembly names * misc cleanup * forward slash is illegal escaped or not * ignore "language" attribute in assembly name ("culture" must be used) * duplicate attributes are ok if unrecognized (just add tests) * drop support for "custom" blob attribute * drop support for publickey[token]=neutral ("null" must be used) * ignore unknown assembly name attributes in mono (compat) * disallow \0 anywhere in the assembly name * disallow \0 in assembly names on mono (compat) * only check for embedded nulls when parsing * fix mono build * make GCC happy * couple test scenarios for publickey vs. publickeytoken (CoreRT parser might trip on these) * produce errors on duplicate known attributes in mono --- src/coreclr/binder/inc/assemblyidentity.hpp | 5 - src/coreclr/binder/inc/stringlexer.hpp | 16 +- src/coreclr/binder/inc/stringlexer.inl | 164 +++--------------- .../binder/inc/textualidentityparser.hpp | 11 +- src/coreclr/binder/stringlexer.cpp | 28 ++- src/coreclr/binder/textualidentityparser.cpp | 71 +------- src/coreclr/vm/assemblyspec.cpp | 8 +- src/coreclr/vm/assemblyspec.hpp | 2 +- .../tests/AssemblyNameTests.cs | 38 ++++ .../System/Reflection/AssemblyName.Mono.cs | 3 + src/mono/mono/metadata/assembly.c | 29 ++-- 11 files changed, 137 insertions(+), 238 deletions(-) diff --git a/src/coreclr/binder/inc/assemblyidentity.hpp b/src/coreclr/binder/inc/assemblyidentity.hpp index cc0916c8780af..ef4768d3b8cd9 100644 --- a/src/coreclr/binder/inc/assemblyidentity.hpp +++ b/src/coreclr/binder/inc/assemblyidentity.hpp @@ -30,12 +30,9 @@ namespace BINDER_SPACE IDENTITY_FLAG_PUBLIC_KEY_TOKEN = 0x004, IDENTITY_FLAG_PUBLIC_KEY = 0x008, IDENTITY_FLAG_CULTURE = 0x010, - IDENTITY_FLAG_LANGUAGE = 0x020, IDENTITY_FLAG_PROCESSOR_ARCHITECTURE = 0x040, IDENTITY_FLAG_RETARGETABLE = 0x080, IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL = 0x100, - IDENTITY_FLAG_CUSTOM = 0x200, - IDENTITY_FLAG_CUSTOM_NULL = 0x400, IDENTITY_FLAG_CONTENT_TYPE = 0x800, IDENTITY_FLAG_FULL_NAME = (IDENTITY_FLAG_SIMPLE_NAME | IDENTITY_FLAG_VERSION) @@ -50,7 +47,6 @@ namespace BINDER_SPACE // Need to pre-populate SBuffers because of bogus asserts static const BYTE byteArr[] = { 0 }; m_publicKeyOrTokenBLOB.SetImmutable(byteArr, sizeof(byteArr)); - m_customBLOB.SetImmutable(byteArr, sizeof(byteArr)); } ~AssemblyIdentity() { @@ -83,7 +79,6 @@ namespace BINDER_SPACE SBuffer m_publicKeyOrTokenBLOB; PEKIND m_kProcessorArchitecture; AssemblyContentType m_kContentType; - SBuffer m_customBLOB; DWORD m_dwIdentityFlags; }; diff --git a/src/coreclr/binder/inc/stringlexer.hpp b/src/coreclr/binder/inc/stringlexer.hpp index 41af7e7baa18d..f08e046982c56 100644 --- a/src/coreclr/binder/inc/stringlexer.hpp +++ b/src/coreclr/binder/inc/stringlexer.hpp @@ -55,32 +55,28 @@ namespace BINDER_SPACE inline StringLexer(); inline ~StringLexer(); - inline void Init(SString &inputString, BOOL fSupportEscaping); + inline void Init(SString &inputString); static inline BOOL IsWhitespace(WCHAR wcChar); static inline BOOL IsEOS(WCHAR wcChar); static inline BOOL IsQuoteCharacter(WCHAR wcChar); - virtual BOOL IsSeparatorChar(WCHAR wcChar) = NULL; - virtual LEXEME_TYPE GetLexemeType(WCHAR wcChar) = NULL; + BOOL IsSeparatorChar(WCHAR wcChar); + LEXEME_TYPE GetLexemeType(WCHAR wcChar); protected: static const WCHAR INVALID_CHARACTER = -1; - LEXEME_TYPE GetNextLexeme(SString ¤tString, BOOL fPermitUnescapedQuotes = FALSE); + LEXEME_TYPE GetNextLexeme(SString ¤tString); inline WCHAR PopCharacter(BOOL *pfIsEscaped); inline void PushCharacter(WCHAR wcCurrentChar, BOOL fIsEscaped); inline WCHAR GetRawCharacter(); - inline void PushRawCharacter(); - inline WCHAR DecodeUTF16Character(); inline WCHAR GetNextCharacter(BOOL *pfIsEscaped); - inline WCHAR ParseUnicode(); - LEXEME_TYPE ParseString(SString ¤tString, - BOOL fPermitUnescapeQuotes); + LEXEME_TYPE ParseString(SString ¤tString); void TrimTrailingWhiteSpaces(SString ¤tString); @@ -89,8 +85,6 @@ namespace BINDER_SPACE WCHAR m_wcCurrentChar; BOOL m_fCurrentCharIsEscaped; - BOOL m_fSupportEscaping; - BOOL m_fReadRawCharacter; }; #include "stringlexer.inl" diff --git a/src/coreclr/binder/inc/stringlexer.inl b/src/coreclr/binder/inc/stringlexer.inl index bfe4bddeaa4c1..42f7f73ed0bbc 100644 --- a/src/coreclr/binder/inc/stringlexer.inl +++ b/src/coreclr/binder/inc/stringlexer.inl @@ -25,12 +25,10 @@ StringLexer::~StringLexer() // Nothing to do here } -void StringLexer::Init(SString &inputString, BOOL fSupportEscaping) +void StringLexer::Init(SString &inputString) { m_cursor = inputString.Begin(); m_end = inputString.End(); - m_fSupportEscaping = fSupportEscaping; - m_fReadRawCharacter = FALSE; } BOOL StringLexer::IsWhitespace(WCHAR wcChar) @@ -55,6 +53,7 @@ WCHAR StringLexer::PopCharacter(BOOL *pfIsEscaped) { m_wcCurrentChar = INVALID_CHARACTER; *pfIsEscaped = m_fCurrentCharIsEscaped; + m_cursor++; } else { @@ -71,172 +70,63 @@ void StringLexer::PushCharacter(WCHAR wcCurrentChar, m_wcCurrentChar = wcCurrentChar; m_fCurrentCharIsEscaped = fIsEscaped; + m_cursor--; } WCHAR StringLexer::GetRawCharacter() { WCHAR wcCurrentChar = 0; - if (m_cursor <= m_end) + if (m_cursor < m_end) { wcCurrentChar = m_cursor[0]; - m_fReadRawCharacter = TRUE; m_cursor++; - } - else - { - m_fReadRawCharacter = FALSE; - } - - return wcCurrentChar; -} - -void StringLexer::PushRawCharacter() -{ - if (m_fReadRawCharacter) - { - m_cursor--; - m_fReadRawCharacter = FALSE; - } -} -WCHAR StringLexer::DecodeUTF16Character() -{ - // See http://www.ietf.org/rfc/rfc2781.txt for details on UTF-16 encoding. - - WCHAR wcCurrentChar = 0; - SCOUNT_T nCharacters = m_end - m_cursor + 1; - WCHAR wcChar1 = GetRawCharacter(); - - if (wcChar1 < 0xd800) - { - wcCurrentChar = wcChar1; + // do not allow \0 anywhere in the string. + if (wcCurrentChar == 0) + { + wcCurrentChar = INVALID_CHARACTER; + } } else { - // StringLexer is not designed to handle UTF-16 characters beyond the Basic Multilingual Plane, - // since it stores all characters in 16-bit WCHARs. - // However, since the vast majority of the time, we (Microsoft) produce the manifests, - // this is likely a non-scenario, as the other Unicode planes would never be used in practice. - - if (wcChar1 <= 0xdbff) // 0xd800 - 0xdbff indicates the first WCHAR of a surrogate pair - { - if (nCharacters >= 2) - { - GetRawCharacter(); // Skip the second WCHAR of the surrogate pair - } - } - // Otherwise, the character is either in the 0xdc00 - 0xdfff range, indicating the second WCHAR of a surrogate pair, - // or in the 0xE000 - 0xFFFF range, which has within it ranges of invalid characters, and which we conservatively treat - // as invalid. - - wcCurrentChar = INVALID_CHARACTER; + // EOS + wcCurrentChar = 0; } return wcCurrentChar; } - WCHAR StringLexer::GetNextCharacter(BOOL *pfIsEscaped) { *pfIsEscaped = FALSE; - WCHAR wcCurrentChar = GetRawCharacter(); // DecodeUTF16Character() + WCHAR wcCurrentChar = GetRawCharacter(); if (wcCurrentChar == L'\\') { - WCHAR wcTempChar = GetRawCharacter(); // DecodeUTF16Character() + WCHAR wcTempChar = GetRawCharacter(); - if (m_fSupportEscaping) - { - // Handle standard escapes - switch (wcTempChar) - { - case L'"': - case L'\'': - case L',': - case L'\\': - case L'/': - case L'=': - break; - case L't': - wcTempChar = 9; - break; - case L'n': - wcTempChar = 10; - break; - case L'r': - wcTempChar = 13; - break; - case L'u': - wcTempChar = ParseUnicode(); - break; - default: - return INVALID_CHARACTER; - } - - *pfIsEscaped = TRUE; - wcCurrentChar = wcTempChar; - } - else - { - // Do not handle escapes except for quotes - switch (wcTempChar) - { - case L'"': - case L'\'': - *pfIsEscaped = TRUE; - wcCurrentChar = wcTempChar; - break; - default: - PushRawCharacter(); - break; - } - } - } - - return wcCurrentChar; -} - -WCHAR StringLexer::ParseUnicode() -{ - int nCharacters = 0; - WCHAR wcUnicodeChar = 0; - - for(;;) - { - WCHAR wcCurrentChar = DecodeUTF16Character(); - nCharacters++; - - if (wcCurrentChar == L';') + // Handle standard escapes + switch (wcTempChar) { + case L'"': + case L'\'': + case L',': + case L'\\': + case L'=': + case L't': + case L'n': + case L'r': break; - } - else if ((wcCurrentChar == INVALID_CHARACTER) || (nCharacters >= 9)) - { + default: return INVALID_CHARACTER; } - wcUnicodeChar <<= 4; - - if ((wcCurrentChar >= L'0') && (wcCurrentChar <= L'9')) - { - wcUnicodeChar += (wcCurrentChar - L'0'); - } - else if ((wcCurrentChar >= L'a') && (wcCurrentChar <= L'f')) - { - wcUnicodeChar += (wcCurrentChar - L'a') + 10; - } - else if ((wcCurrentChar >= L'A') && (wcCurrentChar <= L'F')) - { - wcUnicodeChar += (wcCurrentChar - L'A') + 10; - } - else - { - return INVALID_CHARACTER; - } + *pfIsEscaped = TRUE; + wcCurrentChar = wcTempChar; } - return wcUnicodeChar; + return wcCurrentChar; } #endif diff --git a/src/coreclr/binder/inc/textualidentityparser.hpp b/src/coreclr/binder/inc/textualidentityparser.hpp index a5187d254a652..2b60c3110f37f 100644 --- a/src/coreclr/binder/inc/textualidentityparser.hpp +++ b/src/coreclr/binder/inc/textualidentityparser.hpp @@ -28,12 +28,9 @@ namespace BINDER_SPACE TextualIdentityParser(AssemblyIdentity *pAssemblyIdentity); ~TextualIdentityParser(); - virtual BOOL IsSeparatorChar(WCHAR wcChar); - virtual StringLexer::LEXEME_TYPE GetLexemeType(WCHAR wcChar); - static HRESULT Parse(/* in */ SString &textualIdentity, - /* out */ AssemblyIdentity *pAssemblyIdentity, - /* in */ BOOL fPermitUnescapedQuotes = FALSE); + /* out */ AssemblyIdentity *pAssemblyIdentity); + static HRESULT ToString(/* in */ AssemblyIdentity *pAssemblyIdentity, /* in */ DWORD dwIdentityFlags, /* out */ SString &textualIdentity); @@ -45,6 +42,7 @@ namespace BINDER_SPACE /* in */ BOOL fValidateHex, /* in */ BOOL fIsToken, /* out */ SBuffer &publicKeyOrTokenBLOB); + static void BlobToHex(/* in */ SBuffer &publicKeyOrTokenBLOB, /* out */ SString &publicKeyOrToken); @@ -52,8 +50,7 @@ namespace BINDER_SPACE /* out */ SString &contentString); protected: - BOOL Parse(/* in */ SString &textualIdentity, - /* in */ BOOL fPermitUnescapedQuotes = FALSE); + BOOL Parse(/* in */ SString &textualIdentity); BOOL PopulateAssemblyIdentity(/* in */ SString &attributeString, /* in */ SString &valueString); diff --git a/src/coreclr/binder/stringlexer.cpp b/src/coreclr/binder/stringlexer.cpp index b6b722fa77ab9..44ec23e3b517c 100644 --- a/src/coreclr/binder/stringlexer.cpp +++ b/src/coreclr/binder/stringlexer.cpp @@ -19,7 +19,7 @@ namespace BINDER_SPACE { StringLexer::LEXEME_TYPE - StringLexer::GetNextLexeme(SString ¤tString, BOOL fPermitUnescapedQuotes) + StringLexer::GetNextLexeme(SString ¤tString) { BOOL fIsEscaped = FALSE; WCHAR wcCurrentChar = INVALID_CHARACTER; @@ -43,11 +43,11 @@ namespace BINDER_SPACE // First character of string lexeme; push it back PushCharacter(wcCurrentChar, fIsEscaped); - return ParseString(currentString, fPermitUnescapedQuotes); + return ParseString(currentString); } StringLexer::LEXEME_TYPE - StringLexer::ParseString(SString ¤tString, BOOL fPermitUnescapedQuotes) + StringLexer::ParseString(SString ¤tString) { BOOL fIsFirstCharacter = TRUE; WCHAR wcCurrentChar = INVALID_CHARACTER; @@ -99,7 +99,7 @@ namespace BINDER_SPACE break; } - if (!fPermitUnescapedQuotes && !fIsEscaped && IsQuoteCharacter(wcCurrentChar) && !IsQuoteCharacter(wcOpeningQuote)) + if (!fIsEscaped && IsQuoteCharacter(wcCurrentChar) && !IsQuoteCharacter(wcOpeningQuote)) { // Unescaped quotes in the middle of the string are an error return LEXEME_TYPE_INVALID; @@ -147,4 +147,24 @@ namespace BINDER_SPACE currentString.Truncate(cursor + 1); } } + + BOOL StringLexer::IsSeparatorChar(WCHAR wcChar) + { + return ((wcChar == W(',')) || (wcChar == W('='))); + } + + StringLexer::LEXEME_TYPE StringLexer::GetLexemeType(WCHAR wcChar) + { + switch (wcChar) + { + case W('='): + return LEXEME_TYPE_EQUALS; + case W(','): + return LEXEME_TYPE_COMMA; + case 0: + return LEXEME_TYPE_END_OF_STREAM; + default: + return LEXEME_TYPE_STRING; + } + } }; diff --git a/src/coreclr/binder/textualidentityparser.cpp b/src/coreclr/binder/textualidentityparser.cpp index f69e0bf66b202..35587df3cb7e4 100644 --- a/src/coreclr/binder/textualidentityparser.cpp +++ b/src/coreclr/binder/textualidentityparser.cpp @@ -200,30 +200,9 @@ namespace BINDER_SPACE // Nothing to do here } - BOOL TextualIdentityParser::IsSeparatorChar(WCHAR wcChar) - { - return ((wcChar == W(',')) || (wcChar == W('='))); - } - - StringLexer::LEXEME_TYPE TextualIdentityParser::GetLexemeType(WCHAR wcChar) - { - switch (wcChar) - { - case W('='): - return LEXEME_TYPE_EQUALS; - case W(','): - return LEXEME_TYPE_COMMA; - case 0: - return LEXEME_TYPE_END_OF_STREAM; - default: - return LEXEME_TYPE_STRING; - } - } - /* static */ HRESULT TextualIdentityParser::Parse(SString &textualIdentity, - AssemblyIdentity *pAssemblyIdentity, - BOOL fPermitUnescapedQuotes) + AssemblyIdentity *pAssemblyIdentity) { HRESULT hr = S_OK; @@ -233,7 +212,7 @@ namespace BINDER_SPACE { TextualIdentityParser identityParser(pAssemblyIdentity); - if (!identityParser.Parse(textualIdentity, fPermitUnescapedQuotes)) + if (!identityParser.Parse(textualIdentity)) { IF_FAIL_GO(FUSION_E_INVALID_NAME); } @@ -335,18 +314,6 @@ namespace BINDER_SPACE textualIdentity.Append(ContentTypeToString(pAssemblyIdentity->m_kContentType)); } - if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CUSTOM)) - { - textualIdentity.Append(W(", Custom=")); - tmpString.Clear(); - BlobToHex(pAssemblyIdentity->m_customBLOB, tmpString); - textualIdentity.Append(tmpString); - } - else if (AssemblyIdentity::Have(dwIdentityFlags, - AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL)) - { - textualIdentity.Append(W(", Custom=null")); - } } EX_CATCH_HRESULT(hr); @@ -486,19 +453,19 @@ namespace BINDER_SPACE publicKeyOrToken.CloseBuffer(cbPublicKeyOrTokenBLOB * 2); } - BOOL TextualIdentityParser::Parse(SString &textualIdentity, BOOL fPermitUnescapedQuotes) + BOOL TextualIdentityParser::Parse(SString &textualIdentity) { BOOL fIsValid = TRUE; SString unicodeTextualIdentity; // Lexer modifies input string textualIdentity.ConvertToUnicode(unicodeTextualIdentity); - Init(unicodeTextualIdentity, TRUE /* fSupportEscaping */); + Init(unicodeTextualIdentity); SmallStackSString currentString; // Identity format is simple name (, attr = value)* - GO_IF_NOT_EXPECTED(GetNextLexeme(currentString, fPermitUnescapedQuotes), LEXEME_TYPE_STRING); + GO_IF_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_STRING); m_pAssemblyIdentity->m_simpleName.Set(currentString); m_pAssemblyIdentity->m_simpleName.Normalize(); m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME); @@ -532,7 +499,7 @@ namespace BINDER_SPACE // Lexer modifies input string textualString.ConvertToUnicode(unicodeTextualString); - Init(unicodeTextualString, TRUE /* fSupportEscaping */); + Init(unicodeTextualString); SmallStackSString currentString; GO_IF_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_STRING); @@ -549,8 +516,7 @@ namespace BINDER_SPACE { BOOL fIsValid = TRUE; - if (EqualsCaseInsensitive(attributeString, W("culture")) || - EqualsCaseInsensitive(attributeString, W("language"))) + if (EqualsCaseInsensitive(attributeString, W("culture"))) { GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CULTURE); GO_IF_WILDCARD(valueString); @@ -586,8 +552,7 @@ namespace BINDER_SPACE GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN); GO_IF_WILDCARD(valueString); - if (!EqualsCaseInsensitive(valueString, W("null")) && - !EqualsCaseInsensitive(valueString, W("neutral"))) + if (!EqualsCaseInsensitive(valueString, W("null"))) { GO_IF_VALIDATE_FAILED(ValidatePublicKeyToken, AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN); @@ -606,8 +571,7 @@ namespace BINDER_SPACE GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN); GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY); - if (!EqualsCaseInsensitive(valueString, W("null")) && - !EqualsCaseInsensitive(valueString, W("neutral"))) + if (!EqualsCaseInsensitive(valueString, W("null"))) { GO_IF_VALIDATE_FAILED(ValidatePublicKey, AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY); HexToBlob(valueString, @@ -661,23 +625,6 @@ namespace BINDER_SPACE fIsValid = FALSE; } } - else if (EqualsCaseInsensitive(attributeString, W("custom"))) - { - GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CUSTOM); - - if (EqualsCaseInsensitive(valueString, W("null"))) - { - m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL); - } - else - { - GO_IF_VALIDATE_FAILED(ValidateHex, AssemblyIdentity::IDENTITY_FLAG_CUSTOM); - HexToBlob(valueString, - FALSE /* fValidateHex */, - FALSE /* fIsToken */, - m_pAssemblyIdentity->m_customBLOB); - } - } Exit: return fIsValid; diff --git a/src/coreclr/vm/assemblyspec.cpp b/src/coreclr/vm/assemblyspec.cpp index dfbee7152df19..0cea7dc712107 100644 --- a/src/coreclr/vm/assemblyspec.cpp +++ b/src/coreclr/vm/assemblyspec.cpp @@ -271,6 +271,11 @@ HRESULT AssemblySpec::InitializeSpec(StackingAllocator* alloc, ASSEMBLYNAMEREF* WCHAR* pString; int iString; ((STRINGREF) (*pName)->GetSimpleName())->RefInterpretGetStringValuesDangerousForGC(&pString, &iString); + + // we will not parse names that contain nulls + if (fParse && (wcslen(pString) != (size_t)iString)) + ThrowHR(FUSION_E_INVALID_NAME); + DWORD lgth = WszWideCharToMultiByte(CP_UTF8, 0, pString, iString, NULL, 0, NULL, NULL); if (lgth + 1 < lgth) ThrowHR(E_INVALIDARG); @@ -290,7 +295,8 @@ HRESULT AssemblySpec::InitializeSpec(StackingAllocator* alloc, ASSEMBLYNAMEREF* SetName(lpName); } - if (fParse) { + if (fParse) + { HRESULT hr = ParseName(); // Sometimes Fusion flags invalid characters in the name, sometimes it doesn't // depending on where the invalid characters are diff --git a/src/coreclr/vm/assemblyspec.hpp b/src/coreclr/vm/assemblyspec.hpp index 5d09b5b75a664..d6ce12300170e 100644 --- a/src/coreclr/vm/assemblyspec.hpp +++ b/src/coreclr/vm/assemblyspec.hpp @@ -105,7 +105,7 @@ class AssemblySpec : public BaseAssemblySpec void InitializeSpec(PEAssembly* pPEAssembly); HRESULT InitializeSpec(StackingAllocator* alloc, ASSEMBLYNAMEREF* pName, - BOOL fParse = TRUE); + BOOL fParse); void AssemblyNameInit(ASSEMBLYNAMEREF* pName, PEImage* pImageInfo); //[in,out], [in] diff --git a/src/libraries/System.Reflection/tests/AssemblyNameTests.cs b/src/libraries/System.Reflection/tests/AssemblyNameTests.cs index 05f3bf31a0c68..7e9b8c5849b22 100644 --- a/src/libraries/System.Reflection/tests/AssemblyNameTests.cs +++ b/src/libraries/System.Reflection/tests/AssemblyNameTests.cs @@ -68,6 +68,15 @@ public void Ctor_String(string name, string expectedName) Assert.Equal(ProcessorArchitecture.None, assemblyName.ProcessorArchitecture); } + [Theory] + [InlineData("MyAssemblyName, Version=1.0.0.0, PublicKeyToken=b77a5c561934e089", "MyAssemblyName, Version=1.0.0.0, PublicKeyToken=b77a5c561934e089")] + [InlineData("MyAssemblyName, Version=1.0.0.0, PublicKey=00000000000000000400000000000000", "MyAssemblyName, Version=1.0.0.0, PublicKeyToken=b77a5c561934e089")] + public void Ctor_String_Public_Key(string name, string expectedName) + { + AssemblyName assemblyName = new AssemblyName(name); + Assert.Equal(expectedName, assemblyName.FullName); + } + [Theory] [InlineData(null, typeof(ArgumentNullException))] [InlineData("", typeof(ArgumentException))] @@ -76,11 +85,40 @@ public void Ctor_String(string name, string expectedName) [InlineData("/a", typeof(FileLoadException))] [InlineData(" ", typeof(FileLoadException))] [InlineData(" \t \r \n ", typeof(FileLoadException))] + [InlineData("aa, culture=en-en, culture=en-en", typeof(FileLoadException))] + [InlineData("MyAssemblyName, PublicKey=00000000000000000400000000000000, PublicKeyToken=b77a5c561934e089", typeof(FileLoadException))] public void Ctor_String_Invalid(string assemblyName, Type exceptionType) { Assert.Throws(exceptionType, () => new AssemblyName(assemblyName)); } + [Theory] + [InlineData("aaaa, language=en-en", "aaaa")] + [InlineData("aaaa, foo=bar, foo=baz", "aaaa")] + [InlineData("aaaa, foo = bar, foo = bar", "aaaa")] + [InlineData("aaaa, custom=10", "aaaa")] + [InlineData("aaaa, custom=10, custom=20", "aaaa")] + [InlineData("aaaa, custom=lalala", "aaaa")] + public void Ctor_String_Valid_Legacy(string name, string expectedName) + { + AssemblyName assemblyName = new AssemblyName(name); + Assert.Equal(expectedName, assemblyName.Name); + } + + [Theory] + [InlineData("name\\u50; ", typeof(FileLoadException))] + [InlineData("aa/name ", typeof(FileLoadException))] + [InlineData("aa\\/tname", typeof(FileLoadException))] + [InlineData("aaaa, publickey=neutral", typeof(FileLoadException))] + [InlineData("aaaa, publickeytoken=neutral", typeof(FileLoadException))] + [InlineData("aaaa\0", typeof(FileLoadException))] + [InlineData("aaaa\0potato", typeof(FileLoadException))] + [InlineData("aaaa, publickeytoken=null\0,culture=en-en", typeof(FileLoadException))] + public void Ctor_String_Invalid_Legacy(string assemblyName, Type exceptionType) + { + Assert.Throws(exceptionType, () => new AssemblyName(assemblyName)); + } + [Theory] [InlineData("na,me", typeof(FileLoadException))] [InlineData("na=me", typeof(FileLoadException))] diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/AssemblyName.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/AssemblyName.Mono.cs index 867cf694cb2c4..12b2a5936c3de 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/AssemblyName.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/AssemblyName.Mono.cs @@ -19,6 +19,9 @@ public AssemblyName(string assemblyName) if (assemblyName.Length == 0 || assemblyName[0] == '\0') throw new ArgumentException(SR.Format_StringZeroLength); + if (assemblyName.Contains('\0')) + throw new FileLoadException("The assembly name is invalid."); + using (SafeStringMarshal name = RuntimeMarshal.MarshalString(assemblyName)) { // TODO: Should use CoreRT AssemblyNameParser diff --git a/src/mono/mono/metadata/assembly.c b/src/mono/mono/metadata/assembly.c index e8c4bbee3c0a4..493c3ff47d3c5 100644 --- a/src/mono/mono/metadata/assembly.c +++ b/src/mono/mono/metadata/assembly.c @@ -2544,7 +2544,7 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole gchar *key_uq; gchar *retargetable = NULL; gchar *retargetable_uq; - gchar *procarch; + gchar *procarch = NULL; gchar *procarch_uq; gboolean res; gchar *value, *part_name; @@ -2590,43 +2590,47 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) { *is_version_defined = TRUE; - version = value; - if (strlen (version) == 0) { + if (version != NULL || strlen (value) == 0) { goto cleanup_and_fail; } + version = value; tmp++; continue; } if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) { - culture = value; - if (strlen (culture) == 0) { + if (culture != NULL || strlen (value) == 0) { goto cleanup_and_fail; } + culture = value; tmp++; continue; } if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) { *is_token_defined = TRUE; - token = value; - if (strlen (token) == 0) { + if (token != NULL || key != NULL || strlen (value) == 0) { goto cleanup_and_fail; } + token = value; tmp++; continue; } if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) { - key = value; - if (strlen (key) == 0) { + if (token != NULL || key != NULL || strlen (value) == 0) { goto cleanup_and_fail; } + key = value; tmp++; continue; } if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) { + if (retargetable != NULL) { + goto cleanup_and_fail; + } + retargetable = value; retargetable_uq = unquote (retargetable); if (retargetable_uq != NULL) @@ -2645,6 +2649,10 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole } if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) { + if (procarch != NULL) { + goto cleanup_and_fail; + } + procarch = value; procarch_uq = unquote (procarch); if (procarch_uq != NULL) @@ -2672,7 +2680,8 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole continue; } - goto cleanup_and_fail; + // compat: If we got here, the attribute name is unknown to us. Ignore it. + tmp++; } /* if retargetable flag is set, then we must have a fully qualified name */ From 5605bdff4b104496941cc9e6acfc19783a52e7b8 Mon Sep 17 00:00:00 2001 From: Julius Hardt Date: Sun, 23 Jan 2022 02:32:42 +0100 Subject: [PATCH 147/308] Dispose LdapConnections used by ValidateCredentials (#62036) Ensure that cached LdapConnection instances created by PrincipalContext.ValidateCredentials are disposed when the corresponding PrincipalContext is disposed. Fix #62035 --- .../DirectoryServices/AccountManagement/Context.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Context.cs b/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Context.cs index b132723c385ac..3a04bcc8a4b77 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Context.cs +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Context.cs @@ -44,7 +44,7 @@ internal static class CapabilityMap public const string LDAP_CAP_ACTIVE_DIRECTORY_V61_OID = "1.2.840.113556.1.4.1935"; } - internal sealed class CredentialValidator + internal sealed class CredentialValidator : IDisposable { private enum AuthMethod { @@ -341,6 +341,14 @@ public bool Validate(string userName, string password, ContextOptions connection return (BindSam(_serverName, userName, password)); } } + + public void Dispose() + { + foreach (LdapConnection connection in _connCache.Values) + { + connection.Dispose(); + } + } } // ******************************************** public class PrincipalContext : IDisposable @@ -1014,6 +1022,8 @@ public void Dispose() if (_queryCtx != null) _queryCtx.Dispose(); + _credValidate.Dispose(); + _disposed = true; GC.SuppressFinalize(this); } From 4a6d169f5391532340074b0be4cab737c6ccdfc8 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Sun, 23 Jan 2022 09:39:24 -0500 Subject: [PATCH 148/308] Add runtime support for `ref` fields (#63985) * Add mono and coreclr runtime support for ref fields * Update Reflection.Emit tests to validate ref fields. Add test for TypedReference as a ref field. --- .../System/Reflection/Emit/ModuleBuilder.cs | 25 ++-- .../src/System/Reflection/Emit/TypeBuilder.cs | 2 + src/coreclr/utilcode/util.cpp | 4 +- src/coreclr/vm/field.cpp | 8 +- src/coreclr/vm/jitinterface.cpp | 3 - src/coreclr/vm/methodtablebuilder.cpp | 26 +++- .../src/Resources/Strings.resx | 3 - .../MethodBuilder/MethodBuilderByRefs.cs | 21 +++ .../ModuleBuilder/ModuleBuilderDefineEnum.cs | 4 +- .../tests/System.Reflection.Emit.Tests.csproj | 1 + .../TypeBuilderAddInterfaceImplementaion.cs | 7 - .../TypeBuilder/TypeBuilderDefineEvent.cs | 6 +- .../TypeBuilder/TypeBuilderDefineField.cs | 73 +++++++++-- .../TypeBuilderDefineNestedType.cs | 8 +- .../tests/TypeBuilder/TypeBuilderSetParent.cs | 4 +- .../System.Reflection.Emit/tests/Utilities.cs | 11 +- .../Reflection/Emit/ILGenerator.Mono.cs | 3 - .../Reflection/Emit/TypeBuilder.Mono.cs | 24 ++-- src/mono/mono/metadata/class-init.c | 8 ++ src/mono/mono/metadata/class.c | 9 +- src/mono/mono/metadata/object-internals.h | 1 + src/mono/mono/metadata/object.c | 1 + src/mono/mono/metadata/sre.c | 11 ++ .../classloader/RefFields/InvalidCSharp.il | 123 ++++++++++++++++++ .../RefFields/InvalidCSharp.ilproj | 8 ++ .../Loader/classloader/RefFields/Validate.cs | 59 +++++++++ .../classloader/RefFields/Validate.csproj | 12 ++ src/tests/issues.targets | 5 +- 28 files changed, 391 insertions(+), 79 deletions(-) create mode 100644 src/libraries/System.Reflection.Emit/tests/MethodBuilder/MethodBuilderByRefs.cs create mode 100644 src/tests/Loader/classloader/RefFields/InvalidCSharp.il create mode 100644 src/tests/Loader/classloader/RefFields/InvalidCSharp.ilproj create mode 100644 src/tests/Loader/classloader/RefFields/Validate.cs create mode 100644 src/tests/Loader/classloader/RefFields/Validate.csproj diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs index fe5da8367cdd4..f8b8c1efd35d0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs @@ -233,7 +233,7 @@ private int GetTypeRefNested(Type type, Module? refedModule, string? strRefedMod typeName = UnmangleTypeName(typeName); } - Debug.Assert(!type.IsByRef, "Must not be ByRef."); + Debug.Assert(!type.IsByRef, "Must not be ByRef. Get token from TypeSpec."); Debug.Assert(!type.IsGenericType || type.IsGenericTypeDefinition, "Must not have generic arguments."); ModuleBuilder thisModule = this; @@ -1081,19 +1081,16 @@ private int GetTypeTokenWorkerNoLock(Type type, bool getGenericDefinition) // instructions. Tokens are always relative to the Module. For example, // the token value for System.String is likely to be different from // Module to Module. Calling GetTypeToken will cause a reference to be - // added to the Module. This reference becomes a perminate part of the Module, - // multiple calles to this method with the same class have no additional side affects. - // This function is optimized to use the TypeDef token if Type is within the same module. - // We should also be aware of multiple dynamic modules and multiple implementation of Type!!! - if (type.IsByRef) - { - throw new ArgumentException(SR.Argument_CannotGetTypeTokenForByRef); - } - - if ((type.IsGenericType && (!type.IsGenericTypeDefinition || !getGenericDefinition)) || - type.IsGenericParameter || - type.IsArray || - type.IsPointer) + // added to the Module. This reference becomes a permanent part of the Module, + // multiple calls to this method with the same class have no additional side-effects. + // This function is optimized to use the TypeDef token if the Type is within the + // same module. We should also be aware of multiple dynamic modules and multiple + // implementations of a Type. + if ((type.IsGenericType && (!type.IsGenericTypeDefinition || !getGenericDefinition)) + || type.IsGenericParameter + || type.IsArray + || type.IsPointer + || type.IsByRef) { byte[] sig = SignatureHelper.GetTypeSigToken(this, type).InternalGetSignature(out int length); return GetTokenFromTypeSpec(sig, length); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs index 6d9b8121fa6b4..a242ec948896b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs @@ -1922,7 +1922,9 @@ private EventBuilder DefineEventNoLock(string name, EventAttributes attributes, int tkParent = 0; if (m_typeParent != null) + { tkParent = m_module.GetTypeTokenInternal(m_typeParent); + } ModuleBuilder module = m_module; diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index 44b5250547689..bf31761902dce 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -1806,9 +1806,7 @@ HRESULT validateOneArg( // Validate the referenced type. if(FAILED(hr = validateOneArg(tk, pSig, pulNSentinels, pImport, FALSE))) IfFailGo(hr); break; - case ELEMENT_TYPE_BYREF: //fallthru - if(TypeFromToken(tk)==mdtFieldDef) IfFailGo(VLDTR_E_SIG_BYREFINFIELD); - FALLTHROUGH; + case ELEMENT_TYPE_BYREF: case ELEMENT_TYPE_PINNED: case ELEMENT_TYPE_SZARRAY: // Validate the referenced type. diff --git a/src/coreclr/vm/field.cpp b/src/coreclr/vm/field.cpp index a0e1260976dee..3855f4a22c0df 100644 --- a/src/coreclr/vm/field.cpp +++ b/src/coreclr/vm/field.cpp @@ -61,6 +61,8 @@ VOID FieldDesc::Init(mdFieldDef mb, CorElementType FieldType, DWORD dwMemberAttr FieldType == ELEMENT_TYPE_R8 || FieldType == ELEMENT_TYPE_CLASS || FieldType == ELEMENT_TYPE_VALUETYPE || + FieldType == ELEMENT_TYPE_BYREF || + FieldType == ELEMENT_TYPE_TYPEDBYREF || FieldType == ELEMENT_TYPE_PTR || FieldType == ELEMENT_TYPE_FNPTR ); @@ -70,7 +72,8 @@ VOID FieldDesc::Init(mdFieldDef mb, CorElementType FieldType, DWORD dwMemberAttr m_requiresFullMbValue = 0; SetMemberDef(mb); - m_type = FieldType; + // A TypedByRef should be treated like a regular value type. + m_type = FieldType != ELEMENT_TYPE_TYPEDBYREF ? FieldType : ELEMENT_TYPE_VALUETYPE; m_prot = fdFieldAccessMask & dwMemberAttrs; m_isStatic = fIsStatic != 0; m_isRVA = fIsRVA != 0; @@ -81,7 +84,7 @@ VOID FieldDesc::Init(mdFieldDef mb, CorElementType FieldType, DWORD dwMemberAttr #endif _ASSERTE(GetMemberDef() == mb); // no truncation - _ASSERTE(GetFieldType() == FieldType); + _ASSERTE(GetFieldType() == FieldType || (FieldType == ELEMENT_TYPE_TYPEDBYREF && m_type == ELEMENT_TYPE_VALUETYPE)); _ASSERTE(GetFieldProtection() == (fdFieldAccessMask & dwMemberAttrs)); _ASSERTE((BOOL) IsStatic() == (fIsStatic != 0)); } @@ -152,6 +155,7 @@ TypeHandle FieldDesc::LookupFieldTypeHandle(ClassLoadLevel level, BOOL dropGener _ASSERTE(type == ELEMENT_TYPE_CLASS || type == ELEMENT_TYPE_VALUETYPE || type == ELEMENT_TYPE_STRING || + type == ELEMENT_TYPE_TYPEDBYREF || type == ELEMENT_TYPE_SZARRAY || type == ELEMENT_TYPE_VAR ); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index e28434acabe56..f02693ae03421 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9002,9 +9002,6 @@ CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd, FieldDesc* field = (FieldDesc*) fieldHnd; CorElementType type = field->GetFieldType(); - // TODO should not burn the time to do this for anything but Value Classes - _ASSERTE(type != ELEMENT_TYPE_BYREF); - if (type == ELEMENT_TYPE_I) { PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable(); diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 68d11affa4351..59566e2e71717 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -3935,6 +3935,27 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, break; } + case ELEMENT_TYPE_BYREF: + { + dwLog2FieldSize = LOG2_PTRSIZE; + if (fIsStatic) + { + // Byref-like types cannot be used for static fields + BuildMethodTableThrowException(IDS_CLASSLOAD_BYREFLIKE_STATICFIELD); + } + if (!bmtFP->fIsByRefLikeType) + { + // Non-byref-like types cannot contain byref-like instance fields + BuildMethodTableThrowException(IDS_CLASSLOAD_BYREFLIKE_INSTANCEFIELD); + } + break; + } + + case ELEMENT_TYPE_TYPEDBYREF: + { + goto IS_VALUETYPE; + } + // Class type variable (method type variables aren't allowed in fields) // These only occur in open types used for verification/reflection. case ELEMENT_TYPE_VAR: @@ -4042,7 +4063,10 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, pByValueClass = (MethodTable *)-1; } } // If 'this' is a value class - + } + // TypedReference shares the rest of the code here +IS_VALUETYPE: + { // It's not self-referential so try to load it if (pByValueClass == NULL) { diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index f98789424343b..e9d5e447ee90f 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -903,9 +903,6 @@ Cannot use function evaluation to create a TypedReference object. - - Cannot get TypeToken for a ByRef type. - Cannot set parent to an interface. diff --git a/src/libraries/System.Reflection.Emit/tests/MethodBuilder/MethodBuilderByRefs.cs b/src/libraries/System.Reflection.Emit/tests/MethodBuilder/MethodBuilderByRefs.cs new file mode 100644 index 0000000000000..01baa3bc010d9 --- /dev/null +++ b/src/libraries/System.Reflection.Emit/tests/MethodBuilder/MethodBuilderByRefs.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. + +using System.Linq; +using Xunit; + +namespace System.Reflection.Emit.Tests +{ + public class MethodBuilderByRefs + { + [Fact] + public void ByRef_Ldtoken() + { + TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); + MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.Public, typeof(Type), Type.EmptyTypes); + ILGenerator ilg = method.GetILGenerator(); + ilg.Emit(OpCodes.Ldtoken, typeof(int).MakeByRefType()); + ilg.Emit(OpCodes.Ret); + } + } +} \ No newline at end of file diff --git a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs index 34433ae11f391..e1d927cfa25b0 100644 --- a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs +++ b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs @@ -160,11 +160,11 @@ public void DefineEnum_VoidUnderlyingType_ThrowsArgumentException() } [Fact] - public void DefineEnum_ByRefUnderlyingType_ThrowsCOMExceptionOnCreation() + public void DefineEnum_ByRefUnderlyingType_ThrowsTypeLoadExceptionOnCreation() { ModuleBuilder module = Helpers.DynamicModule(); EnumBuilder enumBuilder = module.DefineEnum("Name", TypeAttributes.Public, typeof(int).MakeByRefType()); - Assert.Throws(() => enumBuilder.CreateTypeInfo()); + Assert.Throws(() => enumBuilder.CreateTypeInfo()); } [Theory] 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 e5d46e991da82..d47bdd3466c79 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 @@ -33,6 +33,7 @@ + diff --git a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderAddInterfaceImplementaion.cs b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderAddInterfaceImplementaion.cs index 8d9adab4662e0..da3e695dcd389 100644 --- a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderAddInterfaceImplementaion.cs +++ b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderAddInterfaceImplementaion.cs @@ -61,13 +61,6 @@ public void AddInterfaceImplementation_NullInterfaceType_ThrowsArgumentNullExcep AssertExtensions.Throws("interfaceType", () => type.AddInterfaceImplementation(null)); } - [Fact] - public void AddInterfaceImplementation_ByRefInterfaceType_ThrowsArgumentExceptioN() - { - TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); - AssertExtensions.Throws(null, () => type.AddInterfaceImplementation(typeof(int).MakeByRefType())); - } - [Fact] public void AddInterfaceImplementation_TypeAlreadyCreated_ThrowsInvalidOperationException() { diff --git a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineEvent.cs b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineEvent.cs index 2c7452339c9e8..59ebb7fc77bb4 100644 --- a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineEvent.cs +++ b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineEvent.cs @@ -106,11 +106,11 @@ public void DefineEvent_Invalid(string name, Type eventType, Type exceptionType) } [Fact] - public void DefineEvent_ByRefEventType_ThrowsArgumentException() + public void DefineEvent_ByRefEventType() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.Class | TypeAttributes.Public); - - AssertExtensions.Throws(null, () => type.DefineEvent("Name", EventAttributes.None, typeof(int).MakeByRefType())); + type.DefineEvent("Name", EventAttributes.None, typeof(int).MakeByRefType()); + type.CreateTypeInfo().AsType(); } [Fact] diff --git a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineField.cs b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineField.cs index e765a08dcc403..a09e69f6738ad 100644 --- a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineField.cs +++ b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineField.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Xunit; @@ -112,15 +113,6 @@ public void DefineField_VoidFieldType_ThrowsArgumentException() AssertExtensions.Throws(null, () => type.DefineField("Name", typeof(void), FieldAttributes.Public)); } - [Fact] - public void DefineField_ByRefFieldType_ThrowsCOMExceptionOnCreation() - { - TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); - type.DefineField("Name", typeof(int).MakeByRefType(), FieldAttributes.Public); - - Assert.Throws(() => type.CreateTypeInfo()); - } - [Theory] [ActiveIssue("https://github.com/dotnet/runtime/issues/2389", TestRuntimes.Mono)] [InlineData((FieldAttributes)(-1), (FieldAttributes)(-38145))] @@ -152,6 +144,69 @@ public void DefineField_DynamicFieldTypeNotCreated_ThrowsTypeLoadException() Assert.Equal(createdFieldType, field.FieldType); } + [Fact] + public void DefineByRefField_Class_ThrowsTypeLoadExceptionOnCreation() + { + TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); + type.DefineField("Name", typeof(int).MakeByRefType(), FieldAttributes.Public); + + Assert.Throws(() => type.CreateTypeInfo()); + } + + [Fact] + public void DefineByRefField_ValueType_NonByRefLike_ThrowsTypeLoadExceptionOnCreation() + { + TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public, baseType: typeof(ValueType)); + type.DefineField("Name", typeof(int).MakeByRefType(), FieldAttributes.Public); + + Assert.Throws(() => type.CreateTypeInfo()); + } + + [Fact] + public void DefineByRefField_ValueType_ByRefLike() + { + TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public, baseType: typeof(ValueType)); + + // Define type to be ByRefLike + CustomAttributeBuilder ca = new(typeof(IsByRefLikeAttribute).GetConstructors()[0], new object[] { }); + type.SetCustomAttribute(ca); + + type.DefineField("Name", typeof(int).MakeByRefType(), FieldAttributes.Public); + + Type createdType = type.CreateTypeInfo().AsType(); + FieldInfo[] fields = createdType.GetFields(); + Assert.Equal(1, fields.Length); + Assert.True(fields[0].FieldType.IsByRef); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/45152")] + public void Instantiate_ValueType_With_ByRefField() + { + TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public, baseType: typeof(ValueType)); + + // Define type to be ByRefLike + CustomAttributeBuilder ca = new(typeof(IsByRefLikeAttribute).GetConstructors()[0], new object[] { }); + type.SetCustomAttribute(ca); + + var field = type.DefineField("Name", typeof(int).MakeByRefType(), FieldAttributes.Public); + + var ctor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { typeof(string) }); + { + ILGenerator il = ctor.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarga_S, 1); + il.Emit(OpCodes.Stfld, field); + il.Emit(OpCodes.Ret); + } + + Type createdType = type.CreateTypeInfo().AsType(); + + var ctorToCall = createdType.GetConstructor(BindingFlags.Public | BindingFlags.Instance, new[] { typeof(string) }); + var str = "12345"; + ctorToCall.Invoke(new[] { str }); + } + [Fact] public void GetField_TypeNotCreated_ThrowsNotSupportedException() { diff --git a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineNestedType.cs b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineNestedType.cs index cf24e8d87adad..d71506544525d 100644 --- a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineNestedType.cs +++ b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineNestedType.cs @@ -210,15 +210,9 @@ public void DefineNestedType_NullInterface_ThrowsArgumentNullException() AssertExtensions.Throws("interfaces", () => type.DefineNestedType("Name", TypeAttributes.NestedPublic, typeof(object), new Type[] { null })); } - [Fact] - public void DefineNestedType_ByRefInterfaceType_ThrowsArgumentException() - { - TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); - AssertExtensions.Throws(null, () => type.DefineNestedType("Name", TypeAttributes.NestedPublic, typeof(object), new Type[] { typeof(int).MakeByRefType() })); - } - public static IEnumerable InvalidInterfaceType_TestData() { + yield return new object[] { typeof(int).MakeByRefType() }; yield return new object[] { typeof(EmptyNonGenericClass) }; yield return new object[] { typeof(EmptyNonGenericStruct) }; yield return new object[] { typeof(EmptyGenericClass) }; diff --git a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderSetParent.cs b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderSetParent.cs index 8a4e5ace9ec8d..5c985d52a4676 100644 --- a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderSetParent.cs +++ b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderSetParent.cs @@ -56,14 +56,14 @@ public void SetParent_InterfaceType_ThrowsArgumentException(TypeAttributes attri } [Fact] - public void SetParent_ByRefType_ThrowsArgumentExceptionOnCreation() + public void SetParent_ByRefType_ThrowsNotSupportedExceptionOnCreation() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); type.SetParent(typeof(int).MakeByRefType()); Assert.Equal(typeof(int).MakeByRefType(), type.BaseType); - AssertExtensions.Throws(null, () => type.CreateTypeInfo()); + Assert.Throws(() => type.CreateTypeInfo()); } [Fact] diff --git a/src/libraries/System.Reflection.Emit/tests/Utilities.cs b/src/libraries/System.Reflection.Emit/tests/Utilities.cs index 8e1c965e19a27..1e951be849a86 100644 --- a/src/libraries/System.Reflection.Emit/tests/Utilities.cs +++ b/src/libraries/System.Reflection.Emit/tests/Utilities.cs @@ -54,9 +54,16 @@ public static ModuleBuilder DynamicModule(string assemblyName = "TestAssembly", return DynamicAssembly(assemblyName).DefineDynamicModule(moduleName); } - public static TypeBuilder DynamicType(TypeAttributes attributes, string assemblyName = "TestAssembly", string moduleName = "TestModule", string typeName = "TestType") + public static TypeBuilder DynamicType(TypeAttributes attributes, string assemblyName = "TestAssembly", string moduleName = "TestModule", string typeName = "TestType", Type? baseType = null) { - return DynamicModule(assemblyName, moduleName).DefineType(typeName, attributes); + if (baseType is null) + { + return DynamicModule(assemblyName, moduleName).DefineType(typeName, attributes); + } + else + { + return DynamicModule(assemblyName, moduleName).DefineType(typeName, attributes, baseType); + } } public static EnumBuilder DynamicEnum(TypeAttributes visibility, Type underlyingType, string enumName = "TestEnum", string assemblyName = "TestAssembly", string moduleName = "TestModule") diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.Mono.cs index 51edf3f644875..64585857fffc0 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.Mono.cs @@ -819,9 +819,6 @@ public virtual void Emit(OpCode opcode, string str) public virtual void Emit(OpCode opcode, Type cls) { - if (cls != null && cls.IsByRef) - throw new ArgumentException("Cannot get TypeToken for a ByRef type."); - make_room(6); ll_emit(opcode); int token = token_gen.GetToken(cls!, opcode != OpCodes.Ldtoken); diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.Mono.cs index 1e73f98f1505f..1209f517736a4 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.Mono.cs @@ -74,6 +74,7 @@ public sealed partial class TypeBuilder : TypeInfo [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] private TypeInfo? created; + private bool is_byreflike_set; private int state; #endregion @@ -273,8 +274,7 @@ public void AddInterfaceImplementation([DynamicallyAccessedMembers(DynamicallyAc { if (interfaceType == null) throw new ArgumentNullException(nameof(interfaceType)); - if (interfaceType.IsByRef) - throw new ArgumentException(SR.Argument_CannotGetTypeTokenForByRef); + check_not_created(); if (interfaces != null) @@ -838,7 +838,7 @@ private bool has_ctor_method() if (parent != null) { if (parent.IsByRef) - throw new ArgumentException(); + throw new NotSupportedException(); if (IsInterface) throw new TypeLoadException(); } @@ -877,17 +877,6 @@ private bool has_ctor_method() } } - if (fields != null) - { - foreach (FieldBuilder fb in fields) - { - if (fb == null) - continue; - if (fb.FieldType.IsByRef) - throw new COMException(); - } - } - if (methods != null) { bool is_concrete = !IsAbstract; @@ -1544,6 +1533,10 @@ public void SetCustomAttribute(CustomAttributeBuilder customBuilder) { attrs |= TypeAttributes.HasSecurity; } + else if (attrname == "System.Runtime.CompilerServices.IsByRefLikeAttribute") + { + is_byreflike_set = true; + } if (cattrs != null) { @@ -1571,8 +1564,7 @@ public EventBuilder DefineEvent(string name, EventAttributes attributes, Type ev if (eventtype == null) throw new ArgumentNullException(nameof(eventtype)); check_not_created(); - if (eventtype.IsByRef) - throw new ArgumentException(SR.Argument_CannotGetTypeTokenForByRef); + EventBuilder res = new EventBuilder(this, name, attributes, eventtype); if (events != null) { diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 2ae4f39dab855..0d8a74442b4d2 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -364,6 +364,14 @@ mono_class_setup_fields (MonoClass *klass) g_free (type_name); break; } + if (m_type_is_byref (field->type)) { + if (!m_class_is_byreflike (klass)) { + char *class_name = mono_type_get_full_name (klass); + mono_class_set_type_load_failure (klass, "Type %s is not a ByRefLike type so ref field, '%s', is invalid", class_name, field->name); + g_free (class_name); + break; + } + } /* The def_value of fields is compute lazily during vtable creation */ } diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index 895a654cbfeaa..eceb20cf4d0f6 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -4626,13 +4626,20 @@ mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class, case MONO_TOKEN_TYPE_REF: case MONO_TOKEN_TYPE_SPEC: { MonoType *type; + MonoClass *klass; if (handle_class) *handle_class = mono_defaults.typehandle_class; type = mono_type_get_checked (image, token, context, error); if (!type) return NULL; - mono_class_init_internal (mono_class_from_mono_type_internal (type)); + klass = mono_class_from_mono_type_internal (type); + mono_class_init_internal (klass); + if (mono_class_has_failure (klass)) { + mono_error_set_for_class_failure (error, klass); + return NULL; + } + /* We return a MonoType* as handle */ return type; } diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 2be830e375b15..efa4b0624548d 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -1222,6 +1222,7 @@ struct _MonoReflectionTypeBuilder { MonoGenericContainer *generic_container; MonoArray *generic_params; MonoReflectionType *created; + gboolean is_byreflike_set; gint32 state; }; diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index d87fade6e6122..5863a967d544f 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -887,6 +887,7 @@ compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int } else { /* fall through */ } + case MONO_TYPE_TYPEDBYREF: case MONO_TYPE_VALUETYPE: { MonoClass *fclass = mono_class_from_mono_type_internal (field->type); if (m_class_has_references (fclass)) { diff --git a/src/mono/mono/metadata/sre.c b/src/mono/mono/metadata/sre.c index 5a9e16eb81b8f..62254b3fa2c3e 100644 --- a/src/mono/mono/metadata/sre.c +++ b/src/mono/mono/metadata/sre.c @@ -3556,6 +3556,11 @@ typebuilder_setup_one_field (MonoDynamicImage *dynamic_image, MonoClass *klass, } } + if (m_type_is_byref (field->type) && !m_class_is_byreflike (klass)) { + mono_error_set_type_load_name (error, NULL, NULL, "Field '%s' is a byref in a non-byref-like type", field->name); + goto leave; + } + if ((fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) && (rva_data = fb->rva_data)) { char *base = mono_array_addr_internal (rva_data, char, 0); size_t size = mono_array_length_internal (rva_data); @@ -3857,6 +3862,12 @@ ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilderHandle ref_ mono_class_setup_supertypes (klass); mono_class_setup_mono_type (klass); + /* Check if the type is marked as byreflike. + * The IsByRefLike attribute only applies to value types and enums. This matches CoreCLR behavior. + */ + if (klass->enumtype || klass->valuetype) + klass->is_byreflike = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoReflectionTypeBuilder, ref_tb), is_byreflike_set); + /* enums are done right away */ if (!klass->enumtype) if (!ensure_runtime_vtable (klass, error)) diff --git a/src/tests/Loader/classloader/RefFields/InvalidCSharp.il b/src/tests/Loader/classloader/RefFields/InvalidCSharp.il new file mode 100644 index 0000000000000..b976227547def --- /dev/null +++ b/src/tests/Loader/classloader/RefFields/InvalidCSharp.il @@ -0,0 +1,123 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern System.Runtime { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) } + +.assembly InvalidCSharp { } + +.class public auto ansi sealed beforefieldinit InvalidCSharp.InvalidStructWithRefField + extends [System.Runtime]System.ValueType +{ + // Type requires IsByRefLikeAttribute to be valid. + .field public string& invalid +} + +// This is invalid metadata and is unable to be loaded. +// - [field sig] (0x80131815 (VER_E_FIELD_SIG)) +// +// .class public auto ansi sealed beforefieldinit InvalidCSharp.InvalidStructWithStaticRefField +// extends [System.Runtime]System.ValueType +// { +// .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( +// 01 00 00 00 +// ) +// .field public static string& invalid +// } + +.class public auto ansi sealed beforefieldinit InvalidCSharp.WithRefField + extends [System.Runtime]System.ValueType +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( + 01 00 00 00 + ) + .field public string& Str + + .method public hidebysig specialname rtspecialname + instance void .ctor ( + string& + ) cil managed + { + ldarg.0 + ldarg.1 + stfld string& InvalidCSharp.WithRefField::Str + ret + } + + .method public hidebysig + instance bool ConfirmFieldInstance ( + string + ) cil managed + { + ldarg.0 + ldfld string& InvalidCSharp.WithRefField::Str + ldind.ref + ldarg.1 + ceq + ret + } +} + +.class public auto ansi sealed beforefieldinit InvalidCSharp.WithRefStructField + extends [System.Runtime]System.ValueType +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( + 01 00 00 00 + ) + .field public valuetype InvalidCSharp.WithRefField& Field + + .method public hidebysig specialname rtspecialname + instance void .ctor ( + valuetype InvalidCSharp.WithRefField& + ) cil managed + { + ldarg.0 + ldarg.1 + stfld valuetype InvalidCSharp.WithRefField& InvalidCSharp.WithRefStructField::Field + ret + } + + .method public hidebysig + instance bool ConfirmFieldInstance ( + valuetype InvalidCSharp.WithRefField& + ) cil managed + { + ldarg.0 + ldfld valuetype InvalidCSharp.WithRefField& InvalidCSharp.WithRefStructField::Field + ldind.ref + ldarg.1 + ldind.ref + ceq + ret + } +} + +.class public auto ansi sealed beforefieldinit InvalidCSharp.WithTypedReferenceField`1 + extends [System.Runtime]System.ValueType +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( + 01 00 00 00 + ) + .field public typedref Field + + .method public hidebysig specialname rtspecialname + instance void .ctor ( + !T + ) cil managed + { + ldarg.0 + ldarga.s 1 + mkrefany !T + stfld typedref InvalidCSharp.WithTypedReferenceField`1::Field + ret + } + + .method public hidebysig + instance class [System.Runtime]System.Type GetFieldType () cil managed + { + ldarg.0 + ldfld typedref InvalidCSharp.WithTypedReferenceField`1::Field + refanytype + call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle ) + ret + } +} \ No newline at end of file diff --git a/src/tests/Loader/classloader/RefFields/InvalidCSharp.ilproj b/src/tests/Loader/classloader/RefFields/InvalidCSharp.ilproj new file mode 100644 index 0000000000000..d577c8f9c7a1a --- /dev/null +++ b/src/tests/Loader/classloader/RefFields/InvalidCSharp.ilproj @@ -0,0 +1,8 @@ + + + Library + + + + + diff --git a/src/tests/Loader/classloader/RefFields/Validate.cs b/src/tests/Loader/classloader/RefFields/Validate.cs new file mode 100644 index 0000000000000..bffcd53de2f00 --- /dev/null +++ b/src/tests/Loader/classloader/RefFields/Validate.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using InvalidCSharp; + +using Xunit; + +class Validate +{ + [Fact] + public static void Validate_Invalid_RefField_Fails() + { + Console.WriteLine($"{nameof(Validate_Invalid_RefField_Fails)}..."); + Assert.Throws(() => { var t = typeof(InvalidStructWithRefField); }); + } + + [Fact] + public static void Validate_RefStructWithRefField_Load() + { + Console.WriteLine($"{nameof(Validate_RefStructWithRefField_Load)}..."); + var t = typeof(WithRefField); + } + + [Fact] + public static void Validate_Create_RefField() + { + var str = nameof(Validate_Create_RefField); + Console.WriteLine($"{str}..."); + + WithRefField s = new(ref str); + Assert.True(s.ConfirmFieldInstance(str)); + + string newStr = new(str); + Assert.False(s.ConfirmFieldInstance(newStr)); + } + + [Fact] + public static void Validate_Create_RefStructField() + { + var str = nameof(Validate_Create_RefStructField); + Console.WriteLine($"{str}..."); + + WithRefField s = new(ref str); + WithRefStructField t = new(ref s); + Assert.True(t.ConfirmFieldInstance(ref s)); + } + + [Fact] + public static void Validate_Create_TypedReferenceRefField() + { + Console.WriteLine($"{nameof(Validate_Create_TypedReferenceRefField)}..."); + + Validate v = new(); + WithTypedReferenceField s = new(v); + Assert.Equal(typeof(Validate), s.GetFieldType()); + } +} \ No newline at end of file diff --git a/src/tests/Loader/classloader/RefFields/Validate.csproj b/src/tests/Loader/classloader/RefFields/Validate.csproj new file mode 100644 index 0000000000000..96fedddd4bdda --- /dev/null +++ b/src/tests/Loader/classloader/RefFields/Validate.csproj @@ -0,0 +1,12 @@ + + + true + Exe + + + + + + + + diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 7b718aa15617d..edf95e8c106f6 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1329,7 +1329,7 @@ - + @@ -2589,6 +2589,9 @@ expected failure: overlapped structs fail at AOT compile time, not runtime + + expected failure: unsupported type with ref field fails at AOT compile time, not runtime + https://github.com/dotnet/runtime/issues/57361 From 605ed5d89dc8e3dde2c9d4ca8072f9bd41d54333 Mon Sep 17 00:00:00 2001 From: Egor Chesakov Date: Sun, 23 Jan 2022 14:07:40 -0800 Subject: [PATCH 149/308] Spmi replay asmdiffs mac os arm64 (#64119) * Split unix-arm64 into linux-arm64 and osx-arm64 in src/coreclr/scripts/superpmi-replay.proj * Split unix-arm64 into linux-arm64 and osx-arm64 in src/coreclr/scripts/superpmi-asmdiffs.proj * Add all subdirectories of $(SuperPMIDirectory) as PMIPATH in src/coreclr/scripts/superpmi-collect.proj --- src/coreclr/scripts/superpmi-asmdiffs.proj | 3 ++- src/coreclr/scripts/superpmi-collect.proj | 9 +++++++-- src/coreclr/scripts/superpmi-replay.proj | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/coreclr/scripts/superpmi-asmdiffs.proj b/src/coreclr/scripts/superpmi-asmdiffs.proj index aef782d769cb9..661a60aca831a 100644 --- a/src/coreclr/scripts/superpmi-asmdiffs.proj +++ b/src/coreclr/scripts/superpmi-asmdiffs.proj @@ -55,7 +55,8 @@ - + + diff --git a/src/coreclr/scripts/superpmi-collect.proj b/src/coreclr/scripts/superpmi-collect.proj index 046a699917fc6..4a6edd8b5923b 100644 --- a/src/coreclr/scripts/superpmi-collect.proj +++ b/src/coreclr/scripts/superpmi-collect.proj @@ -42,6 +42,11 @@ PmiAssembliesPayload - Path that will be sent to helix machine to run collection on PmiAssembliesDirectory - Path on helix machine itself where superpmi.py will discover the sent assemblies. --> + + + + + %HELIX_PYTHONPATH% $(WorkItemDirectory)\pmiAssembliesDirectory @@ -54,7 +59,7 @@ %HELIX_WORKITEM_UPLOAD_ROOT% $(BUILD_SOURCESDIRECTORY)\artifacts\helixresults - $(SuperPMIDirectory)\superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)\pmi.dll -pmi_path $(SuperPMIDirectory)\crossgen2 + $(SuperPMIDirectory)\superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)\pmi.dll -pmi_path @(PmiPathDirectories->'%(FullPath)', ' ') $HELIX_PYTHONPATH @@ -68,7 +73,7 @@ $HELIX_WORKITEM_UPLOAD_ROOT $(BUILD_SOURCESDIRECTORY)/artifacts/helixresults - $(SuperPMIDirectory)/superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)/pmi.dll -pmi_path $(SuperPMIDirectory)/crossgen2 + $(SuperPMIDirectory)/superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)/pmi.dll -pmi_path @(PmiPathDirectories->'%(FullPath)', ' ') diff --git a/src/coreclr/scripts/superpmi-replay.proj b/src/coreclr/scripts/superpmi-replay.proj index e76a4a3d810e5..cac87c580fdde 100644 --- a/src/coreclr/scripts/superpmi-replay.proj +++ b/src/coreclr/scripts/superpmi-replay.proj @@ -55,7 +55,8 @@ - + + From 9d360c9aa24a61da9fc769644102da1b71179911 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Sun, 23 Jan 2022 14:23:32 -0800 Subject: [PATCH 150/308] Update NativeAOT codegen and Crossgen2 for CreateSpan (#63977) - Make sure FieldRVA pointers remain aligned as required by the code generator - Use the same Packing Size approach as the IL Linker will use (See jbevain/cecil#817 for details) - Compilers that generate CreateSpan will need to follow that trick to be compatible with rewriters. - Provide ECMA spec augment describing packing size detail --- docs/design/specs/Ecma-335-Augments.md | 10 ++++++++++ .../aot/ILCompiler.Compiler/Compiler/Compilation.cs | 3 ++- .../ReadyToRun/CopiedFieldRvaNode.cs | 9 ++++++--- src/tests/JIT/Intrinsics/CreateSpan_il.il | 2 +- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/design/specs/Ecma-335-Augments.md b/docs/design/specs/Ecma-335-Augments.md index 1c52fedd4d84c..6e1900c1dc6bd 100644 --- a/docs/design/specs/Ecma-335-Augments.md +++ b/docs/design/specs/Ecma-335-Augments.md @@ -13,6 +13,7 @@ This is a list of additions and edits to be made in ECMA-335 specifications. It - [Static Interface Methods](#static-interface-methods) - [Covariant Return Types](#covariant-return-types) - [Unsigned data conversion with overflow detection](#unsigned-data-conversion-with-overflow-detection) +- [Rules for IL rewriters](#rules-for-il-rewriters) ## Signatures @@ -948,3 +949,12 @@ Conversions from floating-point numbers to integral values truncate the number t on the top of the stack is reinterpreted as an unsigned value before the conversion. Note that integer values of less than 4 bytes are extended to int32 (not native int) on the evaluation stack. + +## Rules for IL Rewriters + +There are apis such as `System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(...)` which require that the PE file have a particular structure. In particular, that api requires that the associated RVA of a FieldDef which is used to create a span must be naturally aligned over the data type that `CreateSpan` is instantiated over. There are 2 major concerns. + +1. That the RVA be aligned when the PE file is constructed. This may be achieved by whatever means is most convenient for the compiler. +2. That in the presence of IL rewriters that the RVA remains aligned. This section descibes metadata which will be processed by IL rewriters in order to maintain the required alignment. + +In order to maintain alignment, if the field needs alignment to be preserved, the field must be of a type locally defined within the module which has a Pack (§II.10.7) value of the desired alignment. Unlike other uses of the .pack directive, in this circumstance the .pack specifies a minimum alignment. diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs index f3f780e87e060..d19b60b104c24 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs @@ -143,8 +143,9 @@ public virtual ISymbolNode GetFieldRvaData(FieldDesc field) { // Use the typical field definition in case this is an instantiated generic type field = field.GetTypicalFieldDefinition(); + int fieldTypePack = (field.FieldType as MetadataType)?.GetClassLayout().PackingSize ?? 1; return NodeFactory.ReadOnlyDataBlob(NameMangler.GetMangledFieldName(field), - ((EcmaField)field).GetFieldRvaData(), NodeFactory.Target.PointerSize); + ((EcmaField)field).GetFieldRvaData(), Math.Max(NodeFactory.Target.PointerSize, fieldTypePack)); } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedFieldRvaNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedFieldRvaNode.cs index e8596cf24c894..a8ff518ac7591 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedFieldRvaNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedFieldRvaNode.cs @@ -46,15 +46,17 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) } ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); - builder.RequireInitialPointerAlignment(); + byte[] rvaData = GetRvaData(factory.Target.PointerSize, out int requiredAlignment); + builder.RequireInitialAlignment(requiredAlignment); builder.AddSymbol(this); - builder.EmitBytes(GetRvaData(factory.Target.PointerSize)); + builder.EmitBytes(rvaData); return builder.ToObjectData(); } - private unsafe byte[] GetRvaData(int targetPointerSize) + private unsafe byte[] GetRvaData(int targetPointerSize, out int requiredAlignment) { int size = 0; + requiredAlignment = targetPointerSize; MetadataReader metadataReader = _module.MetadataReader; BlobReader metadataBlob = new BlobReader(_module.PEReader.GetMetadata().Pointer, _module.PEReader.GetMetadata().Length); @@ -80,6 +82,7 @@ private unsafe byte[] GetRvaData(int targetPointerSize) Debug.Assert(field.HasRva); int currentSize = field.FieldType.GetElementSize().AsInt; + requiredAlignment = Math.Max(requiredAlignment, (field.FieldType as MetadataType)?.GetClassLayout().PackingSize ?? 1); if (currentSize > size) { // We need to handle overlapping fields by reusing blobs based on the rva, and just update diff --git a/src/tests/JIT/Intrinsics/CreateSpan_il.il b/src/tests/JIT/Intrinsics/CreateSpan_il.il index d6a269b6f4d5f..cd950298337bb 100644 --- a/src/tests/JIT/Intrinsics/CreateSpan_il.il +++ b/src/tests/JIT/Intrinsics/CreateSpan_il.il @@ -100,7 +100,7 @@ .class explicit ansi sealed nested private '__StaticArrayInitTypeSize=16' extends [System.Runtime]System.ValueType { - .pack 1 + .pack 4 .size 16 } // end of class '__StaticArrayInitTypeSize=16' From 352a6b8d0ded088314e572303e7fec6ac0684c51 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Sun, 23 Jan 2022 14:25:26 -0800 Subject: [PATCH 151/308] Add alignment to mapped field stream (#63305) * Align MappeFieldDataStream at 8 byte boundary * Add test to verify that the mapped field rva data blob is aligned to ManagedPEBuilder.MappedFieldDataAlignment * Only align when the mapped field data is of size not equal to 0 --- .../PortableExecutable/ManagedTextSection.cs | 16 ++- .../PortableExecutable/PEBuilderTests.cs | 98 ++++++++++++++++++- 2 files changed, 110 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/ManagedTextSection.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/ManagedTextSection.cs index 33bd80dec21f7..1762b12d928ba 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/ManagedTextSection.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/ManagedTextSection.cs @@ -121,7 +121,7 @@ public ManagedTextSection( public const int MappedFieldDataAlignment = 8; - public int CalculateOffsetToMappedFieldDataStream() + internal int CalculateOffsetToMappedFieldDataStreamUnaligned() { int result = ComputeOffsetToImportTable(); @@ -135,6 +135,16 @@ public int CalculateOffsetToMappedFieldDataStream() return result; } + public int CalculateOffsetToMappedFieldDataStream() + { + int result = CalculateOffsetToMappedFieldDataStreamUnaligned(); + if (MappedFieldDataSize != 0) + { + result = BitArithmetic.Align(result, MappedFieldDataAlignment); + } + return result; + } + internal int ComputeOffsetToDebugDirectory() { Debug.Assert(MetadataSize % 4 == 0); @@ -185,7 +195,7 @@ public int GetEntryPointAddress(int rva) { // TODO: constants return RequiresStartupStub ? - rva + CalculateOffsetToMappedFieldDataStream() - (Is32Bit ? 6 : 10) : + rva + CalculateOffsetToMappedFieldDataStreamUnaligned() - (Is32Bit ? 6 : 10) : 0; } @@ -293,6 +303,8 @@ public void Serialize( // mapped field data: if (mappedFieldDataBuilderOpt != null) { + if (mappedFieldDataBuilderOpt.Count != 0) + builder.Align(MappedFieldDataAlignment); builder.LinkSuffix(mappedFieldDataBuilderOpt); } diff --git a/src/libraries/System.Reflection.Metadata/tests/PortableExecutable/PEBuilderTests.cs b/src/libraries/System.Reflection.Metadata/tests/PortableExecutable/PEBuilderTests.cs index 763e26dbc1811..c3dab37bbd359 100644 --- a/src/libraries/System.Reflection.Metadata/tests/PortableExecutable/PEBuilderTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/PortableExecutable/PEBuilderTests.cs @@ -64,7 +64,8 @@ private static void WritePEImage( Blob mvidFixup = default(Blob), byte[] privateKeyOpt = null, bool publicSigned = false, - Machine machine = 0) + Machine machine = 0, + BlobBuilder? mappedFieldData = null) { var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: entryPointHandle.IsNil ? Characteristics.Dll : Characteristics.ExecutableImage, machine: machine); @@ -75,7 +76,8 @@ private static void WritePEImage( ilBuilder, entryPoint: entryPointHandle, flags: CorFlags.ILOnly | (privateKeyOpt != null || publicSigned ? CorFlags.StrongNameSigned : 0), - deterministicIdProvider: content => s_contentId); + deterministicIdProvider: content => s_contentId, + mappedFieldData: mappedFieldData); var peBlob = new BlobBuilder(); @@ -487,6 +489,98 @@ private static MethodDefinitionHandle ComplexEmit(MetadataBuilder metadata, Blob return default(MethodDefinitionHandle); } + [Theory] // Validate FieldRVA alignment on common machine types + [MemberData(nameof(AllMachineTypes))] + public void FieldRVAAlignmentVerify(Machine machine) + { + using (var peStream = new MemoryStream()) + { + var ilBuilder = new BlobBuilder(); + var mappedRVADataBuilder = new BlobBuilder(); + var metadataBuilder = new MetadataBuilder(); + double validationNumber = 0.100001; + var fieldDef = FieldRVAValidationEmit(metadataBuilder, mappedRVADataBuilder, validationNumber); + + WritePEImage(peStream, metadataBuilder, ilBuilder, default(MethodDefinitionHandle), + mappedFieldData: mappedRVADataBuilder, + machine: machine); + + // Validate FieldRVA is aligned as ManagedPEBuilder.MappedFieldDataAlignemnt + peStream.Position = 0; + using (var peReader = new PEReader(peStream, PEStreamOptions.LeaveOpen)) + { + var mdReader = peReader.GetMetadataReader(); + + // Validate that there is only 1 field rva entry + Assert.Equal(1, mdReader.FieldRvaTable.NumberOfRows); + + // Validate that the RVA is aligned properly (which should be at least an 8 byte alignment + Assert.Equal(0, mdReader.FieldRvaTable.GetRva(1) % ManagedPEBuilder.MappedFieldDataAlignment); + + // Validate that the correct data is at the RVA + var fieldRVAData = peReader.GetSectionData(mdReader.FieldRvaTable.GetRva(1)); + Assert.Equal(validationNumber, fieldRVAData.GetReader().ReadDouble()); + } + + VerifyPE(peStream, machine); + } + } + + private static FieldDefinitionHandle FieldRVAValidationEmit(MetadataBuilder metadata, BlobBuilder mappedRVAData, double doubleToWriteAsData) + { + metadata.AddModule( + 0, + metadata.GetOrAddString("ConsoleApplication.exe"), + metadata.GetOrAddGuid(s_guid), + default(GuidHandle), + default(GuidHandle)); + + metadata.AddAssembly( + metadata.GetOrAddString("ConsoleApplication"), + version: new Version(1, 0, 0, 0), + culture: default(StringHandle), + publicKey: metadata.GetOrAddBlob(ImmutableArray.Create(Misc.KeyPair_PublicKey)), + flags: AssemblyFlags.PublicKey, + hashAlgorithm: AssemblyHashAlgorithm.Sha1); + + var mscorlibAssemblyRef = metadata.AddAssemblyReference( + name: metadata.GetOrAddString("mscorlib"), + version: new Version(4, 0, 0, 0), + culture: default(StringHandle), + publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), + flags: default(AssemblyFlags), + hashValue: default(BlobHandle)); + + var systemObjectTypeRef = metadata.AddTypeReference( + mscorlibAssemblyRef, + metadata.GetOrAddString("System"), + metadata.GetOrAddString("Object")); + + mappedRVAData.WriteDouble(doubleToWriteAsData); + + var rvaFieldSignature = new BlobBuilder(); + + new BlobEncoder(rvaFieldSignature). + FieldSignature().Double(); + + var fieldRVADef = metadata.AddFieldDefinition( + FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.HasFieldRVA, + metadata.GetOrAddString("RvaField"), + metadata.GetOrAddBlob(rvaFieldSignature)); + + metadata.AddFieldRelativeVirtualAddress(fieldRVADef, 0); + + metadata.AddTypeDefinition( + TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.BeforeFieldInit, + metadata.GetOrAddString("ConsoleApplication"), + metadata.GetOrAddString("Program"), + systemObjectTypeRef, + fieldList: fieldRVADef, + methodList: MetadataTokens.MethodDefinitionHandle(1)); + + return fieldRVADef; + } + private class TestResourceSectionBuilder : ResourceSectionBuilder { public TestResourceSectionBuilder() From 1f2116cd60ec0f3e39abbf60d7feedc537e5dfd3 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Sun, 23 Jan 2022 18:23:24 -0500 Subject: [PATCH 152/308] Implement hash and HMAC stream one shots This implements hashing and HMAC statics for streams. Additionally, "LiteHmac" and "LiteHash" were introduced. The existing HMAC and hash provider functionality do some bookkeeping we don't need for resetting. Since we do not need to use these hash handles after the digest has been finalized, resetting is unnecessary work. For HMAC, that also means keeping a copy of the key around for some implementations which we don't need to do. The LiteHash and LiteHmac types are implemented as structs with a common interface. To avoid boxing, generics are used and constrained to the interface where possible. The Browser implementation just defers to the existing HashDispenser rather than do anything novel. The HashProviderCng is somewhat specialized in its ability to reset. It did up-front check to determine if the platform supported reusable hash providers, and further had a single implementation for HMAC and Digests. The current Lite hash design requires that they remain separate types. --- .../Interop.Hmac.cs | 10 +- .../ref/System.Security.Cryptography.cs | 50 ++++ .../src/System.Security.Cryptography.csproj | 7 + .../System/Security/Cryptography/HMACMD5.cs | 172 ++++++++++++++ .../System/Security/Cryptography/HMACSHA1.cs | 173 +++++++++++++- .../Security/Cryptography/HMACSHA256.cs | 173 +++++++++++++- .../Security/Cryptography/HMACSHA384.cs | 176 +++++++++++++- .../Security/Cryptography/HMACSHA512.cs | 176 +++++++++++++- .../Cryptography/HashAlgorithmNames.Apple.cs | 19 ++ .../Cryptography/HashAlgorithmNames.cs | 2 +- .../HashProviderDispenser.Apple.cs | 209 +++++----------- .../HashProviderDispenser.OpenSsl.cs | 130 +++------- .../Security/Cryptography/LiteHash.Apple.cs | 215 +++++++++++++++++ .../Security/Cryptography/LiteHash.Browser.cs | 57 +++++ .../Security/Cryptography/LiteHash.Unix.cs | 174 ++++++++++++++ .../Security/Cryptography/LiteHash.Windows.cs | 173 ++++++++++++++ .../Security/Cryptography/LiteHashProvider.cs | 195 +++++++++++++++ .../src/System/Security/Cryptography/MD5.cs | 125 ++++++++++ .../src/System/Security/Cryptography/SHA1.cs | 125 ++++++++++ .../System/Security/Cryptography/SHA256.cs | 125 ++++++++++ .../System/Security/Cryptography/SHA384.cs | 125 ++++++++++ .../System/Security/Cryptography/SHA512.cs | 125 ++++++++++ .../tests/HashAlgorithmTestDriver.cs | 223 +++++++++++------- .../tests/HmacMD5Tests.cs | 100 ++++++++ .../tests/HmacSha1Tests.cs | 102 +++++++- .../tests/HmacSha256Tests.cs | 102 +++++++- .../tests/HmacSha384Tests.cs | 102 +++++++- .../tests/HmacSha512Tests.cs | 102 +++++++- .../tests/HmacTests.cs | 221 +++++++++++++++++ .../tests/MD5Tests.cs | 64 +++++ .../tests/Sha1Tests.cs | 70 ++++++ .../tests/Sha256Tests.cs | 79 +++++++ .../tests/Sha384Tests.cs | 78 +++++- .../tests/Sha512Tests.cs | 85 +++++++ .../tests/StreamHelpers.cs | 147 ++++++++++++ .../System.Security.Cryptography.Tests.csproj | 1 + 36 files changed, 3860 insertions(+), 352 deletions(-) create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.Apple.cs create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Apple.cs create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Browser.cs create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Unix.cs create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Windows.cs create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHashProvider.cs create mode 100644 src/libraries/System.Security.Cryptography/tests/StreamHelpers.cs diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs index 6cf3766ad8ed5..993d6d42ae751 100644 --- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs @@ -16,7 +16,15 @@ internal static partial class AppleCrypto internal static partial SafeHmacHandle HmacCreate(PAL_HashAlgorithm algorithm, ref int cbDigest); [GeneratedDllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacInit")] - internal static partial int HmacInit(SafeHmacHandle ctx, byte[] pbKey, int cbKey); + private static unsafe partial int HmacInit(SafeHmacHandle ctx, byte* pbKey, int cbKey); + + internal static unsafe int HmacInit(SafeHmacHandle ctx, ReadOnlySpan key) + { + fixed (byte* pKey = &MemoryMarshal.GetReference(key)) + { + return HmacInit(ctx, pKey, key.Length); + } + } internal static int HmacUpdate(SafeHmacHandle ctx, ReadOnlySpan data) => HmacUpdate(ctx, ref MemoryMarshal.GetReference(data), data.Length); diff --git a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs index be3a8b7bb3b0b..e671b178a816b 100644 --- a/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs +++ b/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs @@ -681,8 +681,14 @@ protected override void Dispose(bool disposing) { } protected override void HashCore(byte[] rgb, int ib, int cb) { } protected override void HashCore(System.ReadOnlySpan source) { } public static byte[] HashData(byte[] key, byte[] source) { throw null; } + public static byte[] HashData(byte[] key, System.IO.Stream source) { throw null; } + public static byte[] HashData(System.ReadOnlySpan key, System.IO.Stream source) { throw null; } + public static int HashData(System.ReadOnlySpan key, System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan key, System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(byte[] key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected override byte[] HashFinal() { throw null; } public override void Initialize() { } public static bool TryHashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } @@ -703,8 +709,14 @@ protected override void Dispose(bool disposing) { } protected override void HashCore(byte[] rgb, int ib, int cb) { } protected override void HashCore(System.ReadOnlySpan source) { } public static byte[] HashData(byte[] key, byte[] source) { throw null; } + public static byte[] HashData(byte[] key, System.IO.Stream source) { throw null; } + public static byte[] HashData(System.ReadOnlySpan key, System.IO.Stream source) { throw null; } + public static int HashData(System.ReadOnlySpan key, System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan key, System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(byte[] key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected override byte[] HashFinal() { throw null; } public override void Initialize() { } public static bool TryHashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } @@ -722,8 +734,14 @@ protected override void Dispose(bool disposing) { } protected override void HashCore(byte[] rgb, int ib, int cb) { } protected override void HashCore(System.ReadOnlySpan source) { } public static byte[] HashData(byte[] key, byte[] source) { throw null; } + public static byte[] HashData(byte[] key, System.IO.Stream source) { throw null; } + public static byte[] HashData(System.ReadOnlySpan key, System.IO.Stream source) { throw null; } + public static int HashData(System.ReadOnlySpan key, System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan key, System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(byte[] key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected override byte[] HashFinal() { throw null; } public override void Initialize() { } public static bool TryHashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } @@ -743,8 +761,14 @@ protected override void Dispose(bool disposing) { } protected override void HashCore(byte[] rgb, int ib, int cb) { } protected override void HashCore(System.ReadOnlySpan source) { } public static byte[] HashData(byte[] key, byte[] source) { throw null; } + public static byte[] HashData(byte[] key, System.IO.Stream source) { throw null; } + public static byte[] HashData(System.ReadOnlySpan key, System.IO.Stream source) { throw null; } + public static int HashData(System.ReadOnlySpan key, System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan key, System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(byte[] key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected override byte[] HashFinal() { throw null; } public override void Initialize() { } public static bool TryHashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } @@ -764,8 +788,14 @@ protected override void Dispose(bool disposing) { } protected override void HashCore(byte[] rgb, int ib, int cb) { } protected override void HashCore(System.ReadOnlySpan source) { } public static byte[] HashData(byte[] key, byte[] source) { throw null; } + public static byte[] HashData(byte[] key, System.IO.Stream source) { throw null; } + public static byte[] HashData(System.ReadOnlySpan key, System.IO.Stream source) { throw null; } + public static int HashData(System.ReadOnlySpan key, System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan key, System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(byte[] key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.ReadOnlyMemory key, System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected override byte[] HashFinal() { throw null; } public override void Initialize() { } public static bool TryHashData(System.ReadOnlySpan key, System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } @@ -834,8 +864,12 @@ protected MD5() { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The default algorithm implementations might be removed, use strong type references like 'RSA.Create()' instead.")] public static new System.Security.Cryptography.MD5? Create(string algName) { throw null; } public static byte[] HashData(byte[] source) { throw null; } + public static byte[] HashData(System.IO.Stream source) { throw null; } + public static int HashData(System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static bool TryHashData(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } } public sealed partial class Oid @@ -1197,8 +1231,12 @@ protected SHA1() { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The default algorithm implementations might be removed, use strong type references like 'RSA.Create()' instead.")] public static new System.Security.Cryptography.SHA1? Create(string hashName) { throw null; } public static byte[] HashData(byte[] source) { throw null; } + public static byte[] HashData(System.IO.Stream source) { throw null; } + public static int HashData(System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static bool TryHashData(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } } [System.ObsoleteAttribute("Derived cryptographic types are obsolete. Use the Create method on the base type instead.", DiagnosticId = "SYSLIB0021", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] @@ -1222,8 +1260,12 @@ protected SHA256() { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The default algorithm implementations might be removed, use strong type references like 'RSA.Create()' instead.")] public static new System.Security.Cryptography.SHA256? Create(string hashName) { throw null; } public static byte[] HashData(byte[] source) { throw null; } + public static byte[] HashData(System.IO.Stream source) { throw null; } + public static int HashData(System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static bool TryHashData(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } } [System.ObsoleteAttribute("Derived cryptographic types are obsolete. Use the Create method on the base type instead.", DiagnosticId = "SYSLIB0021", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] @@ -1247,8 +1289,12 @@ protected SHA384() { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The default algorithm implementations might be removed, use strong type references like 'RSA.Create()' instead.")] public static new System.Security.Cryptography.SHA384? Create(string hashName) { throw null; } public static byte[] HashData(byte[] source) { throw null; } + public static byte[] HashData(System.IO.Stream source) { throw null; } + public static int HashData(System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static bool TryHashData(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } } [System.ObsoleteAttribute("Derived cryptographic types are obsolete. Use the Create method on the base type instead.", DiagnosticId = "SYSLIB0021", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] @@ -1272,8 +1318,12 @@ protected SHA512() { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The default algorithm implementations might be removed, use strong type references like 'RSA.Create()' instead.")] public static new System.Security.Cryptography.SHA512? Create(string hashName) { throw null; } public static byte[] HashData(byte[] source) { throw null; } + public static byte[] HashData(System.IO.Stream source) { throw null; } + public static int HashData(System.IO.Stream source, System.Span destination) { throw null; } public static byte[] HashData(System.ReadOnlySpan source) { throw null; } public static int HashData(System.ReadOnlySpan source, System.Span destination) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Memory destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask HashDataAsync(System.IO.Stream source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static bool TryHashData(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } } [System.ObsoleteAttribute("Derived cryptographic types are obsolete. Use the Create method on the base type instead.", DiagnosticId = "SYSLIB0021", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index 9a268d9a83d9a..a2a2d2d52ca21 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -278,6 +278,7 @@ + @@ -378,6 +379,7 @@ + + + + + + diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACMD5.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACMD5.cs index 97067a63b3f93..eff5baa635b8d 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACMD5.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACMD5.cs @@ -2,7 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.IO; using System.Runtime.Versioning; +using System.Threading; +using System.Threading.Tasks; using Internal.Cryptography; namespace System.Security.Cryptography @@ -162,6 +165,175 @@ public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source return true; } + /// + /// Computes the HMAC of a stream using the MD5 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated HMAC + /// size. The MD5 algorithm always produces a 128-bit HMAC, or 16 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(ReadOnlySpan key, Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.MD5, HashSizeInBytes, key, source, destination); + } + + /// + /// Computes the HMAC of a stream using the MD5 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(ReadOnlySpan key, Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.MD5, HashSizeInBytes, key, source); + } + + /// + /// Computes the HMAC of a stream using the MD5 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(byte[] key, Stream source) + { + ArgumentNullException.ThrowIfNull(key); + return HashData(new ReadOnlySpan(key), source); + } + + /// + /// Asynchronously computes the HMAC of a stream using the MD5 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync(HashAlgorithmNames.MD5, HashSizeInBytes, key.Span, source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the MD5 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(key); + + return HashDataAsync(new ReadOnlyMemory(key), source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the MD5 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The MD5 algorithm always produces a 128-bit hash, or 16 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync( + HashAlgorithmNames.MD5, + HashSizeInBytes, + key.Span, + source, + destination, + cancellationToken); + } + protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA1.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA1.cs index 006898d72c6ac..cc8d5619da208 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA1.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA1.cs @@ -2,10 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using Internal.Cryptography; -using System; using System.ComponentModel; using System.Diagnostics; +using System.IO; using System.Runtime.Versioning; +using System.Threading; +using System.Threading.Tasks; namespace System.Security.Cryptography { @@ -171,6 +173,175 @@ public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source return true; } + /// + /// Computes the HMAC of a stream using the SHA1 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated HMAC + /// size. The SHA1 algorithm always produces a 160-bit HMAC, or 20 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(ReadOnlySpan key, Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA1, HashSizeInBytes, key, source, destination); + } + + /// + /// Computes the HMAC of a stream using the SHA1 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(ReadOnlySpan key, Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA1, HashSizeInBytes, key, source); + } + + /// + /// Computes the HMAC of a stream using the SHA1 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(byte[] key, Stream source) + { + ArgumentNullException.ThrowIfNull(key); + return HashData(new ReadOnlySpan(key), source); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA1 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync(HashAlgorithmNames.SHA1, HashSizeInBytes, key.Span, source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA1 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(key); + + return HashDataAsync(new ReadOnlyMemory(key), source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA1 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA1 algorithm always produces a 160-bit hash, or 20 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync( + HashAlgorithmNames.SHA1, + HashSizeInBytes, + key.Span, + source, + destination, + cancellationToken); + } + protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA256.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA256.cs index 0cb3ff2ab423d..797f60dd3b49b 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA256.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA256.cs @@ -3,8 +3,10 @@ using Internal.Cryptography; using System.Diagnostics; +using System.IO; using System.Runtime.Versioning; -using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; namespace System.Security.Cryptography { @@ -163,6 +165,175 @@ public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source return true; } + /// + /// Computes the HMAC of a stream using the SHA256 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated HMAC + /// size. The SHA256 algorithm always produces a 256-bit HMAC, or 32 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(ReadOnlySpan key, Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA256, HashSizeInBytes, key, source, destination); + } + + /// + /// Computes the HMAC of a stream using the SHA256 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(ReadOnlySpan key, Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA256, HashSizeInBytes, key, source); + } + + /// + /// Computes the HMAC of a stream using the SHA256 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(byte[] key, Stream source) + { + ArgumentNullException.ThrowIfNull(key); + return HashData(new ReadOnlySpan(key), source); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA256 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync(HashAlgorithmNames.SHA256, HashSizeInBytes, key.Span, source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA256 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(key); + + return HashDataAsync(new ReadOnlyMemory(key), source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA256 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA256 algorithm always produces a 256-bit hash, or 32 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync( + HashAlgorithmNames.SHA256, + HashSizeInBytes, + key.Span, + source, + destination, + cancellationToken); + } + protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA384.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA384.cs index db9781f1fea2b..1162850933c35 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA384.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA384.cs @@ -1,11 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Internal.Cryptography; -using System; using System.Diagnostics; +using System.IO; using System.Runtime.Versioning; -using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using Internal.Cryptography; namespace System.Security.Cryptography { @@ -181,6 +182,175 @@ public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source return true; } + /// + /// Computes the HMAC of a stream using the SHA384 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated HMAC + /// size. The SHA384 algorithm always produces a 384-bit HMAC, or 48 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(ReadOnlySpan key, Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA384, HashSizeInBytes, key, source, destination); + } + + /// + /// Computes the HMAC of a stream using the SHA384 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(ReadOnlySpan key, Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA384, HashSizeInBytes, key, source); + } + + /// + /// Computes the HMAC of a stream using the SHA384 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(byte[] key, Stream source) + { + ArgumentNullException.ThrowIfNull(key); + return HashData(new ReadOnlySpan(key), source); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA384 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync(HashAlgorithmNames.SHA384, HashSizeInBytes, key.Span, source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA384 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(key); + + return HashDataAsync(new ReadOnlyMemory(key), source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA384 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA384 algorithm always produces a 384-bit hash, or 48 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync( + HashAlgorithmNames.SHA384, + HashSizeInBytes, + key.Span, + source, + destination, + cancellationToken); + } + protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA512.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA512.cs index ee743669edf8a..079798b459a2b 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA512.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA512.cs @@ -1,11 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Internal.Cryptography; -using System; using System.Diagnostics; +using System.IO; using System.Runtime.Versioning; -using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using Internal.Cryptography; namespace System.Security.Cryptography { @@ -178,6 +179,175 @@ public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source return true; } + /// + /// Computes the HMAC of a stream using the SHA512 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated HMAC + /// size. The SHA512 algorithm always produces a 512-bit HMAC, or 64 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(ReadOnlySpan key, Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA512, HashSizeInBytes, key, source, destination); + } + + /// + /// Computes the HMAC of a stream using the SHA512 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(ReadOnlySpan key, Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA512, HashSizeInBytes, key, source); + } + + /// + /// Computes the HMAC of a stream using the SHA512 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(byte[] key, Stream source) + { + ArgumentNullException.ThrowIfNull(key); + return HashData(new ReadOnlySpan(key), source); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA512 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync(HashAlgorithmNames.SHA512, HashSizeInBytes, key.Span, source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA512 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The HMAC of the data. + /// + /// or is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(key); + + return HashDataAsync(new ReadOnlyMemory(key), source, cancellationToken); + } + + /// + /// Asynchronously computes the HMAC of a stream using the SHA512 algorithm. + /// + /// The HMAC key. + /// The stream to HMAC. + /// The buffer to receive the HMAC value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA512 algorithm always produces a 512-bit hash, or 64 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HmacStreamAsync( + HashAlgorithmNames.SHA512, + HashSizeInBytes, + key.Span, + source, + destination, + cancellationToken); + } + protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.Apple.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.Apple.cs new file mode 100644 index 0000000000000..3cc658ee23164 --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.Apple.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. + +using PAL_HashAlgorithm = Interop.AppleCrypto.PAL_HashAlgorithm; + +namespace System.Security.Cryptography +{ + internal static partial class HashAlgorithmNames + { + internal static PAL_HashAlgorithm HashAlgorithmToPal(string hashAlgorithmId) => hashAlgorithmId switch { + HashAlgorithmNames.MD5 => PAL_HashAlgorithm.Md5, + HashAlgorithmNames.SHA1 => PAL_HashAlgorithm.Sha1, + HashAlgorithmNames.SHA256 => PAL_HashAlgorithm.Sha256, + HashAlgorithmNames.SHA384 => PAL_HashAlgorithm.Sha384, + HashAlgorithmNames.SHA512 => PAL_HashAlgorithm.Sha512, + _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId)) + }; + } +} diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs index dc0a42f78ac8d..24cb46bdc2fd5 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs @@ -5,7 +5,7 @@ namespace System.Security.Cryptography { - internal static class HashAlgorithmNames + internal static partial class HashAlgorithmNames { // These are accepted by CNG public const string MD5 = "MD5"; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Apple.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Apple.cs index fa80816a75abf..296cafef90359 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Apple.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Apple.cs @@ -5,31 +5,22 @@ using System.Security.Cryptography.Apple; using Internal.Cryptography; +using PAL_HashAlgorithm = Interop.AppleCrypto.PAL_HashAlgorithm; + namespace System.Security.Cryptography { internal static partial class HashProviderDispenser { public static HashProvider CreateHashProvider(string hashAlgorithmId) { - Interop.AppleCrypto.PAL_HashAlgorithm algorithm = HashAlgorithmToPal(hashAlgorithmId); - return new AppleDigestProvider(algorithm); + return new AppleDigestProvider(hashAlgorithmId); } public static HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlySpan key) { - Interop.AppleCrypto.PAL_HashAlgorithm algorithm = HashAlgorithmToPal(hashAlgorithmId); - return new AppleHmacProvider(algorithm, key); + return new AppleHmacProvider(hashAlgorithmId, key); } - private static Interop.AppleCrypto.PAL_HashAlgorithm HashAlgorithmToPal(string hashAlgorithmId) => hashAlgorithmId switch { - HashAlgorithmNames.MD5 => Interop.AppleCrypto.PAL_HashAlgorithm.Md5, - HashAlgorithmNames.SHA1 => Interop.AppleCrypto.PAL_HashAlgorithm.Sha1, - HashAlgorithmNames.SHA256 => Interop.AppleCrypto.PAL_HashAlgorithm.Sha256, - HashAlgorithmNames.SHA384 => Interop.AppleCrypto.PAL_HashAlgorithm.Sha384, - HashAlgorithmNames.SHA512 => Interop.AppleCrypto.PAL_HashAlgorithm.Sha512, - _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId)) - }; - internal static class OneShotHashProvider { public static unsafe int MacData( @@ -38,7 +29,7 @@ public static unsafe int MacData( ReadOnlySpan source, Span destination) { - Interop.AppleCrypto.PAL_HashAlgorithm algorithm = HashAlgorithmToPal(hashAlgorithmId); + Interop.AppleCrypto.PAL_HashAlgorithm algorithm = HashAlgorithmNames.HashAlgorithmToPal(hashAlgorithmId); fixed (byte* pKey = key) fixed (byte* pSource = source) @@ -69,7 +60,7 @@ public static unsafe int MacData( public static unsafe int HashData(string hashAlgorithmId, ReadOnlySpan source, Span destination) { - Interop.AppleCrypto.PAL_HashAlgorithm algorithm = HashAlgorithmToPal(hashAlgorithmId); + Interop.AppleCrypto.PAL_HashAlgorithm algorithm = HashAlgorithmNames.HashAlgorithmToPal(hashAlgorithmId); fixed (byte* pSource = source) fixed (byte* pDestination = destination) @@ -96,205 +87,117 @@ public static unsafe int HashData(string hashAlgorithmId, ReadOnlySpan sou } } - private sealed class AppleHmacProvider : HashProvider + private sealed class AppleDigestProvider : HashProvider { - private readonly byte[] _key; - private readonly SafeHmacHandle _ctx; - + private readonly LiteHash _liteHash; private bool _running; - public override int HashSizeInBytes { get; } - - internal AppleHmacProvider(Interop.AppleCrypto.PAL_HashAlgorithm algorithm, ReadOnlySpan key) + public AppleDigestProvider(string hashAlgorithmId) { - _key = key.ToArray(); - int hashSizeInBytes = 0; - _ctx = Interop.AppleCrypto.HmacCreate(algorithm, ref hashSizeInBytes); - - if (hashSizeInBytes < 0) - { - _ctx.Dispose(); - throw new PlatformNotSupportedException( - SR.Format( - SR.Cryptography_UnknownHashAlgorithm, - Enum.GetName(typeof(Interop.AppleCrypto.PAL_HashAlgorithm), algorithm))); - } - - if (_ctx.IsInvalid) - { - _ctx.Dispose(); - throw new CryptographicException(); - } - - HashSizeInBytes = hashSizeInBytes; + _liteHash = LiteHashProvider.CreateHash(hashAlgorithmId); } public override void AppendHashData(ReadOnlySpan data) { - if (!_running) - { - SetKey(); - } - - if (Interop.AppleCrypto.HmacUpdate(_ctx, data) != 1) - { - throw new CryptographicException(); - } - } - - private void SetKey() - { - if (Interop.AppleCrypto.HmacInit(_ctx, _key, _key.Length) != 1) - { - throw new CryptographicException(); - } - + _liteHash.Append(data); _running = true; } - public override unsafe int FinalizeHashAndReset(Span destination) + public override int FinalizeHashAndReset(Span destination) { - Debug.Assert(destination.Length >= HashSizeInBytes); - - if (!_running) - { - SetKey(); - } - - if (Interop.AppleCrypto.HmacFinal(_ctx, destination) != 1) - { - throw new CryptographicException(); - } - + int written = _liteHash.Finalize(destination); + // Apple's DigestFinal self-resets, so don't bother calling reset. _running = false; - return HashSizeInBytes; + return written; } - public override unsafe int GetCurrentHash(Span destination) + public override int GetCurrentHash(Span destination) { - Debug.Assert(destination.Length >= HashSizeInBytes); + return _liteHash.Current(destination); + } - if (!_running) - { - SetKey(); - } + public override int HashSizeInBytes => _liteHash.HashSizeInBytes; - if (Interop.AppleCrypto.HmacCurrent(_ctx, destination) != 1) + public override void Dispose(bool disposing) + { + if (disposing) { - throw new CryptographicException(); + _liteHash.Dispose(); } - - return HashSizeInBytes; } - public override void Dispose(bool disposing) + public override void Reset() { - if (disposing) + if (_running) { - _ctx?.Dispose(); - Array.Clear(_key); + _liteHash.Reset(); + _running = false; } } - - public override void Reset() => _running = false; } - private sealed class AppleDigestProvider : HashProvider + private sealed class AppleHmacProvider : HashProvider { - private readonly SafeDigestCtxHandle _ctx; + private readonly LiteHmac _liteHmac; + private readonly byte[] _key; private bool _running; - public override int HashSizeInBytes { get; } - - internal AppleDigestProvider(Interop.AppleCrypto.PAL_HashAlgorithm algorithm) + public AppleHmacProvider(string hashAlgorithmId, ReadOnlySpan key) { - int hashSizeInBytes; - _ctx = Interop.AppleCrypto.DigestCreate(algorithm, out hashSizeInBytes); - - if (hashSizeInBytes < 0) - { - _ctx.Dispose(); - throw new PlatformNotSupportedException( - SR.Format( - SR.Cryptography_UnknownHashAlgorithm, - Enum.GetName(typeof(Interop.AppleCrypto.PAL_HashAlgorithm), algorithm))); - } - - if (_ctx.IsInvalid) - { - _ctx.Dispose(); - throw new CryptographicException(); - } - - HashSizeInBytes = hashSizeInBytes; + PAL_HashAlgorithm algorithm = HashAlgorithmNames.HashAlgorithmToPal(hashAlgorithmId); + _liteHmac = new LiteHmac(algorithm, key, preinitialize: false); + _key = key.ToArray(); } public override void AppendHashData(ReadOnlySpan data) { - _running = true; - int ret = Interop.AppleCrypto.DigestUpdate(_ctx, data); - - if (ret != 1) + if (!_running) { - Debug.Assert(ret == 0, $"DigestUpdate return value {ret} was not 0 or 1"); - throw new CryptographicException(); + _liteHmac.Reset(_key); } + + _liteHmac.Append(data); + _running = true; } public override int FinalizeHashAndReset(Span destination) { - Debug.Assert(destination.Length >= HashSizeInBytes); - - int ret = Interop.AppleCrypto.DigestFinal(_ctx, destination); - _running = false; - - if (ret != 1) + if (!_running) { - Debug.Assert(ret == 0, $"DigestFinal return value {ret} was not 0 or 1"); - throw new CryptographicException(); + _liteHmac.Reset(_key); } - return HashSizeInBytes; + int written = _liteHmac.Finalize(destination); + _liteHmac.Reset(_key); + _running = false; + return written; } public override int GetCurrentHash(Span destination) { - Debug.Assert(destination.Length >= HashSizeInBytes); - - int ret = Interop.AppleCrypto.DigestCurrent(_ctx, destination); - - if (ret != 1) + if (!_running) { - Debug.Assert(ret == 0, $"DigestFinal return value {ret} was not 0 or 1"); - throw new CryptographicException(); + _liteHmac.Reset(_key); } - return HashSizeInBytes; + return _liteHmac.Current(destination); } - public override void Reset() - { - if (_running) - { - int ret = Interop.AppleCrypto.DigestReset(_ctx); - - if (ret != 1) - { - Debug.Assert(ret == 0, $"DigestReset return value {ret} was not 0 or 1"); - throw new CryptographicException(); - } - - _running = false; - } - } + public override int HashSizeInBytes => _liteHmac.HashSizeInBytes; public override void Dispose(bool disposing) { if (disposing) { - _ctx?.Dispose(); + _liteHmac.Dispose(); + Array.Clear(_key); } } + + public override void Reset() + { + _running = false; + } } } } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.OpenSsl.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.OpenSsl.cs index db75677b66ae8..32cdc7dd93b1c 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.OpenSsl.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.OpenSsl.cs @@ -14,14 +14,12 @@ internal static partial class HashProviderDispenser { internal static HashProvider CreateHashProvider(string hashAlgorithmId) { - IntPtr evpType = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId); - return new EvpHashProvider(evpType); + return new EvpHashProvider(hashAlgorithmId); } internal static HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlySpan key) { - IntPtr evpType = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId); - return new HmacHashProvider(evpType, key); + return new HmacHashProvider(hashAlgorithmId, key); } internal static class OneShotHashProvider @@ -61,8 +59,16 @@ public static unsafe int HashData(string hashAlgorithmId, ReadOnlySpan sou fixed (byte* pSource = source) fixed (byte* pDestination = destination) { + const int Success = 1; uint length = (uint)destination.Length; - Check(Interop.Crypto.EvpDigestOneShot(evpType, pSource, source.Length, pDestination, &length)); + int ret = Interop.Crypto.EvpDigestOneShot(evpType, pSource, source.Length, pDestination, &length); + + if (ret != Success) + { + Debug.Assert(ret == 0); + throw Interop.Crypto.CreateOpenSslCryptographicException(); + } + Debug.Assert(length == hashSize); } @@ -72,71 +78,40 @@ public static unsafe int HashData(string hashAlgorithmId, ReadOnlySpan sou private sealed class EvpHashProvider : HashProvider { - private readonly IntPtr _algorithmEvp; - private readonly int _hashSize; - private readonly SafeEvpMdCtxHandle _ctx; + private readonly LiteHash _liteHash; private bool _running; - public EvpHashProvider(IntPtr algorithmEvp) + public EvpHashProvider(string hashAlgorithmId) { - _algorithmEvp = algorithmEvp; - Debug.Assert(algorithmEvp != IntPtr.Zero); - - _hashSize = Interop.Crypto.EvpMdSize(_algorithmEvp); - if (_hashSize <= 0 || _hashSize > Interop.Crypto.EVP_MAX_MD_SIZE) - { - throw new CryptographicException(); - } - - _ctx = Interop.Crypto.EvpMdCtxCreate(_algorithmEvp); - - Interop.Crypto.CheckValidOpenSslHandle(_ctx); + _liteHash = LiteHashProvider.CreateHash(hashAlgorithmId); } public override void AppendHashData(ReadOnlySpan data) { - if (data.IsEmpty) - { - return; - } - + _liteHash.Append(data); _running = true; - Check(Interop.Crypto.EvpDigestUpdate(_ctx, data, data.Length)); } public override int FinalizeHashAndReset(Span destination) { - Debug.Assert(destination.Length >= _hashSize); - - uint length = (uint)destination.Length; - Check(Interop.Crypto.EvpDigestFinalEx(_ctx, ref MemoryMarshal.GetReference(destination), ref length)); - Debug.Assert(length == _hashSize); - - // Reset the algorithm provider. - Check(Interop.Crypto.EvpDigestReset(_ctx, _algorithmEvp)); + int written = _liteHash.Finalize(destination); + _liteHash.Reset(); _running = false; - - return _hashSize; + return written; } public override int GetCurrentHash(Span destination) { - Debug.Assert(destination.Length >= _hashSize); - - uint length = (uint)destination.Length; - Check(Interop.Crypto.EvpDigestCurrent(_ctx, ref MemoryMarshal.GetReference(destination), ref length)); - Debug.Assert(length == _hashSize); - - return _hashSize; + return _liteHash.Current(destination); } - public override int HashSizeInBytes => _hashSize; + public override int HashSizeInBytes => _liteHash.HashSizeInBytes; public override void Dispose(bool disposing) { if (disposing) { - _ctx.Dispose(); + _liteHash.Dispose(); } } @@ -144,7 +119,7 @@ public override void Reset() { if (_running) { - Check(Interop.Crypto.EvpDigestReset(_ctx, _algorithmEvp)); + _liteHash.Reset(); _running = false; } } @@ -152,67 +127,40 @@ public override void Reset() private sealed class HmacHashProvider : HashProvider { - private readonly int _hashSize; - private SafeHmacCtxHandle _hmacCtx; + private readonly LiteHmac _liteHmac; private bool _running; - public HmacHashProvider(IntPtr algorithmEvp, ReadOnlySpan key) + public HmacHashProvider(string hashAlgorithmId, ReadOnlySpan key) { - Debug.Assert(algorithmEvp != IntPtr.Zero); - - _hashSize = Interop.Crypto.EvpMdSize(algorithmEvp); - if (_hashSize <= 0 || _hashSize > Interop.Crypto.EVP_MAX_MD_SIZE) - { - throw new CryptographicException(); - } - - _hmacCtx = Interop.Crypto.HmacCreate(ref MemoryMarshal.GetReference(key), key.Length, algorithmEvp); - Interop.Crypto.CheckValidOpenSslHandle(_hmacCtx); + _liteHmac = LiteHashProvider.CreateHmac(hashAlgorithmId, key); } public override void AppendHashData(ReadOnlySpan data) { - if (data.IsEmpty) - { - return; - } - + _liteHmac.Append(data); _running = true; - Check(Interop.Crypto.HmacUpdate(_hmacCtx, data, data.Length)); } public override int FinalizeHashAndReset(Span destination) { - Debug.Assert(destination.Length >= _hashSize); - - int length = destination.Length; - Check(Interop.Crypto.HmacFinal(_hmacCtx, ref MemoryMarshal.GetReference(destination), ref length)); - Debug.Assert(length == _hashSize); - - Check(Interop.Crypto.HmacReset(_hmacCtx)); + int written = _liteHmac.Finalize(destination); + _liteHmac.Reset(); _running = false; - return _hashSize; + return written; } public override int GetCurrentHash(Span destination) { - Debug.Assert(destination.Length >= _hashSize); - - int length = destination.Length; - Check(Interop.Crypto.HmacCurrent(_hmacCtx, ref MemoryMarshal.GetReference(destination), ref length)); - Debug.Assert(length == _hashSize); - - return _hashSize; + return _liteHmac.Current(destination); } - public override int HashSizeInBytes => _hashSize; + public override int HashSizeInBytes => _liteHmac.HashSizeInBytes; public override void Dispose(bool disposing) { - if (disposing && _hmacCtx != null) + if (disposing) { - _hmacCtx.Dispose(); - _hmacCtx = null!; + _liteHmac.Dispose(); } } @@ -220,20 +168,10 @@ public override void Reset() { if (_running) { - Check(Interop.Crypto.HmacReset(_hmacCtx)); + _liteHmac.Reset(); _running = false; } } } - - private static void Check(int result) - { - const int Success = 1; - if (result != Success) - { - Debug.Assert(result == 0); - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - } } } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Apple.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Apple.cs new file mode 100644 index 0000000000000..d00b61334320c --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Apple.cs @@ -0,0 +1,215 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Security.Cryptography.Apple; + +using PAL_HashAlgorithm = Interop.AppleCrypto.PAL_HashAlgorithm; + +namespace System.Security.Cryptography +{ + internal static partial class LiteHashProvider + { + internal static LiteHash CreateHash(string hashAlgorithmId) + { + PAL_HashAlgorithm algorithm = HashAlgorithmNames.HashAlgorithmToPal(hashAlgorithmId); + return new LiteHash(algorithm); + } + + internal static LiteHmac CreateHmac(string hashAlgorithmId, ReadOnlySpan key) + { + PAL_HashAlgorithm algorithm = HashAlgorithmNames.HashAlgorithmToPal(hashAlgorithmId); + return new LiteHmac(algorithm, key, preinitialize: true); + } + } + + internal readonly struct LiteHash : ILiteHash + { + private readonly SafeDigestCtxHandle _ctx; + private readonly int _hashSizeInBytes; + + private const int Success = 1; + + public int HashSizeInBytes => _hashSizeInBytes; + + internal LiteHash(PAL_HashAlgorithm algorithm) + { + int hashSizeInBytes; + _ctx = Interop.AppleCrypto.DigestCreate(algorithm, out hashSizeInBytes); + + if (hashSizeInBytes < 0) + { + _ctx.Dispose(); + throw new PlatformNotSupportedException( + SR.Format( + SR.Cryptography_UnknownHashAlgorithm, + Enum.GetName(typeof(PAL_HashAlgorithm), algorithm))); + } + + if (_ctx.IsInvalid) + { + _ctx.Dispose(); + throw new CryptographicException(); + } + + _hashSizeInBytes = hashSizeInBytes; + } + + public void Append(ReadOnlySpan data) + { + if (data.IsEmpty) + { + return; + } + + int ret = Interop.AppleCrypto.DigestUpdate(_ctx, data); + + if (ret != Success) + { + Debug.Assert(ret == 0, $"{nameof(Interop.AppleCrypto.DigestUpdate)} return value {ret} was not 0 or 1"); + throw new CryptographicException(); + } + } + + public int Current(Span destination) + { + Debug.Assert(destination.Length >= _hashSizeInBytes); + + int ret = Interop.AppleCrypto.DigestCurrent(_ctx, destination); + + if (ret != Success) + { + Debug.Assert(ret == 0, $"{nameof(Interop.AppleCrypto.DigestCurrent)} return value {ret} was not 0 or 1"); + throw new CryptographicException(); + } + + return _hashSizeInBytes; + } + + public int Finalize(Span destination) + { + Debug.Assert(destination.Length >= _hashSizeInBytes); + + int ret = Interop.AppleCrypto.DigestFinal(_ctx, destination); + + if (ret != Success) + { + Debug.Assert(ret == 0, $"{nameof(Interop.AppleCrypto.DigestFinal)} return value {ret} was not 0 or 1"); + throw new CryptographicException(); + } + + return _hashSizeInBytes; + } + + public void Reset() + { + int ret = Interop.AppleCrypto.DigestReset(_ctx); + + if (ret != Success) + { + Debug.Assert(ret == 0, $"DigestReset return value {ret} was not 0 or 1"); + throw new CryptographicException(); + } + } + + public void Dispose() + { + _ctx.Dispose(); + } + } + + internal readonly struct LiteHmac : ILiteHash + { + private readonly SafeHmacHandle _ctx; + private readonly int _hashSizeInBytes; + + private const int Success = 1; + + public int HashSizeInBytes => _hashSizeInBytes; + + internal LiteHmac(PAL_HashAlgorithm algorithm, ReadOnlySpan key, bool preinitialize) + { + int hashSizeInBytes = 0; + _ctx = Interop.AppleCrypto.HmacCreate(algorithm, ref hashSizeInBytes); + + if (hashSizeInBytes < 0) + { + _ctx.Dispose(); + throw new PlatformNotSupportedException( + SR.Format( + SR.Cryptography_UnknownHashAlgorithm, + Enum.GetName(typeof(Interop.AppleCrypto.PAL_HashAlgorithm), algorithm))); + } + + if (_ctx.IsInvalid) + { + _ctx.Dispose(); + throw new CryptographicException(); + } + + if (preinitialize) + { + if (Interop.AppleCrypto.HmacInit(_ctx, key) != Success) + { + _ctx.Dispose(); + throw new CryptographicException(); + } + } + + _hashSizeInBytes = hashSizeInBytes; + } + + public void Append(ReadOnlySpan data) + { + if (data.IsEmpty) + { + return; + } + + if (Interop.AppleCrypto.HmacUpdate(_ctx, data) != Success) + { + Debug.Fail($"{nameof(Interop.AppleCrypto.HmacUpdate)} unexpectedly failed."); + throw new CryptographicException(); + } + } + + public int Current(ReadOnlySpan destination) + { + Debug.Assert(destination.Length >= _hashSizeInBytes); + + if (Interop.AppleCrypto.HmacCurrent(_ctx, destination) != Success) + { + Debug.Fail($"{nameof(Interop.AppleCrypto.HmacCurrent)} unexpectedly failed."); + throw new CryptographicException(); + } + + return _hashSizeInBytes; + } + + public int Finalize(Span destination) + { + Debug.Assert(destination.Length >= _hashSizeInBytes); + + if (Interop.AppleCrypto.HmacFinal(_ctx, destination) != Success) + { + Debug.Fail($"{nameof(Interop.AppleCrypto.HmacFinal)} unexpectedly failed."); + throw new CryptographicException(); + } + + return _hashSizeInBytes; + } + + public void Reset(ReadOnlySpan key) + { + if (Interop.AppleCrypto.HmacInit(_ctx, key) != Success) + { + Debug.Fail($"{nameof(Interop.AppleCrypto.HmacInit)} unexpectedly failed."); + } + } + + public void Dispose() + { + _ctx.Dispose(); + } + } +} diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Browser.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Browser.cs new file mode 100644 index 0000000000000..706427758605c --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Browser.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using Internal.Cryptography; + +namespace System.Security.Cryptography +{ + internal static partial class LiteHashProvider + { + private static LiteHash CreateHash(string hashAlgorithmId) + { + return new LiteHash(hashAlgorithmId); + } + + private static LiteHmac CreateHmac(string hashAlgorithmId, ReadOnlySpan key) + { + return new LiteHmac(hashAlgorithmId, key); + } + } + + internal readonly struct LiteHash : ILiteHash + { + private readonly HashProvider _provider; + private readonly int _hashSizeInBytes; + + public int HashSizeInBytes => _hashSizeInBytes; + + internal LiteHash(string hashAlgorithmId) + { + _provider = HashProviderDispenser.CreateHashProvider(hashAlgorithmId); + _hashSizeInBytes = _provider.HashSizeInBytes; + } + + public void Append(ReadOnlySpan data) => _provider.AppendHashData(data); + public int Finalize(Span destination) => _provider.FinalizeHashAndReset(destination); + public void Dispose() => _provider.Dispose(); + } + + internal readonly struct LiteHmac : ILiteHash + { + private readonly HashProvider _provider; + private readonly int _hashSizeInBytes; + + public int HashSizeInBytes => _hashSizeInBytes; + + internal LiteHmac(string hashAlgorithmId, ReadOnlySpan key) + { + _provider = HashProviderDispenser.CreateMacProvider(hashAlgorithmId, key); + _hashSizeInBytes = _provider.HashSizeInBytes; + } + + public void Append(ReadOnlySpan data) => _provider.AppendHashData(data); + public int Finalize(Span destination) => _provider.FinalizeHashAndReset(destination); + public void Dispose() => _provider.Dispose(); + } +} diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Unix.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Unix.cs new file mode 100644 index 0000000000000..05b55230e14b7 --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Unix.cs @@ -0,0 +1,174 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Win32.SafeHandles; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace System.Security.Cryptography +{ + internal static partial class LiteHashProvider + { + internal static LiteHash CreateHash(string hashAlgorithmId) + { + IntPtr algorithm = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId); + return new LiteHash(algorithm); + } + + internal static LiteHmac CreateHmac(string hashAlgorithmId, ReadOnlySpan key) + { + IntPtr algorithm = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId); + return new LiteHmac(algorithm, key); + } + } + + internal readonly struct LiteHash : ILiteHash + { + private readonly SafeEvpMdCtxHandle _ctx; + private readonly IntPtr _algorithm; + private readonly int _hashSizeInBytes; + + public int HashSizeInBytes => _hashSizeInBytes; + + internal LiteHash(IntPtr algorithm) + { + Debug.Assert(algorithm != IntPtr.Zero); + + _algorithm = algorithm; + _hashSizeInBytes = Interop.Crypto.EvpMdSize(algorithm); + + if (_hashSizeInBytes <= 0 || _hashSizeInBytes > Interop.Crypto.EVP_MAX_MD_SIZE) + { + Debug.Fail($"Unexpected hash '{_hashSizeInBytes}' size from {nameof(Interop.Crypto.EvpMdSize)}."); + throw new CryptographicException(); + } + + _ctx = Interop.Crypto.EvpMdCtxCreate(algorithm); + Interop.Crypto.CheckValidOpenSslHandle(_ctx); + } + + public void Append(ReadOnlySpan data) + { + if (data.IsEmpty) + { + return; + } + + Check(Interop.Crypto.EvpDigestUpdate(_ctx, data, data.Length)); + } + + public int Finalize(Span destination) + { + Debug.Assert(destination.Length >= _hashSizeInBytes); + + uint length = (uint)destination.Length; + Check(Interop.Crypto.EvpDigestFinalEx(_ctx, ref MemoryMarshal.GetReference(destination), ref length)); + + Debug.Assert(length == _hashSizeInBytes); + return _hashSizeInBytes; + } + + public void Reset() + { + Check(Interop.Crypto.EvpDigestReset(_ctx, _algorithm)); + } + + public int Current(Span destination) + { + uint length = (uint)destination.Length; + Check(Interop.Crypto.EvpDigestCurrent(_ctx, ref MemoryMarshal.GetReference(destination), ref length)); + Debug.Assert(length == _hashSizeInBytes); + return _hashSizeInBytes; + } + + public void Dispose() + { + _ctx.Dispose(); + } + + private static void Check(int result) + { + const int Success = 1; + + if (result != Success) + { + Debug.Assert(result == 0); + throw Interop.Crypto.CreateOpenSslCryptographicException(); + } + } + } + + internal readonly struct LiteHmac : ILiteHash + { + private readonly SafeHmacCtxHandle _ctx; + private readonly int _hashSizeInBytes; + + public int HashSizeInBytes => _hashSizeInBytes; + + internal LiteHmac(IntPtr algorithm, ReadOnlySpan key) + { + Debug.Assert(algorithm != IntPtr.Zero); + _hashSizeInBytes = Interop.Crypto.EvpMdSize(algorithm); + + if (_hashSizeInBytes <= 0 || _hashSizeInBytes > Interop.Crypto.EVP_MAX_MD_SIZE) + { + Debug.Fail($"Unexpected hash '{_hashSizeInBytes}' size from {nameof(Interop.Crypto.EvpMdSize)}."); + throw new CryptographicException(); + } + + _ctx = Interop.Crypto.HmacCreate(ref MemoryMarshal.GetReference(key), key.Length, algorithm); + Interop.Crypto.CheckValidOpenSslHandle(_ctx); + } + + public void Append(ReadOnlySpan data) + { + if (data.IsEmpty) + { + return; + } + + Check(Interop.Crypto.HmacUpdate(_ctx, data, data.Length)); + } + + public int Current(Span destination) + { + Debug.Assert(destination.Length >= _hashSizeInBytes); + + int length = destination.Length; + Check(Interop.Crypto.HmacCurrent(_ctx, ref MemoryMarshal.GetReference(destination), ref length)); + Debug.Assert(length == _hashSizeInBytes); + return _hashSizeInBytes; + } + + public int Finalize(Span destination) + { + Debug.Assert(destination.Length >= _hashSizeInBytes); + + int length = destination.Length; + Check(Interop.Crypto.HmacFinal(_ctx, ref MemoryMarshal.GetReference(destination), ref length)); + Debug.Assert(length == _hashSizeInBytes); + return _hashSizeInBytes; + } + + public void Reset() + { + Check(Interop.Crypto.HmacReset(_ctx)); + } + + public void Dispose() + { + _ctx.Dispose(); + } + + private static void Check(int result) + { + const int Success = 1; + + if (result != Success) + { + Debug.Assert(result == 0); + throw Interop.Crypto.CreateOpenSslCryptographicException(); + } + } + } +} diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Windows.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Windows.cs new file mode 100644 index 0000000000000..0fa10b16cbabb --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHash.Windows.cs @@ -0,0 +1,173 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Win32.SafeHandles; +using System.Diagnostics; +using System.Runtime.InteropServices; + +using BCryptCreateHashFlags = Interop.BCrypt.BCryptCreateHashFlags; +using BCryptOpenAlgorithmProviderFlags = Interop.BCrypt.BCryptOpenAlgorithmProviderFlags; +using NTSTATUS = Interop.BCrypt.NTSTATUS; + +namespace System.Security.Cryptography +{ + internal static partial class LiteHashProvider + { + private static LiteHash CreateHash(string hashAlgorithmId) + { + return new LiteHash(hashAlgorithmId); + } + + private static LiteHmac CreateHmac(string hashAlgorithmId, ReadOnlySpan key) + { + return new LiteHmac(hashAlgorithmId, key); + } + } + + internal readonly struct LiteHash : ILiteHash + { + private readonly SafeBCryptHashHandle _hashHandle; + private readonly int _hashSizeInBytes; + + public int HashSizeInBytes => _hashSizeInBytes; + + internal LiteHash(string algorithm) + { + + BCryptOpenAlgorithmProviderFlags algorithmFlags = + BCryptOpenAlgorithmProviderFlags.None; + + // This is a shared handle, do not put this in a using. + SafeBCryptAlgorithmHandle algorithmHandle = Interop.BCrypt.BCryptAlgorithmCache.GetCachedBCryptAlgorithmHandle( + algorithm, + algorithmFlags, + out _hashSizeInBytes); + + SafeBCryptHashHandle hashHandle; + + NTSTATUS ntStatus = Interop.BCrypt.BCryptCreateHash( + algorithmHandle, + out hashHandle, + pbHashObject: IntPtr.Zero, + cbHashObject: 0, + secret: ReadOnlySpan.Empty, + cbSecret: 0, + BCryptCreateHashFlags.None); + + if (ntStatus != NTSTATUS.STATUS_SUCCESS) + { + hashHandle.Dispose(); + throw Interop.BCrypt.CreateCryptographicException(ntStatus); + } + + _hashHandle = hashHandle; + } + + public void Append(ReadOnlySpan data) + { + if (data.IsEmpty) + { + return; + } + + NTSTATUS ntStatus = Interop.BCrypt.BCryptHashData(_hashHandle, data, data.Length, dwFlags: 0); + + if (ntStatus != NTSTATUS.STATUS_SUCCESS) + { + throw Interop.BCrypt.CreateCryptographicException(ntStatus); + } + } + + public int Finalize(Span destination) + { + Debug.Assert(destination.Length >= _hashSizeInBytes); + + NTSTATUS ntStatus = Interop.BCrypt.BCryptFinishHash(_hashHandle, destination, _hashSizeInBytes, dwFlags: 0); + + if (ntStatus != NTSTATUS.STATUS_SUCCESS) + { + throw Interop.BCrypt.CreateCryptographicException(ntStatus); + } + + return _hashSizeInBytes; + } + + public void Dispose() + { + _hashHandle.Dispose(); + } + } + + internal readonly struct LiteHmac : ILiteHash + { + private readonly SafeBCryptHashHandle _hashHandle; + private readonly int _hashSizeInBytes; + + public int HashSizeInBytes => _hashSizeInBytes; + + internal LiteHmac(string algorithm, ReadOnlySpan key) + { + BCryptOpenAlgorithmProviderFlags algorithmFlags = + BCryptOpenAlgorithmProviderFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG; + + // This is a shared handle, do not put this in a using. + SafeBCryptAlgorithmHandle algorithmHandle = Interop.BCrypt.BCryptAlgorithmCache.GetCachedBCryptAlgorithmHandle( + algorithm, + algorithmFlags, + out _hashSizeInBytes); + + SafeBCryptHashHandle hashHandle; + + NTSTATUS ntStatus = Interop.BCrypt.BCryptCreateHash( + algorithmHandle, + out hashHandle, + pbHashObject: IntPtr.Zero, + cbHashObject: 0, + key, + key.Length, + BCryptCreateHashFlags.None); + + if (ntStatus != NTSTATUS.STATUS_SUCCESS) + { + hashHandle.Dispose(); + throw Interop.BCrypt.CreateCryptographicException(ntStatus); + } + + _hashHandle = hashHandle; + } + + public void Append(ReadOnlySpan data) + { + if (data.IsEmpty) + { + return; + } + + NTSTATUS ntStatus = Interop.BCrypt.BCryptHashData(_hashHandle, data, data.Length, dwFlags: 0); + + if (ntStatus != NTSTATUS.STATUS_SUCCESS) + { + throw Interop.BCrypt.CreateCryptographicException(ntStatus); + } + } + + public int Finalize(Span destination) + { + Debug.Assert(destination.Length >= _hashSizeInBytes); + + NTSTATUS ntStatus = Interop.BCrypt.BCryptFinishHash(_hashHandle, destination, _hashSizeInBytes, dwFlags: 0); + + if (ntStatus != NTSTATUS.STATUS_SUCCESS) + { + throw Interop.BCrypt.CreateCryptographicException(ntStatus); + } + + return _hashSizeInBytes; + } + + public void Dispose() + { + _hashHandle.Dispose(); + } + } +} diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHashProvider.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHashProvider.cs new file mode 100644 index 0000000000000..82aceb127fb62 --- /dev/null +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/LiteHashProvider.cs @@ -0,0 +1,195 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Security.Cryptography +{ + internal static partial class LiteHashProvider + { + internal static int HashStream(string hashAlgorithmId, int hashSizeInBytes, Stream source, Span destination) + { + LiteHash hash = CreateHash(hashAlgorithmId); + return ProcessStream(hash, source, destination); + } + + internal static byte[] HashStream(string hashAlgorithmId, int hashSizeInBytes, Stream source) + { + byte[] result = new byte[hashSizeInBytes]; + LiteHash hash = CreateHash(hashAlgorithmId); + int written = ProcessStream(hash, source, result); + Debug.Assert(written == hashSizeInBytes); + return result; + } + + internal static ValueTask HashStreamAsync( + string hashAlgorithmId, + int hashSizeInBytes, + Stream source, + Memory destination, + CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return ValueTask.FromCanceled(cancellationToken); + } + + LiteHash hash = CreateHash(hashAlgorithmId); + return ProcessStreamAsync(hash, source, destination, cancellationToken); + } + + internal static ValueTask HashStreamAsync( + string hashAlgorithmId, + int hashSizeInBytes, + Stream source, + CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return ValueTask.FromCanceled(cancellationToken); + } + + LiteHash hash = CreateHash(hashAlgorithmId); + return ProcessStreamAsync(hash, source, cancellationToken); + } + + internal static int HmacStream( + string hashAlgorithmId, + int hashSizeInBytes, + ReadOnlySpan key, + Stream source, + Span destination) + { + LiteHmac hash = CreateHmac(hashAlgorithmId, key); + return ProcessStream(hash, source, destination); + } + + internal static byte[] HmacStream( + string hashAlgorithmId, + int hashSizeInBytes, + ReadOnlySpan key, + Stream source) + { + byte[] result = new byte[hashSizeInBytes]; + LiteHmac hash = CreateHmac(hashAlgorithmId, key); + int written = ProcessStream(hash, source, result); + Debug.Assert(written == hashSizeInBytes); + return result; + } + + internal static ValueTask HmacStreamAsync( + string hashAlgorithmId, + int hashSizeInBytes, + ReadOnlySpan key, + Stream source, + Memory destination, + CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return ValueTask.FromCanceled(cancellationToken); + } + + LiteHmac hash = CreateHmac(hashAlgorithmId, key); + return ProcessStreamAsync(hash, source, destination, cancellationToken); + } + + internal static ValueTask HmacStreamAsync( + string hashAlgorithmId, + int hashSizeInBytes, + ReadOnlySpan key, + Stream source, + CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return ValueTask.FromCanceled(cancellationToken); + } + + LiteHmac hash = CreateHmac(hashAlgorithmId, key); + return ProcessStreamAsync(hash, source, cancellationToken); + } + + /// This takes ownership of the hash parameter and disposes of it when done. + private static int ProcessStream(T hash, Stream source, Span destination) where T : ILiteHash + { + using (hash) + { + byte[] rented = CryptoPool.Rent(4096); + + int maxRead = 0; + int read; + + try + { + while ((read = source.Read(rented)) > 0) + { + maxRead = Math.Max(maxRead, read); + hash.Append(rented.AsSpan(0, read)); + } + + return hash.Finalize(destination); + } + finally + { + CryptoPool.Return(rented, clearSize: maxRead); + } + } + } + + /// This takes ownership of the hash parameter and disposes of it when done. + private static async ValueTask ProcessStreamAsync( + T hash, + Stream source, + Memory destination, + CancellationToken cancellationToken) where T : ILiteHash + { + using (hash) + { + byte[] rented = CryptoPool.Rent(4096); + + int maxRead = 0; + int read; + + try + { + while ((read = await source.ReadAsync(rented, cancellationToken).ConfigureAwait(false)) > 0) + { + maxRead = Math.Max(maxRead, read); + hash.Append(rented.AsSpan(0, read)); + } + + return hash.Finalize(destination.Span); + } + finally + { + CryptoPool.Return(rented, clearSize: maxRead); + } + } + } + + /// This takes ownership of the hash parameter and disposes of it when done. + private static async ValueTask ProcessStreamAsync( + T hash, + Stream source, + CancellationToken cancellationToken) where T : ILiteHash + { + byte[] result = new byte[hash.HashSizeInBytes]; + int written = await ProcessStreamAsync(hash, source, result, cancellationToken).ConfigureAwait(false); + + Debug.Assert(written == result.Length); + return result; + } + } + + internal interface ILiteHash : IDisposable + { + int HashSizeInBytes { get; } + + void Append(ReadOnlySpan data); + int Finalize(Span destination); + } +} diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD5.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD5.cs index ce70b333089bc..c1ba826d59355 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD5.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MD5.cs @@ -3,7 +3,10 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Runtime.Versioning; +using System.Threading; +using System.Threading.Tasks; using Internal.Cryptography; namespace System.Security.Cryptography @@ -112,6 +115,128 @@ public static bool TryHashData(ReadOnlySpan source, Span destination return true; } + /// + /// Computes the hash of a stream using the MD5 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The MD5 algorithm always produces a 128-bit hash, or 16 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.MD5, HashSizeInBytes, source, destination); + } + + /// + /// Computes the hash of a stream using the MD5 algorithm. + /// + /// The stream to hash. + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.MD5, HashSizeInBytes, source); + } + + /// + /// Asynchronously computes the hash of a stream using the MD5 algorithm. + /// + /// The stream to hash. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync(HashAlgorithmNames.MD5, HashSizeInBytes, source, cancellationToken); + } + + /// + /// Asynchronously computes the hash of a stream using the MD5 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The MD5 algorithm always produces a 128-bit hash, or 16 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync( + HashAlgorithmNames.MD5, + HashSizeInBytes, + source, + destination, + cancellationToken); + } + private sealed class Implementation : MD5 { private readonly HashProvider _hashProvider; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA1.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA1.cs index 0a66bc18b2854..684d69e9a228c 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA1.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA1.cs @@ -4,6 +4,9 @@ using Internal.Cryptography; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace System.Security.Cryptography { @@ -111,6 +114,128 @@ public static bool TryHashData(ReadOnlySpan source, Span destination return true; } + /// + /// Computes the hash of a stream using the SHA1 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA1 algorithm always produces a 160-bit hash, or 20 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.SHA1, HashSizeInBytes, source, destination); + } + + /// + /// Computes the hash of a stream using the SHA1 algorithm. + /// + /// The stream to hash. + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.SHA1, HashSizeInBytes, source); + } + + /// + /// Asynchronously computes the hash of a stream using the SHA1 algorithm. + /// + /// The stream to hash. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync(HashAlgorithmNames.SHA1, HashSizeInBytes, source, cancellationToken); + } + + /// + /// Asynchronously computes the hash of a stream using the SHA1 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA1 algorithm always produces a 160-bit hash, or 20 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync( + HashAlgorithmNames.SHA1, + HashSizeInBytes, + source, + destination, + cancellationToken); + } + private sealed class Implementation : SHA1 { private readonly HashProvider _hashProvider; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA256.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA256.cs index da16eb8606430..fb48e9ffe0031 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA256.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA256.cs @@ -4,6 +4,9 @@ using Internal.Cryptography; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace System.Security.Cryptography { @@ -111,6 +114,128 @@ public static bool TryHashData(ReadOnlySpan source, Span destination return true; } + /// + /// Computes the hash of a stream using the SHA256 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA256 algorithm always produces a 256-bit hash, or 32 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.SHA256, HashSizeInBytes, source, destination); + } + + /// + /// Computes the hash of a stream using the SHA256 algorithm. + /// + /// The stream to hash. + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.SHA256, HashSizeInBytes, source); + } + + /// + /// Asynchronously computes the hash of a stream using the SHA256 algorithm. + /// + /// The stream to hash. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync(HashAlgorithmNames.SHA256, HashSizeInBytes, source, cancellationToken); + } + + /// + /// Asynchronously computes the hash of a stream using the SHA256 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA256 algorithm always produces a 256-bit hash, or 32 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync( + HashAlgorithmNames.SHA256, + HashSizeInBytes, + source, + destination, + cancellationToken); + } + private sealed class Implementation : SHA256 { private readonly HashProvider _hashProvider; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA384.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA384.cs index 1ed1b72c04f61..89ba9d5c78b85 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA384.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA384.cs @@ -4,6 +4,9 @@ using Internal.Cryptography; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace System.Security.Cryptography { @@ -110,6 +113,128 @@ public static bool TryHashData(ReadOnlySpan source, Span destination return true; } + /// + /// Computes the hash of a stream using the SHA384 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA384 algorithm always produces a 384-bit hash, or 48 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.SHA384, HashSizeInBytes, source, destination); + } + + /// + /// Computes the hash of a stream using the SHA384 algorithm. + /// + /// The stream to hash. + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.SHA384, HashSizeInBytes, source); + } + + /// + /// Asynchronously computes the hash of a stream using the SHA384 algorithm. + /// + /// The stream to hash. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync(HashAlgorithmNames.SHA384, HashSizeInBytes, source, cancellationToken); + } + + /// + /// Asynchronously computes the hash of a stream using the SHA384 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA384 algorithm always produces a 384-bit hash, or 48 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync( + HashAlgorithmNames.SHA384, + HashSizeInBytes, + source, + destination, + cancellationToken); + } + private sealed class Implementation : SHA384 { private readonly HashProvider _hashProvider; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA512.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA512.cs index 5c6e52ab9cd9a..924af115013d9 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA512.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA512.cs @@ -4,6 +4,9 @@ using Internal.Cryptography; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace System.Security.Cryptography { @@ -110,6 +113,128 @@ public static bool TryHashData(ReadOnlySpan source, Span destination return true; } + /// + /// Computes the hash of a stream using the SHA512 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA512 algorithm always produces a 512-bit hash, or 64 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static int HashData(Stream source, Span destination) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.SHA512, HashSizeInBytes, source, destination); + } + + /// + /// Computes the hash of a stream using the SHA512 algorithm. + /// + /// The stream to hash. + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static byte[] HashData(Stream source) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStream(HashAlgorithmNames.SHA512, HashSizeInBytes, source); + } + + /// + /// Asynchronously computes the hash of a stream using the SHA512 algorithm. + /// + /// The stream to hash. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The hash of the data. + /// + /// is . + /// + /// + /// does not support reading. + /// + public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync(HashAlgorithmNames.SHA512, HashSizeInBytes, source, cancellationToken); + } + + /// + /// Asynchronously computes the hash of a stream using the SHA512 algorithm. + /// + /// The stream to hash. + /// The buffer to receive the hash value. + /// + /// The token to monitor for cancellation requests. + /// The default value is . + /// + /// The total number of bytes written to . + /// + /// is . + /// + /// + ///

+ /// The buffer in is too small to hold the calculated hash + /// size. The SHA512 algorithm always produces a 512-bit hash, or 64 bytes. + ///

+ ///

-or-

+ ///

+ /// does not support reading. + ///

+ ///
+ public static ValueTask HashDataAsync( + Stream source, + Memory destination, + CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(source); + + if (destination.Length < HashSizeInBytes) + throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination)); + + if (!source.CanRead) + throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source)); + + return LiteHashProvider.HashStreamAsync( + HashAlgorithmNames.SHA512, + HashSizeInBytes, + source, + destination, + cancellationToken); + } + private sealed class Implementation : SHA512 { private readonly HashProvider _hashProvider; diff --git a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTestDriver.cs b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTestDriver.cs index 9f940b3753a63..8890808c6a0cc 100644 --- a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTestDriver.cs +++ b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTestDriver.cs @@ -3,6 +3,8 @@ using System.IO; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Test.Cryptography; using Xunit; @@ -15,6 +17,10 @@ public abstract class HashAlgorithmTestDriver protected abstract byte[] HashData(byte[] source); protected abstract byte[] HashData(ReadOnlySpan source); protected abstract int HashData(ReadOnlySpan source, Span destination); + protected abstract int HashData(Stream source, Span destination); + protected abstract byte[] HashData(Stream source); + protected abstract ValueTask HashDataAsync(Stream source, Memory destination, CancellationToken cancellationToken); + protected abstract ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken); protected void Verify(string input, string output) { @@ -35,6 +41,54 @@ private void VerifyComputeHashStream(Stream input, string output) Assert.Equal(expected, actual); } + private async Task VerifyComputeHashStreamAsync(Stream input, string output) + { + byte[] expected = ByteUtils.HexToByteArray(output); + byte[] actual; + + using (HashAlgorithm hash = Create()) + { + Assert.True(hash.HashSize > 0); + actual = await hash.ComputeHashAsync(input); + } + + Assert.Equal(expected, actual); + } + + private void VerifyOneShotStream(Stream input, string output) + { + byte[] expected = ByteUtils.HexToByteArray(output); + Span buffer = stackalloc byte[512 / 8]; + + int written = HashData(input, buffer); + AssertExtensions.SequenceEqual(expected, buffer.Slice(0, written)); + } + + private async Task VerifyOneShotStreamAsync(Stream input, string output) + { + byte[] expected = ByteUtils.HexToByteArray(output); + Memory buffer = new byte[512 / 8]; + + int written = await HashDataAsync(input, buffer, cancellationToken: default); + AssertExtensions.SequenceEqual(expected, buffer.Slice(0, written).Span); + } + + private void VerifyOneShotAllocatingStream(Stream input, string output) + { + byte[] expected = ByteUtils.HexToByteArray(output); + + byte[] digest = HashData(input); + Assert.Equal(expected, digest); + } + + private async Task VerifyOneShotAllocatingStreamAsync(Stream input, string output) + { + byte[] expected = ByteUtils.HexToByteArray(output); + + byte[] digest = await HashDataAsync(input, cancellationToken: default); + Assert.Equal(expected, digest); + } + private void VerifyICryptoTransformStream(Stream input, string output) { byte[] expected = ByteUtils.HexToByteArray(output); @@ -140,13 +194,13 @@ private void VerifyTransformBlockComputeHashInteraction(byte[] block1, byte[] bl [Fact] public void HashData_ByteArray_Null() { - AssertExtensions.Throws("source", () => HashData(null)); + AssertExtensions.Throws("source", () => HashData((byte[])null)); } [Fact] public void HashData_BufferTooSmall() { - AssertExtensions.Throws("destination", () => HashData(default, default)); + AssertExtensions.Throws("destination", () => HashData(Span.Empty, default)); } [Fact] @@ -320,6 +374,85 @@ protected void VerifyRepeating(string input, int repeatCount, string output) { VerifyICryptoTransformStream(stream, output); } + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + VerifyOneShotStream(stream, output); + } + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + VerifyOneShotAllocatingStream(stream, output); + } + } + + protected async Task VerifyRepeatingAsync(string input, int repeatCount, string output) + { + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + await VerifyComputeHashStreamAsync(stream, output); + } + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + await VerifyOneShotStreamAsync(stream, output); + } + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + await VerifyOneShotAllocatingStreamAsync(stream, output); + } + } + + [Fact] + public void HashData_Null_Stream_Throws() + { + AssertExtensions.Throws("source", () => HashData((Stream)null)); + AssertExtensions.Throws("source", () => HashData((Stream)null, Span.Empty)); + } + + [Fact] + public void HashData_ShortDestination_Throws() + { + AssertExtensions.Throws("destination", () => HashData(Stream.Null, Span.Empty)); + } + + [Fact] + public void HashDataAsync_Null_Stream_Throws() + { + AssertExtensions.Throws( + "source", + () => HashDataAsync((Stream)null, cancellationToken: default)); + + AssertExtensions.Throws( + "source", + () => HashDataAsync((Stream)null, Memory.Empty, cancellationToken: default)); + } + + [Fact] + public void HashDataAsync_ShortDestination_Throws() + { + AssertExtensions.Throws( + "destination", + () => HashDataAsync(Stream.Null, Memory.Empty, cancellationToken: default)); + } + + [Fact] + public void HashDataAsync_Buffer_CancelledToken() + { + Memory buffer = new byte[512 / 8]; + CancellationToken cancelledToken = new CancellationToken(canceled: true); + ValueTask waitable = HashDataAsync(Stream.Null, buffer, cancelledToken); + Assert.True(waitable.IsCanceled, nameof(waitable.IsCanceled)); + AssertExtensions.FilledWith(0, buffer.Span); + } + + [Fact] + public void HashDataAsync_Allocating_CancelledToken() + { + CancellationToken cancelledToken = new CancellationToken(canceled: true); + ValueTask waitable = HashDataAsync(Stream.Null, cancelledToken); + Assert.True(waitable.IsCanceled, nameof(waitable.IsCanceled)); } [Fact] @@ -511,91 +644,5 @@ public void Initialize_DoubleInitialize_Works() Assert.Equal(expectedDigest, hash.Hash); } } - - protected class DataRepeatingStream : Stream - { - private int _remaining; - private byte[] _data; - - public DataRepeatingStream(string data, int repeatCount) - { - _remaining = repeatCount; - _data = ByteUtils.AsciiBytes(data); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (!CanRead) - { - throw new NotSupportedException(); - } - - if (_remaining == 0) - { - return 0; - } - - if (count < _data.Length) - { - throw new InvalidOperationException(); - } - - int multiple = count / _data.Length; - - if (multiple > _remaining) - { - multiple = _remaining; - } - - int localOffset = offset; - - for (int i = 0; i < multiple; i++) - { - Buffer.BlockCopy(_data, 0, buffer, localOffset, _data.Length); - localOffset += _data.Length; - } - - _remaining -= multiple; - return _data.Length * multiple; - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - _data = null; - } - } - - public override void Flush() - { - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override bool CanRead { get { return _data != null; } } - public override bool CanSeek { get { return false; } } - public override bool CanWrite { get { return false; } } - public override long Length { get { throw new NotSupportedException(); } } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - } } } diff --git a/src/libraries/System.Security.Cryptography/tests/HmacMD5Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacMD5Tests.cs index 99ad3814d0a37..d658411811826 100644 --- a/src/libraries/System.Security.Cryptography/tests/HmacMD5Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/HmacMD5Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Test.Cryptography; using Xunit; @@ -55,6 +58,31 @@ protected override int HashDataOneShot(ReadOnlySpan key, ReadOnlySpan key, ReadOnlySpan source, Span destination, out int written) => HMACMD5.TryHashData(key, source, destination, out written); + protected override byte[] HashDataOneShot(ReadOnlySpan key, Stream source) => + HMACMD5.HashData(key, source); + + protected override byte[] HashDataOneShot(byte[] key, Stream source) => + HMACMD5.HashData(key, source); + + protected override int HashDataOneShot(ReadOnlySpan key, Stream source, Span destination) => + HMACMD5.HashData(key, source, destination); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken) => HMACMD5.HashDataAsync(key, source, destination, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + CancellationToken cancellationToken) => HMACMD5.HashDataAsync(key, source, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + byte[] key, + Stream source, + CancellationToken cancellationToken) => HMACMD5.HashDataAsync(key, source, cancellationToken); + [Fact] public void HmacMD5_Rfc2202_1() { @@ -108,5 +136,77 @@ public void HMacMD5_ThrowsArgumentNullForNullConstructorKey() { AssertExtensions.Throws("key", () => new HMACMD5(null)); } + + [Fact] + public void HmacMD5_Stream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl md5 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "1287EF250C2026A0C0CBA832C599AE50"); + } + + [Fact] + public void HmacMD5_Stream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl md5 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "D10B835D95FCC9EECDF1D4BCDAB81897"); + } + + [Fact] + public void HmacMD5_Stream_Empty() + { + // Verfied with: + // echo -n "" | openssl md5 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "C91E40247251F39BDFE6A7B72A5857F9"); + } + + [Fact] + public async Task HmacMD5_Stream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl md5 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "1287EF250C2026A0C0CBA832C599AE50"); + } + + [Fact] + public async Task HmacMD5_Stream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl md5 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "D10B835D95FCC9EECDF1D4BCDAB81897"); + } + + [Fact] + public async Task HmacMD5_Stream_Empty_Async() + { + // Verfied with: + // echo -n "" | openssl md5 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "C91E40247251F39BDFE6A7B72A5857F9"); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha1Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha1Tests.cs index 61b395d572535..d618b7122a32d 100644 --- a/src/libraries/System.Security.Cryptography/tests/HmacSha1Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/HmacSha1Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Test.Cryptography; using Xunit; @@ -55,6 +58,31 @@ protected override int HashDataOneShot(ReadOnlySpan key, ReadOnlySpan key, ReadOnlySpan source, Span destination, out int written) => HMACSHA1.TryHashData(key, source, destination, out written); + protected override byte[] HashDataOneShot(ReadOnlySpan key, Stream source) => + HMACSHA1.HashData(key, source); + + protected override byte[] HashDataOneShot(byte[] key, Stream source) => + HMACSHA1.HashData(key, source); + + protected override int HashDataOneShot(ReadOnlySpan key, Stream source, Span destination) => + HMACSHA1.HashData(key, source, destination); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken) => HMACSHA1.HashDataAsync(key, source, destination, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + CancellationToken cancellationToken) => HMACSHA1.HashDataAsync(key, source, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + byte[] key, + Stream source, + CancellationToken cancellationToken) => HMACSHA1.HashDataAsync(key, source, cancellationToken); + [Fact] public void HmacSha1_Byte_Constructors() { @@ -128,9 +156,81 @@ public void HmacSha1_Rfc2202_7() } [Fact] - public void HMacSha1_Rfc2104_2() + public void HmacSha1_Rfc2104_2() { VerifyHmacRfc2104_2(); } + + [Fact] + public void HmacSha1_Stream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha1 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "3CE5AE476733905861F031DDC2DEDF8CBB1FAA0B"); + } + + [Fact] + public void HmacSha1_Stream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha1 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "E18D7FB16A83CA17DB6CB0F1C083AA7A7094F627"); + } + + [Fact] + public void HmacSha1_Stream_Empty() + { + // Verfied with: + // echo -n "" | openssl sha1 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "5433122F77BCF8A4D9B874B4149823EF5B7C207E"); + } + + [Fact] + public async Task HmacSha1_Stream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha1 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "3CE5AE476733905861F031DDC2DEDF8CBB1FAA0B"); + } + + [Fact] + public async Task HmacSha1_Stream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha1 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "E18D7FB16A83CA17DB6CB0F1C083AA7A7094F627"); + } + + [Fact] + public async Task HmacSha1_Stream_Empty_Async() + { + // Verfied with: + // echo -n "" | openssl sha1 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "5433122F77BCF8A4D9B874B4149823EF5B7C207E"); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha256Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha256Tests.cs index f2f1784404675..587711a920ad2 100644 --- a/src/libraries/System.Security.Cryptography/tests/HmacSha256Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/HmacSha256Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Test.Cryptography; using Xunit; @@ -26,6 +29,31 @@ protected override int HashDataOneShot(ReadOnlySpan key, ReadOnlySpan key, ReadOnlySpan source, Span destination, out int written) => HMACSHA256.TryHashData(key, source, destination, out written); + protected override byte[] HashDataOneShot(ReadOnlySpan key, Stream source) => + HMACSHA256.HashData(key, source); + + protected override byte[] HashDataOneShot(byte[] key, Stream source) => + HMACSHA256.HashData(key, source); + + protected override int HashDataOneShot(ReadOnlySpan key, Stream source, Span destination) => + HMACSHA256.HashData(key, source, destination); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken) => HMACSHA256.HashDataAsync(key, source, destination, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + CancellationToken cancellationToken) => HMACSHA256.HashDataAsync(key, source, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + byte[] key, + Stream source, + CancellationToken cancellationToken) => HMACSHA256.HashDataAsync(key, source, cancellationToken); + private static byte[][] s_testMacs4231 = { null, @@ -86,7 +114,7 @@ public void HmacSha256_Rfc4231_7() } [Fact] - public void HMacSha256_Rfc2104_2() + public void HmacSha256_Rfc2104_2() { VerifyHmacRfc2104_2(); } @@ -96,5 +124,77 @@ public void HmacSha256_ThrowsArgumentNullForNullConstructorKey() { AssertExtensions.Throws("key", () => new HMACSHA256(null)); } + + [Fact] + public void HmacSha256_Stream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "A47B9F5BD5C2DEF403A0279D4C6C407A2D34561E7D1F006D7FE8BDC2C78227D5"); + } + + [Fact] + public void HmacSha256_Stream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "1CF6661B6EFD25D8B6DE734AA39D5D3D44C9A56BB9377A6388EB0FC5E48A108B"); + } + + [Fact] + public void HmacSha256_Stream_Empty() + { + // Verfied with: + // echo -n "" | openssl sha256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "07EFF8B326B7798C9CCFCBDBE579489AC785A7995A04618B1A2813C26744777D"); + } + + [Fact] + public async Task HmacSha256_Stream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "A47B9F5BD5C2DEF403A0279D4C6C407A2D34561E7D1F006D7FE8BDC2C78227D5"); + } + + [Fact] + public async Task HmacSha256_Stream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "1CF6661B6EFD25D8B6DE734AA39D5D3D44C9A56BB9377A6388EB0FC5E48A108B"); + } + + [Fact] + public async Task HmacSha256_Stream_Empty_Async() + { + // Verfied with: + // echo -n "" | openssl sha256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "07EFF8B326B7798C9CCFCBDBE579489AC785A7995A04618B1A2813C26744777D"); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha384Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha384Tests.cs index dbff8c26c50bc..eb3bbf5681e8b 100644 --- a/src/libraries/System.Security.Cryptography/tests/HmacSha384Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/HmacSha384Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Test.Cryptography; using Xunit; @@ -26,6 +29,31 @@ protected override int HashDataOneShot(ReadOnlySpan key, ReadOnlySpan key, ReadOnlySpan source, Span destination, out int written) => HMACSHA384.TryHashData(key, source, destination, out written); + protected override byte[] HashDataOneShot(ReadOnlySpan key, Stream source) => + HMACSHA384.HashData(key, source); + + protected override byte[] HashDataOneShot(byte[] key, Stream source) => + HMACSHA384.HashData(key, source); + + protected override int HashDataOneShot(ReadOnlySpan key, Stream source, Span destination) => + HMACSHA384.HashData(key, source, destination); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken) => HMACSHA384.HashDataAsync(key, source, destination, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + CancellationToken cancellationToken) => HMACSHA384.HashDataAsync(key, source, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + byte[] key, + Stream source, + CancellationToken cancellationToken) => HMACSHA384.HashDataAsync(key, source, cancellationToken); + private static byte[][] s_testMacs4231 = { null, @@ -99,7 +127,7 @@ public void HmacSha384_Rfc4231_7() } [Fact] - public void HMacSha384_Rfc2104_2() + public void HmacSha384_Rfc2104_2() { VerifyHmacRfc2104_2(); } @@ -109,5 +137,77 @@ public void HmacSha384_ThrowsArgumentNullForNullConstructorKey() { AssertExtensions.Throws("key", () => new HMACSHA384(null)); } + + [Fact] + public void HmacSha384_Stream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "6C4977B00CCE179ADCC06EB35E48ABDE9B5604FC9E8B6B25F65E0234EE6394DE40F0C6C6B727B58B19ADFC1E5BB2E84D"); + } + + [Fact] + public void HmacSha384_Stream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "45303A3B5F02C8462D6FA438893DAA05EFFA850B853DF614D45F343D20AFE6D6DBAC6D0656788C4398EDF0AEC01488D4"); + } + + [Fact] + public void HmacSha384_Stream_Empty() + { + // Verfied with: + // echo -n "" | openssl sha384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "6A0FDC1C54C664AD91C7C157D2670C5D44E4D44EBAD2359A0206974C7088B1A867F76971E6C240C33B33A66BA295BB56"); + } + + [Fact] + public async Task HmacSha384_Stream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "6C4977B00CCE179ADCC06EB35E48ABDE9B5604FC9E8B6B25F65E0234EE6394DE40F0C6C6B727B58B19ADFC1E5BB2E84D"); + } + + [Fact] + public async Task HmacSha384_Stream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "45303A3B5F02C8462D6FA438893DAA05EFFA850B853DF614D45F343D20AFE6D6DBAC6D0656788C4398EDF0AEC01488D4"); + } + + [Fact] + public async Task HmacSha384_Stream_Empty_Async() + { + // Verfied with: + // echo -n "" | openssl sha384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "6A0FDC1C54C664AD91C7C157D2670C5D44E4D44EBAD2359A0206974C7088B1A867F76971E6C240C33B33A66BA295BB56"); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha512Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha512Tests.cs index 7bf5ed6652873..7172d68d43dfe 100644 --- a/src/libraries/System.Security.Cryptography/tests/HmacSha512Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/HmacSha512Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Test.Cryptography; using Xunit; @@ -26,6 +29,31 @@ protected override int HashDataOneShot(ReadOnlySpan key, ReadOnlySpan key, ReadOnlySpan source, Span destination, out int written) => HMACSHA512.TryHashData(key, source, destination, out written); + protected override byte[] HashDataOneShot(ReadOnlySpan key, Stream source) => + HMACSHA512.HashData(key, source); + + protected override byte[] HashDataOneShot(byte[] key, Stream source) => + HMACSHA512.HashData(key, source); + + protected override int HashDataOneShot(ReadOnlySpan key, Stream source, Span destination) => + HMACSHA512.HashData(key, source, destination); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken) => HMACSHA512.HashDataAsync(key, source, destination, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + CancellationToken cancellationToken) => HMACSHA512.HashDataAsync(key, source, cancellationToken); + + protected override ValueTask HashDataOneShotAsync( + byte[] key, + Stream source, + CancellationToken cancellationToken) => HMACSHA512.HashDataAsync(key, source, cancellationToken); + private static byte[][] s_testMacs4231 = { null, @@ -99,7 +127,7 @@ public void HmacSha512_Rfc4231_7() } [Fact] - public void HMacSha512_Rfc2104_2() + public void HmacSha512_Rfc2104_2() { VerifyHmacRfc2104_2(); } @@ -109,5 +137,77 @@ public void HmacSha512_ThrowsArgumentNullForNullConstructorKey() { AssertExtensions.Throws("key", () => new HMACSHA512(null)); } + + [Fact] + public void HmacSha512_Stream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "05A7BB210D374B0CC36FFFA561045F1C1EB8E71905A50308B108D4677CCB0452A99B26EE41DD8E1D87D53A4F3E07B1231E5D3FFFCE7FD0C5C5A8B8F5E0206A11"); + } + + [Fact] + public void HmacSha512_Stream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "9040E87E9CC546C507C3DEE90D278975B0C2049F28E71CC6FEEA0F3690EC9D0B736F885FFAA611156DA0C2904FC2EEEAA9562B53EB50F590902B2AE38056C874"); + } + + [Fact] + public void HmacSha512_Stream_Empty() + { + // Verfied with: + // echo -n "" | openssl sha512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + VerifyRepeating( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "2FEC800CA276C44985A35AEC92067E5E53A1BB80A6FDAB1D9C97D54068118F30AD4C33717466D372EA00BBF126E5B79C6F7143DD36C31F72028330E92AE3A359"); + } + + [Fact] + public async Task HmacSha512_Stream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1024, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "05A7BB210D374B0CC36FFFA561045F1C1EB8E71905A50308B108D4677CCB0452A99B26EE41DD8E1D87D53A4F3E07B1231E5D3FFFCE7FD0C5C5A8B8F5E0206A11"); + } + + [Fact] + public async Task HmacSha512_Stream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "0102030405060708", + 1025, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "9040E87E9CC546C507C3DEE90D278975B0C2049F28E71CC6FEEA0F3690EC9D0B736F885FFAA611156DA0C2904FC2EEEAA9562B53EB50F590902B2AE38056C874"); + } + + [Fact] + public async Task HmacSha512_Stream_Empty_Async() + { + // Verfied with: + // echo -n "" | openssl sha512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F + await VerifyRepeatingAsync( + input: "", + 0, + hexKey: "000102030405060708090A0B0C0D0E0F", + output: "2FEC800CA276C44985A35AEC92067E5E53A1BB80A6FDAB1D9C97D54068118F30AD4C33717466D372EA00BBF126E5B79C6F7143DD36C31F72028330E92AE3A359"); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/HmacTests.cs b/src/libraries/System.Security.Cryptography/tests/HmacTests.cs index ca266b43921fe..9083a9fd15e7b 100644 --- a/src/libraries/System.Security.Cryptography/tests/HmacTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/HmacTests.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; +using System.Threading; +using System.Threading.Tasks; using Test.Cryptography; using Xunit; @@ -31,10 +33,123 @@ protected HmacTests(byte[][] testKeys, byte[][] testData, byte[][] testMacs) protected abstract byte[] HashDataOneShot(ReadOnlySpan key, ReadOnlySpan source); protected abstract int HashDataOneShot(ReadOnlySpan key, ReadOnlySpan source, Span destination); protected abstract bool TryHashDataOneShot(ReadOnlySpan key, ReadOnlySpan source, Span destination, out int written); + protected abstract byte[] HashDataOneShot(ReadOnlySpan key, Stream source); + protected abstract byte[] HashDataOneShot(byte[] key, Stream source); + protected abstract int HashDataOneShot(ReadOnlySpan key, Stream source, Span destination); + + protected abstract ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + Memory destination, + CancellationToken cancellationToken); + + protected abstract ValueTask HashDataOneShotAsync( + ReadOnlyMemory key, + Stream source, + CancellationToken cancellationToken); + + protected abstract ValueTask HashDataOneShotAsync( + byte[] key, + Stream source, + CancellationToken cancellationToken); protected abstract int BlockSize { get; } protected abstract int MacSize { get; } + protected void VerifyRepeating(string input, int repeatCount, string hexKey, string output) + { + byte[] key = ByteUtils.HexToByteArray(hexKey); + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + VerifyHashDataStreamAllocating(key, stream, output, spanKey: true); + } + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + VerifyHashDataStreamAllocating(key, stream, output, spanKey: false); + } + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + VerifyHashDataStream(key, stream, output); + } + } + + protected async Task VerifyRepeatingAsync(string input, int repeatCount, string hexKey, string output) + { + byte[] key = ByteUtils.HexToByteArray(hexKey); + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + await VerifyHashDataStreamAllocatingAsync(key, stream, output, memoryKey: true); + } + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + await VerifyHashDataStreamAllocatingAsync(key, stream, output, memoryKey: false); + } + + using (Stream stream = new DataRepeatingStream(input, repeatCount)) + { + await VerifyHashDataStreamAsync(key, stream, output); + } + } + + protected void VerifyHashDataStream(ReadOnlySpan key, Stream stream, string output) + { + Span destination = stackalloc byte[MacSize]; + byte[] expected = ByteUtils.HexToByteArray(output); + int written = HashDataOneShot(key, stream, destination); + + Assert.Equal(MacSize, written); + AssertExtensions.SequenceEqual(expected, destination); + } + + protected async Task VerifyHashDataStreamAsync(ReadOnlyMemory key, Stream stream, string output) + { + Memory destination = new byte[MacSize]; + byte[] expected = ByteUtils.HexToByteArray(output); + int written = await HashDataOneShotAsync(key, stream, destination, cancellationToken: default); + + Assert.Equal(MacSize, written); + AssertExtensions.SequenceEqual(expected, destination.Span); + } + + protected void VerifyHashDataStreamAllocating(byte[] key, Stream stream, string output, bool spanKey) + { + byte[] expected = ByteUtils.HexToByteArray(output); + byte[] hmac; + + if (spanKey) + { + hmac = HashDataOneShot(key.AsSpan(), stream); + } + else + { + hmac = HashDataOneShot(key, stream); + } + + Assert.Equal(expected, hmac); + } + + protected async Task VerifyHashDataStreamAllocatingAsync(byte[] key, Stream stream, string output, bool memoryKey) + { + byte[] expected = ByteUtils.HexToByteArray(output); + byte[] hmac; + + if (memoryKey) + { + hmac = await HashDataOneShotAsync(new ReadOnlyMemory(key), stream, cancellationToken: default); + } + else + { + hmac = await HashDataOneShotAsync(key, stream, cancellationToken: default); + } + + Assert.Equal(expected, hmac); + } + protected void VerifyHmac(int testCaseId, byte[] digestBytes) { byte[] data = _testData[testCaseId]; @@ -386,5 +501,111 @@ public void OneShot_Empty_Matches_Instances(byte[] key, byte[] source) Assert.Equal(mac, oneShot); } } + + [Fact] + public void HashData_Stream_Source_Null() + { + AssertExtensions.Throws( + "source", + () => HashDataOneShot(ReadOnlySpan.Empty, (Stream)null)); + + AssertExtensions.Throws( + "source", + () => HashDataOneShot(Array.Empty(), (Stream)null)); + } + + [Fact] + public void HashData_Stream_Source_Null_Async() + { + AssertExtensions.Throws( + "source", + () => HashDataOneShotAsync(ReadOnlyMemory.Empty, (Stream)null, default)); + + AssertExtensions.Throws( + "source", + () => HashDataOneShotAsync(Array.Empty(), (Stream)null, default)); + } + + [Fact] + public void HashData_Stream_ByteKey_Null() + { + AssertExtensions.Throws( + "key", + () => HashDataOneShot((byte[])null, Stream.Null)); + } + + [Fact] + public void HashData_Stream_ByteKey_Null_Async() + { + AssertExtensions.Throws( + "key", + () => HashDataOneShotAsync((byte[])null, Stream.Null, default)); + } + + [Fact] + public void HashData_Stream_DestinationTooSmall() + { + byte[] destination = new byte[MacSize - 1]; + + AssertExtensions.Throws( + "destination", + () => HashDataOneShot(Array.Empty(), Stream.Null, destination)); + AssertExtensions.FilledWith(0, destination); + + AssertExtensions.Throws( + "destination", + () => HashDataOneShot(ReadOnlySpan.Empty, Stream.Null, destination)); + AssertExtensions.FilledWith(0, destination); + } + + [Fact] + public void HashData_Stream_DestinationTooSmall_Async() + { + byte[] destination = new byte[MacSize - 1]; + + AssertExtensions.Throws( + "destination", + () => HashDataOneShotAsync(Array.Empty(), Stream.Null, destination, default)); + AssertExtensions.FilledWith(0, destination); + + AssertExtensions.Throws( + "destination", + () => HashDataOneShotAsync(ReadOnlyMemory.Empty, Stream.Null, destination, default)); + AssertExtensions.FilledWith(0, destination); + } + + [Fact] + public void HashData_Stream_NotReadable() + { + AssertExtensions.Throws( + "source", + () => HashDataOneShot(Array.Empty(), UntouchableStream.Instance)); + + AssertExtensions.Throws( + "source", + () => HashDataOneShot(ReadOnlySpan.Empty, UntouchableStream.Instance)); + } + + [Fact] + public void HashData_Stream_Cancelled() + { + Memory buffer = new byte[512 / 8]; + CancellationToken cancelledToken = new CancellationToken(canceled: true); + ValueTask waitable = HashDataOneShotAsync(ReadOnlyMemory.Empty, Stream.Null, buffer, cancelledToken); + Assert.True(waitable.IsCanceled, nameof(waitable.IsCanceled)); + AssertExtensions.FilledWith(0, buffer.Span); + + waitable = HashDataOneShotAsync(Array.Empty(), Stream.Null, buffer, cancelledToken); + Assert.True(waitable.IsCanceled, nameof(waitable.IsCanceled)); + AssertExtensions.FilledWith(0, buffer.Span); + } + + [Fact] + public void HashData_Stream_Allocating_Cancelled() + { + CancellationToken cancelledToken = new CancellationToken(canceled: true); + ValueTask waitable = HashDataOneShotAsync(ReadOnlyMemory.Empty, Stream.Null, cancelledToken); + Assert.True(waitable.IsCanceled, nameof(waitable.IsCanceled)); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/MD5Tests.cs b/src/libraries/System.Security.Cryptography/tests/MD5Tests.cs index e301eae2fc300..26ab965bf4799 100644 --- a/src/libraries/System.Security.Cryptography/tests/MD5Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/MD5Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Xunit; namespace System.Security.Cryptography.Tests @@ -25,6 +28,49 @@ protected override bool TryHashData(ReadOnlySpan source, Span destin protected override int HashData(ReadOnlySpan source, Span destination) => MD5.HashData(source, destination); + protected override int HashData(Stream source, Span destination) => + MD5.HashData(source, destination); + + protected override byte[] HashData(Stream source) => MD5.HashData(source); + + protected override ValueTask HashDataAsync(Stream source, Memory destination, CancellationToken cancellationToken) => + MD5.HashDataAsync(source, destination, cancellationToken); + + protected override ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken) => + MD5.HashDataAsync(source, cancellationToken); + + [Fact] + public void MD5_VerifyLargeStream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -md5 + VerifyRepeating("0102030405060708", 1024, "5fc6366852074da6e4795a014574282c"); + } + + [Fact] + public void MD5_VerifyLargeStream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -md5 + VerifyRepeating("0102030405060708", 1025, "c5f6181a24446a583b14282f32786513"); + } + + [Fact] + public async Task MD5_VerifyLargeStream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -md5 + await VerifyRepeatingAsync("0102030405060708", 1025, "c5f6181a24446a583b14282f32786513"); + } + + [Fact] + public async Task MD5_VerifyLargeStream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -md5 + await VerifyRepeatingAsync("0102030405060708", 1024, "5fc6366852074da6e4795a014574282c"); + } + // Test cases are defined in RFC 1321, section A.5 [Fact] @@ -79,10 +125,28 @@ public void MD5_Rfc1321_7() Verify("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"); } + [Fact] + public void MD5_Rfc1321_1_AsStream() + { + VerifyRepeating(string.Empty, 0, "d41d8cd98f00b204e9800998ecf8427e"); + } + [Fact] public void MD5_Rfc1321_7_AsStream() { VerifyRepeating("1234567890", 8, "57edf4a22be3c955ac49da2e2107b67a"); } + + [Fact] + public async Task MD5_Rfc1321_1_AsStream_Async() + { + await VerifyRepeatingAsync(string.Empty, 0, "d41d8cd98f00b204e9800998ecf8427e"); + } + + [Fact] + public async Task MD5_Rfc1321_7_AsStream_Async() + { + await VerifyRepeatingAsync("1234567890", 8, "57edf4a22be3c955ac49da2e2107b67a"); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/Sha1Tests.cs b/src/libraries/System.Security.Cryptography/tests/Sha1Tests.cs index 45d0315852cbe..46f0f24534348 100644 --- a/src/libraries/System.Security.Cryptography/tests/Sha1Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/Sha1Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Xunit; namespace System.Security.Cryptography.Tests @@ -24,12 +27,67 @@ protected override bool TryHashData(ReadOnlySpan source, Span destin protected override int HashData(ReadOnlySpan source, Span destination) => SHA1.HashData(source, destination); + protected override int HashData(Stream source, Span destination) => + SHA1.HashData(source, destination); + + protected override byte[] HashData(Stream source) => SHA1.HashData(source); + + protected override ValueTask HashDataAsync(Stream source, Memory destination, CancellationToken cancellationToken) => + SHA1.HashDataAsync(source, destination, cancellationToken); + + protected override ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken) => + SHA1.HashDataAsync(source, cancellationToken); + [Fact] public void Sha1_Empty() { Verify(Array.Empty(), "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"); } + [Fact] + public void Sha1_Empty_Stream() + { + VerifyRepeating("", 0, "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"); + } + + [Fact] + public async Task Sha1_Empty_Stream_Async() + { + await VerifyRepeatingAsync("", 0, "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"); + } + + [Fact] + public void Sha1_VerifyLargeStream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -sha1 + VerifyRepeating("0102030405060708", 1024, "fc8053215c935a5e9cdc51b94bb40b3e66128d41"); + } + + [Fact] + public void Sha1_VerifyLargeStream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -sha1 + VerifyRepeating("0102030405060708", 1025, "18c6aa8d255c47941958729faaae9614c9793bb2"); + } + + [Fact] + public async Task Sha1_VerifyLargeStream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -sha1 + await VerifyRepeatingAsync("0102030405060708", 1025, "18c6aa8d255c47941958729faaae9614c9793bb2"); + } + + [Fact] + public async Task Sha1_VerifyLargeStream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -sha1 + await VerifyRepeatingAsync("0102030405060708", 1024, "fc8053215c935a5e9cdc51b94bb40b3e66128d41"); + } + // SHA1 tests are defined somewhat obliquely within RFC 3174, section 7.3 // The same tests appear in http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf Appendix A [Fact] @@ -61,5 +119,17 @@ public void Sha1_Rfc3174_4() { VerifyRepeating("0123456701234567012345670123456701234567012345670123456701234567", 10, "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452"); } + + [Fact] + public async Task Sha1_Rfc3174_3_Async() + { + await VerifyRepeatingAsync("a", 1000000, "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F"); + } + + [Fact] + public async Task Sha1_Rfc3174_4_Async() + { + await VerifyRepeatingAsync("0123456701234567012345670123456701234567012345670123456701234567", 10, "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452"); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/Sha256Tests.cs b/src/libraries/System.Security.Cryptography/tests/Sha256Tests.cs index e85dddc08d797..4abad52b94094 100644 --- a/src/libraries/System.Security.Cryptography/tests/Sha256Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/Sha256Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Xunit; namespace System.Security.Cryptography.Tests @@ -24,6 +27,17 @@ protected override bool TryHashData(ReadOnlySpan source, Span destin protected override int HashData(ReadOnlySpan source, Span destination) => SHA256.HashData(source, destination); + protected override int HashData(Stream source, Span destination) => + SHA256.HashData(source, destination); + + protected override byte[] HashData(Stream source) => SHA256.HashData(source); + + protected override ValueTask HashDataAsync(Stream source, Memory destination, CancellationToken cancellationToken) => + SHA256.HashDataAsync(source, destination, cancellationToken); + + protected override ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken) => + SHA256.HashDataAsync(source, cancellationToken); + [Fact] public void Sha256_Empty() { @@ -32,6 +46,62 @@ public void Sha256_Empty() "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); } + [Fact] + public void Sha256_Empty_Stream() + { + VerifyRepeating("", 0, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + } + + [Fact] + public async Task Sha256_Empty_Stream_Async() + { + await VerifyRepeatingAsync("", 0, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + } + + [Fact] + public void Sha256_VerifyLargeStream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -sha256 + VerifyRepeating( + "0102030405060708", + 1024, + "cedca4ad2cce0d0b399931708684800cd16be396ffa5af51297a091650aa3610"); + } + + [Fact] + public void Sha256_VerifyLargeStream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -sha256 + VerifyRepeating( + "0102030405060708", + 1025, + "9e2e99445f5349c379ceb4c995dde401f63012422183a411d02eb251b1e02e65"); + } + + [Fact] + public async Task Sha256_VerifyLargeStream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -sha256 + await VerifyRepeatingAsync( + "0102030405060708", + 1025, + "9e2e99445f5349c379ceb4c995dde401f63012422183a411d02eb251b1e02e65"); + } + + [Fact] + public async Task Sha256_VerifyLargeStream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -sha256 + await VerifyRepeatingAsync( + "0102030405060708", + 1024, + "cedca4ad2cce0d0b399931708684800cd16be396ffa5af51297a091650aa3610"); + } + // These test cases are from http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf Appendix B [Fact] public void Sha256_Fips180_1() @@ -67,5 +137,14 @@ public void Sha256_Fips180_3() 1000000, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); } + + [Fact] + public async Task Sha256_Fips180_3_Async() + { + await VerifyRepeatingAsync( + "a", + 1000000, + "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/Sha384Tests.cs b/src/libraries/System.Security.Cryptography/tests/Sha384Tests.cs index 5ef3ebcb4e039..c7cfea805683c 100644 --- a/src/libraries/System.Security.Cryptography/tests/Sha384Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/Sha384Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Xunit; namespace System.Security.Cryptography.Tests @@ -24,6 +27,17 @@ protected override bool TryHashData(ReadOnlySpan source, Span destin protected override int HashData(ReadOnlySpan source, Span destination) => SHA384.HashData(source, destination); + protected override int HashData(Stream source, Span destination) => + SHA384.HashData(source, destination); + + protected override byte[] HashData(Stream source) => SHA384.HashData(source); + + protected override ValueTask HashDataAsync(Stream source, Memory destination, CancellationToken cancellationToken) => + SHA384.HashDataAsync(source, destination, cancellationToken); + + protected override ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken) => + SHA384.HashDataAsync(source, cancellationToken); + [Fact] public void Sha384_Empty() { @@ -32,6 +46,68 @@ public void Sha384_Empty() "38B060A751AC96384CD9327EB1B1E36A21FDB71114BE07434C0CC7BF63F6E1DA274EDEBFE76F65FBD51AD2F14898B95B"); } + [Fact] + public void Sha384_Empty_Stream() + { + VerifyRepeating( + "", + 0, + "38B060A751AC96384CD9327EB1B1E36A21FDB71114BE07434C0CC7BF63F6E1DA274EDEBFE76F65FBD51AD2F14898B95B"); + } + + [Fact] + public async Task Sha384_Empty_Stream_Async() + { + await VerifyRepeatingAsync( + "", + 0, + "38B060A751AC96384CD9327EB1B1E36A21FDB71114BE07434C0CC7BF63F6E1DA274EDEBFE76F65FBD51AD2F14898B95B"); + } + + [Fact] + public void Sha384_VerifyLargeStream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -sha384 + VerifyRepeating( + "0102030405060708", + 1024, + "d9deec18b8ec0d31270eaeaaf3bcb1de55f1d81482a55d2c023bad873175f1694d8c28e8138d9147dc180e679cd79c58"); + } + + [Fact] + public void Sha384_VerifyLargeStream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -sha384 + VerifyRepeating( + "0102030405060708", + 1025, + "35cf18493364379093c7def8477330f817f9045d2e311d721730b24d98c9d9e9761c7f27821742e0c236509627aea7fa"); + } + + [Fact] + public async Task Sha384_VerifyLargeStream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -sha384 + await VerifyRepeatingAsync( + "0102030405060708", + 1025, + "35cf18493364379093c7def8477330f817f9045d2e311d721730b24d98c9d9e9761c7f27821742e0c236509627aea7fa"); + } + + [Fact] + public async Task Sha384_VerifyLargeStream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -sha384 + await VerifyRepeatingAsync( + "0102030405060708", + 1024, + "d9deec18b8ec0d31270eaeaaf3bcb1de55f1d81482a55d2c023bad873175f1694d8c28e8138d9147dc180e679cd79c58"); + } + // These test cases are from http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf [Fact] public void Sha384_NistShaAll_1() @@ -42,7 +118,7 @@ public void Sha384_NistShaAll_1() } [Fact] - public void Sha256_Fips180_MultiBlock() + public void Sha384_Fips180_MultiBlock() { VerifyMultiBlock( "a", diff --git a/src/libraries/System.Security.Cryptography/tests/Sha512Tests.cs b/src/libraries/System.Security.Cryptography/tests/Sha512Tests.cs index 4586a08d846b0..465f41c15fdf6 100644 --- a/src/libraries/System.Security.Cryptography/tests/Sha512Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/Sha512Tests.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. +using System.IO; +using System.Threading; +using System.Threading.Tasks; using Xunit; namespace System.Security.Cryptography.Tests @@ -24,6 +27,17 @@ protected override bool TryHashData(ReadOnlySpan source, Span destin protected override int HashData(ReadOnlySpan source, Span destination) => SHA512.HashData(source, destination); + protected override int HashData(Stream source, Span destination) => + SHA512.HashData(source, destination); + + protected override byte[] HashData(Stream source) => SHA512.HashData(source); + + protected override ValueTask HashDataAsync(Stream source, Memory destination, CancellationToken cancellationToken) => + SHA512.HashDataAsync(source, destination, cancellationToken); + + protected override ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken) => + SHA512.HashDataAsync(source, cancellationToken); + [Fact] public void Sha512_Empty() { @@ -32,6 +46,68 @@ public void Sha512_Empty() "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"); } + [Fact] + public void Sha512_Empty_Stream() + { + VerifyRepeating( + "", + 0, + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"); + } + + [Fact] + public async Task Sha512_Empty_Stream_Async() + { + await VerifyRepeatingAsync( + "", + 0, + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"); + } + + [Fact] + public void Sha512_VerifyLargeStream_MultipleOf4096() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -sha512 + VerifyRepeating( + "0102030405060708", + 1024, + "da1bdf4632ea5ee0724a57a9bc6fd409d7f8f7417373356281ce36f82b510da95c7dff7d64a43b3cf4854894e124f56b349749a3f76b41611c01fee739f4d923"); + } + + [Fact] + public void Sha512_VerifyLargeStream_NotMultipleOf4096() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -sha512 + VerifyRepeating( + "0102030405060708", + 1025, + "65de1e49167977ade93d12115d0f5915a988b7e0ab73f2b554bd6d87c17155e865ba434a88271fb2dbaf5f9b0cf71d627eaea6b0efce5ec95e4c6017bfbfb34b"); + } + + [Fact] + public async Task Sha512_VerifyLargeStream_NotMultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl dgst -sha512 + await VerifyRepeatingAsync( + "0102030405060708", + 1025, + "65de1e49167977ade93d12115d0f5915a988b7e0ab73f2b554bd6d87c17155e865ba434a88271fb2dbaf5f9b0cf71d627eaea6b0efce5ec95e4c6017bfbfb34b"); + } + + [Fact] + public async Task Sha512_VerifyLargeStream_MultipleOf4096_Async() + { + // Verfied with: + // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl dgst -sha512 + await VerifyRepeatingAsync( + "0102030405060708", + 1024, + "da1bdf4632ea5ee0724a57a9bc6fd409d7f8f7417373356281ce36f82b510da95c7dff7d64a43b3cf4854894e124f56b349749a3f76b41611c01fee739f4d923"); + } + // These test cases are from http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf Appendix C [Fact] public void Sha512_Fips180_1() @@ -67,5 +143,14 @@ public void Sha512_Fips180_3() 1000000, "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"); } + + [Fact] + public async Task Sha512_Fips180_3_Async() + { + await VerifyRepeatingAsync( + "a", + 1000000, + "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"); + } } } diff --git a/src/libraries/System.Security.Cryptography/tests/StreamHelpers.cs b/src/libraries/System.Security.Cryptography/tests/StreamHelpers.cs new file mode 100644 index 0000000000000..022084779355c --- /dev/null +++ b/src/libraries/System.Security.Cryptography/tests/StreamHelpers.cs @@ -0,0 +1,147 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using Test.Cryptography; + +namespace System.Security.Cryptography.Tests +{ + internal class DataRepeatingStream : Stream + { + private int _remaining; + private byte[] _data; + + public DataRepeatingStream(string data, int repeatCount) + { + _remaining = repeatCount; + _data = ByteUtils.AsciiBytes(data); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (!CanRead) + { + throw new NotSupportedException(); + } + + if (_remaining == 0) + { + return 0; + } + + if (count < _data.Length) + { + throw new InvalidOperationException(); + } + + // For (about) half of the reads, we'll read one less byte + // than was asked for. This is to make sure stream readers + // conform to the expectation that Read MAY return less than + // was asked for. + if (count > 1 && Random.Shared.Next(2) == 0) + { + count--; + } + + int multiple = count / _data.Length; + + if (multiple > _remaining) + { + multiple = _remaining; + } + + int localOffset = offset; + + for (int i = 0; i < multiple; i++) + { + Buffer.BlockCopy(_data, 0, buffer, localOffset, _data.Length); + localOffset += _data.Length; + } + + _remaining -= multiple; + return _data.Length * multiple; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _data = null; + } + } + + public override void Flush() + { + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override bool CanRead { get { return _data != null; } } + public override bool CanSeek { get { return false; } } + public override bool CanWrite { get { return false; } } + public override long Length { get { throw new NotSupportedException(); } } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + } + + internal class UntouchableStream : Stream + { + public static Stream Instance { get; } = new UntouchableStream(); + + public override bool CanRead => false; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj index 8621f98748bd1..dafa4adb4bff2 100644 --- a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj +++ b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj @@ -265,6 +265,7 @@ + From 85413211c0c915dd1a3b25b88171e2a500e24bb0 Mon Sep 17 00:00:00 2001 From: Tlakaelel Axayakatl Ceja Date: Sun, 23 Jan 2022 18:09:41 -0800 Subject: [PATCH 153/308] Title and message resources should be enforced to exist to prevent printing empty messages (#64151) Sync ILLink.Shared folder with the latest version in dotnet/linker main branch List of changes include: - Enforce title and message resources to exist to prevent printing empty messages - All diagnostics produced by linker now have a DiagnosticId, a title and a message - Schema for xml link attributes file - Added a readme file to the ILLink.Shared project to keep track of the commit is being used from dotnet/linker --- src/coreclr/tools/Common/Compiler/Logger.cs | 8 +- .../Compiler/Logging/MessageContainer.cs | 2 + .../Compiler/Dataflow/FlowAnnotations.cs | 2 + .../Dataflow/ReflectionMethodBodyScanner.cs | 16 +- .../Dataflow/ReflectionPatternContext.cs | 2 + .../Compiler/LazyGenerics/ModuleCycleInfo.cs | 2 + .../Compiler/UsageBasedMetadataManager.cs | 1 + .../ILCompiler.ReadyToRun.csproj | 1 + .../Compiler/RyuJitCompilation.cs | 1 + .../tools/aot/ILCompiler/ILCompiler.csproj | 8 +- .../tools/aot/ILLink.Shared/DiagnosticId.cs | 156 ++- .../aot/ILLink.Shared/DiagnosticString.cs | 10 +- .../ILLink.Shared/ILLink.LinkAttributes.xsd | 124 +++ .../aot/ILLink.Shared/ILLink.Shared.projitems | 8 +- .../aot/ILLink.Shared/MessageSubCategory.cs | 13 + src/coreclr/tools/aot/ILLink.Shared/README.md | 1 + .../aot/ILLink.Shared/SharedStrings.resx | 999 +++++++++++++++++- 17 files changed, 1278 insertions(+), 76 deletions(-) create mode 100644 src/coreclr/tools/aot/ILLink.Shared/ILLink.LinkAttributes.xsd create mode 100644 src/coreclr/tools/aot/ILLink.Shared/MessageSubCategory.cs create mode 100644 src/coreclr/tools/aot/ILLink.Shared/README.md diff --git a/src/coreclr/tools/Common/Compiler/Logger.cs b/src/coreclr/tools/Common/Compiler/Logger.cs index eb77c7cd681e1..26f763b815595 100644 --- a/src/coreclr/tools/Common/Compiler/Logger.cs +++ b/src/coreclr/tools/Common/Compiler/Logger.cs @@ -10,6 +10,7 @@ using Internal.TypeSystem.Ecma; using ILCompiler.Logging; +using ILLink.Shared; using ILSequencePoint = Internal.IL.ILSequencePoint; using MethodIL = Internal.IL.MethodIL; @@ -198,11 +199,4 @@ private static string GetModuleFileName(ModuleDesc module) return assemblyName; } } - - public static class MessageSubCategory - { - public const string None = ""; - public const string TrimAnalysis = "Trim analysis"; - public const string AotAnalysis = "AOT analysis"; - } } diff --git a/src/coreclr/tools/Common/Compiler/Logging/MessageContainer.cs b/src/coreclr/tools/Common/Compiler/Logging/MessageContainer.cs index 95ed5bf04fa0c..ebe08a14870ed 100644 --- a/src/coreclr/tools/Common/Compiler/Logging/MessageContainer.cs +++ b/src/coreclr/tools/Common/Compiler/Logging/MessageContainer.cs @@ -6,6 +6,8 @@ using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using ILLink.Shared; + using Debug = System.Diagnostics.Debug; namespace ILCompiler.Logging diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs index f3585e0e098f0..64ce9a5ba1218 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs @@ -10,6 +10,8 @@ using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using ILLink.Shared; + using Debug = System.Diagnostics.Debug; namespace ILCompiler.Dataflow diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs index 06d371cd17aea..1f198fbc155e7 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs @@ -1029,8 +1029,8 @@ public override bool HandleCall(MethodIL callingMethodBody, MethodDesc calledMet // We don't know what method the `MakeGenericMethod` was called on, so we have to assume // that the method may have requirements which we can't fullfil -> warn. reflectionContext.RecordUnrecognizedPattern( - (int)DiagnosticId.MakeGenericMethodCannotBeStaticallyAnalyzed, - new DiagnosticString(DiagnosticId.MakeGenericMethodCannotBeStaticallyAnalyzed).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod))); + (int)DiagnosticId.MakeGenericMethod, + new DiagnosticString(DiagnosticId.MakeGenericMethod).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod))); } RequireDynamicallyAccessedMembers( @@ -1048,8 +1048,8 @@ public override bool HandleCall(MethodIL callingMethodBody, MethodDesc calledMet // We don't know what method the `MakeGenericMethod` was called on, so we have to assume // that the method may have requirements which we can't fullfil -> warn. reflectionContext.RecordUnrecognizedPattern( - (int)DiagnosticId.MakeGenericMethodCannotBeStaticallyAnalyzed, - new DiagnosticString(DiagnosticId.MakeGenericMethodCannotBeStaticallyAnalyzed).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod))); + (int)DiagnosticId.MakeGenericMethod, + new DiagnosticString(DiagnosticId.MakeGenericMethod).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod))); } RequireDynamicallyAccessedMembers( @@ -2162,8 +2162,8 @@ public override bool HandleCall(MethodIL callingMethodBody, MethodDesc calledMet // We don't know what method the `MakeGenericMethod` was called on, so we have to assume // that the method may have requirements which we can't fullfil -> warn. reflectionContext.RecordUnrecognizedPattern( - (int)DiagnosticId.MakeGenericMethodCannotBeStaticallyAnalyzed, - new DiagnosticString(DiagnosticId.MakeGenericMethodCannotBeStaticallyAnalyzed).GetMessage( + (int)DiagnosticId.MakeGenericMethod, + new DiagnosticString(DiagnosticId.MakeGenericMethod).GetMessage( DiagnosticUtilities.GetMethodSignatureDisplayName(calledMethod))); } } @@ -3066,8 +3066,8 @@ void ValidateGenericMethodInstantiation( if (!AnalyzeGenericInstantiationTypeArray(genericParametersArray, ref reflectionContext, reflectionMethod, genericMethod.GetMethodDefinition().Instantiation)) { reflectionContext.RecordUnrecognizedPattern( - (int)DiagnosticId.MakeGenericMethodCannotBeStaticallyAnalyzed, - new DiagnosticString(DiagnosticId.MakeGenericMethodCannotBeStaticallyAnalyzed).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(reflectionMethod))); + (int)DiagnosticId.MakeGenericMethod, + new DiagnosticString(DiagnosticId.MakeGenericMethod).GetMessage(DiagnosticUtilities.GetMethodSignatureDisplayName(reflectionMethod))); } else { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionPatternContext.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionPatternContext.cs index 99d97784e7811..61a48fe965a0c 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionPatternContext.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionPatternContext.cs @@ -7,6 +7,8 @@ using Internal.IL; using Internal.TypeSystem; +using ILLink.Shared; + namespace ILCompiler.Dataflow { /// diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LazyGenerics/ModuleCycleInfo.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LazyGenerics/ModuleCycleInfo.cs index 378af488af020..07e2768797cab 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LazyGenerics/ModuleCycleInfo.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LazyGenerics/ModuleCycleInfo.cs @@ -8,6 +8,8 @@ using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using ILLink.Shared; + using Debug = System.Diagnostics.Debug; namespace ILCompiler diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs index 439d4e014e6db..971d932be8c10 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs @@ -15,6 +15,7 @@ using ILCompiler.Metadata; using ILCompiler.DependencyAnalysis; using ILCompiler.DependencyAnalysisFramework; +using ILLink.Shared; using FlowAnnotations = ILCompiler.Dataflow.FlowAnnotations; using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore.DependencyList; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 5154db358a8b8..6c7d67517a9ee 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -283,4 +283,5 @@ + diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs index 0d8b11c51f82e..b27f7db8ec7d8 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs @@ -9,6 +9,7 @@ using ILCompiler.DependencyAnalysis; using ILCompiler.DependencyAnalysisFramework; +using ILLink.Shared; using Internal.IL; using Internal.IL.Stubs; diff --git a/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj b/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj index 6c559924f405c..6c5a4a6d377d8 100644 --- a/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj @@ -1,4 +1,4 @@ - + ilc true @@ -121,10 +121,6 @@ On Linux renaming the library makes it difficult to debug it. --> - + diff --git a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticId.cs b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticId.cs index 8bffef3ab0e5b..e25b16f8ef844 100644 --- a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticId.cs +++ b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticId.cs @@ -5,17 +5,123 @@ namespace ILLink.Shared { public enum DiagnosticId { + // Linker error ids. + XmlFeatureDoesNotSpecifyFeatureValue = 1001, + XmlUnsupportedNonBooleanValueForFeature = 1002, + XmlException = 1003, + _unused_FailedToProcessDescriptorFile = 1004, + CouldNotFindMethodInAssembly = 1005, + CannotStubConstructorWhenBaseTypeDoesNotHaveConstructor = 1006, + CouldNotFindType = 1007, + CouldNotFindConstructor = 1008, + CouldNotFindAssemblyReference = 1009, + CouldNotLoadAssembly = 1010, + FailedToWriteOutput = 1011, + LinkerUnexpectedError = 1012, + ErrorProcessingXmlLocation = 1013, + XmlDocumentLocationHasInvalidFeatureDefault = 1014, + UnrecognizedCommandLineOption = 1015, + InvalidWarningVersion = 1016, + InvalidGenerateWarningSuppressionsValue = 1017, + MissingArgumentForCommanLineOptionName = 1018, + CustomDataFormatIsInvalid = 1019, + NoFilesToLinkSpecified = 1020, + NewMvidAndDeterministicCannotBeUsedAtSameTime = 1021, + AssemblyInCustomStepOptionCouldNotBeFound = 1022, + AssemblyPathInCustomStepMustBeFullyQualified = 1023, + InvalidArgForCustomStep = 1024, + ExpectedSignToControlNewStepInsertion = 1025, + PipelineStepCouldNotBeFound = 1026, + CustomStepTypeCouldNotBeFound = 1027, + CustomStepTypeIsIncompatibleWithLinkerVersion = 1028, + InvalidOptimizationValue = 1029, + InvalidArgumentForTokenOption = 1030, + InvalidAssemblyAction = 1031, + RootAssemblyCouldNotBeFound = 1032, + XmlDescriptorCouldNotBeFound = 1033, + RootAssemblyDoesNotHaveEntryPoint = 1034, + RootAssemblyCannotUseAction = 1035, + InvalidAssemblyName = 1036, + InvalidAssemblyRootMode = 1037, + ExportedTypeCannotBeResolved = 1038, + ReferenceAssemblyCouldNotBeLoaded = 1039, + FailedToResolveMetadataElement = 1040, + TypeUsedWithAttributeValueCouldNotBeFound = 1041, + CannotConverValueToType = 1042, + CustomAttributeArgumentForTypeRequiresNestedNode = 1043, + CouldNotResolveCustomAttributeTypeValue = 1044, + UnexpectedAttributeArgumentType = 1045, + InvalidMetadataOption = 1046, + // Linker diagnostic ids. + TypeHasNoFieldsToPreserve = 2001, + TypeHasNoMethodsToPreserve = 2002, + CouldNotResolveDependencyAssembly = 2003, + CouldNotResolveDependencyType = 2004, + CouldNotResolveDependencyMember = 2005, + _unused_UnrecognizedReflectionPattern = 2006, + XmlCouldNotResolveAssembly = 2007, + XmlCouldNotResolveType = 2008, + XmlCouldNotFindMethodOnType = 2009, + XmlInvalidValueForStub = 2010, + XmlUnkownBodyModification = 2011, + XmlCouldNotFindFieldOnType = 2012, + XmlSubstitutedFieldNeedsToBeStatic = 2013, + XmlMissingSubstitutionValueForField = 2014, + XmlInvalidSubstitutionValueForField = 2015, + XmlCouldNotFindEventOnType = 2016, + XmlCouldNotFindPropertyOnType = 2017, + XmlCouldNotFindGetAccesorOfPropertyOnType = 2018, + XmlCouldNotFindSetAccesorOfPropertyOnType = 2019, + _unused_RearrangedXmlWarning1 = 2020, + _unused_RearrangedXmlWarning2 = 2021, + XmlCouldNotFindMatchingConstructorForCustomAttribute = 2022, + XmlMoreThanOneReturnElementForMethod = 2023, + XmlMoreThanOneValyForParameterOfMethod = 2024, + XmlDuplicatePreserveMember = 2025, RequiresUnreferencedCode = 2026, + AttributeShouldOnlyBeUsedOnceOnMember = 2027, + AttributeDoesntHaveTheRequiredNumberOfParameters = 2028, + XmlElementDoesNotContainRequiredAttributeFullname = 2029, + XmlCouldNotResolveAssemblyForAttribute = 2030, + XmlAttributeTypeCouldNotBeFound = 2031, + UnrecognizedParameterInMethodCreateInstance = 2032, + DeprecatedPreserveDependencyAttribute = 2033, + DynamicDependencyAttributeCouldNotBeAnalyzed = 2034, + UnresolvedAssemblyInDynamicDependencyAttribute = 2035, + UnresolvedTypeInDynamicDependencyAttribute = 2036, + NoMembersResolvedForMemberSignatureOrType = 2037, + XmlMissingNameAttributeInResource = 2038, + XmlInvalidValueForAttributeActionForResource = 2039, + XmlCouldNotFindResourceToRemoveInAssembly = 2040, + DynamicallyAccessedMembersIsNotAllowedOnMethods = 2041, + DynamicallyAccessedMembersCouldNotFindBackingField = 2042, + DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor = 2043, + XmlCouldNotFindAnyTypeInNamespace = 2044, + AttributeIsReferencedButTrimmerRemoveAllInstances = 2045, RequiresUnreferencedCodeAttributeMismatch = 2046, + _unused_DynamicallyAccessedMembersMismatchBetweenOverrides = 2047, + XmlRemoveAttributeInstancesCanOnlyBeUsedOnType = 2048, + _unused_UnrecognizedInternalAttribute = 2049, CorrectnessOfCOMCannotBeGuaranteed = 2050, + XmlPropertyDoesNotContainAttributeName = 2051, + XmlCouldNotFindProperty = 2052, + _unused_XmlInvalidPropertyValueForProperty = 2053, + _unused_XmlInvalidArgumentForParameterOfType = 2054, MakeGenericType = 2055, + DynamicallyAccessedMembersOnPropertyConflictsWithBackingField = 2056, + UnrecognizedTypeNameInTypeGetType = 2057, + ParametersOfAssemblyCreateInstanceCannotBeAnalyzed = 2058, + UnrecognizedTypeInRuntimeHelpersRunClassConstructor = 2059, MakeGenericMethod = 2060, - RequiresOnBaseClass = 2109, - RequiresUnreferencedCodeOnStaticConstructor = 2116, + UnresolvedAssemblyInCreateInstance = 2061, + MethodParameterCannotBeStaticallyDetermined = 2062, + MethodReturnValueCannotBeStaticallyDetermined = 2063, + FieldValueCannotBeStaticallyDetermined = 2064, + ImplicitThisCannotBeStaticallyDetermined = 2065, + TypePassedToGenericParameterCannotBeStaticallyDetermined = 2066, // Dynamically Accessed Members attribute mismatch. - MakeGenericMethodCannotBeStaticallyAnalyzed = 2060, DynamicallyAccessedMembersMismatchParameterTargetsParameter = 2067, DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType = 2068, DynamicallyAccessedMembersMismatchParameterTargetsField = 2069, @@ -41,7 +147,32 @@ public enum DiagnosticId DynamicallyAccessedMembersMismatchTypeArgumentTargetsField = 2089, DynamicallyAccessedMembersMismatchTypeArgumentTargetsThisParameter = 2090, DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter = 2091, + DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides = 2092, + DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides = 2093, + DynamicallyAccessedMembersMismatchOnImplicitThisBetweenOverrides = 2094, + DynamicallyAccessedMembersMismatchOnGenericParameterBetweenOverrides = 2095, + + CaseInsensitiveTypeGetTypeCallIsNotSupported = 2096, + DynamicallyAccessedMembersOnFieldCanOnlyApplyToTypesOrStrings = 2097, + DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings = 2098, + DynamicallyAccessedMembersOnPropertyCanOnlyApplyToTypesOrStrings = 2099, + XmlUnsuportedWildcard = 2100, + AssemblyWithEmbeddedXmlApplyToAnotherAssembly = 2101, + InvalidIsTrimmableValue = 2102, PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined = 2103, + AssemblyProducedTrimWarnings = 2104, + TypeWasNotFoundInAssemblyNorBaseLibrary = 2105, + DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings = 2106, + MethodsAreAssociatedWithStateMachine = 2107, + InvalidScopeInUnconditionalSuppressMessage = 2108, + RequiresUnreferencedCodeOnBaseClass = 2109, + DynamicallyAccessedMembersFieldAccessedViaReflection = 2110, + DynamicallyAccessedMembersMethodAccessedViaReflection = 2111, + DynamicallyAccessedMembersOnTypeReferencesMemberWithRequiresUnreferencedCode = 2112, + DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithRequiresUnreferencedCode = 2113, + DynamicallyAccessedMembersOnTypeReferencesMemberWithDynamicallyAccessedMembers = 2114, + DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithDynamicallyAccessedMembers = 2115, + RequiresUnreferencedCodeOnStaticConstructor = 2116, // Single-file diagnostic ids. AvoidAssemblyLocationInSingleFile = 3000, @@ -62,5 +193,24 @@ public enum DiagnosticId public static class DiagnosticIdExtensions { public static string AsString(this DiagnosticId diagnosticId) => $"IL{(int)diagnosticId}"; + + public static string GetDiagnosticSubcategory(this DiagnosticId diagnosticId) => + (int)diagnosticId switch + { + 2026 => MessageSubCategory.TrimAnalysis, + 2032 => MessageSubCategory.TrimAnalysis, + 2041 => MessageSubCategory.TrimAnalysis, + 2042 => MessageSubCategory.TrimAnalysis, + 2043 => MessageSubCategory.TrimAnalysis, + 2045 => MessageSubCategory.TrimAnalysis, + 2046 => MessageSubCategory.TrimAnalysis, + 2050 => MessageSubCategory.TrimAnalysis, + var x when x >= 2055 && x <= 2099 => MessageSubCategory.TrimAnalysis, + 2103 => MessageSubCategory.TrimAnalysis, + 2106 => MessageSubCategory.TrimAnalysis, + 2107 => MessageSubCategory.TrimAnalysis, + var x when x >= 2109 && x <= 2116 => MessageSubCategory.TrimAnalysis, + _ => MessageSubCategory.None, + }; } } diff --git a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticString.cs b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticString.cs index 103b93ed28bb0..f14b58b060083 100644 --- a/src/coreclr/tools/aot/ILLink.Shared/DiagnosticString.cs +++ b/src/coreclr/tools/aot/ILLink.Shared/DiagnosticString.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; + namespace ILLink.Shared { public readonly struct DiagnosticString @@ -11,15 +13,15 @@ public readonly struct DiagnosticString public DiagnosticString(DiagnosticId diagnosticId) { var resourceManager = SharedStrings.ResourceManager; - _titleFormat = resourceManager.GetString($"{diagnosticId}Title") ?? string.Empty; - _messageFormat = resourceManager.GetString($"{diagnosticId}Message") ?? string.Empty; + _titleFormat = resourceManager.GetString($"{diagnosticId}Title") ?? throw new InvalidOperationException($"{diagnosticId} does not have a matching resource called {diagnosticId}Title"); + _messageFormat = resourceManager.GetString($"{diagnosticId}Message") ?? throw new InvalidOperationException($"{diagnosticId} does not have a matching resource called {diagnosticId}Message"); } public DiagnosticString(string diagnosticResourceStringName) { var resourceManager = SharedStrings.ResourceManager; - _titleFormat = resourceManager.GetString($"{diagnosticResourceStringName}Title") ?? string.Empty; - _messageFormat = resourceManager.GetString($"{diagnosticResourceStringName}Message") ?? string.Empty; + _titleFormat = resourceManager.GetString($"{diagnosticResourceStringName}Title") ?? throw new InvalidOperationException($"{diagnosticResourceStringName} does not have a matching resource called {diagnosticResourceStringName}Title"); + _messageFormat = resourceManager.GetString($"{diagnosticResourceStringName}Message") ?? throw new InvalidOperationException($"{diagnosticResourceStringName} does not have a matching resource called {diagnosticResourceStringName}Message"); } public string GetMessage(params string[] args) => diff --git a/src/coreclr/tools/aot/ILLink.Shared/ILLink.LinkAttributes.xsd b/src/coreclr/tools/aot/ILLink.Shared/ILLink.LinkAttributes.xsd new file mode 100644 index 0000000000000..f1156b0a4d690 --- /dev/null +++ b/src/coreclr/tools/aot/ILLink.Shared/ILLink.LinkAttributes.xsd @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.projitems b/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.projitems index 0a61390d8d025..ffbfab3b98417 100644 --- a/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.projitems +++ b/src/coreclr/tools/aot/ILLink.Shared/ILLink.Shared.projitems @@ -13,6 +13,7 @@ + @@ -21,4 +22,9 @@ Designer - \ No newline at end of file + + + Designer + + + diff --git a/src/coreclr/tools/aot/ILLink.Shared/MessageSubCategory.cs b/src/coreclr/tools/aot/ILLink.Shared/MessageSubCategory.cs new file mode 100644 index 0000000000000..92c1077b14baf --- /dev/null +++ b/src/coreclr/tools/aot/ILLink.Shared/MessageSubCategory.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. + +namespace ILLink.Shared +{ + public static class MessageSubCategory + { + public const string None = ""; + public const string TrimAnalysis = "Trim analysis"; + public const string UnresolvedAssembly = "Unresolved assembly"; + public const string AotAnalysis = "AOT analysis"; + } +} diff --git a/src/coreclr/tools/aot/ILLink.Shared/README.md b/src/coreclr/tools/aot/ILLink.Shared/README.md new file mode 100644 index 0000000000000..229b67e492bf0 --- /dev/null +++ b/src/coreclr/tools/aot/ILLink.Shared/README.md @@ -0,0 +1 @@ +Sources taken from https://github.com/dotnet/linker/tree/890591b13da936d2c38a52afdaeac0db69858d4f/src/ILLink.Shared. diff --git a/src/coreclr/tools/aot/ILLink.Shared/SharedStrings.resx b/src/coreclr/tools/aot/ILLink.Shared/SharedStrings.resx index 0d53dff7e254e..e2db35e707331 100644 --- a/src/coreclr/tools/aot/ILLink.Shared/SharedStrings.resx +++ b/src/coreclr/tools/aot/ILLink.Shared/SharedStrings.resx @@ -53,7 +53,6 @@ value : The object must be serialized with : System.Runtime.Serialization.Formatters.Soap.SoapFormatter : and then encoded with base64 encoding. - mimetype: application/x-microsoft.net.object.bytearray.base64 value : The object must be serialized into a byte array : using a System.ComponentModel.TypeConverter @@ -117,12 +116,954 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + An Xml Feature does not specify a 'featurevalue' attribute. + + + Failed to process '{0}'. Feature '{1}' does not specify a 'featurevalue' attribute. + + + Feature definition has to be a boolean. + + + Failed to process '{0}'. Unsupported non-boolean feature definition '{1}'. + + + An exception was thrown while processing the xml file. + + + Error processing '{0}': {1}. + + + An error ocurred while processing a method in assembly. + + + Error processing method '{0}' in assembly '{1}'. + + + Cannot stub constructor of a type when base type does not have default constructor. Constructors of derived types marked for substitution require to have a default constructor in its base type. + + + Cannot stub constructor on '{0}' when base type does not have default constructor. + + + Could not find predefined type". + + + Missing predefined '{0}' type". + + + Could not find constructor. + + + Could not find constructor on '{0}'. + + + Assembly reference could not be resolved. + + + Assembly reference '{0}' could not be resolved. + + + Assembly cannot be loaded due to failure in processing the reference assembly. + + + Assembly '{0}' cannot be loaded due to failure in processing '{1}' reference + + + There was an error writing the linked assembly 'output'. + + + Failed to write '{0}'. + + + There was an unexpected error while trimming. An exception with more details is printed to the MSBuild log. Please share this stack trace with the IL Linker team to further investigate the cause and possible solution. + + + IL Trimmer has encountered an unexpected error. Please report the issue at https://github.com/dotnet/linker/issues + + + There was an error processing 'XML document location' xml file. The most likely reason for this is that the XML file has syntactical errors. + + + Error processing '{0}'. + + + Element in XML document contains a 'featuredefault' attribute with an invalid value. + + + Failed to process '{0}'. Unsupported value for featuredefault attribute. + + + The string passed to the command-line does not correspond to a valid command-line option. + + + Unrecognized command-line option: '{0}'. + + + The value given for the --warn argument was not a valid warning version. + + + Invalid warning version '{0}'. + + + Invalid value 'value' was used for command-line option '--generate-warning-suppressions'; must be 'cs' or 'xml'. + + + Invalid value '{0}' for '--generate-warning-suppressions' option. + + + The command-line option 'optionName' was specified but no argument was given. + + + Missing argument for '{0}' option. + + + The command-line option --custom-data receives a key-value pair using the format KEY=VALUE. + + + Value used with '--custom-data' has to be in the KEY=VALUE format. + + + No input files were specified. Use one of the resolver options. + + + No input files were specified. Use one of '{0}' options. + + + Options '--new-mvid' and '--deterministic' cannot be used at the same time. + + + Options '--new-mvid' and '--deterministic' cannot be used at the same time. + + + The assembly argument specified for '--custom-step' option could not be found. + + + The assembly '{0}' specified for '--custom-step' option could not be found. + + + The path to the assembly specified for '--custom-step' must be fully qualified. + + + The path to the assembly '{0}' specified for '--custom-step' must be fully qualified. + + + An invalid value was specified for '--custom-step' option. + + + Invalid value '{0}' specified for '--custom-step' option. + + + A custom step that is inserted relative to an existing step in the pipeline must specify whether to be added before (-) or after (+) the step it's relative to. + + + Expected '+' or '-' to control new step insertion. + + + A custom step was specified for insertion relative to a non existent step. + + + Pipeline step '{0}' could not be found. + + + The custom step could not be found in the given assembly. + + + Custom step '{0}' could not be found. + + + Custom step is incompatible with this trimmer version. + + + Custom step '{0}' is incompatible with this trimmer version. + + + The optimization 'text' is invalid. Optimization values can either be 'beforefieldinit', 'overrideremoval', 'unreachablebodies', 'unusedinterfaces', 'ipconstprop', or 'sealer'. + + + Invalid optimization value '{0}'. + + + Invalid argument for 'token' option. + + + Invalid argument for '{0}' option. + + + Invalid assembly action. + + + Invalid assembly action '{0}'. + + + Root assembly could not be found. + + + Root assembly '{0}' could not be found. + + + XML descriptor file could not be found'. + + + XML descriptor file '{0}' could not be found'. + + + Root assembly does not have entry point. + + + Root assembly '{0}' does not have entry point. + + + Referenced root assembly cannot use the specified action. + + + Root assembly '{0}' cannot use action '{1}'. + + + Invalid assembly name. + + + Invalid assembly name '{0}'. + + + Invalid assembly root mode. + + + Invalid assembly root mode '{0}'. + + + Exported type cannot be resolved. + + + Exported type '{0}' cannot be resolved. + + + A reference assembly input passed via -reference could not be loaded. + + + Reference assembly '{0}' could not be loaded. + + + Metadata element cannot be resolved. This usually means there is a version mismatch between dependencies. + + + {0}. + + + Field element cannot be resolved. This usually means there is a version mismatch between dependencies. + + + Field '{0}' reference could not be resolved. + + + Method element cannot be resolved. This usually means there is a version mismatch between dependencies. + + + Method '{0}' reference could not be resolved. + + + Type element cannot be resolved. This usually means there is a version mismatch between dependencies. + + + Type '{0}' reference could not be resolved. + + + The type name used to define custom attribute value could not be resolved. + + + The type '{0}' used with attribute value '{1}' could not be found. + + + The 'value' specified for the custom attribute value cannot be converted to specified argument type 'typeName'. + + + Cannot convert value '{0}' to type '{1}'. + + + The syntax for custom attribute value for 'type' requires to also specify the underlying attribute type. + + + Custom attribute argument for '{0}' requires nested '{1}' node. + + + The value specified for the custom attribute of System.Type type could not be resolved. + + + Could not resolve custom attribute type value '{0}'. + + + The type name used with attribute type is not one of the supported types. + + + Unexpected attribute argument type '{0}'. + + + Invalid metadata value. + + + Invalid metadata value '{0}'. + + + The XML descriptor preserves fields on type, but this type has no fields. + + + Type '{0}' has no fields to preserve. + + + The XML descriptor preserves methods on type, but this type has no methods. + + + Type '{0}' has no methods to preserve. + + + The assembly in PreserveDependency attribute could not be resolved. + + + Could not resolve dependency assembly '{0}' specified in a 'PreserveDependency' attribute. + + + The type in PreserveDependency attribute could not be resolved. + + + Could not resolve dependency type '{0}' specified in a 'PreserveDependency' attribute. + + + The member in PreserveDependency attribute could not be resolved. + + + Could not resolve dependency member '{0}' declared in type '{1}' specified in a 'PreserveDependency' attribute. + + + The assembly in the XML could not be resolved. + + + Could not resolve assembly '{0}'. + + + The type in the XML could not be resolved. + + + Could not resolve type '{0}'. + + + The XML defined a method on a type, but the method was not found. + + + Could not find method '{0}' on type '{1}'. + + + Invalid value for 'signature' stub in the substitution XML. + + + Invalid value for '{0}' stub. + + + The value of the body attribute used in the substitution XML is invalid (the only supported options are remove and stub). + + + Unknown body modification '{0}' for '{1}'. + + + The XML defined a field on a type, but the field was not found. + + + Could not find field '{0}' on type '{1}'. + + + The substituted field 'field' was non-static or constant. Only static non-constant fields are supported. + + + Substituted field '{0}' needs to be static field. + + + A field was specified for substitution but no value to be substituted was given. + + + Missing 'value' attribute for field '{0}'. + + + The value used in the substitution XML for field is not a built-in type, or does not match the type of the field. + + + Invalid value '{0}' for '{1}'. + + + The XML defined a event on a type, but the event was not found. + + + Could not find event '{0}' on type '{1}'. + + + The XML defined a property on a type, but the property was not found. + + + Could not find property '{0}' on type '{1}'. + + + The XML defined the get accessor of property on a type, but the accessor was not found. + + + Could not find the get accessor of property '{0}' on type '{1}'. + + + The XML defined the set accessor of property on a type, but the accessor was not found. + + + Could not find the set accessor of property '{0}' in type '{1}'. + + + The XML attribute arguments use values or types which don't match to any constructor + + + Could not find matching constructor for custom attribute '{0}' arguments. + + + Method 'method' has more than one return element specified. There can only be one return element. + + + There is more than one 'return' child element specified for method '{0}'. + + + Method has more than one parameter for the XML element 'parameter'. There can only be one value specified for each parameter. + + + More than one value specified for parameter '{0}' of method '{1}'. + + + The XML descriptor marks for preservation the member more than once. + + + Duplicate preserve of '{0}'. + Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code Using member '{0}' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code.{1}{2} + + Using dynamic types might cause types or members to be removed by trimmer. + + + Invoking members on dynamic types is not trimming-compatible. Types or members might have been removed by the trimmer. + + + The linker found multiple instances of attribute on a member. This attribute is only allowed to have one instance. + + + Attribute '{0}' should only be used once on '{1} + + + Attribute doesn't have the required number of parameters specified. + + + Attribute '{0}' doesn't have the required number of parameters specified. + + + 'attribute' element does not contain attribute 'fullname' or it's empty. + + + 'attribute' element does not contain attribute 'fullname' or it's empty. + + + The assembly name specified for attribute could not be resolved. + + + Could not resolve assembly '{0}' for attribute '{1}'. + + + The described attribute type could not be found in the assemblies. + + + Attribute type '{0}' could not be found. + + + The value passed as the assembly name or type name to the CreateInstance method can't be statically analyzed. + + + Unrecognized value passed to the parameter '{0}' of method '{1}'. It's not possible to guarantee the availability of the target type. + + + 'PreserveDependencyAttribute' is deprecated. Use 'DynamicDependencyAttribute' instead. + + + 'PreserveDependencyAttribute' is deprecated. Use 'DynamicDependencyAttribute' instead. + + + The input contains an invalid use of DynamicDependencyAttribute. + + + The 'DynamicDependencyAttribute' could not be analyzed. + + + The assembly string given in a DynamicDependencyAttribute constructor could not be resolved. + + + Unresolved assembly '{0}' in 'DynamicDependencyAttribute'. + + + The type in a DynamicDependencyAttribute constructor could not be resolved. + + + Unresolved type '{0}' in 'DynamicDependencyAttribute'. + + + The member signature or DynamicallyAccessedMemberTypes in a DynamicDependencyAttribute constructor did not resolve to any members on the type. + + + No members were resolved for '{0}'. + + + The resource element in a substitution file did not have a 'name' attribute. + + + Missing 'name' attribute for resource. + + + The resource element in a substitution file did not have a valid 'action' attribute. + + + Invalid value '{0}' for attribute 'action' for resource '{1}'. + + + The resource name in a substitution file could not be found in the specified assembly. + + + Could not find embedded resource '{0}' to remove in assembly '{1}'. + + + The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters. + + + The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though. + + + Could not find a unique backing field for property to propagate 'DynamicallyAccessedMembersAttribute'. + + + Could not find a unique backing field for property '{0}' to propagate 'DynamicallyAccessedMembersAttribute'. + + + 'DynamicallyAccessedMembersAttribute' on property conflicts with the same attribute on its accessor. + + + 'DynamicallyAccessedMembersAttribute' on property '{0}' conflicts with the same attribute on its accessor '{1}'. + + + The XML descriptor specifies a namespace but there are no types found in such namespace. + + + Could not find any type in namespace '{0}'. + + + An attribute is being referenced in the code but the attribute instances have been removed using the 'RemoveAttributeInstances' internal attribute. + + + Attribute '{0}' is being referenced in code but the trimmer was instructed to remove all instances of this attribute. If the attribute instances are necessary make sure to either remove the trimmer attribute XML portion which removes the attribute instances, or override the removal by using the trimmer XML descriptor to keep the attribute type (which in turn keeps all of its instances). + + + 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + + {0}. 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + + Internal attribute 'RemoveAttributeInstances' can only be used on attribute types. + + + Internal attribute '{0}' can only be used on attribute types. + + + Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed. + + + P/invoke method '{0}' declares a parameter with COM marshalling. Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed. + + + An attribute element has property but this could not be found. + + + Property element does not contain attribute 'name'. + + + An attribute element has property but this could not be found. + + + Property '{0}' could not be found. + + + Either the type on which the MakeGenericType is called can't be statically determined, or the type parameters to be used for generic arguments can't be statically determined. + + + Call to '{0}' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. + + + 'DynamicallyAccessedMemberAttribute' on property conflicts with the same attribute on its backing field. + + + 'DynamicallyAccessedMemberAttribute' on property '{0}' conflicts with the same attribute on its backing field '{1}'. + + + Unrecognized value passed to the parameter of method. It's not possible to guarantee the availability of the target type. + + + Unrecognized value passed to the parameter 'typeName' of method '{0}'. It's not possible to guarantee the availability of the target type. + + + Parameters passed to method cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead. + + + Parameters passed to method '{0}' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead. + + + The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available. + + + Unrecognized value passed to the parameter 'type' of method '{0}'. It's not possible to guarantee the availability of the target static constructor. + + + Call to 'System.Reflection.MethodInfo.MakeGenericMethod' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. + + + Call to '{0}' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. + + + Calling CreateInstance with assembly name which can't be resolved. + + + The assembly name '{0}' passed to method '{1}' references assembly which is not available. + + + The parameter of method has a DynamicallyAccessedMembersAttribute, but the value passed to it can not be statically analyzed. + + + Value passed to parameter '{0}' of method '{1}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + + + The return value of method has a DynamicallyAccessedMembersAttribute, but the value returned from the method can not be statically analyzed. + + + Value returned from method '{0}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + + + The field has a DynamicallyAccessedMembersAttribute, but the value assigned to it can not be statically analyzed. + + + Value assigned to {0} can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + + + The method has a DynamicallyAccessedMembersAttribute (which applies to the implicit 'this' parameter), but the value used for the 'this' parameter can not be statically analyzed. + + + Value passed to implicit 'this' parameter of method '{0}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + + + The generic parameter of type or method has a DynamicallyAccessedMembersAttribute, but the value used for it can not be statically analyzed. + + + Type passed to generic parameter '{0}' of '{1}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + + + Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations. + + + '{0}' argument does not satisfy {4} in call to '{1}'. The parameter '{2}' of method '{3}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target method return value does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The parameter of method does not have matching annotations. + + + '{0}' method return value does not satisfy {3} requirements. The parameter '{1}' of method '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Value stored in field does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The parameter of method does not have matching annotations. + + + value stored in field '{0}' does not satisfy {3} requirements. The parameter '{1}' of method '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations. + + + 'this' argument does not satisfy {3} in call to '{0}'. The parameter '{1}' of method '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Generic argument does not satisfy 'DynamicallyAccessedMembersAttribute' in target method or type. The parameter of method does not have matching annotations. + + + '{0}' generic argument does not satisfy {4} in '{1}'. The parameter '{2}' of method '{3}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. + + + '{0}' argument does not satisfy {3} in call to '{1}'. The return value of method '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target method return value does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The return value of the source method does not have matching annotations. + + + '{0}' method return value does not satisfy {2} requirements. The return value of method '{1}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Value stored in field does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The return value of the source method does not have matching annotations. + + + value stored in field '{0}' does not satisfy {2} requirements. The return value of method '{1}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. + + + 'this' argument does not satisfy {2} in call to '{0}'. The return value of method '{1}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target generic argument does not satisfy 'DynamicallyAccessedMembersAttribute' in target method or type. The return value of the source method does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + '{0}' generic argument does not satisfy {3} in '{1}'. The return value of method '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The source field does not have matching annotations. + + + '{0}' argument does not satisfy {3} in call to '{1}'. The field '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target method return value does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The source field does not have matching annotations. + + + '{0}' method return value does not satisfy {2} requirements. The field '{1}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Value stored in target field does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The source field does not have matching annotations. + + + value stored in field '{0}' does not satisfy {2} requirements. The field '{1}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The source field does not have matching annotations. + + + 'this' argument does not satisfy {2} in call to '{0}'. The field '{1}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target generic argument does not satisfy 'DynamicallyAccessedMembersAttribute' in target method or type. The source field does not have matching annotations. + + + '{0}' generic argument does not satisfy {3} in '{1}'. The field '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The implicit 'this' argument of source method does not have matching annotations. + + + '{0}' argument does not satisfy {3} in call to '{1}'. The implicit 'this' argument of method '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target method return value does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The implicit 'this' argument of source method does not have matching annotations. + + + '{0}' method return value does not satisfy {2} requirements. The implicit 'this' argument of method '{1}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Value stored in target field does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The implicit 'this' argument of source method does not have matching annotations. + + + value stored in field '{0}' does not satisfy {2} requirements. The implicit 'this' argument of method '{1}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The implicit 'this' argument of source method does not have matching annotations. + + + 'this' argument does not satisfy {2} in call to '{0}'. The implicit 'this' argument of method '{1}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target generic argument does not satisfy 'DynamicallyAccessedMembersAttribute' in target method or type. The implicit 'this' argument of source method does not have matching annotations. + + + '{0}' generic argument does not satisfy {3} in '{1}'. The implicit 'this' argument of method '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations. + + + '{0}' argument does not satisfy {4} in call to '{1}'. The generic parameter '{2}' of '{3}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target method return value does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The generic parameter of the source method or type does not have matching annotations. + + + '{0}' method return value does not satisfy {3} requirements. The generic parameter '{1}' of '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Value stored in target field does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The generic parameter of the source method or type does not have matching annotations. + + + value stored in field '{0}' does not satisfy {3} requirements. The generic parameter '{1}' of '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations. + + + 'this' argument does not satisfy {3} in call to '{0}'. The generic parameter '{1}' of '{2}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + Target generic argument does not satisfy 'DynamicallyAccessedMembersAttribute' in target method or type. The generic parameter of the source method or type does not have matching annotations. + + + '{0}' generic argument does not satisfy {4} in '{1}'. The generic parameter '{2}' of '{3}' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + + + 'DynamicallyAccessedMemberTypes' on the parameter of method don't match overridden parameter of method. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + + + 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter '{0}' of method '{1}' don't match overridden parameter '{2}' of method '{3}'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + + + 'DynamicallyAccessedMemberTypes' on the return value of method don't match overridden return value of method. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + + + 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the return value of method '{0}' don't match overridden return value of method '{1}'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + + + 'DynamicallyAccessedMemberTypes' on the implicit 'this' parameter of method don't match overridden implicit 'this' parameter of method. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + + + 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method '{0}' don't match overridden implicit 'this' parameter of method '{1}'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + + + 'DynamicallyAccessedMemberTypes' on the generic parameter of method or type don't match overridden generic parameter method or type. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + + + 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the generic parameter '{0}' of '{1}' don't match overridden generic parameter '{2}' of '{3}'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + + + Call to 'Type.GetType' method can perform case insensitive lookup of the type, currently ILLink can not guarantee presence of all the matching types. + + + Call to '{0}' can perform case insensitive lookup of the type, currently ILLink can not guarantee presence of all the matching types. + + + Field has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to fields of type 'System.Type' or 'System.String'. + + + Field '{0}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to fields of type 'System.Type' or 'System.String'. + + + Parameter of method has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to parameters of type 'System.Type' or 'System.String'. + + + Parameter '{0}' of method '{1}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to parameters of type 'System.Type' or 'System.String'. + + + Property has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to properties of type 'System.Type' or 'System.String'. + + + Property '{0}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to properties of type 'System.Type' or 'System.String'. + + + XML contains unsupported wildcard for assembly 'fullname' attribute. + + + XML contains unsupported wildcard for assembly 'fullname' attribute. + + + Embedded XML in assembly contains assembly "fullname" attribute for another assembly + + + Embedded XML in assembly '{0}' contains assembly "fullname" attribute for another assembly '{1}' + + + Invalid AssemblyMetadata 'IsTrimmable' attribute in assembly. Value must be "True". + + + Invalid AssemblyMetadata("IsTrimmable", "{0}") attribute in assembly '{1}'. Value must be "True". + + + Value passed to the parameter of method cannot be statically determined as a property accessor. + + + Value passed to the '{0}' parameter of method '{1}' cannot be statically determined as a property accessor. + + + Assembly produced trim warnings. + + + Assembly '{0}' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries + + + Type was not found in the caller assembly nor in the base library. Type name strings used for dynamically accessing a type should be assembly qualified. + + + Type '{0}' was not found in the caller assembly nor in the base library. Type name strings used for dynamically accessing a type should be assembly qualified. + + + Return type of method has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to properties of type 'System.Type' or 'System.String'. + + + Return type of method '{0}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to properties of type 'System.Type' or 'System.String'. + + + Trimmer currently can't correctly handle if the same compiler generated state machine type is associated (via the state machine attributes) with two different methods. + + + Methods '{0}' and '{1}' are both associated with state machine type '{2}'. This is currently unsupported and may lead to incorrectly reported warnings. + + + Invalid scope used in 'UnconditionalSuppressMessageAttribute'. The only scopes supported on global unconditional suppressions are 'module', 'type' and 'member'. + + + Invalid scope '{0}' used in 'UnconditionalSuppressMessageAttribute' on module '{1}' with target '{2}'. + + + Types that derive from a base class with 'RequiresUnreferencedCodeAttribute' need to explicitly use the 'RequiresUnreferencedCodeAttribute' or suppress this warning + + + Type '{0}' derives from '{1}' which has 'RequiresUnreferencedCodeAttribute'. {2}{3} + + + Field with 'DynamicallyAccessedMembersAttribute' is accessed via reflection. Trimmer can't guarantee availability of the requirements of the field. + + + Field '{0}' with 'DynamicallyAccessedMembersAttribute' is accessed via reflection. Trimmer can't guarantee availability of the requirements of the field. + + + Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. + + + Method '{0}' with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. + + + 'DynamicallyAccessedMembersAttribute' on a type or one of its base types references a member which requires unreferenced code. + + + 'DynamicallyAccessedMembersAttribute' on '{0}' or one of its base types references '{1}' which requires unreferenced code.{2}{3} + + + 'DynamicallyAccessedMembersAttribute' on a type or one of its base types references a member which requires unreferenced code. + + + 'DynamicallyAccessedMembersAttribute' on '{0}' or one of its base types references '{1}' which requires unreferenced code.{2}{3} + + + 'DynamicallyAccessedMembersAttribute' on a type or one of its base types references a member which has 'DynamicallyAccessedMembersAttribute' requirements. + + + 'DynamicallyAccessedMembersAttribute' on '{0}' or one of its base types references '{1}' which has 'DynamicallyAccessedMembersAttribute' requirements. + + + 'DynamicallyAccessedMembersAttribute' on a type or one of its base types references a member which has 'DynamicallyAccessedMembersAttribute' requirements. + + + 'DynamicallyAccessedMembersAttribute' on '{0}' or one of its base types references '{1}' which has 'DynamicallyAccessedMembersAttribute' requirements. + + + The use of 'RequiresUnreferencedCodeAttribute' on static constructors is disallowed since is a method not callable by the user, is only called by the runtime. Placing the attribute directly on the static constructor will have no effect, instead use 'RequiresUnreferencedCodeAttribute' on the type which will handle warning and silencing from the static constructor. + + + 'RequiresUnreferencedCodeAttribute' cannot be placed directly on static constructor '{0}', consider placing 'RequiresUnreferencedCodeAttribute' on the type declaration instead. + Avoid accessing Assembly file path when publishing as a single file @@ -141,29 +1082,23 @@ Using member '{0}' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app.{1}{2} + + 'RequiresAssemblyFilesAttribute' annotations must match across all interface implementations or overrides. + + + {0}. 'RequiresAssemblyFilesAttribute' annotations must match across all interface implementations or overrides. + Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. Using member '{0}' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling.{1}{2} - - {0}. 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. - - - 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. - - - {0}. 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. - 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. - - {0}. 'RequiresAssemblyFilesAttribute' annotations must match across all interface implementations or overrides. - - - 'RequiresAssemblyFilesAttribute' annotations must match across all interface implementations or overrides. + + {0}. 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. Base member '{2}' with '{0}' has a derived member '{1}' without '{0}' @@ -177,38 +1112,8 @@ Interface member '{2}' with '{0}' has an implementation member '{1}' without '{0}' - - Type '{0}' derives from '{1}' which has 'RequiresUnreferencedCodeAttribute'. {2}{3} - - - Types that derive from a base class with 'RequiresUnreferencedCodeAttribute' need to explicitly use the 'RequiresUnreferencedCodeAttribute' or suppress this warning - - - Invoking members on dynamic types is not trimming-compatible. Types or members might have been removed by the trimmer. - - - Using dynamic types might cause types or members to be removed by trimmer. - - - Call to '{0}' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. - - - Call to '{0}' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. - - - 'RequiresUnreferencedCodeAttribute' cannot be placed directly on static constructor '{0}', consider placing 'RequiresUnreferencedCodeAttribute' on the type declaration instead. - - - The use of 'RequiresUnreferencedCodeAttribute' on static constructors is disallowed since is a method not callable by the user, is only called by the runtime. Placing the attribute directly on the static constructor will have no effect, instead use 'RequiresUnreferencedCodeAttribute' on the type which will handle warning and silencing from the static constructor. - - - Call to '{0}' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. - - - Value passed to the '{0}' parameter of method '{1}' cannot be statically determined as a property accessor. - - - P/invoke method '{0}' declares a parameter with COM marshalling. Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed. + + P/invoke method declares a parameter with an abstract delegate. Correctness of interop for abstract delegates cannot be guaranteed after native compilation. P/invoke method '{0}' declares a parameter with an abstract delegate. Correctness of interop for abstract delegates cannot be guaranteed after native compilation: the marshalling code for the delegate might not be available. Use a non-abstract delegate type or ensure any delegate instance passed as parameter is marked with `UnmanagedFunctionPointerAttribute`. From 09ff1acdad2e7789908b5db9bb89896144c13042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 24 Jan 2022 14:39:27 +0900 Subject: [PATCH 154/308] Allow generating Dwarf version 5 (#63988) Contributes to https://github.com/dotnet/runtimelab/issues/1738. --- .../BuildIntegration/Microsoft.NETCore.Native.targets | 1 + .../Compiler/CompilationBuilder.Aot.cs | 7 +++++++ .../Compiler/DependencyAnalysis/ObjectWriter.cs | 9 +++++++++ .../aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs | 4 ++++ .../Compiler/RyuJitCompilationBuilder.cs | 3 +++ src/coreclr/tools/aot/ILCompiler/Program.cs | 5 ++++- 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index 1a3b4a2f740b4..365afaa6ce468 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -247,6 +247,7 @@ The .NET Foundation licenses this file to you under the MIT license. + diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilationBuilder.Aot.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilationBuilder.Aot.cs index fb4ad5ce51b7f..232df5cd22d4e 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilationBuilder.Aot.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilationBuilder.Aot.cs @@ -24,6 +24,7 @@ partial class CompilationBuilder protected bool _methodBodyFolding; protected InstructionSetSupport _instructionSetSupport; protected SecurityMitigationOptions _mitigationOptions; + protected bool _useDwarf5; partial void InitializePartial() { @@ -103,6 +104,12 @@ public CompilationBuilder UseMethodImportationErrorProvider(MethodImportationErr return this; } + public CompilationBuilder UseDwarf5(bool value) + { + _useDwarf5 = value; + return this; + } + protected PreinitializationManager GetPreinitializationManager() { if (_preinitializationManager == null) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs index e690b5d420078..5462b8fedc11b 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs @@ -85,6 +85,9 @@ public class ObjectWriter : IDisposable, ITypesDebugInfoWriter [DllImport(NativeObjectWriterFileName)] private static extern void FinishObjWriter(IntPtr objWriter); + [DllImport(NativeObjectWriterFileName)] + private static extern void SetDwarfVersion(IntPtr objWriter, ushort v); + [DllImport(NativeObjectWriterFileName)] private static extern void SwitchSection(IntPtr objWriter, string sectionName, CustomSectionAttributes attributes = 0, string comdatName = null); @@ -884,6 +887,11 @@ public ObjectWriter(string objectFilePath, NodeFactory factory, ObjectWritingOpt _isSingleFileCompilation = _nodeFactory.CompilationModuleGroup.IsSingleFileCompilation; _userDefinedTypeDescriptor = new UserDefinedTypeDescriptor(this, factory); _options = options; + + if ((_options & ObjectWritingOptions.UseDwarf5) != 0) + { + SetDwarfVersion(_nativeObjectWriter, 5); + } } public void Dispose() @@ -1319,5 +1327,6 @@ public enum ObjectWritingOptions { GenerateDebugInfo = 0x01, ControlFlowGuard = 0x02, + UseDwarf5 = 0x4, } } diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs index b27f7db8ec7d8..f05301ce6367e 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs @@ -93,6 +93,9 @@ protected override void CompileInternal(string outputFile, ObjectDumper dumper) NodeFactory.SetMarkingComplete(); ObjectWritingOptions options = default; + if ((_compilationOptions & RyuJitCompilationOptions.UseDwarf5) != 0) + options |= ObjectWritingOptions.UseDwarf5; + if (_debugInformationProvider is not NullDebugInformationProvider) options |= ObjectWritingOptions.GenerateDebugInfo; @@ -243,5 +246,6 @@ public enum RyuJitCompilationOptions { MethodBodyFolding = 0x1, ControlFlowGuardAnnotations = 0x2, + UseDwarf5 = 0x4, } } diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilationBuilder.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilationBuilder.cs index 8b753c7103994..628277d75e6f5 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilationBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilationBuilder.cs @@ -110,6 +110,9 @@ public override ICompilation ToCompilation() if ((_mitigationOptions & SecurityMitigationOptions.ControlFlowGuardAnnotations) != 0) options |= RyuJitCompilationOptions.ControlFlowGuardAnnotations; + if (_useDwarf5) + options |= RyuJitCompilationOptions.UseDwarf5; + var factory = new RyuJitNodeFactory(_context, _compilationGroup, _metadataManager, _interopStubManager, _nameMangler, _vtableSliceProvider, _dictionaryLayoutProvider, GetPreinitializationManager()); JitConfigProvider.Initialize(_context.Target, jitFlagBuilder.ToArray(), _ryujitOptions); diff --git a/src/coreclr/tools/aot/ILCompiler/Program.cs b/src/coreclr/tools/aot/ILCompiler/Program.cs index e973c05b08c2c..6cfa82c81b2b0 100644 --- a/src/coreclr/tools/aot/ILCompiler/Program.cs +++ b/src/coreclr/tools/aot/ILCompiler/Program.cs @@ -61,6 +61,7 @@ internal class Program private string _instructionSet; private string _guard; private int _maxGenericCycle = CompilerTypeSystemContext.DefaultGenericCycleCutoffPoint; + private bool _useDwarf5; private string _singleMethodTypeName; private string _singleMethodName; @@ -178,6 +179,7 @@ private ArgumentSyntax ParseCommandLine(string[] args) syntax.DefineOption("Ot", ref optimizeTime, "Enable optimizations, favor code speed"); syntax.DefineOptionList("m|mibc", ref _mibcFilePaths, "Mibc file(s) for profile guided optimization"); ; syntax.DefineOption("g", ref _enableDebugInfo, "Emit debugging information"); + syntax.DefineOption("gdwarf-5", ref _useDwarf5, "Generate source-level debug information with dwarf version 5"); syntax.DefineOption("nativelib", ref _nativeLib, "Compile as static or shared library"); syntax.DefineOption("exportsfile", ref _exportsFile, "File to write exported method definitions"); syntax.DefineOption("dgmllog", ref _dgmlLogFileName, "Save result of dependency analysis as DGML"); @@ -769,7 +771,8 @@ static string ILLinkify(string rootedAssembly) .UseCompilationRoots(compilationRoots) .UseOptimizationMode(_optimizationMode) .UseSecurityMitigationOptions(securityMitigationOptions) - .UseDebugInfoProvider(debugInfoProvider); + .UseDebugInfoProvider(debugInfoProvider) + .UseDwarf5(_useDwarf5); if (scanResults != null) { From 8cee8faa5becff0a1afc0d8d149fe5f43d675399 Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Mon, 24 Jan 2022 00:54:36 -0700 Subject: [PATCH 155/308] Re-enable failing long path test (#64113) --- .../System.IO.FileSystem/tests/Directory/CreateDirectory.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs b/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs index ae0f89d32da08..4e53a93a4e03a 100644 --- a/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs +++ b/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs @@ -264,15 +264,16 @@ public void DirectoryLongerThanMaxLongPath_ThrowsPathTooLongException() }); } - [ActiveIssue("https://github.com/dotnet/runtime/issues/64019")] [ConditionalFact(nameof(LongPathsAreNotBlocked), nameof(UsingNewNormalization))] [PlatformSpecific(TestPlatforms.Windows)] public void DirectoryLongerThanMaxLongPathWithExtendedSyntax_ThrowsException() { var paths = IOInputs.GetPathsLongerThanMaxLongPath(GetTestFilePath(), useExtendedSyntax: true); + // Ideally this should be PathTooLongException or DirectoryNotFoundException but on some machines + // windows gives us ERROR_INVALID_NAME, producing IOException. Assert.All(paths, path => - AssertExtensions.ThrowsAny(() => Create(path))); + AssertExtensions.ThrowsAny(() => Create(path))); } [ConditionalFact(nameof(LongPathsAreNotBlocked), nameof(UsingNewNormalization))] From f4bfd05ecea3e00b725a71a211501f60a4e863ba Mon Sep 17 00:00:00 2001 From: Maxim Lipnin Date: Mon, 24 Jan 2022 11:04:22 +0300 Subject: [PATCH 156/308] Port MD4 managed implementation from mono/mono (#62074) Porting MD4 managed implementation from mono/mono (MD4.cs and MD4Managed.cs). It adds: - an internal class in the System.Net.Security with a single HashData method for now; - a set of related MD 4 unit tests to System.Net.Security.Unit.Tests project. --- .../src/System.Net.Security.csproj | 1 + .../src/System/Net/Security/MD4.cs | 256 ++++++++++++++++++ .../tests/UnitTests/MD4Tests.cs | 158 +++++++++++ .../System.Net.Security.Unit.Tests.csproj | 6 +- 4 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs create mode 100644 src/libraries/System.Net.Security/tests/UnitTests/MD4Tests.cs diff --git a/src/libraries/System.Net.Security/src/System.Net.Security.csproj b/src/libraries/System.Net.Security/src/System.Net.Security.csproj index 9f90dbd3951f0..047cbdcc98aea 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -363,6 +363,7 @@ + diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs new file mode 100644 index 0000000000000..bdf3547912c91 --- /dev/null +++ b/src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// +// MD4.cs - Message Digest 4 Abstract class +// +// Author: +// Sebastien Pouliot (sebastien@xamarin.com) +// +// (C) 2003 Motus Technologies Inc. (http://www.motus.com) +// Copyright 2013 Xamarin Inc. (http://www.xamarin.com) +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Buffers.Binary; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; + +// +// This class is a port of the Mono managed implementation of the MD4 algorithm +// and required to support NTLM in Android only. +// It's an implementation detail and is not intended to be a public API. +// Assuming that NTLM would be System.Net.Security, it makes sense to put MD4 here as well. +// +namespace System.Net.Security +{ + internal sealed class MD4 + { + private const int S11 = 3; + private const int S12 = 7; + private const int S13 = 11; + private const int S14 = 19; + private const int S21 = 3; + private const int S22 = 5; + private const int S23 = 9; + private const int S24 = 13; + private const int S31 = 3; + private const int S32 = 9; + private const int S33 = 11; + private const int S34 = 15; + + internal static void HashData(ReadOnlySpan source, Span destination) + { + Debug.Assert(destination.Length == 128 >> 3); + + Span buffer = stackalloc byte[64]; + buffer.Clear(); + // Initialize the context + Span state = stackalloc uint[4] { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + Span count = stackalloc uint[2] { 0, 0 }; + + HashCore(source, state, count, buffer); + + // Save number of bits + Span bits = stackalloc byte[8]; + Encode(bits, count); + + // Pad out to 56 mod 64 + uint index = ((count[0] >> 3) & 0x3f); + int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); + Span padding = stackalloc byte[padLen]; + padding.Clear(); + padding[0] = 0x80; + HashCore(padding, state, count, buffer); + + // Append length (before padding) + HashCore(bits, state, count, buffer); + + // Write state to destination + Encode(destination, state); + } + + private static void HashCore(ReadOnlySpan input, Span state, Span count, Span buffer) + { + // Compute number of bytes mod 64 + int index = (int)((count[0] >> 3) & 0x3F); + // Update number of bits + count[0] += (uint)(input.Length << 3); + if (count[0] < (input.Length << 3)) + { + count[1]++; + } + + count[1] += (uint)(input.Length >> 29); + + int partLen = 64 - index; + int i = 0; + // Transform as many times as possible. + if (input.Length >= partLen) + { + if (index != 0) + { + input.Slice(0, partLen).CopyTo(buffer.Slice(index)); + MD4Transform(state, buffer); + index = 0; + } + else + { + partLen = 0; + } + + for (i = partLen; i + 63 < input.Length; i += 64) + { + MD4Transform(state, input.Slice(i)); + } + } + + // Buffer remaining input + input.Slice(i).CopyTo(buffer.Slice(index)); + } + + //--- private methods --------------------------------------------------- + + // F, G and H are basic MD4 functions. + private static uint F(uint x, uint y, uint z) + { + return (uint)(((x) & (y)) | ((~x) & (z))); + } + + private static uint G(uint x, uint y, uint z) + { + return (uint)(((x) & (y)) | ((x) & (z)) | ((y) & (z))); + } + + private static uint H(uint x, uint y, uint z) + { + return (uint)((x) ^ (y) ^ (z)); + } + + // FF, GG and HH are transformations for rounds 1, 2 and 3. + // Rotation is separate from addition to prevent recomputation. + private static void FF(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += F(b, c, d) + x; + a = BitOperations.RotateLeft(a, s); + } + + private static void GG(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += G(b, c, d) + x + 0x5a827999; + a = BitOperations.RotateLeft(a, s); + } + + private static void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += H(b, c, d) + x + 0x6ed9eba1; + a = BitOperations.RotateLeft(a, s); + } + + private static void Encode(Span output, Span input) + { + for (int i = 0, j = 0; j < output.Length; i++, j += 4) + { + BinaryPrimitives.WriteUInt32LittleEndian(output.Slice(j), input[i]); + } + } + + private static void Decode(Span output, ReadOnlySpan input) + { + for (int i = 0, j = 0; i < output.Length; i++, j += 4) + { + output[i] = BinaryPrimitives.ReadUInt32LittleEndian(input.Slice(j)); + } + } + + private static void MD4Transform(Span state, ReadOnlySpan block) + { + uint a = state[0]; + uint b = state[1]; + uint c = state[2]; + uint d = state[3]; + Span x = stackalloc uint[16]; + + Decode(x, block); + + // Round 1 + FF(ref a, b, c, d, x[0], S11); // 1 + FF(ref d, a, b, c, x[1], S12); // 2 + FF(ref c, d, a, b, x[2], S13); // 3 + FF(ref b, c, d, a, x[3], S14); // 4 + FF(ref a, b, c, d, x[4], S11); // 5 + FF(ref d, a, b, c, x[5], S12); // 6 + FF(ref c, d, a, b, x[6], S13); // 7 + FF(ref b, c, d, a, x[7], S14); // 8 + FF(ref a, b, c, d, x[8], S11); // 9 + FF(ref d, a, b, c, x[9], S12); // 10 + FF(ref c, d, a, b, x[10], S13); // 11 + FF(ref b, c, d, a, x[11], S14); // 12 + FF(ref a, b, c, d, x[12], S11); // 13 + FF(ref d, a, b, c, x[13], S12); // 14 + FF(ref c, d, a, b, x[14], S13); // 15 + FF(ref b, c, d, a, x[15], S14); // 16 + + // Round 2 + GG(ref a, b, c, d, x[0], S21); // 17 + GG(ref d, a, b, c, x[4], S22); // 18 + GG(ref c, d, a, b, x[8], S23); // 19 + GG(ref b, c, d, a, x[12], S24); // 20 + GG(ref a, b, c, d, x[1], S21); // 21 + GG(ref d, a, b, c, x[5], S22); // 22 + GG(ref c, d, a, b, x[9], S23); // 23 + GG(ref b, c, d, a, x[13], S24); // 24 + GG(ref a, b, c, d, x[2], S21); // 25 + GG(ref d, a, b, c, x[6], S22); // 26 + GG(ref c, d, a, b, x[10], S23); // 27 + GG(ref b, c, d, a, x[14], S24); // 28 + GG(ref a, b, c, d, x[3], S21); // 29 + GG(ref d, a, b, c, x[7], S22); // 30 + GG(ref c, d, a, b, x[11], S23); // 31 + GG(ref b, c, d, a, x[15], S24); // 32 + + HH(ref a, b, c, d, x[0], S31); // 33 + HH(ref d, a, b, c, x[8], S32); // 34 + HH(ref c, d, a, b, x[4], S33); // 35 + HH(ref b, c, d, a, x[12], S34); // 36 + HH(ref a, b, c, d, x[2], S31); // 37 + HH(ref d, a, b, c, x[10], S32); // 38 + HH(ref c, d, a, b, x[6], S33); // 39 + HH(ref b, c, d, a, x[14], S34); // 40 + HH(ref a, b, c, d, x[1], S31); // 41 + HH(ref d, a, b, c, x[9], S32); // 42 + HH(ref c, d, a, b, x[5], S33); // 43 + HH(ref b, c, d, a, x[13], S34); // 44 + HH(ref a, b, c, d, x[3], S31); // 45 + HH(ref d, a, b, c, x[11], S32); // 46 + HH(ref c, d, a, b, x[7], S33); // 47 + HH(ref b, c, d, a, x[15], S34); // 48 + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + } + } +} diff --git a/src/libraries/System.Net.Security/tests/UnitTests/MD4Tests.cs b/src/libraries/System.Net.Security/tests/UnitTests/MD4Tests.cs new file mode 100644 index 0000000000000..a3667ebb896e5 --- /dev/null +++ b/src/libraries/System.Net.Security/tests/UnitTests/MD4Tests.cs @@ -0,0 +1,158 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Net.Security; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace System.Net.Security.Tests +{ + public class MD4Tests + { + // MD4("") = 31d6cfe0d16ae931b73c59d7e0c089c0 + [Fact] + public void TryEncrypt_Empty() + { + ReadOnlySpan input = new byte[0]; + ReadOnlySpan expected = new byte[] { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 }; + Verify(input, expected); + } + + // // MD4("a") = bde52cb31de33e46245e05fbdbd6fb24 + [Fact] + public void TryEncrypt_SingleLetter() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("a")); + ReadOnlySpan expected = new byte[] { 0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24 }; + Verify(input, expected); + } + + // MD4("abc") = a448017aaf21d8525fc10ae87aa6729d + [Fact] + public void TryEncrypt_ThreeLetters() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("abc")); + ReadOnlySpan expected = new byte[] { 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d }; + Verify(input, expected); + } + + // MD4("message digest") = d9130a8164549fe818874806e1c7014b + [Fact] + public void TryEncrypt_Phrase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("message digest")); + ReadOnlySpan expected = new byte[] { 0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b }; + Verify(input, expected); + } + + // MD4("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9 + [Fact] + public void TryEncrypt_AlphabetInLowercase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("abcdefghijklmnopqrstuvwxyz")); + ReadOnlySpan expected = new byte[] { 0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = 043f8582f241db351ce627e153e7f0e4 + [Fact] + public void TryEncrypt_AlphabetInUpperLowerCasesAndNumbers() + { + ReadOnlySpan input = new ReadOnlySpan((Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"))); + ReadOnlySpan expected = new byte[] { 0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4 }; + Verify(input, expected); + } + + // MD4("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536 + [Fact] + public void TryEncrypt_RepeatedSequenceOfNumbers() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("12345678901234567890123456789012345678901234567890123456789012345678901234567890")); + ReadOnlySpan expected = new byte[] { 0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012") = 14fdf2056bf88b3491c385d8ac4f48e6 + // 55 bytes (padLen == 56 - 55 => 1) + [Fact] + public void TryEncrypt_55bytes_HitsEdgeCaseForPaddingLength() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012")); + ReadOnlySpan expected = new byte[] { 0x14, 0xfd, 0xf2, 0x05, 0x6b, 0xf8, 0x8b, 0x34, 0x91, 0xc3, 0x85, 0xd8, 0xac, 0x4f, 0x48, 0xe6 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123") = db837dbb6098a50a2d3974bc1cc76133 + // 56 bytes (padLen == 120 - 56 => 64) + [Fact] + public void TryEncrypt_56bytes_HitsEdgeCaseForPaddingLength() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123")); + ReadOnlySpan expected = new byte[] { 0xdb, 0x83, 0x7d, 0xbb, 0x60, 0x98, 0xa5, 0x0a, 0x2d, 0x39, 0x74, 0xbc, 0x1c, 0xc7, 0x61, 0x33 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890") = ce64c40ecfbe896462f3c1a925884624 + [Fact] + public void TryEncrypt_63bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890")); + ReadOnlySpan expected = new byte[] { 0xce, 0x64, 0xc4, 0x0e, 0xcf, 0xbe, 0x89, 0x64, 0x62, 0xf3, 0xc1, 0xa9, 0x25, 0x88, 0x46, 0x24 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901") = 4b0e77758d2ede1eb21d267d492ae70b + [Fact] + public void TryEncrypt_64bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901")); + ReadOnlySpan expected = new byte[] { 0x4b, 0x0e, 0x77, 0x75, 0x8d, 0x2e, 0xde, 0x1e, 0xb2, 0x1d, 0x26, 0x7d, 0x49, 0x2a, 0xe7, 0x0b }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789012") = 3b46ad159b3fd800d254e3c4cc71fe36 + [Fact] + public void TryEncrypt_65bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789012")); + ReadOnlySpan expected = new byte[] { 0x3b, 0x46, 0xad, 0x15, 0x9b, 0x3f, 0xd8, 0x00, 0xd2, 0x54, 0xe3, 0xc4, 0xcc, 0x71, 0xfe, 0x36 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890") = a3e23048e4ade47a0f00fa8aed2a0248 + [Fact] + public void TryEncrypt_127bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890")); + ReadOnlySpan expected = new byte[] { 0xa3, 0xe2, 0x30, 0x48, 0xe4, 0xad, 0xe4, 0x7a, 0x0f, 0x00, 0xfa, 0x8a, 0xed, 0x2a, 0x02, 0x48 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901") = de49da96c105be37b242f2bee86c4759 + [Fact] + public void TryEncrypt_128bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901")); + ReadOnlySpan expected = new byte[] { 0xde, 0x49, 0xda, 0x96, 0xc1, 0x05, 0xbe, 0x37, 0xb2, 0x42, 0xf2, 0xbe, 0xe8, 0x6c, 0x47, 0x59 }; + Verify(input, expected); + } + + // MD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789012") = a6c10c320f8827d08248a2d8b124b040 + [Fact] + public void TryEncrypt_129bytes_HitsEdgeCase() + { + ReadOnlySpan input = new ReadOnlySpan(Encoding.Default.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678901ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789012")); + ReadOnlySpan expected = new byte[] { 0xa6, 0xc1, 0x0c, 0x32, 0x0f, 0x88, 0x27, 0xd0, 0x82, 0x48, 0xa2, 0xd8, 0xb1, 0x24, 0xb0, 0x40 }; + Verify(input, expected); + } + + private void Verify(ReadOnlySpan input, ReadOnlySpan expected) + { + Span output = stackalloc byte[expected.Length]; + MD4.HashData(input, output); + Assert.Equal(expected.ToArray(), output.ToArray()); + } + } +} diff --git a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj index da4dde4e192b9..28b3f81b02b3d 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj @@ -10,13 +10,17 @@ 436 $(NoWarn);3021 - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-Android annotations true + + + + From bb5ca4c9380196bcce4fc62ce5e6c9d52f001b2c Mon Sep 17 00:00:00 2001 From: Peter Sollich Date: Mon, 24 Jan 2022 09:24:38 +0100 Subject: [PATCH 157/308] Fix one source of perf regression in GCHeap::Alloc. This impacts the System.Collections.CtorFromCollectionNonGeneric family of benchmarks. (#64091) These benchmarks manage to make GCHeap::Alloc into a hotspot, so the call to IsHeapPointer() at the end matters for performance. --- src/coreclr/gc/gc.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index e270bcdc91ee4..9ab892a5ad338 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -44081,12 +44081,8 @@ GCHeap::Alloc(gc_alloc_context* context, size_t size, uint32_t flags REQD_ALIGN_ } CHECK_ALLOC_AND_POSSIBLY_REGISTER_FOR_FINALIZATION(newAlloc, size, flags & GC_ALLOC_FINALIZE); - #ifdef USE_REGIONS - if (!IsHeapPointer (newAlloc)) - { - GCToOSInterface::DebugBreak(); - } + assert (IsHeapPointer (newAlloc)); #endif //USE_REGIONS return newAlloc; From 73bf54ffa4c7ca3e9ff471456ed57a719b66a847 Mon Sep 17 00:00:00 2001 From: Wraith Date: Mon, 24 Jan 2022 08:53:39 +0000 Subject: [PATCH 158/308] Add blsr (#63545) --- src/coreclr/jit/emitxarch.h | 2 +- src/coreclr/jit/hwintrinsic.h | 19 ++++++ src/coreclr/jit/instrsxarch.h | 2 +- src/coreclr/jit/lower.cpp | 42 +++++++------ src/coreclr/jit/lower.h | 4 +- src/coreclr/jit/lowerarmarch.cpp | 16 +++++ src/coreclr/jit/lowerxarch.cpp | 105 +++++++++++++++++++++++++++++++ 7 files changed, 168 insertions(+), 22 deletions(-) diff --git a/src/coreclr/jit/emitxarch.h b/src/coreclr/jit/emitxarch.h index d6ed324deb242..5cef7d5aa12f2 100644 --- a/src/coreclr/jit/emitxarch.h +++ b/src/coreclr/jit/emitxarch.h @@ -193,7 +193,7 @@ bool IsDstDstSrcAVXInstruction(instruction ins); bool IsDstSrcSrcAVXInstruction(instruction ins); bool HasRegularWideForm(instruction ins); bool HasRegularWideImmediateForm(instruction ins); -bool DoesWriteZeroFlag(instruction ins); +static bool DoesWriteZeroFlag(instruction ins); bool DoesWriteSignFlag(instruction ins); bool DoesResetOverflowAndCarryFlags(instruction ins); bool IsFlagsAlwaysModified(instrDesc* id); diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h index 43bd543c599f1..4551ed9e4e1ce 100644 --- a/src/coreclr/jit/hwintrinsic.h +++ b/src/coreclr/jit/hwintrinsic.h @@ -577,6 +577,25 @@ struct HWIntrinsicInfo return lookup(id).ins[type - TYP_BYTE]; } + static instruction lookupIns(GenTreeHWIntrinsic* intrinsicNode) + { + assert(intrinsicNode != nullptr); + + NamedIntrinsic intrinsic = intrinsicNode->GetHWIntrinsicId(); + var_types type = TYP_UNKNOWN; + + if (lookupCategory(intrinsic) == HW_Category_Scalar) + { + type = intrinsicNode->TypeGet(); + } + else + { + type = intrinsicNode->GetSimdBaseType(); + } + + return lookupIns(intrinsic, type); + } + static HWIntrinsicCategory lookupCategory(NamedIntrinsic id) { return lookup(id).category; diff --git a/src/coreclr/jit/instrsxarch.h b/src/coreclr/jit/instrsxarch.h index 458f919fe2793..08d4c4a8c8675 100644 --- a/src/coreclr/jit/instrsxarch.h +++ b/src/coreclr/jit/instrsxarch.h @@ -595,7 +595,7 @@ INST3(FIRST_BMI_INSTRUCTION, "FIRST_BMI_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE INST3(andn, "andn", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF2), INS_Flags_IsDstDstSrcAVXInstruction) // Logical AND NOT INST3(blsi, "blsi", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF3), INS_Flags_IsDstDstSrcAVXInstruction) // Extract Lowest Set Isolated Bit INST3(blsmsk, "blsmsk", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF3), INS_Flags_IsDstDstSrcAVXInstruction) // Get Mask Up to Lowest Set Bit -INST3(blsr, "blsr", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF3), INS_Flags_IsDstDstSrcAVXInstruction) // Reset Lowest Set Bit +INST3(blsr, "blsr", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF3), Resets_OF | Writes_SF | Writes_ZF | Undefined_AF | Undefined_PF | Writes_CF | INS_Flags_IsDstDstSrcAVXInstruction) // Reset Lowest Set Bit INST3(bextr, "bextr", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF7), INS_Flags_IsDstDstSrcAVXInstruction) // Bit Field Extract // BMI2 diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index f29baa320940d..d19e1460c4a03 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -139,7 +139,7 @@ GenTree* Lowering::LowerNode(GenTree* node) case GT_AND: case GT_OR: case GT_XOR: - return LowerBinaryArithmetic(node->AsOp()); + return LowerBinaryArithmeticCommon(node->AsOp()); case GT_MUL: case GT_MULHI: @@ -2708,10 +2708,16 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) if (op2->IsIntegralConst(0) && (op1->gtNext == op2) && (op2->gtNext == cmp) && #ifdef TARGET_XARCH - op1->OperIs(GT_AND, GT_OR, GT_XOR, GT_ADD, GT_SUB, GT_NEG)) + (op1->OperIs(GT_AND, GT_OR, GT_XOR, GT_ADD, GT_SUB, GT_NEG) +#ifdef FEATURE_HW_INTRINSICS + || (op1->OperIs(GT_HWINTRINSIC) && + emitter::DoesWriteZeroFlag(HWIntrinsicInfo::lookupIns(op1->AsHWIntrinsic()))) +#endif // FEATURE_HW_INTRINSICS + ) #else // TARGET_ARM64 - op1->OperIs(GT_AND, GT_ADD, GT_SUB)) + op1->OperIs(GT_AND, GT_ADD, GT_SUB) #endif + ) { op1->gtFlags |= GTF_SET_FLAGS; op1->SetUnusedValue(); @@ -5117,7 +5123,7 @@ GenTree* Lowering::LowerAdd(GenTreeOp* node) } //------------------------------------------------------------------------ -// LowerBinaryArithmetic: lowers the given binary arithmetic node. +// LowerBinaryArithmeticCommon: lowers the given binary arithmetic node. // // Recognizes opportunities for using target-independent "combined" nodes // (currently AND_NOT on ARMArch). Performs containment checks. @@ -5128,41 +5134,39 @@ GenTree* Lowering::LowerAdd(GenTreeOp* node) // Returns: // The next node to lower. // -GenTree* Lowering::LowerBinaryArithmetic(GenTreeOp* node) +GenTree* Lowering::LowerBinaryArithmeticCommon(GenTreeOp* binOp) { // TODO-CQ-XArch: support BMI2 "andn" in codegen and condition // this logic on the support for the instruction set on XArch. CLANG_FORMAT_COMMENT_ANCHOR; #ifdef TARGET_ARMARCH - if (comp->opts.OptimizationEnabled() && node->OperIs(GT_AND)) + if (comp->opts.OptimizationEnabled() && binOp->OperIs(GT_AND)) { GenTree* opNode = nullptr; GenTree* notNode = nullptr; - if (node->gtGetOp1()->OperIs(GT_NOT)) + if (binOp->gtGetOp1()->OperIs(GT_NOT)) { - notNode = node->gtGetOp1(); - opNode = node->gtGetOp2(); + notNode = binOp->gtGetOp1(); + opNode = binOp->gtGetOp2(); } - else if (node->gtGetOp2()->OperIs(GT_NOT)) + else if (binOp->gtGetOp2()->OperIs(GT_NOT)) { - notNode = node->gtGetOp2(); - opNode = node->gtGetOp1(); + notNode = binOp->gtGetOp2(); + opNode = binOp->gtGetOp1(); } if (notNode != nullptr) { - node->gtOp1 = opNode; - node->gtOp2 = notNode->AsUnOp()->gtGetOp1(); - node->ChangeOper(GT_AND_NOT); + binOp->gtOp1 = opNode; + binOp->gtOp2 = notNode->AsUnOp()->gtGetOp1(); + binOp->ChangeOper(GT_AND_NOT); BlockRange().Remove(notNode); } } -#endif // TARGET_ARMARCH - - ContainCheckBinary(node); +#endif - return node->gtNext; + return LowerBinaryArithmetic(binOp); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h index 92a4ef43f2370..624cc1372dc5a 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -297,7 +297,8 @@ class Lowering final : public Phase void LowerStoreIndir(GenTreeStoreInd* node); GenTree* LowerAdd(GenTreeOp* node); GenTree* LowerMul(GenTreeOp* mul); - GenTree* LowerBinaryArithmetic(GenTreeOp* node); + GenTree* LowerBinaryArithmeticCommon(GenTreeOp* binOp); + GenTree* LowerBinaryArithmetic(GenTreeOp* binOp); bool LowerUnsignedDivOrMod(GenTreeOp* divMod); GenTree* LowerConstIntDivOrMod(GenTree* node); GenTree* LowerSignedDivOrMod(GenTree* node); @@ -343,6 +344,7 @@ class Lowering final : public Phase void LowerHWIntrinsicToScalar(GenTreeHWIntrinsic* node); void LowerHWIntrinsicGetElement(GenTreeHWIntrinsic* node); void LowerHWIntrinsicWithElement(GenTreeHWIntrinsic* node); + GenTree* TryLowerAndOpToResetLowestSetBit(GenTreeOp* binOp); #elif defined(TARGET_ARM64) bool IsValidConstForMovImm(GenTreeHWIntrinsic* node); void LowerHWIntrinsicFusedMultiplyAddScalar(GenTreeHWIntrinsic* node); diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index e1812d7e8df6f..67e1269dfd429 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -281,6 +281,22 @@ GenTree* Lowering::LowerMul(GenTreeOp* mul) return mul->gtNext; } +//------------------------------------------------------------------------ +// LowerBinaryArithmetic: lowers the given binary arithmetic node. +// +// Arguments: +// node - the arithmetic node to lower +// +// Returns: +// The next node to lower. +// +GenTree* Lowering::LowerBinaryArithmetic(GenTreeOp* binOp) +{ + ContainCheckBinary(binOp); + + return binOp->gtNext; +} + //------------------------------------------------------------------------ // LowerBlockStore: Lower a block store node // diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 413e4ba74a6a4..a6b0ceb91ba95 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -159,6 +159,33 @@ GenTree* Lowering::LowerMul(GenTreeOp* mul) return mul->gtNext; } +//------------------------------------------------------------------------ +// LowerBinaryArithmetic: lowers the given binary arithmetic node. +// +// Arguments: +// node - the arithmetic node to lower +// +// Returns: +// The next node to lower. +// +GenTree* Lowering::LowerBinaryArithmetic(GenTreeOp* binOp) +{ +#ifdef FEATURE_HW_INTRINSICS + if (comp->opts.OptimizationEnabled() && binOp->OperIs(GT_AND) && varTypeIsIntegral(binOp)) + { + GenTree* blsrNode = TryLowerAndOpToResetLowestSetBit(binOp); + if (blsrNode != nullptr) + { + return blsrNode->gtNext; + } + } +#endif + + ContainCheckBinary(binOp); + + return binOp->gtNext; +} + //------------------------------------------------------------------------ // LowerBlockStore: Lower a block store node // @@ -3697,6 +3724,84 @@ void Lowering::LowerHWIntrinsicToScalar(GenTreeHWIntrinsic* node) LowerNode(cast); } } + +//---------------------------------------------------------------------------------------------- +// Lowering::TryLowerAndOpToResetLowestSetBit: Lowers a tree AND(X, ADD(X, -1) to HWIntrinsic::ResetLowestSetBit +// +// Arguments: +// andNode - GT_AND node of integral type +// +// Return Value: +// Returns the replacement node if one is created else nullptr indicating no replacement +// +GenTree* Lowering::TryLowerAndOpToResetLowestSetBit(GenTreeOp* andNode) +{ + assert(andNode->OperIs(GT_AND) && varTypeIsIntegral(andNode)); + + GenTree* op1 = andNode->gtGetOp1(); + if (!op1->OperIs(GT_LCL_VAR) || comp->lvaGetDesc(op1->AsLclVar())->IsAddressExposed()) + { + return nullptr; + } + + GenTree* op2 = andNode->gtGetOp2(); + if (!op2->OperIs(GT_ADD)) + { + return nullptr; + } + + GenTree* addOp2 = op2->gtGetOp2(); + if (!addOp2->IsIntegralConst(-1)) + { + return nullptr; + } + + GenTree* addOp1 = op2->gtGetOp1(); + if (!addOp1->OperIs(GT_LCL_VAR) || (addOp1->AsLclVar()->GetLclNum() != op1->AsLclVar()->GetLclNum())) + { + return nullptr; + } + + NamedIntrinsic intrinsic; + if (op1->TypeIs(TYP_LONG) && comp->compOpportunisticallyDependsOn(InstructionSet_BMI1_X64)) + { + intrinsic = NamedIntrinsic::NI_BMI1_X64_ResetLowestSetBit; + } + else if (comp->compOpportunisticallyDependsOn(InstructionSet_BMI1)) + { + intrinsic = NamedIntrinsic::NI_BMI1_ResetLowestSetBit; + } + else + { + return nullptr; + } + + LIR::Use use; + if (!BlockRange().TryGetUse(andNode, &use)) + { + return nullptr; + } + + GenTreeHWIntrinsic* blsrNode = comp->gtNewScalarHWIntrinsicNode(andNode->TypeGet(), op1, intrinsic); + + JITDUMP("Lower: optimize AND(X, ADD(X, -1))\n"); + DISPNODE(andNode); + JITDUMP("to:\n"); + DISPNODE(blsrNode); + + use.ReplaceWith(blsrNode); + + BlockRange().InsertBefore(andNode, blsrNode); + BlockRange().Remove(andNode); + BlockRange().Remove(op2); + BlockRange().Remove(addOp1); + BlockRange().Remove(addOp2); + + ContainCheckHWIntrinsic(blsrNode); + + return blsrNode; +} + #endif // FEATURE_HW_INTRINSICS //---------------------------------------------------------------------------------------------- From 85b144a0317dd1ae2b901205434fae02089723a8 Mon Sep 17 00:00:00 2001 From: Carlos Sanchez <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 24 Jan 2022 00:54:11 -0800 Subject: [PATCH 159/308] Fix FileSystemAclExtensions.Create when passing a null FileSecurity (#61297) * Make FileSecurity parameter nullable. * Add missing ArgumentException message for FileMode.Append. * Refactor tests to ensure FileSecurity is tested with all FileMode and FileSystemRights combinations. Separate special cases. * Remove exception that throws when FileSecurity is null. Ensure we have logic that can create a FileHandle when FileSecurity is null. Fix bug where FileShare.Inheritable causes IOException because it is being unexpectedly passed to the P/Invoke (it should just be saved in the SECURITY_ATTRIBUTES struct). Add documentation to mention this parameter as optional. Ensure all exceptions match exactly what we have in .NET Framework, with simpler logic. * Address suggestions Co-authored-by: carlossanlop --- .../ref/System.IO.FileSystem.AccessControl.cs | 2 +- .../src/Resources/Strings.resx | 3 + .../src/System/IO/FileSystemAclExtensions.cs | 99 ++++- .../tests/FileSystemAclExtensionsTests.cs | 416 +++++++++++------- 4 files changed, 333 insertions(+), 187 deletions(-) diff --git a/src/libraries/System.IO.FileSystem.AccessControl/ref/System.IO.FileSystem.AccessControl.cs b/src/libraries/System.IO.FileSystem.AccessControl/ref/System.IO.FileSystem.AccessControl.cs index 64455bbc92ccb..ae5a0e9562c7d 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/ref/System.IO.FileSystem.AccessControl.cs +++ b/src/libraries/System.IO.FileSystem.AccessControl/ref/System.IO.FileSystem.AccessControl.cs @@ -9,7 +9,7 @@ namespace System.IO public static partial class FileSystemAclExtensions { public static void Create(this System.IO.DirectoryInfo directoryInfo, System.Security.AccessControl.DirectorySecurity directorySecurity) { } - public static System.IO.FileStream Create(this System.IO.FileInfo fileInfo, System.IO.FileMode mode, System.Security.AccessControl.FileSystemRights rights, System.IO.FileShare share, int bufferSize, System.IO.FileOptions options, System.Security.AccessControl.FileSecurity fileSecurity) { throw null; } + public static System.IO.FileStream Create(this System.IO.FileInfo fileInfo, System.IO.FileMode mode, System.Security.AccessControl.FileSystemRights rights, System.IO.FileShare share, int bufferSize, System.IO.FileOptions options, System.Security.AccessControl.FileSecurity? fileSecurity) { throw null; } public static System.IO.DirectoryInfo CreateDirectory(this System.Security.AccessControl.DirectorySecurity directorySecurity, string path) { throw null; } public static System.Security.AccessControl.DirectorySecurity GetAccessControl(this System.IO.DirectoryInfo directoryInfo) { throw null; } public static System.Security.AccessControl.DirectorySecurity GetAccessControl(this System.IO.DirectoryInfo directoryInfo, System.Security.AccessControl.AccessControlSections includeSections) { throw null; } diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/Resources/Strings.resx b/src/libraries/System.IO.FileSystem.AccessControl/src/Resources/Strings.resx index d71dfd08146e4..5b24a6296c36d 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/src/Resources/Strings.resx +++ b/src/libraries/System.IO.FileSystem.AccessControl/src/Resources/Strings.resx @@ -122,6 +122,9 @@ Type must be an IdentityReference, such as NTAccount or SecurityIdentifier. + + Append access can be requested only in write-only mode. + The value '{0}' is not valid for this usage of the type {1}. diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs b/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs index 51b3f926ba519..c47f9e255dc91 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs +++ b/src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs @@ -159,10 +159,10 @@ public static void Create(this DirectoryInfo directoryInfo, DirectorySecurity di /// One of the enumeration values for controlling the kind of access other FileStream objects can have to the same file. /// The number of bytes buffered for reads and writes to the file. /// One of the enumeration values that describes how to create or overwrite the file. - /// An object that determines the access control and audit security for the file. + /// An optional object that determines the access control and audit security for the file. /// A file stream for the newly created file. /// The and combination is invalid. - /// or is . + /// is . /// or are out of their legal enum range. ///-or- /// is not a positive number. @@ -170,18 +170,13 @@ public static void Create(this DirectoryInfo directoryInfo, DirectorySecurity di /// An I/O error occurs. /// Access to the path is denied. /// This extension method was added to .NET Core to bring the functionality that was provided by the `System.IO.FileStream.#ctor(System.String,System.IO.FileMode,System.Security.AccessControl.FileSystemRights,System.IO.FileShare,System.Int32,System.IO.FileOptions,System.Security.AccessControl.FileSecurity)` .NET Framework constructor. - public static FileStream Create(this FileInfo fileInfo, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, FileSecurity fileSecurity) + public static FileStream Create(this FileInfo fileInfo, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, FileSecurity? fileSecurity) { if (fileInfo == null) { throw new ArgumentNullException(nameof(fileInfo)); } - if (fileSecurity == null) - { - throw new ArgumentNullException(nameof(fileSecurity)); - } - // don't include inheritable in our bounds check for share FileShare tempshare = share & ~FileShare.Inheritable; @@ -200,18 +195,33 @@ public static FileStream Create(this FileInfo fileInfo, FileMode mode, FileSyste throw new ArgumentOutOfRangeException(nameof(bufferSize), SR.ArgumentOutOfRange_NeedPosNum); } - // Do not allow using combinations of non-writing file system rights with writing file modes + // Do not combine writing modes with exclusively read rights + // Write contains AppendData, WriteAttributes, WriteData and WriteExtendedAttributes if ((rights & FileSystemRights.Write) == 0 && (mode == FileMode.Truncate || mode == FileMode.CreateNew || mode == FileMode.Create || mode == FileMode.Append)) { throw new ArgumentException(SR.Format(SR.Argument_InvalidFileModeAndFileSystemRightsCombo, mode, rights)); } + // Additionally, append is disallowed if any read rights are provided + // ReadAndExecute contains ExecuteFile, ReadAttributes, ReadData, ReadExtendedAttributes and ReadPermissions + if ((rights & FileSystemRights.ReadAndExecute) != 0 && mode == FileMode.Append) + { + throw new ArgumentException(SR.Argument_InvalidAppendMode); + } + + // Cannot truncate unless all of the write rights are provided + // Write contains AppendData, WriteAttributes, WriteData and WriteExtendedAttributes + if (mode == FileMode.Truncate && (rights & FileSystemRights.Write) != FileSystemRights.Write) + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidFileModeAndFileSystemRightsCombo, mode, rights)); + } + SafeFileHandle handle = CreateFileHandle(fileInfo.FullName, mode, rights, share, options, fileSecurity); try { - return new FileStream(handle, GetFileStreamFileAccess(rights), bufferSize, (options & FileOptions.Asynchronous) != 0); + return new FileStream(handle, GetFileAccessFromRights(rights), bufferSize, (options & FileOptions.Asynchronous) != 0); } catch { @@ -258,23 +268,48 @@ public static DirectoryInfo CreateDirectory(this DirectorySecurity directorySecu // In the context of a FileStream, the only ACCESS_MASK ACE rights we care about are reading/writing data and the generic read/write rights. // See: https://docs.microsoft.com/en-us/windows/win32/secauthz/access-mask - private static FileAccess GetFileStreamFileAccess(FileSystemRights rights) + private static FileAccess GetFileAccessFromRights(FileSystemRights rights) { FileAccess access = 0; - if ((rights & FileSystemRights.ReadData) != 0 || ((int)rights & Interop.Kernel32.GenericOperations.GENERIC_READ) != 0) + + if ((rights & FileSystemRights.FullControl) != 0 || + (rights & FileSystemRights.Modify) != 0) + { + return FileAccess.ReadWrite; + } + + if ((rights & FileSystemRights.ReadData) != 0 || // Same as ListDirectory + (rights & FileSystemRights.ReadExtendedAttributes) != 0 || + (rights & FileSystemRights.ExecuteFile) != 0 || // Same as Traverse + (rights & FileSystemRights.ReadAttributes) != 0 || + (rights & FileSystemRights.ReadPermissions) != 0 || + (rights & FileSystemRights.TakeOwnership) != 0 || + ((int)rights & Interop.Kernel32.GenericOperations.GENERIC_READ) != 0) { access = FileAccess.Read; } - if ((rights & FileSystemRights.WriteData) != 0 || ((int)rights & Interop.Kernel32.GenericOperations.GENERIC_WRITE) != 0) + if ((rights & FileSystemRights.AppendData) != 0 || // Same as CreateDirectories + (rights & FileSystemRights.ChangePermissions) != 0 || + (rights & FileSystemRights.Delete) != 0 || + (rights & FileSystemRights.DeleteSubdirectoriesAndFiles) != 0 || + (rights & FileSystemRights.WriteAttributes) != 0 || + (rights & FileSystemRights.WriteData) != 0 || // Same as CreateFiles + (rights & FileSystemRights.WriteExtendedAttributes) != 0 || + ((int)rights & Interop.Kernel32.GenericOperations.GENERIC_WRITE) != 0) + { + access |= FileAccess.Write; + } + + if (access == 0) { - access = access == FileAccess.Read ? FileAccess.ReadWrite : FileAccess.Write; + throw new ArgumentOutOfRangeException(nameof(rights)); } return access; } - private static unsafe SafeFileHandle CreateFileHandle(string fullPath, FileMode mode, FileSystemRights rights, FileShare share, FileOptions options, FileSecurity security) + private static unsafe SafeFileHandle CreateFileHandle(string fullPath, FileMode mode, FileSystemRights rights, FileShare share, FileOptions options, FileSecurity? security) { Debug.Assert(fullPath != null); @@ -291,23 +326,39 @@ private static unsafe SafeFileHandle CreateFileHandle(string fullPath, FileMode SafeFileHandle handle; - fixed (byte* pSecurityDescriptor = security.GetSecurityDescriptorBinaryForm()) + var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES { - var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES + nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), + bInheritHandle = ((share & FileShare.Inheritable) != 0) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, + }; + + if (security != null) + { + fixed (byte* pSecurityDescriptor = security.GetSecurityDescriptorBinaryForm()) { - nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES), - bInheritHandle = ((share & FileShare.Inheritable) != 0) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, - lpSecurityDescriptor = (IntPtr)pSecurityDescriptor - }; + secAttrs.lpSecurityDescriptor = (IntPtr)pSecurityDescriptor; + handle = CreateFileHandleInternal(fullPath, mode, rights, share, flagsAndAttributes, &secAttrs); + } + } + else + { + handle = CreateFileHandleInternal(fullPath, mode, rights, share, flagsAndAttributes, &secAttrs); + } + + return handle; + static unsafe SafeFileHandle CreateFileHandleInternal(string fullPath, FileMode mode, FileSystemRights rights, FileShare share, int flagsAndAttributes, Interop.Kernel32.SECURITY_ATTRIBUTES* secAttrs) + { + SafeFileHandle handle; using (DisableMediaInsertionPrompt.Create()) { - handle = Interop.Kernel32.CreateFile(fullPath, (int)rights, share, &secAttrs, mode, flagsAndAttributes, IntPtr.Zero); + // The Inheritable bit is only set in the SECURITY_ATTRIBUTES struct, + // and should not be passed to the CreateFile P/Invoke. + handle = Interop.Kernel32.CreateFile(fullPath, (int)rights, (share & ~FileShare.Inheritable), secAttrs, mode, flagsAndAttributes, IntPtr.Zero); ValidateFileHandle(handle, fullPath); } + return handle; } - - return handle; } private static void ValidateFileHandle(SafeFileHandle handle, string fullPath) diff --git a/src/libraries/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs b/src/libraries/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs index 22f2e6ffdd09c..80eb1805310b5 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs +++ b/src/libraries/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs @@ -196,7 +196,7 @@ public void DirectoryInfo_Create_NotFound() var dirInfo = new DirectoryInfo(dirPath); var security = new DirectorySecurity(); // Fails because the DirectorySecurity lacks any rights to create parent folder - Assert.Throws(() => CreateDirectoryWithSecurity(dirInfo, security)); + Assert.Throws(() => CreateDirectoryWithSecurity(dirInfo, security)); } [Fact] @@ -284,156 +284,196 @@ public void FileInfo_Create_NullFileInfo() { FileInfo info = null; var security = new FileSecurity(); - Assert.Throws("fileInfo", () => - CreateFileWithSecurity(info, FileMode.CreateNew, FileSystemRights.WriteData, FileShare.Delete, DefaultBufferSize, FileOptions.None, security)); - } - - [Fact] - public void FileInfo_Create_NullFileSecurity() - { - var info = new FileInfo("path"); - - Assert.Throws("fileSecurity", () => - CreateFileWithSecurity(info, FileMode.CreateNew, FileSystemRights.WriteData, FileShare.Delete, DefaultBufferSize, FileOptions.None, null)); + info.Create(FileMode.CreateNew, FileSystemRights.FullControl, FileShare.None, DefaultBufferSize, FileOptions.None, security)); } [Fact] - public void FileInfo_Create_NotFound() + public void FileInfo_Create_DirectoryNotFound() { using var tempRootDir = new TempAclDirectory(); string path = Path.Combine(tempRootDir.Path, Guid.NewGuid().ToString(), "file.txt"); - var fileInfo = new FileInfo(path); + var info = new FileInfo(path); var security = new FileSecurity(); - Assert.Throws(() => - CreateFileWithSecurity(fileInfo, FileMode.CreateNew, FileSystemRights.WriteData, FileShare.Delete, DefaultBufferSize, FileOptions.None, security)); + info.Create(FileMode.CreateNew, FileSystemRights.FullControl, FileShare.None, DefaultBufferSize, FileOptions.None, security)); } [Theory] [InlineData((FileMode)int.MinValue)] [InlineData((FileMode)0)] [InlineData((FileMode)int.MaxValue)] - public void FileInfo_Create_FileSecurity_InvalidFileMode(FileMode invalidMode) - { - var security = new FileSecurity(); - var info = new FileInfo("path"); - - Assert.Throws("mode", () => - CreateFileWithSecurity(info, invalidMode, FileSystemRights.WriteData, FileShare.Delete, DefaultBufferSize, FileOptions.None, security)); - } + public void FileInfo_Create_FileSecurity_OutOfRange_FileMode(FileMode invalidMode) => + FileInfo_Create_FileSecurity_ArgumentOutOfRangeException("mode", mode: invalidMode); [Theory] [InlineData((FileShare)(-1))] [InlineData((FileShare)int.MaxValue)] - public void FileInfo_Create_FileSecurity_InvalidFileShare(FileShare invalidFileShare) - { - var security = new FileSecurity(); - var info = new FileInfo("path"); - - Assert.Throws("share", () => - CreateFileWithSecurity(info, FileMode.CreateNew, FileSystemRights.WriteData, invalidFileShare, DefaultBufferSize, FileOptions.None, security)); - } + public void FileInfo_Create_FileSecurity_OutOfRange_FileShare(FileShare invalidFileShare) => + FileInfo_Create_FileSecurity_ArgumentOutOfRangeException("share", share: invalidFileShare); [Theory] [InlineData(int.MinValue)] [InlineData(0)] - public void FileInfo_Create_FileSecurity_InvalidBufferSize(int invalidBufferSize) - { - var security = new FileSecurity(); - var info = new FileInfo("path"); + public void FileInfo_Create_FileSecurity_OutOfRange_BufferSize(int invalidBufferSize) => + FileInfo_Create_FileSecurity_ArgumentOutOfRangeException("bufferSize", bufferSize: invalidBufferSize); + + public static IEnumerable WriteModes_ReadRights_ForbiddenCombo_Data() => + from mode in s_writableModes + from rights in s_readableRights + where + // These combinations are allowed, exclude them + !(rights == FileSystemRights.CreateFiles && + (mode == FileMode.Append || mode == FileMode.Create || mode == FileMode.CreateNew)) + select new object[] { mode, rights }; + + // Do not combine writing modes with exclusively read rights + [Theory] + [MemberData(nameof(WriteModes_ReadRights_ForbiddenCombo_Data))] + public void FileInfo_Create_FileSecurity_WriteModes_ReadRights_ForbiddenCombo(FileMode mode, FileSystemRights rights) => + FileInfo_Create_FileSecurity_ArgumentException(mode, rights); - Assert.Throws("bufferSize", () => - CreateFileWithSecurity(info, FileMode.CreateNew, FileSystemRights.WriteData, FileShare.Delete, invalidBufferSize, FileOptions.None, security)); - } + public static IEnumerable OpenOrCreateMode_ReadRights_AllowedCombo_Data() => + from rights in s_readableRights + select new object[] { rights }; + // OpenOrCreate allows using exclusively read rights [Theory] - [InlineData(FileMode.Truncate, FileSystemRights.Read)] - [InlineData(FileMode.Truncate, FileSystemRights.ReadData)] - [InlineData(FileMode.CreateNew, FileSystemRights.Read)] - [InlineData(FileMode.CreateNew, FileSystemRights.ReadData)] - [InlineData(FileMode.Create, FileSystemRights.Read)] - [InlineData(FileMode.Create, FileSystemRights.ReadData)] - [InlineData(FileMode.Append, FileSystemRights.Read)] - [InlineData(FileMode.Append, FileSystemRights.ReadData)] - public void FileInfo_Create_FileSecurity_ForbiddenCombo_FileModeFileSystemSecurity(FileMode mode, FileSystemRights rights) - { - var security = new FileSecurity(); - var info = new FileInfo("path"); + [MemberData(nameof(OpenOrCreateMode_ReadRights_AllowedCombo_Data))] + public void FileInfo_Create_FileSecurity_OpenOrCreateMode_ReadRights_AllowedCombo(FileSystemRights rights) => + FileInfo_Create_FileSecurity_Successful(FileMode.OpenOrCreate, rights); - Assert.Throws(() => - CreateFileWithSecurity(info, mode, rights, FileShare.Delete, DefaultBufferSize, FileOptions.None, security)); - } + // Append, Create and CreateNew allow using CreateFiles rights + // These combinations were excluded from WriteModes_ReadRights_ForbiddenCombo_Data + [Theory] + [InlineData(FileMode.Append)] + [InlineData(FileMode.Create)] + [InlineData(FileMode.CreateNew)] + public void FileInfo_Create_FileSecurity_WriteModes_CreateFilesRights_AllowedCombo(FileMode mode) => + FileInfo_Create_FileSecurity_Successful(mode, FileSystemRights.CreateFiles); + + public static IEnumerable AppendMode_UnexpectedReadRights_Data() => + from writeRights in s_writableRights + from readRights in new[] { + FileSystemRights.ExecuteFile, + FileSystemRights.ReadAttributes, FileSystemRights.ReadData, FileSystemRights.ReadExtendedAttributes, FileSystemRights.ReadPermissions, + FileSystemRights.Read, // Contains ReadAttributes, ReadData, ReadExtendedAttributes, ReadPermissions + FileSystemRights.ReadAndExecute, // Contains Read and ExecuteFile + } + select new object[] { writeRights | readRights }; + + // Append is allowed if at least one write permission is provided + // But append is disallowed if any read rights are provided + [Theory] + [MemberData(nameof(AppendMode_UnexpectedReadRights_Data))] + public void FileInfo_Create_FileSecurity_AppendMode_UnexpectedReadRights(FileSystemRights rights) => + FileInfo_Create_FileSecurity_ArgumentException(FileMode.Append, rights); + + public static IEnumerable AppendMode_OnlyWriteRights_Data() => + from writeRights in s_writableRights + select new object[] { writeRights }; + + // Append succeeds if only write permissions were provided (no read permissions) + [Theory] + [MemberData(nameof(AppendMode_OnlyWriteRights_Data))] + public void FileInfo_Create_FileSecurity_AppendMode_OnlyWriteRights(FileSystemRights rights) => + FileInfo_Create_FileSecurity_Successful(FileMode.Append, rights); + + public static IEnumerable WritableRights_Data() => + from rights in s_writableRights + select new object[] { rights }; + + // Cannot truncate unless all write rights are provided + [Theory] + [MemberData(nameof(WritableRights_Data))] + public void FileInfo_Create_FileSecurity_TruncateMode_IncompleteWriteRights(FileSystemRights rights) => + FileInfo_Create_FileSecurity_ArgumentException(FileMode.Truncate, rights); [Fact] - public void FileInfo_Create_DefaultFileSecurity() + public void FileInfo_Create_FileSecurity_TruncateMode_AllWriteRights_Throws() { + // Truncate, with all write rights, throws with different messages in each framework: + // - In .NET Framework, throws "Could not find file" + // - In .NET, throws IOException: "The parameter is incorrect" + var security = new FileSecurity(); - Verify_FileSecurity_CreateFile(security); + var info = new FileInfo(Guid.NewGuid().ToString()); + Assert.Throws(() => info.Create(FileMode.Truncate, FileSystemRights.Write | FileSystemRights.ReadData, FileShare.None, DefaultBufferSize, FileOptions.None, security)); } - private void CreateFileWithSecurity(FileInfo info, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, FileSecurity security) - { - if (PlatformDetection.IsNetFramework) - { - FileSystemAclExtensions.Create(info, mode, rights, share, bufferSize, options, security); - } - else - { - info.Create(mode, rights, share, bufferSize, options, security); - } - } + public static IEnumerable WriteRights_AllArguments_Data() => + from mode in s_writableModes + from rights in s_writableRights + from share in Enum.GetValues() + from options in Enum.GetValues() + where !(rights == FileSystemRights.CreateFiles && + (mode == FileMode.Append || mode == FileMode.Create || mode == FileMode.CreateNew)) && + !(mode == FileMode.Truncate && rights != FileSystemRights.Write) && + options != FileOptions.Encrypted // Using FileOptions.Encrypted throws UnauthorizedAccessException when attempting to read the created file + select new object[] { mode, rights, share, options }; [Theory] - // Must have at least one Read, otherwise the TempAclDirectory will fail to delete that item on dispose - [MemberData(nameof(RightsToAllow))] - public void FileInfo_Create_AllowSpecific_AccessRules(FileSystemRights rights) - { - using var tempRootDir = new TempAclDirectory(); - string path = Path.Combine(tempRootDir.Path, "file.txt"); - var fileInfo = new FileInfo(path); + [MemberData(nameof(WriteRights_AllArguments_Data))] + public void FileInfo_WriteRights_WithSecurity_Null(FileMode mode, FileSystemRights rights, FileShare share, FileOptions options) => + Verify_FileSecurity_CreateFile(mode, rights, share, DefaultBufferSize, options, expectedSecurity: null); // Null security - FileSecurity expectedSecurity = GetFileSecurity(rights); + [Theory] + [MemberData(nameof(WriteRights_AllArguments_Data))] + public void FileInfo_WriteRights_WithSecurity_Default(FileMode mode, FileSystemRights rights, FileShare share, FileOptions options) => + Verify_FileSecurity_CreateFile(mode, rights, share, DefaultBufferSize, options, new FileSecurity()); // Default security - using FileStream stream = fileInfo.Create( - FileMode.Create, - FileSystemRights.FullControl, - FileShare.ReadWrite | FileShare.Delete, - DefaultBufferSize, - FileOptions.None, - expectedSecurity); + [Theory] + [MemberData(nameof(WriteRights_AllArguments_Data))] + public void FileInfo_WriteRights_WithSecurity_Custom(FileMode mode, FileSystemRights rights, FileShare share, FileOptions options) => + Verify_FileSecurity_CreateFile(mode, rights, share, DefaultBufferSize, options, GetFileSecurity(rights)); // Custom security (AccessRule Allow) + + public static IEnumerable ReadRights_AllArguments_Data() => + from mode in new[] { FileMode.Create, FileMode.CreateNew, FileMode.OpenOrCreate } + from rights in s_readableRights + from share in Enum.GetValues() + from options in Enum.GetValues() + where options != FileOptions.Encrypted // Using FileOptions.Encrypted throws UnauthorizedAccessException when attempting to read the created file + select new object[] { mode, rights, share, options }; - Assert.True(fileInfo.Exists); - tempRootDir.CreatedSubfiles.Add(fileInfo); + [Theory] + [MemberData(nameof(ReadRights_AllArguments_Data))] + public void FileInfo_ReadRights_WithSecurity_Null(FileMode mode, FileSystemRights rights, FileShare share, FileOptions options) => + // Writable FileModes require at least one write right + Verify_FileSecurity_CreateFile(mode, rights | FileSystemRights.WriteData, share, DefaultBufferSize, options, expectedSecurity: null); // Null security - var actualInfo = new FileInfo(fileInfo.FullName); - FileSecurity actualSecurity = actualInfo.GetAccessControl(AccessControlSections.Access); - VerifyAccessSecurity(expectedSecurity, actualSecurity); - } + [Theory] + [MemberData(nameof(ReadRights_AllArguments_Data))] + public void FileInfo_ReadRights_WithSecurity_Default(FileMode mode, FileSystemRights rights, FileShare share, FileOptions options) => + // Writable FileModes require at least one write right + Verify_FileSecurity_CreateFile(mode, rights | FileSystemRights.WriteData, share, DefaultBufferSize, options, new FileSecurity()); // Default security + [Theory] + [MemberData(nameof(ReadRights_AllArguments_Data))] + public void FileInfo_ReadRights_WithSecurity_Custom(FileMode mode, FileSystemRights rights, FileShare share, FileOptions options) => + // Writable FileModes require at least one write right + Verify_FileSecurity_CreateFile(mode, rights | FileSystemRights.WriteData, share, DefaultBufferSize, options, GetFileSecurity(rights)); // Custom security (AccessRule Allow) [Theory] [MemberData(nameof(RightsToDeny))] - public void FileInfo_Create_DenySpecific_AccessRules(FileSystemRights rightsToDeny) + public void FileInfo_Create_FileSecurity_DenyAccessRule(FileSystemRights rightsToDeny) { var expectedSecurity = new FileSecurity(); var identity = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null); - var allowAccessRule = new FileSystemAccessRule(identity, FileSystemRights.Read, AccessControlType.Allow); - expectedSecurity.AddAccessRule(allowAccessRule); + // Add write deny rule var denyAccessRule = new FileSystemAccessRule(identity, rightsToDeny, AccessControlType.Deny); expectedSecurity.AddAccessRule(denyAccessRule); using var tempRootDir = new TempAclDirectory(); - string path = Path.Combine(tempRootDir.Path, "file.txt"); + string path = Path.Combine(tempRootDir.Path, Guid.NewGuid().ToString()); var fileInfo = new FileInfo(path); using FileStream stream = fileInfo.Create( - FileMode.Create, - FileSystemRights.FullControl, - FileShare.ReadWrite | FileShare.Delete, + FileMode.CreateNew, + FileSystemRights.Write, // Create expects at least one write right + FileShare.None, DefaultBufferSize, FileOptions.None, expectedSecurity); @@ -451,7 +491,6 @@ public void FileInfo_Create_DenySpecific_AccessRules(FileSystemRights rightsToDe #region DirectorySecurity CreateDirectory [Fact] - [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] public void DirectorySecurity_CreateDirectory_NullSecurity() { DirectorySecurity security = null; @@ -474,7 +513,7 @@ public void DirectorySecurity_CreateDirectory_InvalidPath() public void DirectorySecurity_CreateDirectory_DirectoryAlreadyExists() { using var tempRootDir = new TempAclDirectory(); - string path = Path.Combine(tempRootDir.Path, "createMe"); + string path = Path.Combine(tempRootDir.Path, Guid.NewGuid().ToString()); DirectorySecurity expectedSecurity = GetDirectorySecurity(FileSystemRights.FullControl); DirectoryInfo dirInfo = expectedSecurity.CreateDirectory(path); @@ -496,84 +535,137 @@ public void DirectorySecurity_CreateDirectory_DirectoryAlreadyExists() #region Helper methods - public static IEnumerable RightsToDeny() - { - yield return new object[] { FileSystemRights.AppendData }; - yield return new object[] { FileSystemRights.ChangePermissions }; - // yield return new object[] { FileSystemRights.CreateDirectories }; // CreateDirectories == AppendData - yield return new object[] { FileSystemRights.CreateFiles }; - yield return new object[] { FileSystemRights.Delete }; - yield return new object[] { FileSystemRights.DeleteSubdirectoriesAndFiles }; - yield return new object[] { FileSystemRights.ExecuteFile }; - // yield return new object[] { FileSystemRights.FullControl }; // Contains ReadData, should not deny that - // yield return new object[] { FileSystemRights.ListDirectory }; ListDirectory == ReadData - // yield return new object[] { FileSystemRights.Modify }; // Contains ReadData, should not deny that - // yield return new object[] { FileSystemRights.Read }; // Contains ReadData, should not deny that - // yield return new object[] { FileSystemRights.ReadAndExecute }; // Contains ReadData, should not deny that - yield return new object[] { FileSystemRights.ReadAttributes }; - // yield return new object[] { FileSystemRights.ReadData }; // Minimum right required to delete a file or directory - yield return new object[] { FileSystemRights.ReadExtendedAttributes }; - yield return new object[] { FileSystemRights.ReadPermissions }; - // yield return new object[] { FileSystemRights.Synchronize }; // CreateFile always requires Synchronize access - yield return new object[] { FileSystemRights.TakeOwnership }; - //yield return new object[] { FileSystemRights.Traverse }; // Traverse == ExecuteFile - yield return new object[] { FileSystemRights.Write }; - yield return new object[] { FileSystemRights.WriteAttributes }; - // yield return new object[] { FileSystemRights.WriteData }; // WriteData == CreateFiles - yield return new object[] { FileSystemRights.WriteExtendedAttributes }; - } - - public static IEnumerable RightsToAllow() - { - yield return new object[] { FileSystemRights.AppendData }; - yield return new object[] { FileSystemRights.ChangePermissions }; - // yield return new object[] { FileSystemRights.CreateDirectories }; // CreateDirectories == AppendData - yield return new object[] { FileSystemRights.CreateFiles }; - yield return new object[] { FileSystemRights.Delete }; - yield return new object[] { FileSystemRights.DeleteSubdirectoriesAndFiles }; - yield return new object[] { FileSystemRights.ExecuteFile }; - yield return new object[] { FileSystemRights.FullControl }; - // yield return new object[] { FileSystemRights.ListDirectory }; ListDirectory == ReadData - yield return new object[] { FileSystemRights.Modify }; - yield return new object[] { FileSystemRights.Read }; - yield return new object[] { FileSystemRights.ReadAndExecute }; - yield return new object[] { FileSystemRights.ReadAttributes }; - // yield return new object[] { FileSystemRights.ReadData }; // Minimum right required to delete a file or directory - yield return new object[] { FileSystemRights.ReadExtendedAttributes }; - yield return new object[] { FileSystemRights.ReadPermissions }; - yield return new object[] { FileSystemRights.Synchronize }; - yield return new object[] { FileSystemRights.TakeOwnership }; - // yield return new object[] { FileSystemRights.Traverse }; // Traverse == ExecuteFile - yield return new object[] { FileSystemRights.Write }; - yield return new object[] { FileSystemRights.WriteAttributes }; - // yield return new object[] { FileSystemRights.WriteData }; // WriteData == CreateFiles - yield return new object[] { FileSystemRights.WriteExtendedAttributes }; - } - - private void Verify_FileSecurity_CreateFile(FileSecurity expectedSecurity) - { - Verify_FileSecurity_CreateFile(FileMode.Create, FileSystemRights.WriteData, FileShare.Read, DefaultBufferSize, FileOptions.None, expectedSecurity); + public static IEnumerable RightsToDeny() => + from rights in new[] { + FileSystemRights.AppendData, // Same as CreateDirectories + FileSystemRights.ChangePermissions, + FileSystemRights.Delete, + FileSystemRights.DeleteSubdirectoriesAndFiles, + FileSystemRights.ExecuteFile, // Same as Traverse + FileSystemRights.ReadAttributes, + FileSystemRights.ReadExtendedAttributes, + FileSystemRights.ReadPermissions, + FileSystemRights.TakeOwnership, + FileSystemRights.Write, // Contains AppendData, WriteData, WriteAttributes, WriteExtendedAttributes + FileSystemRights.WriteAttributes, + FileSystemRights.WriteData, // Same as CreateFiles + FileSystemRights.WriteExtendedAttributes, + // Rights that should not be denied: + // - Synchronize: CreateFile always requires Synchronize access + // - ReadData: Minimum right required to delete a file or directory + // - ListDirectory: Equivalent to ReadData + // - Modify: Contains ReadData + // - Read: Contains ReadData + // - ReadAndExecute: Contains ReadData + // - FullControl: Contains ReadData and Synchronize + } + select new object[] { rights }; + + public static IEnumerable RightsToAllow() => + from rights in new[] { + FileSystemRights.AppendData, // Same as CreateDirectories + FileSystemRights.ChangePermissions, + FileSystemRights.Delete, + FileSystemRights.DeleteSubdirectoriesAndFiles, + FileSystemRights.ExecuteFile, // Same as Traverse + FileSystemRights.Modify, // Contains Read, Write and ReadAndExecute + FileSystemRights.Read, // Contains ReadData, ReadPermissions, ReadAttributes, ReadExtendedAttributes + FileSystemRights.ReadAndExecute, // Contains Read and ExecuteFile + FileSystemRights.ReadAttributes, + FileSystemRights.ReadData, // Minimum right required to delete a file or directory. Equivalent to ListDirectory + FileSystemRights.ReadExtendedAttributes, + FileSystemRights.ReadPermissions, + FileSystemRights.Synchronize, // CreateFile always requires Synchronize access + FileSystemRights.TakeOwnership, + FileSystemRights.Write, // Contains AppendData, WriteData, WriteAttributes, WriteExtendedAttributes + FileSystemRights.WriteAttributes, + FileSystemRights.WriteData, // Same as CreateFiles + FileSystemRights.WriteExtendedAttributes, + FileSystemRights.FullControl, // Contains Modify, DeleteSubdirectoriesAndFiles, Delete, ChangePermissions, TakeOwnership, Synchronize + } + select new object[] { rights }; + + private static readonly FileMode[] s_writableModes = new[] + { + FileMode.Append, + FileMode.Create, + FileMode.CreateNew, + FileMode.Truncate + // Excludes OpenOrCreate because it has a different behavior compared to Create/CreateNew + }; + + private static readonly FileSystemRights[] s_readableRights = new[] + { + // Excludes combined rights + FileSystemRights.ExecuteFile, + FileSystemRights.ReadAttributes, + FileSystemRights.ReadData, + FileSystemRights.ReadExtendedAttributes, + FileSystemRights.ReadPermissions + }; + + private static readonly FileSystemRights[] s_writableRights = new[] + { + // Excludes combined rights + FileSystemRights.AppendData, // Same as CreateDirectories + FileSystemRights.WriteAttributes, + FileSystemRights.WriteData, + FileSystemRights.WriteExtendedAttributes + }; + + private void FileInfo_Create_FileSecurity_ArgumentOutOfRangeException(string paramName, FileMode mode = FileMode.CreateNew, FileShare share = FileShare.None, int bufferSize = DefaultBufferSize) + { + var security = new FileSecurity(); + var info = new FileInfo(Guid.NewGuid().ToString()); + Assert.Throws(paramName, () => + info.Create(mode, FileSystemRights.FullControl, share, bufferSize, FileOptions.None, security)); + } + + private void FileInfo_Create_FileSecurity_ArgumentException(FileMode mode, FileSystemRights rights) + { + var security = new FileSecurity(); + var info = new FileInfo(Guid.NewGuid().ToString()); + Assert.Throws(() => + info.Create(mode, rights, FileShare.None, DefaultBufferSize, FileOptions.None, security)); + } + + private void FileInfo_Create_FileSecurity_Successful(FileMode mode, FileSystemRights rights) + { + var security = new FileSecurity(); + var info = new FileInfo(Guid.NewGuid().ToString()); + info.Create(mode, rights, FileShare.None, DefaultBufferSize, FileOptions.None, security).Dispose(); } private void Verify_FileSecurity_CreateFile(FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, FileSecurity expectedSecurity) { using var tempRootDir = new TempAclDirectory(); - string path = Path.Combine(tempRootDir.Path, "file.txt"); + string path = Path.Combine(tempRootDir.Path, Guid.NewGuid().ToString()); var fileInfo = new FileInfo(path); - fileInfo.Create(mode, rights, share, bufferSize, options, expectedSecurity).Dispose(); - Assert.True(fileInfo.Exists); - tempRootDir.CreatedSubfiles.Add(fileInfo); + using (FileStream fs = fileInfo.Create(mode, rights, share, bufferSize, options, expectedSecurity)) + { + Assert.True(fileInfo.Exists); + tempRootDir.CreatedSubfiles.Add(fileInfo); - var actualFileInfo = new FileInfo(path); - FileSecurity actualSecurity = actualFileInfo.GetAccessControl(AccessControlSections.Access); - VerifyAccessSecurity(expectedSecurity, actualSecurity); + var actualFileInfo = new FileInfo(path); + FileSecurity actualSecurity = actualFileInfo.GetAccessControl(); + + if (expectedSecurity != null) + { + VerifyAccessSecurity(expectedSecurity, actualSecurity); + } + else + { + int count = actualSecurity.GetAccessRules(includeExplicit: true, includeInherited: false, typeof(SecurityIdentifier)).Count; + Assert.Equal(0, count); + } + } } private void Verify_DirectorySecurity_CreateDirectory(DirectorySecurity expectedSecurity) { using var tempRootDir = new TempAclDirectory(); - string path = Path.Combine(tempRootDir.Path, "createMe"); + string path = Path.Combine(tempRootDir.Path, Guid.NewGuid().ToString()); DirectoryInfo dirInfo = expectedSecurity.CreateDirectory(path); Assert.True(dirInfo.Exists); tempRootDir.CreatedSubdirectories.Add(dirInfo); From a9c96461388aad0c47f8d49435893203ee60224a Mon Sep 17 00:00:00 2001 From: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:55:05 +0300 Subject: [PATCH 160/308] Tune FP CSEs live across a call better (#63903) The problem was that the comparison of a weighted refcount, which usually has the order of hundreds or tens, with a small digit like "4" was too weak and missed some cases where we were still trying to CSE cheaps floats across calls and ending up with lots of stack shuffling. Fix this by using different tuning parameters, namely the costs estimated for the uses and defs (increase them to account for the spills and reloads). --- src/coreclr/jit/optcse.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index 805e5b7d2eb3f..108fde7e98497 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -2599,17 +2599,18 @@ class CSE_Heuristic cse_use_cost *= slotCount; } - // If this CSE is live across a call then we may need to spill an additional caller save register + // If this CSE is live across a call then we may have additional costs // if (candidate->LiveAcrossCall()) { - if (candidate->Expr()->IsCnsFltOrDbl() && (CNT_CALLEE_SAVED_FLOAT == 0) && - (candidate->CseDsc()->csdUseWtCnt <= 4)) + // If we have a floating-point CSE that is both live across a call and there + // are no callee-saved FP registers available, the RA will have to spill at + // the def site and reload at the (first) use site, if the variable is a register + // candidate. Account for that. + if (varTypeIsFloating(candidate->Expr()) && (CNT_CALLEE_SAVED_FLOAT == 0) && !candidate->IsConservative()) { - // Floating point constants are expected to be contained, so unless there are more than 4 uses - // we better not to CSE them, especially on platforms without callee-saved registers - // for values living across calls - return false; + cse_def_cost += 1; + cse_use_cost += 1; } // If we don't have a lot of variables to enregister or we have a floating point type From bde7069e7e1a2eb05fe9cc838b4de0f982a72544 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 24 Jan 2022 10:08:44 +0100 Subject: [PATCH 161/308] [main] Update dependencies from dotnet/arcade dotnet/icu dotnet/xharness dotnet/emsdk (#64098) Co-authored-by: dotnet-maestro[bot] --- .config/dotnet-tools.json | 2 +- eng/Version.Details.xml | 96 +++++++------- eng/Versions.props | 40 +++--- eng/common/internal/NuGet.config | 7 + eng/common/templates/job/execute-sdl.yml | 13 +- eng/common/templates/job/onelocbuild.yml | 3 +- eng/common/templates/jobs/jobs.yml | 4 +- .../templates/post-build/common-variables.yml | 69 ---------- .../templates/post-build/post-build.yml | 74 +++++------ .../post-build/setup-maestro-vars.yml | 123 ++++++++---------- global.json | 8 +- 11 files changed, 175 insertions(+), 264 deletions(-) create mode 100644 eng/common/internal/NuGet.config diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 0e5219042b700..26dc5ae6a75f4 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "1.0.0-prerelease.22067.1", + "version": "1.0.0-prerelease.22071.1", "commands": [ "xharness" ] diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index af284815b19ec..ee709f74031a4 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + https://github.com/dotnet/icu - 4170ccfbbcada3e22aa4428a84524fabef006e38 + 8a4a45cc99e7d6e5244c16f581171633091b96b3 https://github.com/dotnet/msquic a7213b4676c1803bb251771291a525482d42e511 - + https://github.com/dotnet/emsdk - 4eb953d7051890da4f36167125c6b41e06d7f56d + aaa56a6622c4991cf65d553250af3c0ade1320bc https://github.com/dotnet/wcf @@ -50,77 +50,77 @@ - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 https://github.com/microsoft/vstest @@ -238,21 +238,21 @@ https://github.com/dotnet/linker e485816b48273d03bd6266a64dad9bea97f861d5 - + https://github.com/dotnet/xharness - 3060cda4543b80824a9238bcd176bb1a5af72044 + bd2a12f9cc6c93c249f987b42c1c761550369674 - + https://github.com/dotnet/xharness - 3060cda4543b80824a9238bcd176bb1a5af72044 + bd2a12f9cc6c93c249f987b42c1c761550369674 - + https://github.com/dotnet/xharness - 3060cda4543b80824a9238bcd176bb1a5af72044 + bd2a12f9cc6c93c249f987b42c1c761550369674 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 04f7adea4cff9..85e7bdd4cdc82 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -54,21 +54,21 @@ 2.0.0-alpha.1.21525.11 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 2.5.1-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 - 7.0.0-beta.22068.3 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 2.5.1-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 + 7.0.0-beta.22071.6 6.0.0-preview.1.102 @@ -160,9 +160,9 @@ 1.0.1-prerelease-00006 16.9.0-preview-20201201-01 - 1.0.0-prerelease.22067.1 - 1.0.0-prerelease.22067.1 - 1.0.0-prerelease.22067.1 + 1.0.0-prerelease.22071.1 + 1.0.0-prerelease.22071.1 + 1.0.0-prerelease.22071.1 1.0.2-alpha.0.22069.1 2.4.2-pre.22 0.12.0-pre.20 @@ -180,7 +180,7 @@ 7.0.100-1.22063.2 $(MicrosoftNETILLinkTasksVersion) - 7.0.0-alpha.1.22067.1 + 7.0.0-preview.2.22071.2 7.0.0-alpha.1.21529.3 @@ -193,7 +193,7 @@ 11.1.0-alpha.1.22067.2 11.1.0-alpha.1.22067.2 - 7.0.0-alpha.1.21601.1 + 7.0.0-alpha.2.22071.3 $(MicrosoftNETWorkloadEmscriptenManifest70100Version) 1.1.87-gba258badda diff --git a/eng/common/internal/NuGet.config b/eng/common/internal/NuGet.config new file mode 100644 index 0000000000000..769650362f4aa --- /dev/null +++ b/eng/common/internal/NuGet.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml index 8cf772b3cbf81..a4837c32c3869 100644 --- a/eng/common/templates/job/execute-sdl.yml +++ b/eng/common/templates/job/execute-sdl.yml @@ -29,14 +29,6 @@ parameters: # Optional: download a list of pipeline artifacts. 'downloadArtifacts' controls build artifacts, # not pipeline artifacts, so doesn't affect the use of this parameter. pipelineArtifactNames: [] - # Optional: location and ID of the AzDO build that the build/pipeline artifacts should be - # downloaded from. By default, uses runtime expressions to decide based on the variables set by - # the 'setupMaestroVars' dependency. Overriding this parameter is necessary if SDL tasks are - # running without Maestro++/BAR involved, or to download artifacts from a specific existing build - # to iterate quickly on SDL changes. - AzDOProjectName: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - AzDOPipelineId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - AzDOBuildId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] jobs: - job: Run_SDL @@ -55,11 +47,14 @@ jobs: - name: GuardianVersion value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} pool: - vmImage: windows-2019 + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - checkout: self clean: true + - template: /eng/common/templates/post-build/setup-maestro-vars.yml + - ${{ if ne(parameters.downloadArtifacts, 'false')}}: - ${{ if ne(parameters.artifactNames, '') }}: - ${{ each artifactName in parameters.artifactNames }}: diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index c4fc18b3ee77a..0b93fd5b490eb 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -4,7 +4,8 @@ parameters: # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool pool: - vmImage: 'windows-2019' + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex GithubPat: $(BotAccount-dotnet-bot-repo-PAT) diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml index ff4ab75c886dc..dafa603dc5d90 100644 --- a/eng/common/templates/jobs/jobs.yml +++ b/eng/common/templates/jobs/jobs.yml @@ -83,7 +83,9 @@ jobs: - ${{ if eq(parameters.enableSourceBuild, true) }}: - Source_Build_Complete pool: - vmImage: 'windows-2019' + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 + runAsPublic: ${{ parameters.runAsPublic }} publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml index c99fd7503767c..c830e6f277606 100644 --- a/eng/common/templates/post-build/common-variables.yml +++ b/eng/common/templates/post-build/common-variables.yml @@ -4,54 +4,6 @@ variables: - group: DotNet-DotNetCli-Storage - group: DotNet-MSRC-Storage - group: Publish-Build-Assets - - # .NET Core 3.1 Dev - - name: PublicDevRelease_31_Channel_Id - value: 128 - - # .NET 5 Dev - - name: Net_5_Dev_Channel_Id - value: 131 - - # .NET Eng - Validation - - name: Net_Eng_Validation_Channel_Id - value: 9 - - # .NET Eng - Latest - - name: Net_Eng_Latest_Channel_Id - value: 2 - - # .NET 3 Eng - Validation - - name: NET_3_Eng_Validation_Channel_Id - value: 390 - - # .NET 3 Eng - - name: NetCore_3_Tools_Channel_Id - value: 344 - - # .NET Core 3.0 Internal Servicing - - name: InternalServicing_30_Channel_Id - value: 184 - - # .NET Core 3.0 Release - - name: PublicRelease_30_Channel_Id - value: 19 - - # .NET Core 3.1 Release - - name: PublicRelease_31_Channel_Id - value: 129 - - # General Testing - - name: GeneralTesting_Channel_Id - value: 529 - - # .NET Core 3.1 Blazor Features - - name: NetCore_31_Blazor_Features_Channel_Id - value: 531 - - # .NET Core Experimental - - name: NetCore_Experimental_Channel_Id - value: 562 # Whether the build is internal or not - name: IsInternalBuild @@ -70,27 +22,6 @@ variables: - name: SymbolToolVersion value: 1.0.1 - # Feed Configurations - # These should include the suffix "/index.json" - - # Default locations for Installers and checksums - # Public Locations - - name: ChecksumsBlobFeedUrl - value: https://dotnetclichecksums.blob.core.windows.net/dotnet/index.json - - name: InstallersBlobFeedUrl - value: https://dotnetcli.blob.core.windows.net/dotnet/index.json - - # Private Locations - - name: InternalChecksumsBlobFeedUrl - value: https://dotnetclichecksumsmsrc.blob.core.windows.net/dotnet/index.json - - name: InternalChecksumsBlobFeedKey - value: $(dotnetclichecksumsmsrc-storage-key) - - - name: InternalInstallersBlobFeedUrl - 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 diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index 8985b429c8543..9583d27dbbf89 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -90,25 +90,19 @@ stages: variables: - template: common-variables.yml jobs: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - job: displayName: NuGet Validation - dependsOn: setupMaestroVars condition: eq( ${{ parameters.enableNugetValidation }}, 'true') pool: - vmImage: 'windows-2019' - variables: - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 + steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + - task: DownloadBuildArtifacts@0 displayName: Download Package Artifacts inputs: @@ -129,19 +123,16 @@ stages: - job: displayName: Signing Validation - dependsOn: setupMaestroVars condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true')) - variables: - - template: common-variables.yml - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] pool: - vmImage: 'windows-2019' + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + - task: DownloadBuildArtifacts@0 displayName: Download Package Artifacts inputs: @@ -186,19 +177,16 @@ stages: - job: displayName: SourceLink Validation - dependsOn: setupMaestroVars condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true') - variables: - - template: common-variables.yml - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] pool: - vmImage: 'windows-2019' + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + - task: DownloadBuildArtifacts@0 displayName: Download Blob Artifacts inputs: @@ -224,7 +212,6 @@ stages: - template: /eng/common/templates/job/execute-sdl.yml parameters: enable: ${{ parameters.SDLValidationParameters.enable }} - dependsOn: setupMaestroVars additionalParameters: ${{ parameters.SDLValidationParameters.params }} continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }} artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }} @@ -239,21 +226,18 @@ stages: variables: - template: common-variables.yml jobs: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - job: displayName: Publish Using Darc - dependsOn: setupMaestroVars timeoutInMinutes: 120 - variables: - - name: BARBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] pool: - vmImage: 'windows-2019' + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + - task: PowerShell@2 displayName: Publish Using Darc inputs: diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml index 4a22b2e6f6de7..826d3ed5f74c2 100644 --- a/eng/common/templates/post-build/setup-maestro-vars.yml +++ b/eng/common/templates/post-build/setup-maestro-vars.yml @@ -2,77 +2,68 @@ parameters: BARBuildId: '' PromoteToChannelIds: '' -jobs: -- job: setupMaestroVars - displayName: Setup Maestro Vars - variables: - - template: common-variables.yml - pool: - vmImage: 'windows-2019' - steps: - - checkout: none - - - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Release Configs - inputs: - buildType: current - artifactName: ReleaseConfigs - checkDownloadedFiles: true - - - task: PowerShell@2 - name: setReleaseVars - displayName: Set Release Configs Vars +steps: + - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}: + - task: DownloadBuildArtifacts@0 + displayName: Download Release Configs inputs: - targetType: inline - script: | - try { - if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { - $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt + buildType: current + artifactName: ReleaseConfigs + checkDownloadedFiles: true - $BarId = $Content | Select -Index 0 - $Channels = $Content | Select -Index 1 - $IsStableBuild = $Content | Select -Index 2 + - task: PowerShell@2 + name: setReleaseVars + displayName: Set Release Configs Vars + inputs: + targetType: inline + script: | + try { + if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { + $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt - $AzureDevOpsProject = $Env:System_TeamProject - $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId - $AzureDevOpsBuildId = $Env:Build_BuildId - } - else { - $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" + $BarId = $Content | Select -Index 0 + $Channels = $Content | Select -Index 1 + $IsStableBuild = $Content | Select -Index 2 - $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $apiHeaders.Add('Accept', 'application/json') - $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") - - $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } - - $BarId = $Env:BARBuildId - $Channels = $Env:PromoteToMaestroChannels -split "," - $Channels = $Channels -join "][" - $Channels = "[$Channels]" + $AzureDevOpsProject = $Env:System_TeamProject + $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId + $AzureDevOpsBuildId = $Env:Build_BuildId + } + else { + $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" - $IsStableBuild = $buildInfo.stable - $AzureDevOpsProject = $buildInfo.azureDevOpsProject - $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId - $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId - } + $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' + $apiHeaders.Add('Accept', 'application/json') + $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") - Write-Host "##vso[task.setvariable variable=BARBuildId;isOutput=true]$BarId" - Write-Host "##vso[task.setvariable variable=TargetChannels;isOutput=true]$Channels" - Write-Host "##vso[task.setvariable variable=IsStableBuild;isOutput=true]$IsStableBuild" + $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + + $BarId = $Env:BARBuildId + $Channels = $Env:PromoteToMaestroChannels -split "," + $Channels = $Channels -join "][" + $Channels = "[$Channels]" - Write-Host "##vso[task.setvariable variable=AzDOProjectName;isOutput=true]$AzureDevOpsProject" - Write-Host "##vso[task.setvariable variable=AzDOPipelineId;isOutput=true]$AzureDevOpsBuildDefinitionId" - Write-Host "##vso[task.setvariable variable=AzDOBuildId;isOutput=true]$AzureDevOpsBuildId" + $IsStableBuild = $buildInfo.stable + $AzureDevOpsProject = $buildInfo.azureDevOpsProject + $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId + $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId } - catch { - Write-Host $_ - Write-Host $_.Exception - Write-Host $_.ScriptStackTrace - exit 1 - } - env: - MAESTRO_API_TOKEN: $(MaestroApiAccessToken) - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} + + Write-Host "##vso[task.setvariable variable=BARBuildId]$BarId" + Write-Host "##vso[task.setvariable variable=TargetChannels]$Channels" + Write-Host "##vso[task.setvariable variable=IsStableBuild]$IsStableBuild" + + Write-Host "##vso[task.setvariable variable=AzDOProjectName]$AzureDevOpsProject" + Write-Host "##vso[task.setvariable variable=AzDOPipelineId]$AzureDevOpsBuildDefinitionId" + Write-Host "##vso[task.setvariable variable=AzDOBuildId]$AzureDevOpsBuildId" + } + catch { + Write-Host $_ + Write-Host $_.Exception + Write-Host $_.ScriptStackTrace + exit 1 + } + env: + MAESTRO_API_TOKEN: $(MaestroApiAccessToken) + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} diff --git a/global.json b/global.json index 6e753c749b04a..e0d86ef423d93 100644 --- a/global.json +++ b/global.json @@ -12,10 +12,10 @@ "python3": "3.7.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.22068.3", - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22068.3", - "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22068.3", - "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.22068.3", + "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.22071.6", + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22071.6", + "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22071.6", + "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.22071.6", "Microsoft.Build.NoTargets": "3.1.0", "Microsoft.Build.Traversal": "3.0.23", "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.22066.4" From 7435abedcdf4c82a32e2afbafdd05bbc8f11d8ef Mon Sep 17 00:00:00 2001 From: Eaton Zveare Date: Mon, 24 Jan 2022 04:14:20 -0500 Subject: [PATCH 162/308] Update zip extraction to never throw any exceptions when the LastWriteTime update fails (#63912) --- .../IO/Compression/ZipFileExtensions.ZipArchiveEntry.Extract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFileExtensions.ZipArchiveEntry.Extract.cs b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFileExtensions.ZipArchiveEntry.Extract.cs index 5d800c1f62ca7..fe725937441e2 100644 --- a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFileExtensions.ZipArchiveEntry.Extract.cs +++ b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFileExtensions.ZipArchiveEntry.Extract.cs @@ -83,7 +83,7 @@ public static void ExtractToFile(this ZipArchiveEntry source, string destination { File.SetLastWriteTime(destinationFileName, source.LastWriteTime.DateTime); } - catch (UnauthorizedAccessException) + catch { // some OSes like Android (#35374) might not support setting the last write time, the extraction should not fail because of that } From 11991bb444daaad255aa0a898a10e9c7b552dbc6 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Mon, 24 Jan 2022 09:58:24 +0000 Subject: [PATCH 163/308] Use kebab-case in FB automation labels (#64048) --- .github/fabricbot.json | 130 ++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/.github/fabricbot.json b/.github/fabricbot.json index 723e3f5c493f2..4679bc697e375 100644 --- a/.github/fabricbot.json +++ b/.github/fabricbot.json @@ -996,7 +996,7 @@ "subCapability": "IssueCommentResponder", "version": "1.0", "config": { - "taskName": "Replace `needs-author-action` label with `needs further triage` label when the author comments on an issue", + "taskName": "Replace `needs-author-action` label with `needs-further-triage` label when the author comments on an issue", "conditions": { "operator": "and", "operands": [ @@ -1030,7 +1030,7 @@ { "name": "addLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -1052,7 +1052,7 @@ "subCapability": "IssuesOnlyResponder", "version": "1.0", "config": { - "taskName": "Remove `no recent activity` label from issues when issue is modified", + "taskName": "Remove `no-recent-activity` label from issues when issue is modified", "conditions": { "operator": "and", "operands": [ @@ -1070,7 +1070,7 @@ { "name": "hasLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } }, { @@ -1079,7 +1079,7 @@ { "name": "labelAdded", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ] @@ -1090,7 +1090,7 @@ { "name": "removeLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ], @@ -1107,14 +1107,14 @@ "subCapability": "IssueCommentResponder", "version": "1.0", "config": { - "taskName": "Remove `no recent activity` label when an issue is commented on", + "taskName": "Remove `no-recent-activity` label when an issue is commented on", "conditions": { "operator": "and", "operands": [ { "name": "hasLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ] @@ -1123,7 +1123,7 @@ { "name": "removeLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ], @@ -1149,7 +1149,7 @@ { "name": "hasLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } }, { @@ -1158,7 +1158,7 @@ { "name": "labelAdded", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ] @@ -1171,12 +1171,12 @@ "issues", "project_card" ], - "taskName": "Remove `no recent activity` label from PRs when modified", + "taskName": "Remove `no-recent-activity` label from PRs when modified", "actions": [ { "name": "removeLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ] @@ -1194,7 +1194,7 @@ { "name": "hasLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } }, { @@ -1207,12 +1207,12 @@ "eventNames": [ "issue_comment" ], - "taskName": "Remove `no recent activity` label from PRs when commented on", + "taskName": "Remove `no-recent-activity` label from PRs when commented on", "actions": [ { "name": "removeLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ] @@ -1230,7 +1230,7 @@ { "name": "hasLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } }, { @@ -1243,12 +1243,12 @@ "eventNames": [ "pull_request_review" ], - "taskName": "Remove `no recent activity` label from PRs when new review is added", + "taskName": "Remove `no-recent-activity` label from PRs when new review is added", "actions": [ { "name": "removeLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ] @@ -1345,7 +1345,7 @@ { "name": "hasLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } }, { @@ -1359,7 +1359,7 @@ { "name": "addReply", "parameters": { - "comment": "This issue will now be closed since it had been marked `no recent activity` but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days." + "comment": "This issue will now be closed since it had been marked `no-recent-activity` but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days." } }, { @@ -1375,7 +1375,7 @@ "subCapability": "ScheduledSearch", "version": "1.1", "config": { - "taskName": "Close PRs with no recent activity", + "taskName": "Close PRs with no-recent-activity", "frequency": [ { "weekDay": 0, @@ -1460,7 +1460,7 @@ { "name": "hasLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } }, { @@ -1474,7 +1474,7 @@ { "name": "addReply", "parameters": { - "comment": "This pull request will now be closed since it had been marked `no recent activity` but received no further activity in the past 14 days. It is still possible to reopen or comment on the pull request, but please note that it will be locked if it remains inactive for another 30 days." + "comment": "This pull request will now be closed since it had been marked `no-recent-activity` but received no further activity in the past 14 days. It is still possible to reopen or comment on the pull request, but please note that it will be locked if it remains inactive for another 30 days." } }, { @@ -1490,7 +1490,7 @@ "subCapability": "ScheduledSearch", "version": "1.1", "config": { - "taskName": "Add no recent activity label to issues", + "taskName": "Add no-recent-activity label to issues", "frequency": [ { "weekDay": 0, @@ -1587,7 +1587,7 @@ { "name": "noLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ], @@ -1595,13 +1595,13 @@ { "name": "addLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } }, { "name": "addReply", "parameters": { - "comment": "This issue has been automatically marked `no recent activity` because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will remove `no recent activity`." + "comment": "This issue has been automatically marked `no-recent-activity` because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will remove `no-recent-activity`." } } ] @@ -1614,7 +1614,7 @@ "subCapability": "ScheduledSearch", "version": "1.1", "config": { - "taskName": "Add no recent activity label to PRs", + "taskName": "Add no-recent-activity label to PRs", "frequency": [ { "weekDay": 0, @@ -1711,7 +1711,7 @@ { "name": "noLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ], @@ -1719,13 +1719,13 @@ { "name": "addLabel", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } }, { "name": "addReply", "parameters": { - "comment": "This pull request has been automatically marked `no recent activity` because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will remove `no recent activity`." + "comment": "This pull request has been automatically marked `no-recent-activity` because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will remove `no-recent-activity`." } } ] @@ -1742,7 +1742,7 @@ "inPrLabelText": "Status: In PR", "fixedLabelText": "Status: Fixed", "fixedLabelEnabled": false, - "label_inPr": "in pr" + "label_inPr": "in-pr" } }, { @@ -2239,7 +2239,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -2267,7 +2267,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -2280,7 +2280,7 @@ { "name": "labelRemoved", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -2502,7 +2502,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -2524,7 +2524,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -2543,7 +2543,7 @@ { "name": "labelRemoved", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -2625,7 +2625,7 @@ { "name": "labelAdded", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -2928,7 +2928,7 @@ { "name": "addLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -3006,7 +3006,7 @@ { "name": "addLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -3130,7 +3130,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -3152,7 +3152,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -3171,7 +3171,7 @@ { "name": "labelRemoved", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -3258,7 +3258,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -3280,7 +3280,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -3299,7 +3299,7 @@ { "name": "labelRemoved", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -3369,7 +3369,7 @@ { "name": "labelRemoved", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -3398,7 +3398,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -3837,7 +3837,7 @@ { "name": "labelAdded", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -3989,7 +3989,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -4018,7 +4018,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -4029,7 +4029,7 @@ { "name": "labelRemoved", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -4210,7 +4210,7 @@ { "name": "labelAdded", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -4317,7 +4317,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -4350,7 +4350,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -4369,7 +4369,7 @@ { "name": "labelRemoved", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -5159,7 +5159,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -5187,7 +5187,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -5215,7 +5215,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -5287,7 +5287,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -5315,7 +5315,7 @@ { "name": "hasLabel", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } } ] @@ -5328,7 +5328,7 @@ { "name": "labelRemoved", "parameters": { - "label": "needs further triage" + "label": "needs-further-triage" } }, { @@ -5383,7 +5383,7 @@ { "name": "labelAdded", "parameters": { - "label": "no recent activity" + "label": "no-recent-activity" } } ] From 42c29676a715c7bf7e61411c7e9e3746626cc7a5 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Mon, 24 Jan 2022 10:23:01 +0000 Subject: [PATCH 164/308] Onboard new Triage & PR Boards (#64198) --- .github/fabricbot.json | 1452 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1452 insertions(+) diff --git a/.github/fabricbot.json b/.github/fabricbot.json index 4679bc697e375..030256bef724d 100644 --- a/.github/fabricbot.json +++ b/.github/fabricbot.json @@ -8524,5 +8524,1457 @@ } ] } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Infrastructure-libraries" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Microsoft.Win32" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.EventLog" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.PerformanceCounter" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.TraceSource" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Drawing" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Management" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ServiceProcess" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "reopened" + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isInMilestone", + "parameters": {} + } + ] + } + ] + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "area-Infrastructure-libraries" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-Microsoft.Win32" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Diagnostics.EventLog" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Diagnostics.PerformanceCounter" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Diagnostics.TraceSource" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Drawing" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Management" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.ServiceProcess" + } + } + ] + } + ] + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "operator": "or", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "isOrgProject": true + } + } + ] + }, + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "isOrgProject": true, + "columnName": "Triaged" + } + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "[Area Pod: Carlos / Santi - Issue Triage] Add new issue to Board", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "columnName": "Needs Triage", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueCommentResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Infrastructure-libraries" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Microsoft.Win32" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.EventLog" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.PerformanceCounter" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.TraceSource" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Drawing" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Management" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ServiceProcess" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isCloseAndComment", + "parameters": {} + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "activitySenderHasPermissions", + "parameters": { + "permissions": "write" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "isOrgProject": true + } + } + ] + }, + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "columnName": "Triaged", + "isOrgProject": true + } + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issue_comment" + ], + "taskName": "[Area Pod: Carlos / Santi - Issue Triage] Needs Further Triage", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "columnName": "Needs Triage", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "columnName": "Needs Triage", + "isOrgProject": true + } + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Infrastructure-libraries" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Microsoft.Win32" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.EventLog" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.PerformanceCounter" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.TraceSource" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Drawing" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Management" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ServiceProcess" + } + } + ] + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "[Area Pod: Carlos / Santi - Issue Triage] Remove relabeled issues", + "actions": [ + { + "name": "removeFromProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "isOrgProject": true + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "columnName": "Triaged" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "addedToMilestone", + "parameters": {} + }, + { + "name": "labelAdded", + "parameters": { + "label": "needs-author-action" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "api-ready-for-review" + } + }, + { + "name": "isAction", + "parameters": { + "action": "closed" + } + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "[Area Pod: Carlos / Santi - Issue Triage] Move to Triaged Column", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - Issue Triage", + "columnName": "Triaged", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Infrastructure-libraries" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-Microsoft.Win32" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.EventLog" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.PerformanceCounter" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.TraceSource" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Drawing" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Management" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ServiceProcess" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - PRs", + "isOrgProject": true + } + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "[Area Pod: Carlos / Santi - PRs] Add new PR to Board", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - PRs", + "columnName": "Needs Champion", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - PRs", + "columnName": "Needs Champion", + "isOrgProject": true + } + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Infrastructure-libraries" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Microsoft.Win32" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.EventLog" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.PerformanceCounter" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.TraceSource" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Drawing" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Management" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ServiceProcess" + } + } + ] + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "[Area Pod: Carlos / Santi - PRs] Remove relabeled PRs", + "actions": [ + { + "name": "removeFromProject", + "parameters": { + "projectName": "Area Pod: Carlos / Santi - PRs", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-FileSystem" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Console" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Process" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO.Compression" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Linq.Parallel" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Memory" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "reopened" + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isInMilestone", + "parameters": {} + } + ] + } + ] + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "area-Extensions-FileSystem" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Console" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Diagnostics.Process" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.IO" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.IO.Compression" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Linq.Parallel" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "area-System.Memory" + } + } + ] + } + ] + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "operator": "or", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "isOrgProject": true + } + } + ] + }, + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "isOrgProject": true, + "columnName": "Triaged" + } + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "[Area Pod: Adam / David - Issue Triage] Add new issue to Board", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "columnName": "Needs Triage", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueCommentResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-FileSystem" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Console" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Process" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO.Compression" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Linq.Parallel" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Memory" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isCloseAndComment", + "parameters": {} + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "activitySenderHasPermissions", + "parameters": { + "permissions": "write" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "isOrgProject": true + } + } + ] + }, + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "columnName": "Triaged", + "isOrgProject": true + } + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issue_comment" + ], + "taskName": "[Area Pod: Adam / David - Issue Triage] Needs Further Triage", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "columnName": "Needs Triage", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "columnName": "Needs Triage", + "isOrgProject": true + } + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-FileSystem" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Console" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Process" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO.Compression" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Linq.Parallel" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Memory" + } + } + ] + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "[Area Pod: Adam / David - Issue Triage] Remove relabeled issues", + "actions": [ + { + "name": "removeFromProject", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "isOrgProject": true + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "columnName": "Triaged" + } + } + ] + }, + { + "operator": "or", + "operands": [ + { + "name": "addedToMilestone", + "parameters": {} + }, + { + "name": "labelAdded", + "parameters": { + "label": "needs-author-action" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "api-ready-for-review" + } + }, + { + "name": "isAction", + "parameters": { + "action": "closed" + } + } + ] + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "[Area Pod: Adam / David - Issue Triage] Move to Triaged Column", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Adam / David - Issue Triage", + "columnName": "Triaged", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "or", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-FileSystem" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Console" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Process" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO.Compression" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Linq.Parallel" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Memory" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Adam / David - PRs", + "isOrgProject": true + } + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "[Area Pod: Adam / David - PRs] Add new PR to Board", + "actions": [ + { + "name": "addToProject", + "parameters": { + "projectName": "Area Pod: Adam / David - PRs", + "columnName": "Needs Champion", + "isOrgProject": true + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isInProjectColumn", + "parameters": { + "projectName": "Area Pod: Adam / David - PRs", + "columnName": "Needs Champion", + "isOrgProject": true + } + }, + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-FileSystem" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Console" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Process" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO.Compression" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Linq.Parallel" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Memory" + } + } + ] + } + ] + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "[Area Pod: Adam / David - PRs] Remove relabeled PRs", + "actions": [ + { + "name": "removeFromProject", + "parameters": { + "projectName": "Area Pod: Adam / David - PRs", + "isOrgProject": true + } + } + ] + } } ] \ No newline at end of file From 773e822f66ca5d67b3d6e54adf63fb63c346eb34 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Mon, 24 Jan 2022 02:48:35 -0800 Subject: [PATCH 165/308] Exclusively use GitHub teams for Libraries area mentions (#64199) --- .github/fabricbot.json | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/.github/fabricbot.json b/.github/fabricbot.json index 030256bef724d..accae195f26ee 100644 --- a/.github/fabricbot.json +++ b/.github/fabricbot.json @@ -13,8 +13,7 @@ ], "mentionees": [ "dotnet/area-system-security", - "vcsjones", - "krwq" + "vcsjones" ] }, { @@ -33,8 +32,7 @@ "area-System.Linq.Parallel" ], "mentionees": [ - "dotnet/area-system-linq-parallel", - "tarekgh" + "dotnet/area-system-linq-parallel" ] }, { @@ -42,8 +40,7 @@ "area-System.Text.Encoding" ], "mentionees": [ - "dotnet/area-system-text-encoding", - "tarekgh" + "dotnet/area-system-text-encoding" ] }, { @@ -51,8 +48,7 @@ "area-System.Text.Encodings.Web" ], "mentionees": [ - "dotnet/area-system-text-encodings-web", - "tarekgh" + "dotnet/area-system-text-encodings-web" ] }, { @@ -175,8 +171,7 @@ "area-System.Buffers" ], "mentionees": [ - "dotnet/area-system-buffers", - "GrabYourPitchforks" + "dotnet/area-system-buffers" ] }, { @@ -377,8 +372,7 @@ "area-Extensions-FileSystem" ], "mentionees": [ - "dotnet/area-extensions-filesystem", - "maryamariyan" + "dotnet/area-extensions-filesystem" ] }, { @@ -776,8 +770,7 @@ "area-System.Resources" ], "mentionees": [ - "dotnet/area-system-resources", - "tarekgh" + "dotnet/area-system-resources" ] }, { From d964b638f1ad47a729ab2e6cf4d6822f76ea3e4f Mon Sep 17 00:00:00 2001 From: Christopher Moore Date: Mon, 24 Jan 2022 12:53:54 +0000 Subject: [PATCH 166/308] Reduce buffer size used in XmlReader when using Async mode (#63459) The current choice of AsyncBufferSize resulted in the character buffer in the XmlTextReader being allocated on the Large Object Heap (LOH) Fixes https://github.com/dotnet/runtime/issues/61459 --- .../System.Private.Xml/src/System/Xml/Core/XmlReader.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs index c6a6c1ce3e32f..599ff04f757fd 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs @@ -81,7 +81,9 @@ public abstract partial class XmlReader : IDisposable internal const int BiggerBufferSize = 8192; internal const int MaxStreamLengthForDefaultBufferSize = 64 * 1024; // 64kB - internal const int AsyncBufferSize = 64 * 1024; //64KB + // Chosen to be small enough that the character buffer in XmlTextReader when using Async = true + // is not allocated on the Large Object Heap (LOH) + internal const int AsyncBufferSize = 32 * 1024; // Settings public virtual XmlReaderSettings? Settings => null; From 0a9aecb192e76e7bdf02cead9f93deadbcd2382e Mon Sep 17 00:00:00 2001 From: Katya Sokolova Date: Mon, 24 Jan 2022 15:02:05 +0100 Subject: [PATCH 167/308] Ignoring leading dot when comparing cookie domains (#64038) * ignoring leading dot when comparin cookie domain * Simplify cookie comparing logic to equality and moving it to CookieComparer to fix the build * Domain comparing optimizarion and more unit tests * small check optimization * Renaming method --- .../Common/src/System/Net/CookieComparer.cs | 22 +++++---- .../src/System/Net/Cookie.cs | 2 +- .../src/System/Net/CookieCollection.cs | 4 +- .../tests/UnitTests/CookieContainerTest.cs | 45 +++++++++++++++++++ 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/libraries/Common/src/System/Net/CookieComparer.cs b/src/libraries/Common/src/System/Net/CookieComparer.cs index 7d511ace0a9ac..529ec06a51a1f 100644 --- a/src/libraries/Common/src/System/Net/CookieComparer.cs +++ b/src/libraries/Common/src/System/Net/CookieComparer.cs @@ -5,23 +5,29 @@ namespace System.Net { internal static class CookieComparer { - internal static int Compare(Cookie left, Cookie right) + internal static bool Equals(Cookie left, Cookie right) { - int result; - - if ((result = string.Compare(left.Name, right.Name, StringComparison.OrdinalIgnoreCase)) != 0) + if (!string.Equals(left.Name, right.Name, StringComparison.OrdinalIgnoreCase)) { - return result; + return false; } - if ((result = string.Compare(left.Domain, right.Domain, StringComparison.OrdinalIgnoreCase)) != 0) + if (!EqualDomains(left.Domain, right.Domain)) { - return result; + return false; } // NB: Only the path is case sensitive as per spec. However, many Windows applications assume // case-insensitivity. - return string.Compare(left.Path, right.Path, StringComparison.Ordinal); + return string.Equals(left.Path, right.Path, StringComparison.Ordinal); + } + + internal static bool EqualDomains(ReadOnlySpan left, ReadOnlySpan right) + { + if (left.Length != 0 && left[0] == '.') left = left.Slice(1); + if (right.Length != 0 && right[0] == '.') right = right.Slice(1); + + return left.Equals(right, StringComparison.OrdinalIgnoreCase); } } } diff --git a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs index 8ed63ef9f97b3..4d0bfa918fd24 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs @@ -717,7 +717,7 @@ public override bool Equals([NotNullWhen(true)] object? comparand) && string.Equals(Name, other.Name, StringComparison.OrdinalIgnoreCase) && string.Equals(Value, other.Value, StringComparison.Ordinal) && string.Equals(Path, other.Path, StringComparison.Ordinal) - && string.Equals(Domain, other.Domain, StringComparison.OrdinalIgnoreCase) + && CookieComparer.EqualDomains(Domain, other.Domain) && (Version == other.Version); } diff --git a/src/libraries/System.Net.Primitives/src/System/Net/CookieCollection.cs b/src/libraries/System.Net.Primitives/src/System/Net/CookieCollection.cs index e8c7c78b68c0b..edfe5ce52551a 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/CookieCollection.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/CookieCollection.cs @@ -203,7 +203,7 @@ internal int InternalAdd(Cookie cookie, bool isStrict) for (int i = 0; i < listCount; i++) { Cookie c = (Cookie)m_list[i]!; - if (CookieComparer.Compare(cookie, c) == 0) + if (CookieComparer.Equals(cookie, c)) { ret = 0; // Will replace or reject @@ -237,7 +237,7 @@ internal int IndexOf(Cookie cookie) int idx = 0; foreach (Cookie? c in m_list) { - if (CookieComparer.Compare(cookie, c!) == 0) + if (CookieComparer.Equals(cookie, c!)) { return idx; } diff --git a/src/libraries/System.Net.Primitives/tests/UnitTests/CookieContainerTest.cs b/src/libraries/System.Net.Primitives/tests/UnitTests/CookieContainerTest.cs index b3673331aebcd..53cb06963caa7 100644 --- a/src/libraries/System.Net.Primitives/tests/UnitTests/CookieContainerTest.cs +++ b/src/libraries/System.Net.Primitives/tests/UnitTests/CookieContainerTest.cs @@ -866,6 +866,51 @@ public void SetCookies_DomainCheckFailure_IgnoresAbsenceOfLeadingDot(string doma Assert.Throws(() => container.SetCookies(uri, cookie)); } + [Theory] + [InlineData("example.com", "example.com" )] + [InlineData("example.com", ".example.com" )] + [InlineData(".example.com", "example.com" )] + [InlineData(".example.com", ".example.com")] + public void SetCookies_DomainCheckSuccess_IgnoresLeadingDot(params string[] domains) + { + var uri = new Uri($"https://{domains[0].Trim('.')}/", UriKind.Absolute); + var container = new CookieContainer(); + + // First HTTP response... + container.SetCookies(uri, $"foo=bar; Path=/; Domain={domains[0]}"); + + // Second HTTP response... + container.SetCookies(uri, $"foo=baz; Path=/; Domain={domains[1]}"); + + CookieCollection acceptedCookies = container.GetCookies(uri); + Assert.Equal(1, acceptedCookies.Count); + Assert.Equal(domains[1], acceptedCookies[0].Domain); + } + + [Theory] + [InlineData("test.example.com", "example.com")] + [InlineData("test.example.com", ".example.com")] + [InlineData("example.com", "test.example.com")] + [InlineData(".example.com", "test.example.com")] + public void SetCookies_DomainCheckFailure_IgnoresLeadingDot(params string[] domains) + { + var uri = new Uri($"https://test.example.com/", UriKind.Absolute); + var container = new CookieContainer(); + + // First HTTP response... + container.SetCookies(uri, $"foo=bar; Path=/; Domain={domains[0]}"); + + // Second HTTP response... + container.SetCookies(uri, $"foo=baz; Path=/; Domain={domains[1]}"); + + CookieCollection acceptedCookies = container.GetCookies(uri); + Assert.Equal(2, acceptedCookies.Count); + foreach (Cookie cookie in acceptedCookies) + { + Assert.Contains(cookie.Domain, domains); + } + } + // Test default-path calculation as defined in // https://tools.ietf.org/html/rfc6265#section-5.1.4 public static readonly TheoryData DefaultPathData = new TheoryData() From 65b12267400471f1c11e9a396250a6beb3b495a2 Mon Sep 17 00:00:00 2001 From: Joshua Peterson Date: Mon, 24 Jan 2022 09:15:38 -0500 Subject: [PATCH 168/308] Add missing handle function enter/return macros (#64061) The mono_field_static_get_value method uses a handle, but did not set up enter/exit macros properly, so this handle was leaked. Some code in Unity calls this embedding API method pretty often, which can lead to the mark stack overflowing in the GC code. --- src/mono/mono/metadata/object.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index 5863a967d544f..9a39381533e5a 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -3242,9 +3242,13 @@ mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value) { MONO_REQ_GC_NEUTRAL_MODE; + HANDLE_FUNCTION_ENTER (); + ERROR_DECL (error); mono_field_static_get_value_checked (vt, field, value, MONO_HANDLE_NEW (MonoString, NULL), error); mono_error_cleanup (error); + + HANDLE_FUNCTION_RETURN (); } /** From 5a9e584d684d45ce67b6e9c9cf27114db20efd1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 24 Jan 2022 23:28:06 +0900 Subject: [PATCH 169/308] Drop support for .NET 5 SDK (#64186) We had to duplicate a lot of Microsoft.NET.ILLink.targets logic. --- .../Microsoft.NETCore.Native.Publish.targets | 2 +- .../Microsoft.NETCore.Native.targets | 41 ------------------- 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets index 18258d4288b01..ae6229a0a7afe 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets @@ -48,7 +48,7 @@ - + diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index 365afaa6ce468..8fc0d8e6842e9 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -40,8 +40,6 @@ The .NET Foundation licenses this file to you under the MIT license. true true - true - copyused @@ -132,13 +130,6 @@ The .NET Foundation licenses this file to you under the MIT license. - - - - true - - - @@ -200,35 +191,6 @@ The .NET Foundation licenses this file to you under the MIT license. Outputs="%(ManagedBinary.IlcRspFile)" DependsOnTargets="$(IlcCompileDependsOn)"> - - - true - - - - - - - <__SingleWarnIntermediateAssembly Include="@(ManagedAssemblyToLink)" /> - <__SingleWarnIntermediateAssembly Remove="@(IntermediateAssembly)" /> - - <_SingleWarnIntermediateAssembly Include="@(ManagedAssemblyToLink)" /> - <_SingleWarnIntermediateAssembly Remove="@(__SingleWarnIntermediateAssembly)" /> - - <_SingleWarnIntermediateAssembly> - false - - - - - - - - false - - - <_IlcRootedAssemblies Include="@(TrimmerRootAssembly)" /> <_IlcRootedAssemblies Include="@(ManagedAssemblyToLink)" Condition="%(ManagedAssemblyToLink.TrimMode) == 'copy'" /> @@ -287,9 +249,6 @@ The .NET Foundation licenses this file to you under the MIT license. - - - From 0ac0071e457434c73bdd119911d1094f6ccee544 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 24 Jan 2022 09:43:25 -0500 Subject: [PATCH 170/308] Implement IEquatable on value types overriding Equals (and enable CA1066/1077) (#63690) --- eng/CodeAnalysis.src.globalconfig | 4 +- .../System.Private.CoreLib.csproj | 2 - .../Diagnostics/SymbolStore/SymAddressKind.cs | 49 ------------ .../System/Diagnostics/SymbolStore/Token.cs | 39 ---------- .../src/System/Reflection/MdImport.cs | 2 + .../src/System/RuntimeHandles.cs | 2 +- .../src/System/ModuleHandle.cs | 2 +- .../General/TypeUnifier.NativeFormat.cs | 2 + .../Runtime/TypeInfos/RuntimeNamedTypeInfo.cs | 2 + .../NativeFormat/Generator/ReaderGen.cs | 1 + .../NativeFormat/NativeFormatReaderGen.cs | 1 + .../NativeFormat/NativeMetadataReader.cs | 7 +- .../Common/TypeSystem/Common/LayoutInt.cs | 2 + .../Unix/System.Native/Interop.IPAddress.cs | 16 +++- .../src/ServiceLookup/ServiceCacheKey.cs | 13 +++- ...crosoft.Extensions.Logging.Abstractions.cs | 2 +- .../src/EventId.cs | 3 +- .../ImmutableDictionary_2.HashBucket.cs | 2 + .../ImmutableHashSet_1.HashBucket.cs | 2 + .../ref/System.Collections.Specialized.cs | 5 +- .../Collections/Specialized/BitVector32.cs | 11 ++- .../tests/BitVector32Tests.cs | 15 ++++ .../ref/System.ComponentModel.Composition.cs | 3 +- .../ReflectionModel/LazyMemberInfo.cs | 25 +++--- .../System.ComponentModel.TypeConverter.cs | 3 +- .../MemberRelationshipService.cs | 50 +++++------- .../ComponentModel/InterlockedBitVector32.cs | 6 +- .../ref/System.Data.Common.cs | 39 ++++++---- .../src/System/Data/DataKey.cs | 4 +- .../src/System/Data/SQLTypes/SQLBinary.cs | 25 +++--- .../src/System/Data/SQLTypes/SQLBoolean.cs | 28 +++---- .../src/System/Data/SQLTypes/SQLByte.cs | 28 +++---- .../src/System/Data/SQLTypes/SQLDateTime.cs | 28 +++---- .../src/System/Data/SQLTypes/SQLDecimal.cs | 25 +++--- .../src/System/Data/SQLTypes/SQLDouble.cs | 28 +++---- .../src/System/Data/SQLTypes/SQLGuid.cs | 28 +++---- .../src/System/Data/SQLTypes/SQLInt16.cs | 28 +++---- .../src/System/Data/SQLTypes/SQLInt32.cs | 28 +++---- .../src/System/Data/SQLTypes/SQLInt64.cs | 28 +++---- .../src/System/Data/SQLTypes/SQLMoney.cs | 29 +++---- .../src/System/Data/SQLTypes/SQLSingle.cs | 28 +++---- .../src/System/Data/SQLTypes/SQLString.cs | 25 +++--- .../src/System/Data/Selection.cs | 14 ++-- .../System/Data/SqlTypes/SqlBinaryTest.cs | 3 + .../System/Data/SqlTypes/SqlBooleanTest.cs | 4 + .../tests/System/Data/SqlTypes/SqlByteTest.cs | 3 + .../System/Data/SqlTypes/SqlDateTimeTest.cs | 2 + .../System/Data/SqlTypes/SqlDecimalTest.cs | 2 + .../System/Data/SqlTypes/SqlDoubleTest.cs | 3 + .../tests/System/Data/SqlTypes/SqlGuidTest.cs | 3 + .../System/Data/SqlTypes/SqlInt16Test.cs | 3 + .../System/Data/SqlTypes/SqlInt64Test.cs | 3 + .../System/Data/SqlTypes/SqlMoneyTest.cs | 2 + .../System/Data/SqlTypes/SqlSingleTest.cs | 3 + .../System/Data/SqlTypes/SqlStringTest.cs | 3 + ...stem.Diagnostics.PerformanceCounter.csproj | 3 +- ...agnostics.PerformanceCounter.netcoreapp.cs | 12 +++ ...stem.Diagnostics.PerformanceCounter.csproj | 1 + .../src/System/Diagnostics/CounterSample.cs | 2 +- .../ref/System.Diagnostics.StackTrace.cs | 2 +- .../Diagnostics/SymbolStore/SymbolToken.cs | 2 +- .../ref/System.Drawing.Common.netcoreapp.cs | 4 + .../src/System/Drawing/CharacterRange.cs | 30 +++---- .../src/System/Drawing/Printing/TriState.cs | 78 +++++++------------ .../tests/CharacterRangeTests.cs | 1 + .../src/System/IO/Packaging/PackUriHelper.cs | 2 + .../Expressions/Interpreter/LocalVariables.cs | 23 ++---- .../ref/System.Net.Sockets.cs | 3 +- .../System/Net/Sockets/IPPacketInformation.cs | 48 ++++-------- .../IPPacketInformationTest.cs | 7 ++ .../src/System/ArraySegment.cs | 10 ++- .../Diagnostics/Tracing/EventDescriptor.cs | 2 +- .../src/System/HashCode.cs | 2 + .../src/System/IntPtr.cs | 2 + .../src/System/Nullable.cs | 2 + .../CustomAttributeNamedArgument.cs | 17 ++-- .../CustomAttributeTypedArgument.cs | 11 ++- .../InteropServices/ArrayWithOffset.cs | 4 +- .../Runtime/InteropServices/GCHandle.cs | 9 ++- .../Runtime/Serialization/StreamingContext.cs | 2 + .../src/System/Threading/CancellationToken.cs | 2 +- .../System/Threading/LowLevelLifoSemaphore.cs | 9 ++- .../PortableThreadPool.ThreadCounts.cs | 5 +- .../PortableThreadPool.WorkerTracking.cs | 11 ++- .../src/System/TimeZoneInfo.AdjustmentRule.cs | 6 ++ .../src/System/UIntPtr.cs | 2 + .../System/Xml/BinaryXml/XmlBinaryReader.cs | 49 ++++-------- .../src/System/Xml/Xsl/Pair.cs | 43 ++++------ .../src/System/Xml/Xsl/XmlQueryCardinality.cs | 2 +- .../System/Runtime/Caching/CacheExpires.cs | 55 +++---------- .../src/System/Runtime/Caching/CacheUsage.cs | 62 +++------------ .../ref/System.Runtime.InteropServices.cs | 2 +- .../Runtime/InteropServices/GCHandleTests.cs | 1 + .../System.Runtime/ref/System.Runtime.cs | 18 +++-- ...stomAttribute_Named_Typed_ArgumentTests.cs | 22 ++++++ ...iceProcess.ServiceController.netcoreapp.cs | 3 + ...em.ServiceProcess.ServiceController.csproj | 2 + .../SessionChangeDescription.cs | 39 ++++------ .../src/Internal/Synthesis/EngineSiteSapi.cs | 38 ++++----- .../System.Text.Rune.netstandard20.cs | 2 +- .../Symbolic/SymbolicMatch.cs | 12 ++- .../Symbolic/SymbolicRegexInfo.cs | 6 +- .../System.Threading/ref/System.Threading.cs | 2 +- .../src/System/Threading/LockCookie.cs | 37 +++------ .../ref/System.Transactions.Local.cs | 5 +- .../System/Transactions/TransactionOptions.cs | 7 +- .../src/Mono/RuntimeHandles.cs | 6 +- .../src/System/ModuleHandle.cs | 2 +- .../src/System/Nullable.Mono.cs | 2 + .../BrowserDebugProxy/DevToolsHelper.cs | 12 ++- .../WasmAppBuilder/PInvokeTableGenerator.cs | 2 + 111 files changed, 650 insertions(+), 813 deletions(-) delete mode 100644 src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/SymAddressKind.cs delete mode 100644 src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/Token.cs create mode 100644 src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.netcoreapp.cs diff --git a/eng/CodeAnalysis.src.globalconfig b/eng/CodeAnalysis.src.globalconfig index 0fc9bf8e5a7ee..e5ae41903b5a7 100644 --- a/eng/CodeAnalysis.src.globalconfig +++ b/eng/CodeAnalysis.src.globalconfig @@ -152,10 +152,10 @@ dotnet_diagnostic.CA1064.severity = none dotnet_diagnostic.CA1065.severity = none # CA1066: Implement IEquatable when overriding Object.Equals -dotnet_diagnostic.CA1066.severity = none +dotnet_diagnostic.CA1066.severity = warning # CA1067: Override Object.Equals(object) when implementing IEquatable -dotnet_diagnostic.CA1067.severity = none +dotnet_diagnostic.CA1067.severity = warning # CA1068: CancellationToken parameters must come last dotnet_diagnostic.CA1068.severity = none diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index e1230d59401d8..3d21bffd3d24f 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -140,8 +140,6 @@ - - diff --git a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/SymAddressKind.cs b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/SymAddressKind.cs deleted file mode 100644 index dc2a0a05708c1..0000000000000 --- a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/SymAddressKind.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================ -** -** -** -** Represents address Kinds used with local variables, parameters, and -** fields. -** -** -===========================================================*/ -// Only statics, does not need to be marked with the serializable attribute - -namespace System.Diagnostics.SymbolStore -{ - internal enum SymAddressKind - { - // ILOffset: addr1 = IL local var or param index. - ILOffset = 1, - - // NativeRVA: addr1 = RVA into module. - NativeRVA = 2, - - // NativeRegister: addr1 = register the var is stored in. - NativeRegister = 3, - - // NativeRegisterRelative: addr1 = register, addr2 = offset. - NativeRegisterRelative = 4, - - // NativeOffset: addr1 = offset from start of parent. - NativeOffset = 5, - - // NativeRegisterRegister: addr1 = reg low, addr2 = reg high. - NativeRegisterRegister = 6, - - // NativeRegisterStack: addr1 = reg low, addr2 = reg stk, addr3 = offset. - NativeRegisterStack = 7, - - // NativeStackRegister: addr1 = reg stk, addr2 = offset, addr3 = reg high. - NativeStackRegister = 8, - - // BitField: addr1 = field start, addr = field length. - BitField = 9, - - // NativeSectionOffset: addr1 = section, addr = offset - NativeSectionOffset = 10, - } -} diff --git a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/Token.cs b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/Token.cs deleted file mode 100644 index fbd9f7e4bc1ae..0000000000000 --- a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/SymbolStore/Token.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================ -** -** -** Small value class used by the SymbolStore package for passing -** around metadata tokens. -** -===========================================================*/ - -using System.Diagnostics.CodeAnalysis; - -namespace System.Diagnostics.SymbolStore -{ - internal struct SymbolToken - { - internal int m_token; - - public SymbolToken(int val) { m_token = val; } - - public int GetToken() { return m_token; } - - public override int GetHashCode() { return m_token; } - - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj is SymbolToken) - return Equals((SymbolToken)obj); - else - return false; - } - - public bool Equals(SymbolToken obj) - { - return obj.m_token == m_token; - } - } -} diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs index 9368fc25d340b..cdc15dc8fb6e0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs @@ -194,7 +194,9 @@ public int this[int index] } } +#pragma warning disable CA1066 // IEquatable interface implementation isn't used internal readonly struct MetadataImport +#pragma warning restore CA1067 { private readonly IntPtr m_metadataImport2; private readonly object? m_keepalive; diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 977d73e5c3b99..32a37b6d4219f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -1246,7 +1246,7 @@ public void GetObjectData(SerializationInfo info, StreamingContext context) } } - public unsafe partial struct ModuleHandle + public unsafe partial struct ModuleHandle : IEquatable { #region Public Static Members public static readonly ModuleHandle EmptyHandle; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ModuleHandle.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ModuleHandle.cs index 3714e7ce510fb..d1bb831f34772 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ModuleHandle.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ModuleHandle.cs @@ -6,7 +6,7 @@ namespace System { - public struct ModuleHandle + public struct ModuleHandle : IEquatable { public static readonly ModuleHandle EmptyHandle; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs index b44cf57cdff6d..fe06816cf93e3 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs @@ -34,6 +34,8 @@ // - The TypeUnifier extension class provides a more friendly interface to the rest of the codebase. // +#pragma warning disable CA1067 // override Equals because it implements IEquatable + namespace System.Reflection.Runtime.General { internal static partial class TypeUnifier diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs index 209a91e0cb102..fdbcf0b53685d 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs @@ -10,6 +10,8 @@ using Internal.Reflection.Tracing; +#pragma warning disable CA1067 // override Equals because it implements IEquatable + namespace System.Reflection.Runtime.TypeInfos { // diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs index 55b09b37b3431..aa1a796bfaa0f 100644 --- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs +++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/ReaderGen.cs @@ -20,6 +20,7 @@ public void EmitSource() WriteLine("#pragma warning disable 649"); WriteLine("#pragma warning disable 169"); WriteLine("#pragma warning disable 282 // There is no defined ordering between fields in multiple declarations of partial class or struct"); + WriteLine("#pragma warning disable CA1066 // IEquatable implementations aren't used"); WriteLine("#pragma warning disable IDE0059"); WriteLine(); diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs index 1d92be5677148..bbc23ec878484 100644 --- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs +++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs @@ -6,6 +6,7 @@ #pragma warning disable 649 #pragma warning disable 169 #pragma warning disable 282 // There is no defined ordering between fields in multiple declarations of partial class or struct +#pragma warning disable CA1066 // IEquatable implementations aren't used #pragma warning disable IDE0059 using System; diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs index 8eba905400e42..5b7921f972f97 100644 --- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs +++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeMetadataReader.cs @@ -1,12 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - #pragma warning disable 169 - -// There is no defined ordering between fields in multiple declarations of partial class or struct -#pragma warning disable 282 - +#pragma warning disable 282 // There is no defined ordering between fields in multiple declarations of partial class or struct +#pragma warning disable CA1066 // IEquatable implementations aren't used using System; using System.IO; diff --git a/src/coreclr/tools/Common/TypeSystem/Common/LayoutInt.cs b/src/coreclr/tools/Common/TypeSystem/Common/LayoutInt.cs index 2ec3883af9f08..c794377bf1971 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/LayoutInt.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/LayoutInt.cs @@ -12,7 +12,9 @@ namespace Internal.TypeSystem /// type system do not have a known size. This type is used to make such sizes viral through the type layout /// computations) /// +#pragma warning disable CA1066 // IEquatable implementation wouldn't be used public struct LayoutInt +#pragma warning restore CA1066 { private int _value; diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.IPAddress.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.IPAddress.cs index 567f97df901ce..4bbd79987510b 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.IPAddress.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.IPAddress.cs @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using System.Text; internal static partial class Interop { @@ -33,6 +32,19 @@ public bool IsIPv6 private uint _isIPv6; // Non-zero if this is an IPv6 address; zero for IPv4. internal uint ScopeId; // Scope ID (IPv6 only) + public override unsafe int GetHashCode() + { + HashCode h = default; + fixed (byte* ptr = Address) + { + h.AddBytes(new ReadOnlySpan(ptr, IsIPv6 ? IPv6AddressBytes : IPv4AddressBytes)); + } + return h.ToHashCode(); + } + + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is IPAddress other && Equals(other); + public bool Equals(IPAddress other) { int addressByteCount; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCacheKey.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCacheKey.cs index 8f812ae45e6a8..737c23d7f4445 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCacheKey.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceCacheKey.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { @@ -33,10 +34,14 @@ public ServiceCacheKey(Type? type, int slot) Slot = slot; } - public bool Equals(ServiceCacheKey other) - { - return Type == other.Type && Slot == other.Slot; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(ServiceCacheKey other) => + Type == other.Type && Slot == other.Slot; + + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is ServiceCacheKey other && Equals(other); public override int GetHashCode() { 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 1404880a97288..33e79ca09252e 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 @@ -6,7 +6,7 @@ namespace Microsoft.Extensions.Logging { - public readonly partial struct EventId + public readonly partial struct EventId : System.IEquatable { private readonly object _dummy; private readonly int _dummyPrimitive; diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/EventId.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/EventId.cs index 972fb1ec0488c..1cb4775b275b9 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/EventId.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/EventId.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.Logging @@ -8,7 +9,7 @@ namespace Microsoft.Extensions.Logging /// /// Identifies a logging event. The primary identifier is the "Id" property, with the "Name" property providing a short description of this type of event. /// - public readonly struct EventId + public readonly struct EventId : IEquatable { /// /// Implicitly creates an EventId from the given . diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.HashBucket.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.HashBucket.cs index aa8d7636cfbca..2562372c666b4 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.HashBucket.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.HashBucket.cs @@ -15,7 +15,9 @@ public partial class ImmutableDictionary /// /// Contains all the key/values in the collection that hash to the same value. /// +#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals internal readonly struct HashBucket : IEnumerable> +#pragma warning restore CA1066 { /// /// One of the values in this bucket. diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.HashBucket.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.HashBucket.cs index 82fd48fbc62e5..04ca794da7808 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.HashBucket.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.HashBucket.cs @@ -30,7 +30,9 @@ internal enum OperationResult /// /// Contains all the keys in the collection that hash to the same value. /// +#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals internal readonly struct HashBucket +#pragma warning restore CA1066 { /// /// One of the values in this bucket. diff --git a/src/libraries/System.Collections.Specialized/ref/System.Collections.Specialized.cs b/src/libraries/System.Collections.Specialized/ref/System.Collections.Specialized.cs index 1864717141ca4..00fc77efe910c 100644 --- a/src/libraries/System.Collections.Specialized/ref/System.Collections.Specialized.cs +++ b/src/libraries/System.Collections.Specialized/ref/System.Collections.Specialized.cs @@ -6,7 +6,7 @@ namespace System.Collections.Specialized { - public partial struct BitVector32 + public partial struct BitVector32 : System.IEquatable { private int _dummyPrimitive; public BitVector32(System.Collections.Specialized.BitVector32 value) { throw null; } @@ -18,11 +18,12 @@ public partial struct BitVector32 public static int CreateMask(int previous) { throw null; } public static System.Collections.Specialized.BitVector32.Section CreateSection(short maxValue) { throw null; } public static System.Collections.Specialized.BitVector32.Section CreateSection(short maxValue, System.Collections.Specialized.BitVector32.Section previous) { throw null; } + public bool Equals(System.Collections.Specialized.BitVector32 other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? o) { throw null; } public override int GetHashCode() { throw null; } public override string ToString() { throw null; } public static string ToString(System.Collections.Specialized.BitVector32 value) { throw null; } - public readonly partial struct Section + public readonly partial struct Section : System.IEquatable { private readonly int _dummyPrimitive; public short Mask { get { throw null; } } diff --git a/src/libraries/System.Collections.Specialized/src/System/Collections/Specialized/BitVector32.cs b/src/libraries/System.Collections.Specialized/src/System/Collections/Specialized/BitVector32.cs index ce4ba761ab7af..60a2580cfb6fd 100644 --- a/src/libraries/System.Collections.Specialized/src/System/Collections/Specialized/BitVector32.cs +++ b/src/libraries/System.Collections.Specialized/src/System/Collections/Specialized/BitVector32.cs @@ -10,7 +10,7 @@ namespace System.Collections.Specialized /// Provides a simple light bit vector with easy integer or Boolean access to /// a 32 bit storage. /// - public struct BitVector32 + public struct BitVector32 : IEquatable { private uint _data; @@ -151,7 +151,12 @@ private static Section CreateSectionHelper(short maxValue, short priorMask, shor return new Section(mask, offset); } - public override bool Equals([NotNullWhen(true)] object? o) => o is BitVector32 other && _data == other._data; + public override bool Equals([NotNullWhen(true)] object? o) => o is BitVector32 other && Equals(other); + + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(BitVector32 other) => _data == other._data; public override int GetHashCode() => _data.GetHashCode(); @@ -182,7 +187,7 @@ public override string ToString() /// /// Represents an section of the vector that can contain a integer number. /// - public readonly struct Section + public readonly struct Section : IEquatable
{ private readonly short _mask; private readonly short _offset; diff --git a/src/libraries/System.Collections.Specialized/tests/BitVector32Tests.cs b/src/libraries/System.Collections.Specialized/tests/BitVector32Tests.cs index 61734a09b741f..69453b6c574d5 100644 --- a/src/libraries/System.Collections.Specialized/tests/BitVector32Tests.cs +++ b/src/libraries/System.Collections.Specialized/tests/BitVector32Tests.cs @@ -518,17 +518,32 @@ public static void EqualsTest() Assert.True(new BitVector32(0).Equals(original)); Assert.True(original.Equals(new BitVector32(0))); + Assert.True(original.Equals((object)original)); + Assert.True(new BitVector32().Equals((object)original)); + Assert.True(original.Equals((object)new BitVector32())); + Assert.True(new BitVector32(0).Equals((object)original)); + Assert.True(original.Equals((object)new BitVector32(0))); + BitVector32 other = new BitVector32(int.MaxValue / 2 - 1); Assert.True(other.Equals(other)); Assert.True(new BitVector32(int.MaxValue / 2 - 1).Equals(other)); Assert.True(other.Equals(new BitVector32(int.MaxValue / 2 - 1))); + Assert.True(other.Equals((object)other)); + Assert.True(new BitVector32(int.MaxValue / 2 - 1).Equals((object)other)); + Assert.True(other.Equals((object)new BitVector32(int.MaxValue / 2 - 1))); + Assert.False(other.Equals(original)); Assert.False(original.Equals(other)); Assert.False(other.Equals(null)); Assert.False(original.Equals(null)); Assert.False(other.Equals(int.MaxValue / 2 - 1)); Assert.False(original.Equals(0)); + + Assert.False(other.Equals((object)original)); + Assert.False(original.Equals((object)other)); + Assert.False(other.Equals(int.MaxValue / 2 - 1)); + Assert.False(original.Equals(0)); } [Fact] diff --git a/src/libraries/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs b/src/libraries/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs index f55f6b216d37f..60accaee91e87 100644 --- a/src/libraries/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs +++ b/src/libraries/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs @@ -608,7 +608,7 @@ public ImportDefinition(System.Linq.Expressions.Expression { private object _dummy; private int _dummyPrimitive; @@ -616,6 +616,7 @@ public partial struct LazyMemberInfo public LazyMemberInfo(System.Reflection.MemberTypes memberType, System.Func accessorsCreator) { throw null; } public LazyMemberInfo(System.Reflection.MemberTypes memberType, params System.Reflection.MemberInfo[] accessors) { throw null; } public System.Reflection.MemberTypes MemberType { get { throw null; } } + public bool Equals(System.ComponentModel.Composition.ReflectionModel.LazyMemberInfo other) { throw null; } public override bool Equals(object? obj) { throw null; } public System.Reflection.MemberInfo[] GetAccessors() { throw null; } public override int GetHashCode() { throw null; } diff --git a/src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/ReflectionModel/LazyMemberInfo.cs b/src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/ReflectionModel/LazyMemberInfo.cs index 480e339c4080f..02d1f811e71b7 100644 --- a/src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/ReflectionModel/LazyMemberInfo.cs +++ b/src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/ReflectionModel/LazyMemberInfo.cs @@ -8,7 +8,7 @@ namespace System.ComponentModel.Composition.ReflectionModel { - public struct LazyMemberInfo + public struct LazyMemberInfo : IEquatable { private readonly MemberTypes _memberType; private MemberInfo?[]? _accessors; @@ -106,31 +106,32 @@ public override int GetHashCode() throw new Exception(SR.Diagnostic_InternalExceptionMessage); } - public override bool Equals(object? obj) - { - if (obj is not LazyMemberInfo that) - { - return false; - } + public override bool Equals(object? obj) => + obj is LazyMemberInfo other && Equals(other); + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(LazyMemberInfo other) + { // Different member types mean different members - if (_memberType != that._memberType) + if (_memberType != other._memberType) { return false; } // if any of the lazy memebers create accessors in a delay-loaded fashion, we simply compare the creators - if ((_accessorsCreator != null) || (that._accessorsCreator != null)) + if ((_accessorsCreator != null) || (other._accessorsCreator != null)) { - return object.Equals(_accessorsCreator, that._accessorsCreator); + return object.Equals(_accessorsCreator, other._accessorsCreator); } // we are dealing with explicitly passed accessors in both cases - if (_accessors == null || that._accessors == null) + if (_accessors == null || other._accessors == null) { throw new Exception(SR.Diagnostic_InternalExceptionMessage); } - return _accessors.SequenceEqual(that._accessors); + return _accessors.SequenceEqual(other._accessors); } public static bool operator ==(LazyMemberInfo left, LazyMemberInfo right) diff --git a/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs b/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs index 510fffca71406..8fe3c9a37f821 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs @@ -2164,7 +2164,7 @@ public InstanceDescriptor(System.Reflection.MemberInfo? member, System.Collectio public object? Invoke() { throw null; } } [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct MemberRelationship + public readonly partial struct MemberRelationship : System.IEquatable { private readonly object _dummy; private readonly int _dummyPrimitive; @@ -2173,6 +2173,7 @@ public readonly partial struct MemberRelationship public bool IsEmpty { get { throw null; } } public System.ComponentModel.MemberDescriptor Member { get { throw null; } } public object? Owner { get { throw null; } } + public bool Equals(System.ComponentModel.Design.Serialization.MemberRelationship other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(System.ComponentModel.Design.Serialization.MemberRelationship left, System.ComponentModel.Design.Serialization.MemberRelationship right) { throw null; } diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/Serialization/MemberRelationshipService.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/Serialization/MemberRelationshipService.cs index 6691792d7fcfe..090fa91accbf7 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/Serialization/MemberRelationshipService.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/Serialization/MemberRelationshipService.cs @@ -153,7 +153,7 @@ private static void ThrowRelationshipNotSupported(MemberRelationship source, Mem /// /// Used as storage in our relationship table /// - private struct RelationshipEntry + private struct RelationshipEntry : IEquatable { internal WeakReference _owner; internal MemberDescriptor _member; @@ -169,20 +169,19 @@ internal RelationshipEntry(MemberRelationship rel) public override bool Equals([NotNullWhen(true)] object? o) { Debug.Assert(o is RelationshipEntry, "This is only called indirectly from a dictionary only containing RelationshipEntry structs."); - return this == (RelationshipEntry)o; + return Equals((RelationshipEntry)o); } - public static bool operator ==(RelationshipEntry re1, RelationshipEntry re2) + public bool Equals(RelationshipEntry other) { - object? owner1 = (re1._owner.IsAlive ? re1._owner.Target : null); - object? owner2 = (re2._owner.IsAlive ? re2._owner.Target : null); - return owner1 == owner2 && re1._member.Equals(re2._member); + object? owner1 = (_owner.IsAlive ? _owner.Target : null); + object? owner2 = (other._owner.IsAlive ? other._owner.Target : null); + return owner1 == owner2 && _member.Equals(other._member); } - public static bool operator !=(RelationshipEntry re1, RelationshipEntry re2) - { - return !(re1 == re2); - } + public static bool operator ==(RelationshipEntry re1, RelationshipEntry re2) => re1.Equals(re2); + + public static bool operator !=(RelationshipEntry re1, RelationshipEntry re2) => !re1.Equals(re2); public override int GetHashCode() => _hashCode; } @@ -191,7 +190,7 @@ public override bool Equals([NotNullWhen(true)] object? o) /// /// This class represents a single relationship between an object and a member. /// - public readonly struct MemberRelationship + public readonly struct MemberRelationship : IEquatable { public static readonly MemberRelationship Empty; @@ -222,37 +221,26 @@ public MemberRelationship(object owner, MemberDescriptor member) /// /// Infrastructure support to make this a first class struct /// - public override bool Equals([NotNullWhen(true)] object? obj) - { - return obj is MemberRelationship rel && rel.Owner == Owner && rel.Member == Member; - } + public override bool Equals([NotNullWhen(true)] object? obj) => obj is MemberRelationship rel && Equals(rel); /// /// Infrastructure support to make this a first class struct /// - public override int GetHashCode() - { - if (Owner == null) - { - return base.GetHashCode(); - } + public bool Equals(MemberRelationship other) => other.Owner == Owner && other.Member == Member; - return Owner.GetHashCode() ^ Member.GetHashCode(); - } /// /// Infrastructure support to make this a first class struct /// - public static bool operator ==(MemberRelationship left, MemberRelationship right) - { - return left.Owner == right.Owner && left.Member == right.Member; - } + public override int GetHashCode() => Owner is null ? base.GetHashCode() : Owner.GetHashCode() ^ Member.GetHashCode(); /// /// Infrastructure support to make this a first class struct /// - public static bool operator !=(MemberRelationship left, MemberRelationship right) - { - return !(left == right); - } + public static bool operator ==(MemberRelationship left, MemberRelationship right) => left.Equals(right); + + /// + /// Infrastructure support to make this a first class struct + /// + public static bool operator !=(MemberRelationship left, MemberRelationship right) => !left.Equals(right); } } diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/InterlockedBitVector32.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/InterlockedBitVector32.cs index 2190f32299fbb..7aa25ce5bdf63 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/InterlockedBitVector32.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/InterlockedBitVector32.cs @@ -11,7 +11,7 @@ namespace System.ComponentModel /// Provides a subset of the surface area, using volatile /// operations for reads and interlocked operations for writes. ///
- internal struct InterlockedBitVector32 + internal struct InterlockedBitVector32 : IEquatable { private int _data; @@ -44,7 +44,9 @@ public static int CreateMask(int previous) return previous == 0 ? 1 : previous << 1; } - public override bool Equals([NotNullWhen(true)] object? o) => o is InterlockedBitVector32 vector && _data == vector._data; + public override bool Equals([NotNullWhen(true)] object? o) => o is InterlockedBitVector32 other && Equals(other); + + public bool Equals(InterlockedBitVector32 other) => _data == other._data; public override int GetHashCode() => base.GetHashCode(); } diff --git a/src/libraries/System.Data.Common/ref/System.Data.Common.cs b/src/libraries/System.Data.Common/ref/System.Data.Common.cs index 569f83d8ac777..5e664573d5ea6 100644 --- a/src/libraries/System.Data.Common/ref/System.Data.Common.cs +++ b/src/libraries/System.Data.Common/ref/System.Data.Common.cs @@ -2737,7 +2737,7 @@ public SqlAlreadyFilledException(string? message) { } public SqlAlreadyFilledException(string? message, System.Exception? e) { } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlBinary : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlBinary : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private object _dummy; private int _dummyPrimitive; @@ -2752,6 +2752,7 @@ public partial struct SqlBinary : System.Data.SqlTypes.INullable, System.ICompar public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlBinary Concat(System.Data.SqlTypes.SqlBinary x, System.Data.SqlTypes.SqlBinary y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlBinary x, System.Data.SqlTypes.SqlBinary y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlBinary other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -2777,7 +2778,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public override string ToString() { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlBoolean : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlBoolean : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly System.Data.SqlTypes.SqlBoolean False; @@ -2796,6 +2797,7 @@ public partial struct SqlBoolean : System.Data.SqlTypes.INullable, System.ICompa public int CompareTo(System.Data.SqlTypes.SqlBoolean value) { throw null; } public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlBoolean x, System.Data.SqlTypes.SqlBoolean y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlBoolean other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -2847,7 +2849,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public static System.Data.SqlTypes.SqlBoolean Xor(System.Data.SqlTypes.SqlBoolean x, System.Data.SqlTypes.SqlBoolean y) { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlByte : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlByte : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly System.Data.SqlTypes.SqlByte MaxValue; @@ -2864,6 +2866,7 @@ public partial struct SqlByte : System.Data.SqlTypes.INullable, System.IComparab public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlByte Divide(System.Data.SqlTypes.SqlByte x, System.Data.SqlTypes.SqlByte y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlByte x, System.Data.SqlTypes.SqlByte y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlByte other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -2987,7 +2990,7 @@ public enum SqlCompareOptions BinarySort = 32768, } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlDateTime : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlDateTime : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly System.Data.SqlTypes.SqlDateTime MaxValue; @@ -3010,6 +3013,7 @@ public partial struct SqlDateTime : System.Data.SqlTypes.INullable, System.IComp public int CompareTo(System.Data.SqlTypes.SqlDateTime value) { throw null; } public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlDateTime x, System.Data.SqlTypes.SqlDateTime y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlDateTime other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -3038,7 +3042,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public override string ToString() { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlDecimal : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlDecimal : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly byte MaxPrecision; @@ -3068,6 +3072,7 @@ public partial struct SqlDecimal : System.Data.SqlTypes.INullable, System.ICompa public static System.Data.SqlTypes.SqlDecimal ConvertToPrecScale(System.Data.SqlTypes.SqlDecimal n, int precision, int scale) { throw null; } public static System.Data.SqlTypes.SqlDecimal Divide(System.Data.SqlTypes.SqlDecimal x, System.Data.SqlTypes.SqlDecimal y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlDecimal x, System.Data.SqlTypes.SqlDecimal y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlDecimal other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public static System.Data.SqlTypes.SqlDecimal Floor(System.Data.SqlTypes.SqlDecimal n) { throw null; } public override int GetHashCode() { throw null; } @@ -3124,7 +3129,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public static System.Data.SqlTypes.SqlDecimal Truncate(System.Data.SqlTypes.SqlDecimal n, int position) { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlDouble : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlDouble : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly System.Data.SqlTypes.SqlDouble MaxValue; @@ -3139,6 +3144,7 @@ public partial struct SqlDouble : System.Data.SqlTypes.INullable, System.ICompar public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlDouble Divide(System.Data.SqlTypes.SqlDouble x, System.Data.SqlTypes.SqlDouble y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlDouble x, System.Data.SqlTypes.SqlDouble y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlDouble other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -3187,7 +3193,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public override string ToString() { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlGuid : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlGuid : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private object _dummy; private int _dummyPrimitive; @@ -3201,6 +3207,7 @@ public partial struct SqlGuid : System.Data.SqlTypes.INullable, System.IComparab public int CompareTo(System.Data.SqlTypes.SqlGuid value) { throw null; } public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlGuid x, System.Data.SqlTypes.SqlGuid y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlGuid other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -3229,7 +3236,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public override string ToString() { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlInt16 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlInt16 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly System.Data.SqlTypes.SqlInt16 MaxValue; @@ -3246,6 +3253,7 @@ public partial struct SqlInt16 : System.Data.SqlTypes.INullable, System.ICompara public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlInt16 Divide(System.Data.SqlTypes.SqlInt16 x, System.Data.SqlTypes.SqlInt16 y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlInt16 x, System.Data.SqlTypes.SqlInt16 y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlInt16 other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -3303,7 +3311,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public static System.Data.SqlTypes.SqlInt16 Xor(System.Data.SqlTypes.SqlInt16 x, System.Data.SqlTypes.SqlInt16 y) { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlInt32 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlInt32 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly System.Data.SqlTypes.SqlInt32 MaxValue; @@ -3320,6 +3328,7 @@ public partial struct SqlInt32 : System.Data.SqlTypes.INullable, System.ICompara public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlInt32 Divide(System.Data.SqlTypes.SqlInt32 x, System.Data.SqlTypes.SqlInt32 y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlInt32 x, System.Data.SqlTypes.SqlInt32 y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlInt32 other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -3377,7 +3386,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public static System.Data.SqlTypes.SqlInt32 Xor(System.Data.SqlTypes.SqlInt32 x, System.Data.SqlTypes.SqlInt32 y) { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlInt64 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlInt64 : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly System.Data.SqlTypes.SqlInt64 MaxValue; @@ -3394,6 +3403,7 @@ public partial struct SqlInt64 : System.Data.SqlTypes.INullable, System.ICompara public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlInt64 Divide(System.Data.SqlTypes.SqlInt64 x, System.Data.SqlTypes.SqlInt64 y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlInt64 x, System.Data.SqlTypes.SqlInt64 y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlInt64 other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -3451,7 +3461,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public static System.Data.SqlTypes.SqlInt64 Xor(System.Data.SqlTypes.SqlInt64 x, System.Data.SqlTypes.SqlInt64 y) { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlMoney : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlMoney : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly System.Data.SqlTypes.SqlMoney MaxValue; @@ -3469,6 +3479,7 @@ public partial struct SqlMoney : System.Data.SqlTypes.INullable, System.ICompara public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlMoney Divide(System.Data.SqlTypes.SqlMoney x, System.Data.SqlTypes.SqlMoney y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlMoney x, System.Data.SqlTypes.SqlMoney y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlMoney other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -3535,7 +3546,7 @@ public SqlNullValueException(string? message) { } public SqlNullValueException(string? message, System.Exception? e) { } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlSingle : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlSingle : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private int _dummyPrimitive; public static readonly System.Data.SqlTypes.SqlSingle MaxValue; @@ -3551,6 +3562,7 @@ public partial struct SqlSingle : System.Data.SqlTypes.INullable, System.ICompar public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlSingle Divide(System.Data.SqlTypes.SqlSingle x, System.Data.SqlTypes.SqlSingle y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlSingle x, System.Data.SqlTypes.SqlSingle y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlSingle other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public static System.Xml.XmlQualifiedName GetXsdType(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } @@ -3599,7 +3611,7 @@ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter wri public override string ToString() { throw null; } } [System.Xml.Serialization.XmlSchemaProviderAttribute("GetXsdType")] - public partial struct SqlString : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable + public partial struct SqlString : System.Data.SqlTypes.INullable, System.IComparable, System.Xml.Serialization.IXmlSerializable, System.IEquatable { private object _dummy; private int _dummyPrimitive; @@ -3630,6 +3642,7 @@ public partial struct SqlString : System.Data.SqlTypes.INullable, System.ICompar public int CompareTo(object? value) { throw null; } public static System.Data.SqlTypes.SqlString Concat(System.Data.SqlTypes.SqlString x, System.Data.SqlTypes.SqlString y) { throw null; } public static System.Data.SqlTypes.SqlBoolean Equals(System.Data.SqlTypes.SqlString x, System.Data.SqlTypes.SqlString y) { throw null; } + public bool Equals(System.Data.SqlTypes.SqlString other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public override int GetHashCode() { throw null; } public byte[]? GetNonUnicodeBytes() { throw null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/DataKey.cs b/src/libraries/System.Data.Common/src/System/Data/DataKey.cs index 379035bb75d6b..7f1a15f75f51b 100644 --- a/src/libraries/System.Data.Common/src/System/Data/DataKey.cs +++ b/src/libraries/System.Data.Common/src/System/Data/DataKey.cs @@ -5,7 +5,7 @@ namespace System.Data { - internal readonly struct DataKey + internal readonly struct DataKey : IEquatable { private const int maxColumns = 32; @@ -154,7 +154,7 @@ public override bool Equals(object? value) return Equals((DataKey)value); } - internal bool Equals(DataKey value) + public bool Equals(DataKey value) { //check to see if this.columns && key2's columns are equal... DataColumn[] column1 = _columns; diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBinary.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBinary.cs index a757be446e73a..f6a45dbba5f2c 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBinary.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBinary.cs @@ -12,7 +12,7 @@ namespace System.Data.SqlTypes { [XmlSchemaProvider("GetXsdType")] - public struct SqlBinary : INullable, IComparable, IXmlSerializable + public struct SqlBinary : INullable, IComparable, IXmlSerializable, IEquatable { // NOTE: If any instance fields change, update SqlTypeWorkarounds type in System.Data.SqlClient. private byte[]? _value; @@ -362,20 +362,15 @@ public int CompareTo(SqlBinary value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlBinary)) - { - return false; - } - - SqlBinary i = (SqlBinary)value; - - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlBinary other && Equals(other); + + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlBinary other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // Hash a byte array. // Trailing zeroes/spaces would affect the hash value, so caller needs to diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBoolean.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBoolean.cs index 1efff18021e52..d7b723f9f05f0 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBoolean.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLBoolean.cs @@ -18,7 +18,7 @@ namespace System.Data.SqlTypes [StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public struct SqlBoolean : INullable, IComparable, IXmlSerializable + public struct SqlBoolean : INullable, IComparable, IXmlSerializable, IEquatable { // m_value: 2 (true), 1 (false), 0 (unknown/Null) private byte m_value; // Do not rename (binary serialization) @@ -465,26 +465,18 @@ public int CompareTo(SqlBoolean value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlBoolean)) - { - return false; - } - - SqlBoolean i = (SqlBoolean)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlBoolean other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlBoolean other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { - return IsNull ? 0 : Value.GetHashCode(); - } + public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLByte.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLByte.cs index f7c1cdde43226..3dc5548ffed7a 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLByte.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLByte.cs @@ -18,7 +18,7 @@ namespace System.Data.SqlTypes [StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public struct SqlByte : INullable, IComparable, IXmlSerializable + public struct SqlByte : INullable, IComparable, IXmlSerializable, IEquatable { private bool m_fNotNull; // false if null. Do not rename (binary serialization) private byte m_value; // Do not rename (binary serialization) @@ -474,26 +474,18 @@ public int CompareTo(SqlByte value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlByte)) - { - return false; - } - - SqlByte i = (SqlByte)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlByte other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlByte other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { - return IsNull ? 0 : Value.GetHashCode(); - } + public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDateTime.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDateTime.cs index 195ca26628ea4..1edd44bedf338 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDateTime.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDateTime.cs @@ -21,7 +21,7 @@ namespace System.Data.SqlTypes [StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public struct SqlDateTime : INullable, IComparable, IXmlSerializable + public struct SqlDateTime : INullable, IComparable, IXmlSerializable, IEquatable { private bool m_fNotNull; // false if null. Do not rename (binary serialization) private int m_day; // Day from 1900/1/1, could be negative. Range: Jan 1 1753 - Dec 31 9999. Do not rename (binary serialization) @@ -621,26 +621,18 @@ public int CompareTo(SqlDateTime value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlDateTime)) - { - return false; - } - - SqlDateTime i = (SqlDateTime)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlDateTime other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlDateTime other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { - return IsNull ? 0 : Value.GetHashCode(); - } + public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs index 784d50d2bb1cf..336639fbf0e5b 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs @@ -18,7 +18,7 @@ namespace System.Data.SqlTypes ///
[StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] - public struct SqlDecimal : INullable, IComparable, IXmlSerializable + public struct SqlDecimal : INullable, IComparable, IXmlSerializable, IEquatable { // data in CSsNumeric in SQL Server // BYTE m_cbLen; // # of DWORDs + 1 (1 is for sign) @@ -3278,20 +3278,15 @@ public int CompareTo(SqlDecimal value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlDecimal)) - { - return false; - } - - SqlDecimal i = (SqlDecimal)value; - - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlDecimal other && Equals(other); + + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlDecimal other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose public override int GetHashCode() diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDouble.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDouble.cs index 3f10f94312400..4cc9ac4e321e0 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDouble.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDouble.cs @@ -19,7 +19,7 @@ namespace System.Data.SqlTypes [StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public struct SqlDouble : INullable, IComparable, IXmlSerializable + public struct SqlDouble : INullable, IComparable, IXmlSerializable, IEquatable { private bool m_fNotNull; // false if null. Do not rename (binary serialization) private double m_value; // Do not rename (binary serialization) @@ -390,26 +390,18 @@ public int CompareTo(SqlDouble value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlDouble)) - { - return false; - } - - SqlDouble i = (SqlDouble)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlDouble other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlDouble other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { - return IsNull ? 0 : Value.GetHashCode(); - } + public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLGuid.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLGuid.cs index 8e3c58dff3dad..2742c25d53b53 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLGuid.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLGuid.cs @@ -16,7 +16,7 @@ namespace System.Data.SqlTypes [Serializable] [XmlSchemaProvider("GetXsdType")] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public struct SqlGuid : INullable, IComparable, IXmlSerializable + public struct SqlGuid : INullable, IComparable, IXmlSerializable, IEquatable { private const int SizeOfGuid = 16; @@ -281,26 +281,18 @@ public int CompareTo(SqlGuid value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlGuid)) - { - return false; - } - - SqlGuid i = (SqlGuid)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlGuid other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlGuid other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { - return IsNull ? 0 : Value.GetHashCode(); - } + public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt16.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt16.cs index 5833a00938561..d3879a06cf91b 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt16.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt16.cs @@ -17,7 +17,7 @@ namespace System.Data.SqlTypes [StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public struct SqlInt16 : INullable, IComparable, IXmlSerializable + public struct SqlInt16 : INullable, IComparable, IXmlSerializable, IEquatable { private bool m_fNotNull; // false if null. Do not rename (binary serialization) private short m_value; // Do not rename (binary serialization) @@ -475,26 +475,18 @@ public int CompareTo(SqlInt16 value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlInt16)) - { - return false; - } - - SqlInt16 i = (SqlInt16)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlInt16 other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlInt16 other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { - return IsNull ? 0 : Value.GetHashCode(); - } + public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt32.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt32.cs index 271d6509e71f5..8ce08e74e4403 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt32.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt32.cs @@ -17,7 +17,7 @@ namespace System.Data.SqlTypes [StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public struct SqlInt32 : INullable, IComparable, IXmlSerializable + public struct SqlInt32 : INullable, IComparable, IXmlSerializable, IEquatable { private bool m_fNotNull; // false if null, the default ctor (plain 0) will make it Null. Do not rename (binary serialization) private int m_value; // Do not rename (binary serialization) @@ -490,26 +490,18 @@ public int CompareTo(SqlInt32 value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlInt32)) - { - return false; - } - - SqlInt32 i = (SqlInt32)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlInt32 other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlInt32 other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { - return IsNull ? 0 : Value.GetHashCode(); - } + public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt64.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt64.cs index b7f33674ce03a..393945b030395 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt64.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLInt64.cs @@ -18,7 +18,7 @@ namespace System.Data.SqlTypes [StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public struct SqlInt64 : INullable, IComparable, IXmlSerializable + public struct SqlInt64 : INullable, IComparable, IXmlSerializable, IEquatable { private bool m_fNotNull; // false if null. Do not rename (binary serialization) private long m_value; // Do not rename (binary serialization) @@ -549,26 +549,18 @@ public int CompareTo(SqlInt64 value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlInt64)) - { - return false; - } - - SqlInt64 i = (SqlInt64)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlInt64 other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlInt64 other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { - return IsNull ? 0 : Value.GetHashCode(); - } + public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLMoney.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLMoney.cs index 5431c8737d4af..64c0d168631c8 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLMoney.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLMoney.cs @@ -21,7 +21,7 @@ namespace System.Data.SqlTypes ///
[StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] - public struct SqlMoney : INullable, IComparable, IXmlSerializable + public struct SqlMoney : INullable, IComparable, IXmlSerializable, IEquatable { // NOTE: If any instance fields change, update SqlTypeWorkarounds type in System.Data.SqlClient. private bool _fNotNull; // false if null @@ -539,27 +539,20 @@ public int CompareTo(SqlMoney value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlMoney)) - { - return false; - } - - SqlMoney i = (SqlMoney)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlMoney other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlMoney other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { + public override int GetHashCode() => // Don't use Value property, because Value will convert to Decimal, which is not necessary. - return IsNull ? 0 : _value.GetHashCode(); - } + IsNull ? 0 : _value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLSingle.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLSingle.cs index 59f29dcc89cbc..5fa7562824e13 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLSingle.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLSingle.cs @@ -17,7 +17,7 @@ namespace System.Data.SqlTypes /// [StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] - public struct SqlSingle : INullable, IComparable, IXmlSerializable + public struct SqlSingle : INullable, IComparable, IXmlSerializable, IEquatable { private bool _fNotNull; // false if null private float _value; @@ -400,26 +400,18 @@ public int CompareTo(SqlSingle value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlSingle)) - { - return false; - } - - SqlSingle i = (SqlSingle)value; + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlSingle other && Equals(other); - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlSingle other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose - public override int GetHashCode() - { - return IsNull ? 0 : Value.GetHashCode(); - } + public override int GetHashCode() => IsNull ? 0 : Value.GetHashCode(); XmlSchema? IXmlSerializable.GetSchema() { return null; } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLString.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLString.cs index cac4122feba68..0c22570d2462d 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLString.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLString.cs @@ -34,7 +34,7 @@ public enum SqlCompareOptions [StructLayout(LayoutKind.Sequential)] [XmlSchemaProvider("GetXsdType")] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public struct SqlString : INullable, IComparable, IXmlSerializable + public struct SqlString : INullable, IComparable, IXmlSerializable, IEquatable { private string? m_value; // Do not rename (binary serialization) private CompareInfo? m_cmpInfo; // Do not rename (binary serialization) @@ -871,20 +871,15 @@ public int CompareTo(SqlString value) } // Compares this instance with a specified object - public override bool Equals([NotNullWhen(true)] object? value) - { - if (!(value is SqlString)) - { - return false; - } - - SqlString i = (SqlString)value; - - if (i.IsNull || IsNull) - return (i.IsNull && IsNull); - else - return (this == i).Value; - } + public override bool Equals([NotNullWhen(true)] object? value) => + value is SqlString other && Equals(other); + + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(SqlString other) => + other.IsNull || IsNull ? other.IsNull && IsNull : + (this == other).Value; // For hashing purpose public override int GetHashCode() diff --git a/src/libraries/System.Data.Common/src/System/Data/Selection.cs b/src/libraries/System.Data.Common/src/System/Data/Selection.cs index 21a6d951393c1..fd76acfda7c36 100644 --- a/src/libraries/System.Data.Common/src/System/Data/Selection.cs +++ b/src/libraries/System.Data.Common/src/System/Data/Selection.cs @@ -9,7 +9,7 @@ namespace System.Data { - internal readonly struct IndexField + internal readonly struct IndexField : IEquatable { public readonly DataColumn Column; public readonly bool IsDescending; // false = Asc; true = Desc what is default value for this? @@ -22,15 +22,15 @@ internal IndexField(DataColumn column, bool isDescending) IsDescending = isDescending; } - public static bool operator ==(IndexField if1, IndexField if2) => - if1.Column == if2.Column && if1.IsDescending == if2.IsDescending; + public static bool operator ==(IndexField if1, IndexField if2) => if1.Equals(if2); - public static bool operator !=(IndexField if1, IndexField if2) => !(if1 == if2); + public static bool operator !=(IndexField if1, IndexField if2) => !if1.Equals(if2); // must override Equals if == operator is defined - public override bool Equals([NotNullWhen(true)] object? obj) => obj is IndexField ? - this == (IndexField)obj : - false; + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is IndexField other && Equals(other); + + public bool Equals(IndexField other) => Column == other.Column && IsDescending == other.IsDescending; // must override GetHashCode if Equals is redefined public override int GetHashCode() => diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBinaryTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBinaryTest.cs index 6a631b392bea9..8655d3feea003 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBinaryTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBinaryTest.cs @@ -122,8 +122,11 @@ public void ComparisonMethods() // Equals Assert.False(_test1.Equals(_test2)); + Assert.False(_test1.Equals((object)_test2)); Assert.False(_test3.Equals(_test2)); + Assert.False(_test3.Equals((object)_test2)); Assert.True(_test3.Equals(_test1)); + Assert.True(_test3.Equals((object)_test1)); // NotEquals Assert.True(SqlBinary.NotEquals(_test1, _test2).Value); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBooleanTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBooleanTest.cs index 4da63a4bcdcf8..b52f671dad2d4 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBooleanTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlBooleanTest.cs @@ -242,10 +242,14 @@ public void EqualsTest() SqlBoolean sqlFalse2 = new SqlBoolean(false); Assert.True(_sqlTrue.Equals(sqlTrue2)); + Assert.True(_sqlTrue.Equals((object)sqlTrue2)); Assert.True(_sqlFalse.Equals(sqlFalse2)); + Assert.True(_sqlFalse.Equals((object)sqlFalse2)); Assert.False(_sqlTrue.Equals(_sqlFalse)); + Assert.False(_sqlTrue.Equals((object)_sqlFalse)); Assert.False(_sqlFalse.Equals(_sqlTrue)); + Assert.False(_sqlFalse.Equals((object)_sqlTrue)); Assert.False(_sqlTrue.Equals(SqlBoolean.Null)); Assert.False(_sqlFalse.Equals(SqlBoolean.Null)); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlByteTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlByteTest.cs index 2ae5976e9f1a9..9af75f4f46997 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlByteTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlByteTest.cs @@ -155,9 +155,12 @@ public void EqualsMethod() SqlByte testByte180II = new SqlByte(180); Assert.False(testByte0.Equals(testByte158)); + Assert.False(testByte0.Equals((object)testByte158)); Assert.False(testByte158.Equals(testByte180)); + Assert.False(testByte158.Equals((object)testByte180)); Assert.False(testByte180.Equals(new SqlString("TEST"))); Assert.True(testByte180.Equals(testByte180II)); + Assert.True(testByte180.Equals((object)testByte180II)); } [Fact] diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDateTimeTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDateTimeTest.cs index 6d3287ed49b0f..0c835ff00c540 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDateTimeTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDateTimeTest.cs @@ -175,8 +175,10 @@ public void CompareTo() public void EqualsMethods() { Assert.False(_test1.Equals(_test2)); + Assert.False(_test1.Equals((object)_test2)); Assert.False(_test2.Equals(new SqlString("TEST"))); Assert.True(_test2.Equals(_test3)); + Assert.True(_test2.Equals((object)_test3)); // Static Equals()-method Assert.True(SqlDateTime.Equals(_test2, _test3).Value); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDecimalTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDecimalTest.cs index 6fd72ba4157aa..b9807ebcc102e 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDecimalTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDecimalTest.cs @@ -225,8 +225,10 @@ public void CompareTo() public void EqualsMethods() { Assert.False(_test1.Equals(_test2)); + Assert.False(_test1.Equals((object)_test2)); Assert.False(_test2.Equals(new SqlString("TEST"))); Assert.True(_test2.Equals(_test3)); + Assert.True(_test2.Equals((object)_test3)); // Static Equals()-method Assert.True(SqlDecimal.Equals(_test2, _test2).Value); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDoubleTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDoubleTest.cs index 4f0856e2ba226..db913271dc020 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDoubleTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlDoubleTest.cs @@ -134,9 +134,12 @@ public void EqualsMethods() SqlDouble test22 = new SqlDouble(1.8e180); Assert.False(test0.Equals(test1)); + Assert.False(test0.Equals((object)test1)); Assert.False(test1.Equals(test2)); + Assert.False(test1.Equals((object)test2)); Assert.False(test2.Equals(new SqlString("TEST"))); Assert.True(test2.Equals(test22)); + Assert.True(test2.Equals((object)test22)); // Static Equals()-method Assert.True(SqlDouble.Equals(test2, test22).Value); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlGuidTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlGuidTest.cs index 84dcb3a3f5373..4c21e38d07ef2 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlGuidTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlGuidTest.cs @@ -126,9 +126,12 @@ public void CompareTo() public void EqualsMethods() { Assert.False(_test1.Equals(_test2)); + Assert.False(_test1.Equals((object)_test2)); Assert.False(_test2.Equals(_test4)); + Assert.False(_test2.Equals((object)_test4)); Assert.False(_test2.Equals(new SqlString("TEST"))); Assert.True(_test2.Equals(_test3)); + Assert.True(_test2.Equals((object)_test3)); // Static Equals()-method Assert.True(SqlGuid.Equals(_test2, _test3).Value); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt16Test.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt16Test.cs index 3c240d6d9ed0f..7c00f4845884d 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt16Test.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt16Test.cs @@ -157,9 +157,12 @@ public void EqualsMethod() SqlInt16 test180II = new SqlInt16(180); Assert.False(test0.Equals(test158)); + Assert.False(test0.Equals((object)test158)); Assert.False(test158.Equals(test180)); + Assert.False(test158.Equals((object)test180)); Assert.False(test180.Equals(new SqlString("TEST"))); Assert.True(test180.Equals(test180II)); + Assert.True(test180.Equals((object)test180II)); } [Fact] diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt64Test.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt64Test.cs index 601b6a8bdb1bc..ed466fb50b277 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt64Test.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlInt64Test.cs @@ -159,9 +159,12 @@ public void EqualsMethod() SqlInt64 test180II = new SqlInt64(180); Assert.False(test0.Equals(test158)); + Assert.False(test0.Equals((object)test158)); Assert.False(test158.Equals(test180)); + Assert.False(test158.Equals((object)test180)); Assert.False(test180.Equals(new SqlString("TEST"))); Assert.True(test180.Equals(test180II)); + Assert.True(test180.Equals((object)test180II)); } [Fact] diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlMoneyTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlMoneyTest.cs index 726302190b388..db99ba4de6691 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlMoneyTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlMoneyTest.cs @@ -131,7 +131,9 @@ public void CompareTo() public void EqualsMethods() { Assert.False(_test1.Equals(_test2)); + Assert.False(_test1.Equals((object)_test2)); Assert.True(_test2.Equals(_test3)); + Assert.True(_test2.Equals((object)_test3)); Assert.False(SqlMoney.Equals(_test1, _test2).Value); Assert.True(SqlMoney.Equals(_test3, _test2).Value); } diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlSingleTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlSingleTest.cs index 2c92e08226e49..3ff6c803aaef6 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlSingleTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlSingleTest.cs @@ -132,9 +132,12 @@ public void EqualsMethods() SqlSingle test22 = new SqlSingle(1.8e32); Assert.False(test0.Equals(test1)); + Assert.False(test0.Equals((object)test1)); Assert.False(test1.Equals(test2)); + Assert.False(test1.Equals((object)test2)); Assert.False(test2.Equals(new SqlString("TEST"))); Assert.True(test2.Equals(test22)); + Assert.True(test2.Equals((object)test22)); // Static Equals()-method Assert.True(SqlSingle.Equals(test2, test22).Value); diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringTest.cs index 86a4b1683c4c9..56f8fa51b06ca 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringTest.cs @@ -262,9 +262,12 @@ public void CompareTo() public void EqualsMethods() { Assert.False(_test1.Equals(_test2)); + Assert.False(_test1.Equals((object)_test2)); Assert.False(_test3.Equals(_test1)); + Assert.False(_test3.Equals((object)_test1)); Assert.False(_test2.Equals(new SqlString("TEST"))); Assert.True(_test2.Equals(_test3)); + Assert.True(_test2.Equals((object)_test3)); // Static Equals()-method Assert.True(SqlString.Equals(_test2, _test3).Value); diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.csproj b/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.csproj index 9851685566186..220c3e850b5f1 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.csproj +++ b/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.csproj @@ -6,6 +6,7 @@ + @@ -18,4 +19,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.netcoreapp.cs b/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.netcoreapp.cs new file mode 100644 index 0000000000000..b33f32066185b --- /dev/null +++ b/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.netcoreapp.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. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ + +namespace System.Diagnostics +{ + public readonly partial struct CounterSample : System.IEquatable + { + } +} diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj b/src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj index 28133feec83ed..5ebf58e40c57e 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj @@ -3,6 +3,7 @@ true $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);$(NetCoreAppMinimum)-windows;$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) $(NoWarn);CA1847 + $(NoWarn);CA1066 annotations true Provides the System.Diagnostics.PerformanceCounter class, which allows access to Windows performance counters. diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/CounterSample.cs b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/CounterSample.cs index c89df23ed9aac..315ec5a87ccb4 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/CounterSample.cs +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/CounterSample.cs @@ -6,7 +6,7 @@ namespace System.Diagnostics /// /// A struct holding the raw data for a performance counter. /// - public readonly struct CounterSample + public readonly struct CounterSample : IEquatable { private readonly long _rawValue; private readonly long _baseValue; diff --git a/src/libraries/System.Diagnostics.StackTrace/ref/System.Diagnostics.StackTrace.cs b/src/libraries/System.Diagnostics.StackTrace/ref/System.Diagnostics.StackTrace.cs index 0efbf90bb1da1..60e755ecf790c 100644 --- a/src/libraries/System.Diagnostics.StackTrace/ref/System.Diagnostics.StackTrace.cs +++ b/src/libraries/System.Diagnostics.StackTrace/ref/System.Diagnostics.StackTrace.cs @@ -170,7 +170,7 @@ public enum SymAddressKind BitField = 9, NativeSectionOffset = 10, } - public readonly partial struct SymbolToken + public readonly partial struct SymbolToken : System.IEquatable { private readonly int _dummyPrimitive; public SymbolToken(int val) { throw null; } diff --git a/src/libraries/System.Diagnostics.StackTrace/src/System/Diagnostics/SymbolStore/SymbolToken.cs b/src/libraries/System.Diagnostics.StackTrace/src/System/Diagnostics/SymbolStore/SymbolToken.cs index b6a894f144fc9..8b27f618770fb 100644 --- a/src/libraries/System.Diagnostics.StackTrace/src/System/Diagnostics/SymbolStore/SymbolToken.cs +++ b/src/libraries/System.Diagnostics.StackTrace/src/System/Diagnostics/SymbolStore/SymbolToken.cs @@ -5,7 +5,7 @@ namespace System.Diagnostics.SymbolStore { - public readonly struct SymbolToken + public readonly struct SymbolToken : IEquatable { private readonly int _token; diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.netcoreapp.cs b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.netcoreapp.cs index f9d987de24d1c..1514ee19e8c33 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.netcoreapp.cs +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.netcoreapp.cs @@ -6,6 +6,10 @@ namespace System.Drawing { + public partial struct CharacterRange : System.IEquatable + { + public bool Equals(System.Drawing.CharacterRange other) { throw null; } + } public sealed partial class Graphics { public void DrawRectangle(System.Drawing.Pen pen, System.Drawing.RectangleF rect) { } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/CharacterRange.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/CharacterRange.cs index 157533b84283c..a0dccdc4b2876 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/CharacterRange.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/CharacterRange.cs @@ -7,51 +7,43 @@ namespace System.Drawing { [StructLayout(LayoutKind.Sequential)] - public struct CharacterRange + public struct CharacterRange : IEquatable { private int _first; private int _length; - /// - /// Initializes a new instance of the class with the specified coordinates. - /// + /// Initializes a new instance of the class with the specified coordinates. public CharacterRange(int First, int Length) { _first = First; _length = Length; } - /// - /// Gets the First character position of this . - /// + /// Gets the First character position of this . public int First { get => _first; set => _first = value; } - /// - /// Gets the Length of this . - /// + /// Gets the Length of this . public int Length { get => _length; set => _length = value; } - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (!(obj is CharacterRange cr)) - { - return false; - } + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is CharacterRange other && Equals(other); - return First == cr.First && Length == cr.Length; - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(CharacterRange other) => First == other.First && Length == other.Length; public static bool operator ==(CharacterRange cr1, CharacterRange cr2) => cr1.Equals(cr2); - public static bool operator !=(CharacterRange cr1, CharacterRange cr2) => !(cr1 == cr2); + public static bool operator !=(CharacterRange cr1, CharacterRange cr2) => !cr1.Equals(cr2); public override int GetHashCode() => HashCode.Combine(First, Length); } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/TriState.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/TriState.cs index 665a642a3e4f3..bb7b163d1ce95 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/TriState.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/TriState.cs @@ -1,9 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + namespace System.Drawing.Printing { - internal readonly partial struct TriState + internal readonly partial struct TriState : IEquatable { private readonly byte _value; // 0 is "default", not false @@ -11,73 +14,46 @@ internal readonly partial struct TriState public static readonly TriState False = new TriState(1); public static readonly TriState True = new TriState(2); - private TriState(byte value) - { - _value = value; - } + private TriState(byte value) => _value = value; - public bool IsDefault - { - get { return this == Default; } - } + public bool IsDefault => this == Default; - public bool IsFalse - { - get { return this == False; } - } + public bool IsFalse => this == False; - public bool IsNotDefault - { - get { return this != Default; } - } + public bool IsNotDefault => this != Default; - public bool IsTrue - { - get { return this == True; } - } + public bool IsTrue => this == True; - public static bool operator ==(TriState left, TriState right) - { - return left._value == right._value; - } + public static bool operator ==(TriState left, TriState right) => left.Equals(right); - public static bool operator !=(TriState left, TriState right) - { - return !(left == right); - } + public static bool operator !=(TriState left, TriState right) => !left.Equals(right); - public override bool Equals(object? o) + public override bool Equals([NotNullWhen(true)] object? o) { - TriState state = (TriState)o!; - return _value == state._value; + Debug.Assert(o is TriState); + return Equals((TriState)o); } - public override int GetHashCode() - { - return _value; - } + public bool Equals(TriState other) => _value == other._value; - public static implicit operator TriState(bool value) - { - return (value) ? True : False; - } + public override int GetHashCode() => _value; + + public static implicit operator TriState(bool value) => value ? True : False; public static explicit operator bool(TriState value) { if (value.IsDefault) + { throw new InvalidCastException(SR.TriStateCompareError); - else - return (value == TriState.True); - } + } - /// - /// Provides some interesting information about the TriState in String form. - /// - public override string ToString() - { - if (this == Default) return "Default"; - else if (this == False) return "False"; - else return "True"; + return (value == TriState.True); } + + /// Provides some interesting information about the TriState in String form. + public override string ToString() => + this == Default ? "Default" : + this == False ? "False" : + "True"; } } diff --git a/src/libraries/System.Drawing.Common/tests/CharacterRangeTests.cs b/src/libraries/System.Drawing.Common/tests/CharacterRangeTests.cs index 7147cb809be6b..989ee85c09312 100644 --- a/src/libraries/System.Drawing.Common/tests/CharacterRangeTests.cs +++ b/src/libraries/System.Drawing.Common/tests/CharacterRangeTests.cs @@ -84,6 +84,7 @@ public void Equals_Invoke_ReturnsExpected(CharacterRange range, object obj, bool Assert.Equal(expected, range.Equals(obj)); if (obj is CharacterRange otherRange) { + Assert.Equal(expected, range.Equals(otherRange)); Assert.Equal(expected, range == otherRange); Assert.Equal(!expected, range != otherRange); Assert.Equal(expected, range.GetHashCode().Equals(otherRange.GetHashCode())); diff --git a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.cs b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.cs index 15c89947da327..5825a149f3315 100644 --- a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.cs +++ b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.cs @@ -611,7 +611,9 @@ private static bool IsPartNameEmpty(string partName) /// to reduce the parsing and number of allocations for Strings and Uris /// we cache the results after parsing. /// + #pragma warning disable CA1067 // Override Equals because it implements IEquatable; not overriding to avoid possible regressions in code that's working internal sealed class ValidatedPartUri : Uri, IComparable, IEquatable +#pragma warning restore CA1067 { //------------------------------------------------------ // diff --git a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LocalVariables.cs b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LocalVariables.cs index d078d82a597f4..f42254df42dd3 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LocalVariables.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LocalVariables.cs @@ -44,7 +44,7 @@ public override string ToString() => string.Create(CultureInfo.InvariantCulture, $"{Index}: {(IsBoxed ? "boxed" : null)} {(InClosure ? "in closure" : null)}"); } - internal readonly struct LocalDefinition + internal readonly struct LocalDefinition : IEquatable { internal LocalDefinition(int localIndex, ParameterExpression parameter) { @@ -53,27 +53,14 @@ internal LocalDefinition(int localIndex, ParameterExpression parameter) } public int Index { get; } + public ParameterExpression Parameter { get; } - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj is LocalDefinition) - { - LocalDefinition other = (LocalDefinition)obj; - return other.Index == Index && other.Parameter == Parameter; - } + public override bool Equals([NotNullWhen(true)] object? obj) => obj is LocalDefinition other && Equals(other); - return false; - } + public bool Equals(LocalDefinition other) => other.Index == Index && other.Parameter == Parameter; - public override int GetHashCode() - { - if (Parameter == null) - { - return 0; - } - return Parameter.GetHashCode() ^ Index.GetHashCode(); - } + public override int GetHashCode() => Parameter is null ? 0 : Parameter.GetHashCode() ^ Index.GetHashCode(); } internal sealed class LocalVariables diff --git a/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs b/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs index 212c063b3b330..e813cca044ee0 100644 --- a/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs +++ b/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs @@ -74,13 +74,14 @@ public enum IOControlCode : long [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] AddressListSort = (long)3355443225, } - public partial struct IPPacketInformation + public partial struct IPPacketInformation : System.IEquatable { private object _dummy; private int _dummyPrimitive; public System.Net.IPAddress Address { get { throw null; } } public int Interface { get { throw null; } } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] object? comparand) { throw null; } + public bool Equals(System.Net.Sockets.IPPacketInformation other) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(System.Net.Sockets.IPPacketInformation packetInformation1, System.Net.Sockets.IPPacketInformation packetInformation2) { throw null; } public static bool operator !=(System.Net.Sockets.IPPacketInformation packetInformation1, System.Net.Sockets.IPPacketInformation packetInformation2) { throw null; } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/IPPacketInformation.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/IPPacketInformation.cs index 06d4eca31750b..b0597b626c480 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/IPPacketInformation.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/IPPacketInformation.cs @@ -5,7 +5,7 @@ namespace System.Net.Sockets { - public struct IPPacketInformation + public struct IPPacketInformation : IEquatable { private readonly IPAddress _address; private readonly int _networkInterface; @@ -16,41 +16,27 @@ internal IPPacketInformation(IPAddress address, int networkInterface) _networkInterface = networkInterface; } - public IPAddress Address - { - get - { - return _address; - } - } + public IPAddress Address => _address; - public int Interface - { - get - { - return _networkInterface; - } - } + public int Interface => _networkInterface; - public static bool operator ==(IPPacketInformation packetInformation1, IPPacketInformation packetInformation2) - { - return packetInformation1._networkInterface == packetInformation2._networkInterface && - ((packetInformation1._address == null && packetInformation2._address == null) || - (packetInformation1._address != null && packetInformation1._address.Equals(packetInformation2._address))); - } + public static bool operator ==(IPPacketInformation packetInformation1, IPPacketInformation packetInformation2) => + packetInformation1.Equals(packetInformation2); - public static bool operator !=(IPPacketInformation packetInformation1, IPPacketInformation packetInformation2) - { - return !(packetInformation1 == packetInformation2); - } + public static bool operator !=(IPPacketInformation packetInformation1, IPPacketInformation packetInformation2) => + !packetInformation1.Equals(packetInformation2); public override bool Equals([NotNullWhen(true)] object? comparand) => - comparand is IPPacketInformation other && this == other; + comparand is IPPacketInformation other && Equals(other); - public override int GetHashCode() - { - return unchecked(_networkInterface.GetHashCode() * (int)0xA5555529) + - (_address == null ? 0 : _address.GetHashCode()); - } + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(IPPacketInformation other) => + _networkInterface == other._networkInterface && + (_address is null ? other._address is null : _address.Equals(other._address)); + + public override int GetHashCode() => + unchecked(_networkInterface.GetHashCode() * (int)0xA5555529) + (_address?.GetHashCode() ?? 0); } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs index 443924b66d2b4..19dbc7f470d00 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs @@ -13,7 +13,10 @@ public class IPPacketInformationTest public void Equals_DefaultValues_Success() { Assert.Equal(default(IPPacketInformation), default(IPPacketInformation)); + Assert.True(default(IPPacketInformation) == default(IPPacketInformation)); + Assert.True(default(IPPacketInformation).Equals(default(IPPacketInformation))); + Assert.False(default(IPPacketInformation) != default(IPPacketInformation)); } @@ -31,10 +34,14 @@ public void Equals_NonDefaultValue_Success() Assert.Equal(packetInfo, packetInfoCopy); Assert.True(packetInfo == packetInfoCopy); + Assert.True(packetInfo.Equals(packetInfoCopy)); + Assert.True(packetInfo.Equals((object)packetInfoCopy)); Assert.False(packetInfo != packetInfoCopy); Assert.NotEqual(default, packetInfo); Assert.False(packetInfo == default(IPPacketInformation)); + Assert.False(packetInfo.Equals(default(IPPacketInformation))); + Assert.False(packetInfo.Equals((object)default(IPPacketInformation))); Assert.True(packetInfo != default(IPPacketInformation)); int ignored = packetInfo.Interface; // just make sure it doesn't throw, nothing else to verify diff --git a/src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs b/src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs index 06c31c4d6e009..2d6c817b87268 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs @@ -26,8 +26,16 @@ namespace System // (ie, users could assign a new value to the old location). [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] +#pragma warning disable CA1066 // adding IEquatable implementation could change semantics of code like that in xunit that queries for IEquatable vs enumerating contents public readonly struct ArraySegment : IList, IReadOnlyList +#pragma warning restore CA1066 { + // ArraySegment doesn't implement IEquatable, even though it provides a strongly-typed + // Equals(T), as that results in different comparison semantics than comparing item-by-item + // the elements returned from its IEnumerable implementation. This then is a breaking change + // for usage like that in xunit's Assert.Equal, which will prioritize using an instance's IEquatable + // over its IEnumerable. + // Do not replace the array allocation with Array.Empty. We don't want to have the overhead of // instantiating another generic type in addition to ArraySegment for new type parameters. #pragma warning disable CA1825 @@ -120,7 +128,7 @@ public void CopyTo(ArraySegment destination) } public override bool Equals([NotNullWhen(true)] object? obj) => - obj is ArraySegment && Equals((ArraySegment)obj); + obj is ArraySegment other && Equals(other); public bool Equals(ArraySegment obj) => obj._array == _array && obj._offset == _offset && obj._count == _count; diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventDescriptor.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventDescriptor.cs index c3994e613a316..b1aaccd7f7f7c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventDescriptor.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventDescriptor.cs @@ -15,7 +15,7 @@ namespace System.Diagnostics.Tracing #if ES_BUILD_STANDALONE [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] #endif - internal struct EventDescriptor + internal readonly struct EventDescriptor : IEquatable { #region private [FieldOffset(0)] diff --git a/src/libraries/System.Private.CoreLib/src/System/HashCode.cs b/src/libraries/System.Private.CoreLib/src/System/HashCode.cs index d9735f05b4434..f40830e416d36 100644 --- a/src/libraries/System.Private.CoreLib/src/System/HashCode.cs +++ b/src/libraries/System.Private.CoreLib/src/System/HashCode.cs @@ -47,6 +47,8 @@ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; +#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals + namespace System { // xxHash32 is used for the hash code. diff --git a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs index 7fb1803d6f5ab..355578395db40 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs @@ -11,6 +11,8 @@ using Internal.Runtime.CompilerServices; #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types +#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals + #if TARGET_64BIT using nint_t = System.Int64; #else diff --git a/src/libraries/System.Private.CoreLib/src/System/Nullable.cs b/src/libraries/System.Private.CoreLib/src/System/Nullable.cs index 0fa9141483ee2..089f970057dc8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Nullable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Nullable.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Runtime.Versioning; +#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals + namespace System { // Because we have special type system support that says a boxed Nullable diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeNamedArgument.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeNamedArgument.cs index 9699e14e5d1e5..b2baa777460a6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeNamedArgument.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeNamedArgument.cs @@ -1,9 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace System.Reflection { - public readonly partial struct CustomAttributeNamedArgument + public readonly partial struct CustomAttributeNamedArgument : IEquatable { public static bool operator ==(CustomAttributeNamedArgument left, CustomAttributeNamedArgument right) => left.Equals(right); public static bool operator !=(CustomAttributeNamedArgument left, CustomAttributeNamedArgument right) => !left.Equals(right); @@ -46,10 +48,15 @@ public override int GetHashCode() return base.GetHashCode(); } - public override bool Equals(object? obj) - { - return obj == (object)this; - } + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is CustomAttributeNamedArgument other && Equals(other); + + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(CustomAttributeNamedArgument other) => + _memberInfo == other._memberInfo && + _value == other._value; internal Type ArgumentType => _memberInfo is FieldInfo fi ? diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeTypedArgument.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeTypedArgument.cs index 3198e9fd45802..b0e306af8f838 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeTypedArgument.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/CustomAttributeTypedArgument.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Text; namespace System.Reflection { - public readonly partial struct CustomAttributeTypedArgument + public readonly partial struct CustomAttributeTypedArgument : IEquatable { public static bool operator ==(CustomAttributeTypedArgument left, CustomAttributeTypedArgument right) => left.Equals(right); public static bool operator !=(CustomAttributeTypedArgument left, CustomAttributeTypedArgument right) => !left.Equals(right); @@ -86,7 +87,13 @@ internal string ToString(bool typed) } public override int GetHashCode() => base.GetHashCode(); - public override bool Equals(object? obj) => obj == (object)this; + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is CustomAttributeTypedArgument cata && Equals(cata); + + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(CustomAttributeTypedArgument other) => _value == other._value && _argumentType == other._argumentType; public Type ArgumentType => _argumentType; public object? Value => _value; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ArrayWithOffset.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ArrayWithOffset.cs index 8a80faa9977b6..92d42d6795567 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ArrayWithOffset.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ArrayWithOffset.cs @@ -6,7 +6,7 @@ namespace System.Runtime.InteropServices { - public readonly struct ArrayWithOffset + public readonly struct ArrayWithOffset : IEquatable { private readonly object? m_array; private readonly int m_offset; @@ -52,7 +52,7 @@ public ArrayWithOffset(object? array, int offset) public override bool Equals([NotNullWhen(true)] object? obj) { - return obj is ArrayWithOffset && Equals((ArrayWithOffset)obj); + return obj is ArrayWithOffset awo && Equals(awo); } public bool Equals(ArrayWithOffset obj) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs index 579633db55caf..a1c849b48c71b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs @@ -23,7 +23,7 @@ namespace System.Runtime.InteropServices /// Pinned - same as Normal, but allows the address of the actual object to be taken. /// [StructLayout(LayoutKind.Sequential)] - public partial struct GCHandle + public partial struct GCHandle : IEquatable { // The actual integer handle value that the EE uses internally. private IntPtr _handle; @@ -163,7 +163,12 @@ public static GCHandle FromIntPtr(IntPtr value) public override int GetHashCode() => _handle.GetHashCode(); - public override bool Equals([NotNullWhen(true)] object? o) => o is GCHandle && _handle == ((GCHandle)o)._handle; + public override bool Equals([NotNullWhen(true)] object? o) => o is GCHandle other && Equals(other); + + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(GCHandle other) => _handle == other._handle; public static bool operator ==(GCHandle a, GCHandle b) => (nint)a._handle == (nint)b._handle; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Serialization/StreamingContext.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Serialization/StreamingContext.cs index 3501457fa82d1..1b3b86c0b9a64 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Serialization/StreamingContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Serialization/StreamingContext.cs @@ -3,6 +3,8 @@ using System.Diagnostics.CodeAnalysis; +#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals + namespace System.Runtime.Serialization { public readonly struct StreamingContext diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationToken.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationToken.cs index ab03e12e87be0..27f29cb0dd949 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationToken.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationToken.cs @@ -27,7 +27,7 @@ namespace System.Threading /// /// [DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")] - public readonly struct CancellationToken + public readonly struct CancellationToken : IEquatable { // The backing TokenSource. // if null, it implicitly represents the same thing as new CancellationToken(false). diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.cs index 6b6b86eb28b71..25a229c87ef66 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.cs @@ -242,7 +242,7 @@ private bool WaitForSignal(int timeoutMs) } } - private struct Counts + private struct Counts : IEquatable { private const byte SignalCountShift = 0; private const byte WaiterCountShift = 32; @@ -350,10 +350,11 @@ public void DecrementCountOfWaitersSignaledToWake() public Counts InterlockedCompareExchange(Counts newCounts, Counts oldCounts) => new Counts(Interlocked.CompareExchange(ref _data, newCounts._data, oldCounts._data)); - public static bool operator ==(Counts lhs, Counts rhs) => lhs._data == rhs._data; - public static bool operator !=(Counts lhs, Counts rhs) => lhs._data != rhs._data; + public static bool operator ==(Counts lhs, Counts rhs) => lhs.Equals(rhs); + public static bool operator !=(Counts lhs, Counts rhs) => !lhs.Equals(rhs); - public override bool Equals([NotNullWhen(true)] object? obj) => obj is Counts counts && _data == counts._data; + public override bool Equals([NotNullWhen(true)] object? obj) => obj is Counts other && Equals(other); + public bool Equals(Counts other) => _data == other._data; public override int GetHashCode() => (int)_data + (int)(_data >> 32); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.ThreadCounts.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.ThreadCounts.cs index 43aa0fcf7102c..3242f165aff9a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.ThreadCounts.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.ThreadCounts.cs @@ -11,7 +11,7 @@ internal sealed partial class PortableThreadPool /// /// Tracks information on the number of threads we want/have in different states in our thread pool. /// - private struct ThreadCounts + private struct ThreadCounts : IEquatable { // SOS's ThreadPool command depends on this layout private const byte NumProcessingWorkShift = 0; @@ -126,7 +126,8 @@ public ThreadCounts InterlockedCompareExchange(ThreadCounts newCounts, ThreadCou public static bool operator ==(ThreadCounts lhs, ThreadCounts rhs) => lhs._data == rhs._data; public static bool operator !=(ThreadCounts lhs, ThreadCounts rhs) => lhs._data != rhs._data; - public override bool Equals([NotNullWhen(true)] object? obj) => obj is ThreadCounts other && _data == other._data; + public override bool Equals([NotNullWhen(true)] object? obj) => obj is ThreadCounts other && Equals(other); + public bool Equals(ThreadCounts other) => _data == other._data; public override int GetHashCode() => (int)_data + (int)(_data >> 32); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerTracking.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerTracking.cs index 8c588965add43..8a5f1d8bba581 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerTracking.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerTracking.cs @@ -58,7 +58,7 @@ private short GetAndResetHighWatermarkCountOfThreadsProcessingUserCallbacks() /// /// Tracks thread count information that is used when the EnableWorkerTracking config option is enabled. /// - private struct CountsOfThreadsProcessingUserCallbacks + private struct CountsOfThreadsProcessingUserCallbacks : IEquatable { private const byte CurrentShift = 0; private const byte HighWatermarkShift = 16; @@ -114,13 +114,16 @@ public CountsOfThreadsProcessingUserCallbacks InterlockedCompareExchange( public static bool operator ==( CountsOfThreadsProcessingUserCallbacks lhs, - CountsOfThreadsProcessingUserCallbacks rhs) => lhs._data == rhs._data; + CountsOfThreadsProcessingUserCallbacks rhs) => lhs.Equals(rhs); public static bool operator !=( CountsOfThreadsProcessingUserCallbacks lhs, - CountsOfThreadsProcessingUserCallbacks rhs) => lhs._data != rhs._data; + CountsOfThreadsProcessingUserCallbacks rhs) => !lhs.Equals(rhs); public override bool Equals([NotNullWhen(true)] object? obj) => - obj is CountsOfThreadsProcessingUserCallbacks other && _data == other._data; + obj is CountsOfThreadsProcessingUserCallbacks other && Equals(other); + + public bool Equals(CountsOfThreadsProcessingUserCallbacks other) => _data == other._data; + public override int GetHashCode() => (int)_data; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.AdjustmentRule.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.AdjustmentRule.cs index 6f53ab75ce351..7c754b4f28570 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.AdjustmentRule.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.AdjustmentRule.cs @@ -56,6 +56,12 @@ public bool Equals([NotNullWhen(true)] AdjustmentRule? other) => _daylightTransitionEnd.Equals(other._daylightTransitionEnd) && _daylightTransitionStart.Equals(other._daylightTransitionStart); + /// Indicates whether the current instance is equal to another instance. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is AdjustmentRule other && Equals(other); + public override int GetHashCode() => _dateStart.GetHashCode(); private AdjustmentRule( diff --git a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs index bc7859c0d18d9..12a2dce1d7258 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs @@ -11,6 +11,8 @@ using Internal.Runtime.CompilerServices; #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types +#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals + #if TARGET_64BIT using nuint_t = System.UInt64; #else diff --git a/src/libraries/System.Private.Xml/src/System/Xml/BinaryXml/XmlBinaryReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/BinaryXml/XmlBinaryReader.cs index 074f795ea54c0..33d1e3dff11c2 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/BinaryXml/XmlBinaryReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/BinaryXml/XmlBinaryReader.cs @@ -59,7 +59,7 @@ private enum ScanState }; // Note: also used by XmlBinaryWriter - internal struct QName + internal struct QName : IEquatable { public string prefix; public string localname; @@ -95,45 +95,26 @@ public void CheckPrefixNS(string prefix, string namespaceUri) throw new XmlException(SR.XmlBinary_NoRemapPrefix, new string[] { prefix, this.namespaceUri, namespaceUri }); } - public override int GetHashCode() - { - return this.prefix.GetHashCode() ^ this.localname.GetHashCode(); - } + public int GetNSHashCode() => + HashCode.Combine(this.namespaceUri, this.localname); - public int GetNSHashCode() - { - return HashCode.Combine(this.namespaceUri, this.localname); - } + public override int GetHashCode() => + this.prefix.GetHashCode() ^ this.localname.GetHashCode(); + public override bool Equals([NotNullWhen(true)] object? other) => + other is QName qname && Equals(qname); - public override bool Equals([NotNullWhen(true)] object? other) - { - if (other is QName that) - { - return this == that; - } - return false; - } + public bool Equals(QName other) => + prefix == other.prefix && + localname == other.localname && + namespaceUri == other.namespaceUri; - public override string ToString() - { - if (prefix.Length == 0) - return this.localname; - else - return $"{this.prefix}:{this.localname}"; - } + public static bool operator ==(QName a, QName b) => a.Equals(b); - public static bool operator ==(QName a, QName b) - { - return ((a.prefix == b.prefix) - && (a.localname == b.localname) - && (a.namespaceUri == b.namespaceUri)); - } + public static bool operator !=(QName a, QName b) => !a.Equals(b); - public static bool operator !=(QName a, QName b) - { - return !(a == b); - } + public override string ToString() => + prefix.Length == 0 ? localname : $"{this.prefix}:{this.localname}"; }; private struct ElemInfo diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Pair.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Pair.cs index 8e3e1a4b841a7..33b4fe98b3f92 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Pair.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Pair.cs @@ -7,49 +7,34 @@ namespace System.Xml.Xsl { - internal struct Int32Pair + internal readonly struct Int32Pair : IEquatable { - private readonly int _left; - private readonly int _right; - public Int32Pair(int left, int right) { - _left = left; - _right = right; + Left = left; + Right = right; } - public int Left { get { return _left; } } - public int Right { get { return _right; } } + public int Left { get; } + public int Right { get; } - public override bool Equals([NotNullWhen(true)] object? other) - { - if (other is Int32Pair) - { - Int32Pair o = (Int32Pair)other; - return _left == o._left && _right == o._right; - } + public override bool Equals([NotNullWhen(true)] object? other) => + other is Int32Pair o && Equals(o); - return false; - } + public bool Equals(Int32Pair other) => Left == other.Left && Right == other.Right; - public override int GetHashCode() - { - return _left.GetHashCode() ^ _right.GetHashCode(); - } + public override int GetHashCode() => Left.GetHashCode() ^ Right.GetHashCode(); } - internal struct StringPair + internal readonly struct StringPair { - private readonly string _left; - private readonly string _right; - public StringPair(string left, string right) { - _left = left; - _right = right; + Left = left; + Right = right; } - public string Left { get { return _left; } } - public string Right { get { return _right; } } + public string Left { get; } + public string Right { get; } } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryCardinality.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryCardinality.cs index 1046765a2d3b2..a95ce13c1737c 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryCardinality.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryCardinality.cs @@ -11,7 +11,7 @@ namespace System.Xml.Xsl /// Cardinality of part of XmlQueryType /// struct is being used because enum doesn't allow members /// - internal struct XmlQueryCardinality + internal readonly struct XmlQueryCardinality : IEquatable { private readonly int _value; diff --git a/src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheExpires.cs b/src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheExpires.cs index e4eab06b7adb3..f9cc0fd36dadf 100644 --- a/src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheExpires.cs +++ b/src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheExpires.cs @@ -13,7 +13,7 @@ namespace System.Runtime.Caching { - internal struct ExpiresEntryRef + internal readonly struct ExpiresEntryRef : IEquatable { internal static readonly ExpiresEntryRef INVALID = new ExpiresEntryRef(0, 0); @@ -31,55 +31,18 @@ internal ExpiresEntryRef(int pageIndex, int entryIndex) _ref = ((((uint)pageIndex) << PAGE_SHIFT) | (((uint)(entryIndex)) & ENTRY_MASK)); } - public override bool Equals(object value) - { - if (value is ExpiresEntryRef) - { - return _ref == ((ExpiresEntryRef)value)._ref; - } + public override bool Equals(object value) => value is ExpiresEntryRef other && Equals(other); - return false; - } + public bool Equals(ExpiresEntryRef other) => _ref == other._ref; - public static bool operator !=(ExpiresEntryRef r1, ExpiresEntryRef r2) - { - return r1._ref != r2._ref; - } - public static bool operator ==(ExpiresEntryRef r1, ExpiresEntryRef r2) - { - return r1._ref == r2._ref; - } + public static bool operator ==(ExpiresEntryRef r1, ExpiresEntryRef r2) => r1.Equals(r2); + public static bool operator !=(ExpiresEntryRef r1, ExpiresEntryRef r2) => !r1.Equals(r2); - public override int GetHashCode() - { - return (int)_ref; - } + public override int GetHashCode() => (int)_ref; - internal int PageIndex - { - get - { - int result = (int)(_ref >> PAGE_SHIFT); - return result; - } - } - - internal int Index - { - get - { - int result = (int)(_ref & ENTRY_MASK); - return result; - } - } - - internal bool IsInvalid - { - get - { - return _ref == 0; - } - } + internal int PageIndex => (int)(_ref >> PAGE_SHIFT); + internal int Index => (int)(_ref & ENTRY_MASK); + internal bool IsInvalid => _ref == 0; } [StructLayout(LayoutKind.Explicit)] diff --git a/src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheUsage.cs b/src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheUsage.cs index 73ed9f30d3d5c..7b7ea64279211 100644 --- a/src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheUsage.cs +++ b/src/libraries/System.Runtime.Caching/src/System/Runtime/Caching/CacheUsage.cs @@ -13,7 +13,7 @@ namespace System.Runtime.Caching { - internal struct UsageEntryRef + internal readonly struct UsageEntryRef : IEquatable { internal static readonly UsageEntryRef INVALID = new UsageEntryRef(0, 0); @@ -31,38 +31,18 @@ internal UsageEntryRef(int pageIndex, int entryIndex) _ref = ((((uint)pageIndex) << PAGE_SHIFT) | (((uint)(entryIndex)) & ENTRY_MASK)); } - public override bool Equals(object value) - { - if (value is UsageEntryRef) - { - return _ref == ((UsageEntryRef)value)._ref; - } + public override bool Equals(object value) => + value is UsageEntryRef other && Equals(other); - return false; - } - public static bool operator ==(UsageEntryRef r1, UsageEntryRef r2) - { - return r1._ref == r2._ref; - } + public bool Equals(UsageEntryRef other) => _ref == other._ref; - public static bool operator !=(UsageEntryRef r1, UsageEntryRef r2) - { - return r1._ref != r2._ref; - } + public static bool operator ==(UsageEntryRef r1, UsageEntryRef r2) => r1.Equals(r2); - public override int GetHashCode() - { - return (int)_ref; - } + public static bool operator !=(UsageEntryRef r1, UsageEntryRef r2) => !r1.Equals(r2); - internal int PageIndex - { - get - { - int result = (int)(_ref >> PAGE_SHIFT); - return result; - } - } + public override int GetHashCode() => (int)_ref; + + internal int PageIndex => (int)(_ref >> PAGE_SHIFT); internal int Ref1Index { @@ -84,29 +64,11 @@ internal int Ref2Index } } - internal bool IsRef1 - { - get - { - return ((int)(sbyte)(_ref & ENTRY_MASK)) > 0; - } - } + internal bool IsRef1 => ((int)(sbyte)(_ref & ENTRY_MASK)) > 0; - internal bool IsRef2 - { - get - { - return ((int)(sbyte)(_ref & ENTRY_MASK)) < 0; - } - } + internal bool IsRef2 => ((int)(sbyte)(_ref & ENTRY_MASK)) < 0; - internal bool IsInvalid - { - get - { - return _ref == 0; - } - } + internal bool IsInvalid => _ref == 0; } internal struct UsageEntryLink diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 901b76346b82c..e58de5b8a040a 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -98,7 +98,7 @@ public sealed partial class AllowReversePInvokeCallsAttribute : System.Attribute { public AllowReversePInvokeCallsAttribute() { } } - public readonly partial struct ArrayWithOffset + public readonly partial struct ArrayWithOffset : System.IEquatable { private readonly object _dummy; private readonly int _dummyPrimitive; diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/GCHandleTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/GCHandleTests.cs index bf5ec1713cdbc..8a79b7a66db45 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/GCHandleTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/GCHandleTests.cs @@ -138,6 +138,7 @@ public void Equals_Object_ReturnsExpected(GCHandle handle, object other, bool ex Assert.Equal(expected, handle.Equals(other)); if (other is GCHandle otherHandle) { + Assert.Equal(expected, handle.Equals(otherHandle)); Assert.Equal(expected, handle == otherHandle); Assert.Equal(!expected, handle != otherHandle); } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index c57c5b13cc119..57c9f8368994e 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -4826,7 +4826,7 @@ public MissingMethodException(string? message, System.Exception? inner) { } public MissingMethodException(string? className, string? methodName) { } public override string Message { get { throw null; } } } - public partial struct ModuleHandle + public partial struct ModuleHandle : System.IEquatable { private object _dummy; private int _dummyPrimitive; @@ -6367,6 +6367,7 @@ internal AdjustmentRule() { } public static System.TimeZoneInfo.AdjustmentRule CreateAdjustmentRule(System.DateTime dateStart, System.DateTime dateEnd, System.TimeSpan daylightDelta, System.TimeZoneInfo.TransitionTime daylightTransitionStart, System.TimeZoneInfo.TransitionTime daylightTransitionEnd) { throw null; } public static System.TimeZoneInfo.AdjustmentRule CreateAdjustmentRule(System.DateTime dateStart, System.DateTime dateEnd, System.TimeSpan daylightDelta, System.TimeZoneInfo.TransitionTime daylightTransitionStart, System.TimeZoneInfo.TransitionTime daylightTransitionEnd, System.TimeSpan baseUtcOffsetDelta) { throw null; } public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] System.TimeZoneInfo.AdjustmentRule? other) { throw null; } + public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public override int GetHashCode() { throw null; } void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } @@ -11648,7 +11649,7 @@ protected CustomAttributeFormatException(System.Runtime.Serialization.Serializat public CustomAttributeFormatException(string? message) { } public CustomAttributeFormatException(string? message, System.Exception? inner) { } } - public readonly partial struct CustomAttributeNamedArgument + public readonly partial struct CustomAttributeNamedArgument : System.IEquatable { private readonly object _dummy; private readonly int _dummyPrimitive; @@ -11658,13 +11659,14 @@ public readonly partial struct CustomAttributeNamedArgument public System.Reflection.MemberInfo MemberInfo { get { throw null; } } public string MemberName { get { throw null; } } public System.Reflection.CustomAttributeTypedArgument TypedValue { get { throw null; } } - public override bool Equals(object? obj) { throw null; } + public bool Equals(System.Reflection.CustomAttributeNamedArgument other) { throw null; } + public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(System.Reflection.CustomAttributeNamedArgument left, System.Reflection.CustomAttributeNamedArgument right) { throw null; } public static bool operator !=(System.Reflection.CustomAttributeNamedArgument left, System.Reflection.CustomAttributeNamedArgument right) { throw null; } public override string ToString() { throw null; } } - public readonly partial struct CustomAttributeTypedArgument + public readonly partial struct CustomAttributeTypedArgument : System.IEquatable { private readonly object _dummy; private readonly int _dummyPrimitive; @@ -11672,7 +11674,8 @@ public readonly partial struct CustomAttributeTypedArgument public CustomAttributeTypedArgument(System.Type argumentType, object? value) { throw null; } public System.Type ArgumentType { get { throw null; } } public object? Value { get { throw null; } } - public override bool Equals(object? obj) { throw null; } + public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } + public bool Equals(System.Reflection.CustomAttributeTypedArgument other) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(System.Reflection.CustomAttributeTypedArgument left, System.Reflection.CustomAttributeTypedArgument right) { throw null; } public static bool operator !=(System.Reflection.CustomAttributeTypedArgument left, System.Reflection.CustomAttributeTypedArgument right) { throw null; } @@ -13493,7 +13496,7 @@ public sealed partial class FieldOffsetAttribute : System.Attribute public FieldOffsetAttribute(int offset) { } public int Value { get { throw null; } } } - public partial struct GCHandle + public partial struct GCHandle : System.IEquatable { private int _dummyPrimitive; public bool IsAllocated { get { throw null; } } @@ -13502,6 +13505,7 @@ public partial struct GCHandle public static System.Runtime.InteropServices.GCHandle Alloc(object? value) { throw null; } public static System.Runtime.InteropServices.GCHandle Alloc(object? value, System.Runtime.InteropServices.GCHandleType type) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? o) { throw null; } + public bool Equals(System.Runtime.InteropServices.GCHandle other) { throw null; } public void Free() { } public static System.Runtime.InteropServices.GCHandle FromIntPtr(System.IntPtr value) { throw null; } public override int GetHashCode() { throw null; } @@ -14770,7 +14774,7 @@ public static partial class Utf8 } namespace System.Threading { - public readonly partial struct CancellationToken + public readonly partial struct CancellationToken : System.IEquatable { private readonly object _dummy; private readonly int _dummyPrimitive; diff --git a/src/libraries/System.Runtime/tests/System/Reflection/CustomAttribute_Named_Typed_ArgumentTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/CustomAttribute_Named_Typed_ArgumentTests.cs index 4460797182c87..c406e36ea21c3 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/CustomAttribute_Named_Typed_ArgumentTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/CustomAttribute_Named_Typed_ArgumentTests.cs @@ -52,6 +52,28 @@ public static void Test_CustomAttributeTypedArgument_Constructor() Assert.True(false, "Expected to find MyAttr Attribute"); } + [Fact] + public static void Test_CustomAttributeTypedArgument_Equals() + { + Type t = typeof(MyClass); + foreach (CustomAttributeData cad in CustomAttributeData.GetCustomAttributes(t)) + { + foreach (CustomAttributeTypedArgument cata in cad.ConstructorArguments) + { + Assert.True(cata.Equals(cata)); + Assert.True(cata.Equals((object)cata)); + + var notEqualArgument = new CustomAttributeTypedArgument(new [] { new CustomAttributeTypedArgument(0) }); + Assert.False(cata.Equals(notEqualArgument)); + Assert.False(cata.Equals((object)notEqualArgument)); + + return; + } + } + + Assert.True(false, "Expected to find MyAttr Attribute"); + } + [Fact] public static void Test_CustomAttributeTypedArgument_ToString() { diff --git a/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.netcoreapp.cs b/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.netcoreapp.cs index 3fd806b0f5649..1298a7c23d690 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.netcoreapp.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.netcoreapp.cs @@ -10,4 +10,7 @@ public partial class ServiceController : System.ComponentModel.Component { public void Stop(bool stopDependentServices) { } } + public readonly partial struct SessionChangeDescription : System.IEquatable + { + } } diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj b/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj index 8fd0582994dd4..fac46aed04ba2 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj +++ b/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj @@ -17,6 +17,8 @@ System.ServiceProcess.ServiceType true true SR.PlatformNotSupported_ServiceController + + $(NoWarn);CA1066 +#endif { internal SessionChangeDescription(SessionChangeReason reason, int id) { @@ -17,34 +20,20 @@ internal SessionChangeDescription(SessionChangeReason reason, int id) public int SessionId { get; } - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (!(obj is SessionChangeDescription)) - { - return false; - } + public override int GetHashCode() => + (int)Reason ^ SessionId; - return Equals((SessionChangeDescription)obj); - } + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is SessionChangeDescription other && Equals(other); - public override int GetHashCode() - { - return (int)Reason ^ SessionId; - } + public bool Equals(SessionChangeDescription changeDescription) => + (Reason == changeDescription.Reason) && + (SessionId == changeDescription.SessionId); - public bool Equals(SessionChangeDescription changeDescription) - { - return (Reason == changeDescription.Reason) && (SessionId == changeDescription.SessionId); - } + public static bool operator ==(SessionChangeDescription a, SessionChangeDescription b) => + a.Equals(b); - public static bool operator ==(SessionChangeDescription a, SessionChangeDescription b) - { - return a.Equals(b); - } - - public static bool operator !=(SessionChangeDescription a, SessionChangeDescription b) - { - return !a.Equals(b); - } + public static bool operator !=(SessionChangeDescription a, SessionChangeDescription b) => + !a.Equals(b); } } diff --git a/src/libraries/System.Speech/src/Internal/Synthesis/EngineSiteSapi.cs b/src/libraries/System.Speech/src/Internal/Synthesis/EngineSiteSapi.cs index d6bf03a57d2f1..e44843b0c8193 100644 --- a/src/libraries/System.Speech/src/Internal/Synthesis/EngineSiteSapi.cs +++ b/src/libraries/System.Speech/src/Internal/Synthesis/EngineSiteSapi.cs @@ -176,8 +176,9 @@ internal interface ISpEngineSite void CompleteSkip(int skipped); void LoadResource([MarshalAs(UnmanagedType.LPWStr)] string resource, ref string mediaType, out IStream stream); } + [StructLayout(LayoutKind.Sequential)] - internal struct SpeechEventSapi + internal struct SpeechEventSapi : IEquatable { public short EventId; public short ParameterType; @@ -185,27 +186,22 @@ internal struct SpeechEventSapi public long AudioStreamOffset; public IntPtr Param1; // Always just a numeric type - contains no unmanaged resources so does not need special clean-up. public IntPtr Param2; // Can be a numeric type, or pointer to string or object. Use SafeSapiLParamHandle to cleanup. - public static bool operator ==(SpeechEventSapi event1, SpeechEventSapi event2) - { - return event1.EventId == event2.EventId && event1.ParameterType == event2.ParameterType && event1.StreamNumber == event2.StreamNumber && event1.AudioStreamOffset == event2.AudioStreamOffset && event1.Param1 == event2.Param1 && event1.Param2 == event2.Param2; - } - public static bool operator !=(SpeechEventSapi event1, SpeechEventSapi event2) - { - return !(event1 == event2); - } - public override bool Equals(object obj) - { - if (!(obj is SpeechEventSapi)) - { - return false; - } - return this == (SpeechEventSapi)obj; - } - public override int GetHashCode() - { - return base.GetHashCode(); - } + public static bool operator ==(SpeechEventSapi event1, SpeechEventSapi event2) => event1.Equals(event2); + public static bool operator !=(SpeechEventSapi event1, SpeechEventSapi event2) => !event1.Equals(event2); + + public override bool Equals(object obj) => + obj is SpeechEventSapi other && Equals(other); + + public bool Equals(SpeechEventSapi other) => + EventId == other.EventId && + ParameterType == other.ParameterType && + StreamNumber == other.StreamNumber && + AudioStreamOffset == other.AudioStreamOffset && + Param1 == other.Param1 && + Param2 == other.Param2; + + public override int GetHashCode() => base.GetHashCode(); } #endregion diff --git a/src/libraries/System.Text.Encodings.Web/src/Polyfills/System.Text.Rune.netstandard20.cs b/src/libraries/System.Text.Encodings.Web/src/Polyfills/System.Text.Rune.netstandard20.cs index 66c637eda2a2b..774ee9e426c7e 100644 --- a/src/libraries/System.Text.Encodings.Web/src/Polyfills/System.Text.Rune.netstandard20.cs +++ b/src/libraries/System.Text.Encodings.Web/src/Polyfills/System.Text.Rune.netstandard20.cs @@ -14,7 +14,7 @@ namespace System.Text { - internal readonly struct Rune + internal readonly struct Rune : IEquatable { private const int MaxUtf16CharsPerRune = 2; // supplementary plane code points are encoded as 2 UTF-16 code units diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicMatch.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicMatch.cs index c6754b8577b0d..5ba715c25ef4c 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicMatch.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicMatch.cs @@ -5,7 +5,7 @@ namespace System.Text.RegularExpressions.Symbolic { - internal readonly struct SymbolicMatch + internal readonly struct SymbolicMatch : IEquatable { /// Indicates failure to find a match. internal static SymbolicMatch NoMatch => new SymbolicMatch(-1, -1); @@ -20,17 +20,21 @@ public SymbolicMatch(int index, int length) } public int Index { get; } + public int Length { get; } + public bool Success => Index >= 0; public static bool operator ==(SymbolicMatch left, SymbolicMatch right) => - left.Index == right.Index && left.Length == right.Length; + left.Equals(right); public static bool operator !=(SymbolicMatch left, SymbolicMatch right) => - !(left == right); + !left.Equals(right); public override bool Equals([NotNullWhen(true)] object? obj) => - obj is SymbolicMatch other && this == other; + obj is SymbolicMatch other && Equals(other); + + public bool Equals(SymbolicMatch other) => Index == other.Index && Length == other.Length; public override int GetHashCode() => HashCode.Combine(Index, Length); } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexInfo.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexInfo.cs index ba522d513392c..4e60696eb0717 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexInfo.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexInfo.cs @@ -4,7 +4,7 @@ namespace System.Text.RegularExpressions.Symbolic { /// Misc information of structural properties of a that is computed bottom up. - internal readonly struct SymbolicRegexInfo + internal readonly struct SymbolicRegexInfo : IEquatable { private const uint IsAlwaysNullableMask = 1; private const uint StartsWithLineAnchorMask = 2; @@ -177,7 +177,9 @@ public static SymbolicRegexInfo Not(SymbolicRegexInfo info) => containsSomeCharacter: info.ContainsSomeCharacter, isLazy: info.IsLazy); - public override bool Equals(object? obj) => obj is SymbolicRegexInfo i && i._info == _info; + public override bool Equals(object? obj) => obj is SymbolicRegexInfo i && Equals(i); + + public bool Equals(SymbolicRegexInfo other) => _info == other._info; public override int GetHashCode() => _info.GetHashCode(); diff --git a/src/libraries/System.Threading/ref/System.Threading.cs b/src/libraries/System.Threading/ref/System.Threading.cs index 1237c49cecaed..3c5f1268e8873 100644 --- a/src/libraries/System.Threading/ref/System.Threading.cs +++ b/src/libraries/System.Threading/ref/System.Threading.cs @@ -235,7 +235,7 @@ public static partial class LazyInitializer public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, System.Func valueFactory) where T : class { throw null; } public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, [System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("syncLock")] ref object? syncLock, System.Func valueFactory) where T : class { throw null; } } - public partial struct LockCookie + public partial struct LockCookie : System.IEquatable { private int _dummyPrimitive; public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } diff --git a/src/libraries/System.Threading/src/System/Threading/LockCookie.cs b/src/libraries/System.Threading/src/System/Threading/LockCookie.cs index 6a76ceb023d0a..a9c9011179f8f 100644 --- a/src/libraries/System.Threading/src/System/Threading/LockCookie.cs +++ b/src/libraries/System.Threading/src/System/Threading/LockCookie.cs @@ -9,40 +9,27 @@ namespace System.Threading /// Stores the lock state of a before its lock state is changed, such that the lock state may /// later be restored. /// - public struct LockCookie + public struct LockCookie : IEquatable { internal LockCookieFlags _flags; internal ushort _readerLevel; internal ushort _writerLevel; internal int _threadID; - public override int GetHashCode() - { - return (int)_flags + _readerLevel + _writerLevel + _threadID; - } + public override int GetHashCode() => + (int)_flags + _readerLevel + _writerLevel + _threadID; - public override bool Equals([NotNullWhen(true)] object? obj) - { - return obj is LockCookie && Equals((LockCookie)obj); - } + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is LockCookie other && Equals(other); - public bool Equals(LockCookie obj) - { - return - _flags == obj._flags && - _readerLevel == obj._readerLevel && - _writerLevel == obj._writerLevel && - _threadID == obj._threadID; - } + public bool Equals(LockCookie obj) => + _flags == obj._flags && + _readerLevel == obj._readerLevel && + _writerLevel == obj._writerLevel && + _threadID == obj._threadID; - public static bool operator ==(LockCookie a, LockCookie b) - { - return a.Equals(b); - } + public static bool operator ==(LockCookie a, LockCookie b) => a.Equals(b); - public static bool operator !=(LockCookie a, LockCookie b) - { - return !(a == b); - } + public static bool operator !=(LockCookie a, LockCookie b) => !a.Equals(b); } } diff --git a/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs b/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs index 91804388b42fa..f52ae1ffd8b91 100644 --- a/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs +++ b/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs @@ -202,12 +202,13 @@ protected TransactionManagerCommunicationException(System.Runtime.Serialization. public TransactionManagerCommunicationException(string? message) { } public TransactionManagerCommunicationException(string? message, System.Exception? innerException) { } } - public partial struct TransactionOptions + public partial struct TransactionOptions : System.IEquatable { - private int _dummyPrimitive; + private readonly int _dummyPrimitive; public System.Transactions.IsolationLevel IsolationLevel { get { throw null; } set { } } public System.TimeSpan Timeout { get { throw null; } set { } } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } + public bool Equals(System.Transactions.TransactionOptions other) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(System.Transactions.TransactionOptions x, System.Transactions.TransactionOptions y) { throw null; } public static bool operator !=(System.Transactions.TransactionOptions x, System.Transactions.TransactionOptions y) { throw null; } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs index 1fa34283bb455..4ce7bb4bd1394 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs @@ -5,7 +5,7 @@ namespace System.Transactions { - public struct TransactionOptions + public struct TransactionOptions : IEquatable { private TimeSpan _timeout; private IsolationLevel _isolationLevel; @@ -26,7 +26,10 @@ public IsolationLevel IsolationLevel public override bool Equals([NotNullWhen(true)] object? obj) => obj is TransactionOptions transactionOptions && Equals(transactionOptions); - private bool Equals(TransactionOptions other) => + /// Indicates whether the current instance is equal to another instance of the same type. + /// An instance to compare with this instance. + /// true if the current instance is equal to the other instance; otherwise, false. + public bool Equals(TransactionOptions other) => _timeout == other._timeout && _isolationLevel == other._isolationLevel; diff --git a/src/mono/System.Private.CoreLib/src/Mono/RuntimeHandles.cs b/src/mono/System.Private.CoreLib/src/Mono/RuntimeHandles.cs index c62dde6612049..90b612313c19d 100644 --- a/src/mono/System.Private.CoreLib/src/Mono/RuntimeHandles.cs +++ b/src/mono/System.Private.CoreLib/src/Mono/RuntimeHandles.cs @@ -7,7 +7,7 @@ namespace Mono { - internal unsafe struct RuntimeClassHandle + internal unsafe struct RuntimeClassHandle : IEquatable { private readonly RuntimeStructs.MonoClass* value; @@ -125,7 +125,7 @@ private int GetConstraintsCount() } } - internal struct RuntimeEventHandle + internal struct RuntimeEventHandle : IEquatable { private readonly IntPtr value; @@ -165,7 +165,7 @@ public override int GetHashCode() } } - internal struct RuntimePropertyHandle + internal struct RuntimePropertyHandle : IEquatable { private readonly IntPtr value; diff --git a/src/mono/System.Private.CoreLib/src/System/ModuleHandle.cs b/src/mono/System.Private.CoreLib/src/System/ModuleHandle.cs index 9f73b99fb6db9..c30bf25582a3a 100644 --- a/src/mono/System.Private.CoreLib/src/System/ModuleHandle.cs +++ b/src/mono/System.Private.CoreLib/src/System/ModuleHandle.cs @@ -6,7 +6,7 @@ namespace System { - public struct ModuleHandle + public struct ModuleHandle : IEquatable { private readonly IntPtr value; diff --git a/src/mono/System.Private.CoreLib/src/System/Nullable.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Nullable.Mono.cs index 23f7668e73549..c120455199922 100644 --- a/src/mono/System.Private.CoreLib/src/System/Nullable.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Nullable.Mono.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#pragma warning disable CA1066 // Implement IEquatable when overriding Object.Equals + namespace System { public partial struct Nullable diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs index af1cead1c9593..9b9c5a410cf2f 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs @@ -14,7 +14,7 @@ namespace Microsoft.WebAssembly.Diagnostics { - public struct SessionId + public struct SessionId : IEquatable { public readonly string sessionId; @@ -26,7 +26,9 @@ public SessionId(string sessionId) // hashset treats 0 as unset public override int GetHashCode() => sessionId?.GetHashCode() ?? -1; - public override bool Equals(object obj) => (obj is SessionId) ? ((SessionId)obj).sessionId == sessionId : false; + public override bool Equals(object obj) => obj is SessionId other && Equals(other); + + public bool Equals(SessionId other) => other.sessionId == sessionId; public static bool operator ==(SessionId a, SessionId b) => a.sessionId == b.sessionId; @@ -37,7 +39,7 @@ public SessionId(string sessionId) public override string ToString() => $"session-{sessionId}"; } - public struct MessageId + public struct MessageId : IEquatable { public readonly string sessionId; public readonly int id; @@ -54,7 +56,9 @@ public MessageId(string sessionId, int id) public override int GetHashCode() => (sessionId?.GetHashCode() ?? 0) ^ id.GetHashCode(); - public override bool Equals(object obj) => (obj is MessageId) ? ((MessageId)obj).sessionId == sessionId && ((MessageId)obj).id == id : false; + public override bool Equals(object obj) => obj is MessageId other && Equals(other); + + public bool Equals(MessageId other) => other.sessionId == sessionId && other.id == id; } internal class DotnetObjectId diff --git a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs index 9526a602876f2..34b42e2db3ad6 100644 --- a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs +++ b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs @@ -478,7 +478,9 @@ private static bool IsBlittable (Type type) private static void Error (string msg) => throw new LogAsErrorException(msg); } +#pragma warning disable CA1067 internal sealed class PInvoke : IEquatable +#pragma warning restore CA1067 { public PInvoke(string entryPoint, string module, MethodInfo method) { From 6cf765e72719a73d43c37e8d1ddfcb54a0e89564 Mon Sep 17 00:00:00 2001 From: imhameed Date: Mon, 24 Jan 2022 10:28:49 -0500 Subject: [PATCH 171/308] [mono] Temporarily disable two tests that fail on arm64 LLVM FullAOT. (#64180) --- src/tests/issues.targets | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index edf95e8c106f6..d6aa159fba256 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2805,6 +2805,13 @@ This test includes an intentionally-invalid UnmanagedCallersOnly method. Invalid UnmanagedCallersOnly methods cause failures at AOT-time. + + + https://github.com/dotnet/runtime/issues/64179 + + + https://github.com/dotnet/runtime/issues/64179 + From eb8a502a0cac4733cdfb30e39288a808f51851ba Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 24 Jan 2022 10:33:04 -0500 Subject: [PATCH 172/308] Delete stale reference in System.Drawing.Primitives (#64202) --- .../src/System.Drawing.Primitives.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj b/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj index 162b5d563a72d..e8328af20cde9 100644 --- a/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj +++ b/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj @@ -36,7 +36,6 @@ Link="Common\Interop\Windows\User32\Interop.Win32SystemColors.cs" /> - From d99fa6789ad213df87358b0bd6fbffd9e0c31371 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 24 Jan 2022 10:42:15 -0600 Subject: [PATCH 173/308] Respond to feedback in GenerateMultiTargetRoslynComponentTargetsFile (#63943) * Respond to feedback in GenerateMultiTargetRoslynComponentTargetsFile Two small follow up changes from #58446 - Fix a type-o that breaks incremental build. Forgot to use MSBuild property syntax - Instead of having the infrastructure hard-code removing 'Abstractions', packages can set their own Disable source gen property name. * PR feedback --- docs/coding-guidelines/libraries-packaging.md | 7 +++++++ eng/packaging.targets | 7 +++---- .../src/Microsoft.Extensions.Logging.Abstractions.csproj | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/coding-guidelines/libraries-packaging.md b/docs/coding-guidelines/libraries-packaging.md index 9e07a0683fd8d..66909e4df855c 100644 --- a/docs/coding-guidelines/libraries-packaging.md +++ b/docs/coding-guidelines/libraries-packaging.md @@ -86,5 +86,12 @@ In the analyzer project make sure to do the following. Ensure it only targets `n ``` +In order to mitigate design-time/build-time performance issues with source generators, we generate build logic to allow the end user to disable the source generator from the package. By default, the MSBuild property an end user can set is named `Disable{PackageId}SourceGenerator`. If a package needs a custom property name, this can be overriden by setting the following property in the project that produces the package +```xml + + CustomPropertyName + +``` + ### .NETFramework RID specific assets When targeting .NETFramework, RID specific assets are automatically added to the package if the project contains other compatible RID specific assets, mainly `netstandard2.0-windows`. diff --git a/eng/packaging.targets b/eng/packaging.targets index 667837fbff106..c305c64dd9409 100644 --- a/eng/packaging.targets +++ b/eng/packaging.targets @@ -162,19 +162,18 @@ <_MultiTargetRoslynComponentTargetPrefix>$(PackageId.Replace('.', '_')) - <_MultiTargetRoslynComponentDisableSourceGeneratorPropertyName>Disable$(PackageId.Replace('.', ''))SourceGenerator - <_MultiTargetRoslynComponentDisableSourceGeneratorPropertyName>$(_MultiTargetRoslynComponentDisableSourceGeneratorPropertyName.Replace('Abstractions', '')) + Disable$(PackageId.Replace('.', ''))SourceGenerator 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 8ca2bab854730..eb95f66e4f5a3 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 @@ -18,6 +18,7 @@ Microsoft.Extensions.Logging.LogLevel Microsoft.Extensions.Logging.Logger<T> Microsoft.Extensions.Logging.LoggerMessage Microsoft.Extensions.Logging.Abstractions.NullLogger + DisableMicrosoftExtensionsLoggingSourceGenerator From 2713e11deefb1757644dc2366c35379dd95f7b08 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Mon, 24 Jan 2022 12:52:58 -0500 Subject: [PATCH 174/308] Use the static HashData(Stream) method in more places --- .../AsymmetricAlgorithmHelpers.Hash.cs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Hash.cs b/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Hash.cs index dc3e3426596e9..a4c41cfbcac62 100644 --- a/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Hash.cs +++ b/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Hash.cs @@ -34,16 +34,21 @@ public static byte[] HashData(byte[] data, int offset, int count, HashAlgorithmN throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name); } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 is used when the user asks for it.")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5351", Justification = "MD5 is used when the user asks for it.")] public static byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) { // The classes that call us are sealed and their base class has checked this already. Debug.Assert(data != null); Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); - using (HashAlgorithm hasher = GetHashAlgorithm(hashAlgorithm)) - { - return hasher.ComputeHash(data); - } + return + hashAlgorithm == HashAlgorithmName.SHA256 ? SHA256.HashData(data) : + hashAlgorithm == HashAlgorithmName.SHA1 ? SHA1.HashData(data) : + hashAlgorithm == HashAlgorithmName.SHA512 ? SHA512.HashData(data) : + hashAlgorithm == HashAlgorithmName.SHA384 ? SHA384.HashData(data) : + hashAlgorithm == HashAlgorithmName.MD5 ? MD5.HashData(data) : + throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 is used when the user asks for it.")] @@ -61,15 +66,5 @@ public static bool TryHashData(ReadOnlySpan source, Span destination hashAlgorithm == HashAlgorithmName.MD5 ? MD5.TryHashData(source, destination, out bytesWritten) : throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name); } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 is used when the user asks for it.")] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5351", Justification = "MD5 is used when the user asks for it.")] - private static HashAlgorithm GetHashAlgorithm(HashAlgorithmName hashAlgorithmName) => - hashAlgorithmName == HashAlgorithmName.SHA256 ? SHA256.Create() : - hashAlgorithmName == HashAlgorithmName.SHA1 ? SHA1.Create() : - hashAlgorithmName == HashAlgorithmName.SHA512 ? SHA512.Create() : - hashAlgorithmName == HashAlgorithmName.SHA384 ? SHA384.Create() : - hashAlgorithmName == HashAlgorithmName.MD5 ? MD5.Create() : - throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmName.Name); } } From 02eaf5f1bb8f8eac1c7528a1b223087a1b76a7d4 Mon Sep 17 00:00:00 2001 From: Gleb Balykov Date: Mon, 24 Jan 2022 21:21:44 +0300 Subject: [PATCH 175/308] Add executable bit to tizen sh files (#64216) --- eng/common/cross/arm/tizen-build-rootfs.sh | 0 eng/common/cross/arm/tizen-fetch.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 eng/common/cross/arm/tizen-build-rootfs.sh mode change 100644 => 100755 eng/common/cross/arm/tizen-fetch.sh diff --git a/eng/common/cross/arm/tizen-build-rootfs.sh b/eng/common/cross/arm/tizen-build-rootfs.sh old mode 100644 new mode 100755 diff --git a/eng/common/cross/arm/tizen-fetch.sh b/eng/common/cross/arm/tizen-fetch.sh old mode 100644 new mode 100755 From b923e9929d7a7e723e21817cd2f307aa44e3f20b Mon Sep 17 00:00:00 2001 From: Carlos Sanchez <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 24 Jan 2022 10:40:18 -0800 Subject: [PATCH 176/308] Bump Intellisensense package version to latest from `dotnet7-transport` (#63352) --- NuGet.config | 1 + eng/Versions.props | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index f74e0c4a70248..01da668976261 100644 --- a/NuGet.config +++ b/NuGet.config @@ -15,6 +15,7 @@ + diff --git a/eng/Versions.props b/eng/Versions.props index 85e7bdd4cdc82..6484ee772cec7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -114,7 +114,7 @@ 4.3.0 4.3.0 4.3.0 - 6.0.0-rc.2.21454.1 + 6.0.0 4.3.1 5.0.0 5.0.0 @@ -175,7 +175,7 @@ 7.0.100-alpha.1.21528.1 1.1.1-beta1.21467.5 - 6.0.0-preview-20211019.1 + 6.0.0-preview-20220104.1 7.0.100-1.22063.2 $(MicrosoftNETILLinkTasksVersion) From 0ef4f467482c1404b01d1f6ada0b2968ac219fc5 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 24 Jan 2022 11:01:19 -0800 Subject: [PATCH 177/308] Ensure that we aren't accidentally generating instructions for unsupported ISAs (#64140) * Assert that the ISA of the set intrinsic ID is supported * Ensure gtNewSimdCmpOpAllNode and gtNewSimdCmpOpAnyNode don't generate AVX2 instructions when not supported * Ensure codegen for Vector128.Dot when SSSE3 is disabled is correct * Update src/coreclr/jit/hwintrinsiccodegenarm64.cpp Co-authored-by: Jan Kotas * Ensure Vector256.Sum has a check for AVX2 Co-authored-by: Jan Kotas --- src/coreclr/jit/gentree.cpp | 61 ++++++++++++++------- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 3 + src/coreclr/jit/hwintrinsiccodegenxarch.cpp | 3 + src/coreclr/jit/hwintrinsicxarch.cpp | 25 +++++---- src/coreclr/jit/lowerxarch.cpp | 2 +- 5 files changed, 64 insertions(+), 30 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 678a2a60409db..8c9450cfbf564 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -19294,20 +19294,22 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, NamedIntrinsic intrinsic = NI_Illegal; -#if defined(TARGET_XARCH) - if (simdSize == 32) - { - assert(compIsaSupportedDebugOnly(InstructionSet_AVX)); - assert(varTypeIsFloating(simdBaseType) || compIsaSupportedDebugOnly(InstructionSet_AVX2)); - } -#endif // TARGET_XARCH - switch (op) { #if defined(TARGET_XARCH) case GT_EQ: { - intrinsic = (simdSize == 32) ? NI_Vector256_op_Equality : NI_Vector128_op_Equality; + if (simdSize == 32) + { + assert(compIsaSupportedDebugOnly(InstructionSet_AVX)); + assert(varTypeIsFloating(simdBaseType) || compIsaSupportedDebugOnly(InstructionSet_AVX2)); + + intrinsic = NI_Vector256_op_Equality; + } + else + { + intrinsic = NI_Vector128_op_Equality; + } break; } @@ -19323,6 +19325,12 @@ GenTree* Compiler::gtNewSimdCmpOpAllNode(genTreeOps op, if (simdSize == 32) { + // TODO-XArch-CQ: It's a non-trivial amount of work to support these + // for floating-point while only utilizing AVX. It would require, among + // other things, inverting the comparison and potentially support for a + // new Avx.TestNotZ intrinsic to ensure the codegen remains efficient. + assert(compIsaSupportedDebugOnly(InstructionSet_AVX2)); + intrinsic = NI_Vector256_op_Equality; getAllBitsSet = NI_Vector256_get_AllBitsSet; } @@ -19433,14 +19441,6 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, NamedIntrinsic intrinsic = NI_Illegal; -#if defined(TARGET_XARCH) - if (simdSize == 32) - { - assert(compIsaSupportedDebugOnly(InstructionSet_AVX)); - assert(varTypeIsFloating(simdBaseType) || compIsaSupportedDebugOnly(InstructionSet_AVX2)); - } -#endif // TARGET_XARCH - switch (op) { #if defined(TARGET_XARCH) @@ -19453,7 +19453,20 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, // We want to generate a comparison along the lines of // GT_XX(op1, op2).As() != Vector128.Zero - intrinsic = (simdSize == 32) ? NI_Vector256_op_Inequality : NI_Vector128_op_Inequality; + if (simdSize == 32) + { + // TODO-XArch-CQ: It's a non-trivial amount of work to support these + // for floating-point while only utilizing AVX. It would require, among + // other things, inverting the comparison and potentially support for a + // new Avx.TestNotZ intrinsic to ensure the codegen remains efficient. + assert(compIsaSupportedDebugOnly(InstructionSet_AVX2)); + + intrinsic = NI_Vector256_op_Inequality; + } + else + { + intrinsic = NI_Vector128_op_Inequality; + } op1 = gtNewSimdCmpOpNode(op, simdType, op1, op2, simdBaseJitType, simdSize, /* isSimdAsHWIntrinsic */ false); @@ -19475,7 +19488,17 @@ GenTree* Compiler::gtNewSimdCmpOpAnyNode(genTreeOps op, case GT_NE: { - intrinsic = (simdSize == 32) ? NI_Vector256_op_Inequality : NI_Vector128_op_Inequality; + if (simdSize == 32) + { + assert(compIsaSupportedDebugOnly(InstructionSet_AVX)); + assert(varTypeIsFloating(simdBaseType) || compIsaSupportedDebugOnly(InstructionSet_AVX2)); + + intrinsic = NI_Vector256_op_Inequality; + } + else + { + intrinsic = NI_Vector128_op_Inequality; + } break; } #elif defined(TARGET_ARM64) diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index e4b9a1326680c..6dfe48047c094 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -206,6 +206,9 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { const HWIntrinsic intrin(node); + // We need to validate that other phases of the compiler haven't introduced unsupported intrinsics + assert(compiler->compIsaSupportedDebugOnly(HWIntrinsicInfo::lookupIsa(intrin.id))); + regNumber targetReg = node->GetRegNum(); regNumber op1Reg = REG_NA; diff --git a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp index d6490c59b2e36..10c8dcaedb197 100644 --- a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp @@ -86,6 +86,9 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); size_t numArgs = node->GetOperandCount(); + // We need to validate that other phases of the compiler haven't introduced unsupported intrinsics + assert(compiler->compIsaSupportedDebugOnly(isa)); + int ival = HWIntrinsicInfo::lookupIval(intrinsicId, compiler->compOpportunisticallyDependsOn(InstructionSet_AVX)); assert(HWIntrinsicInfo::RequiresCodegen(intrinsicId)); diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index f1b84825f2176..aec1be705f3db 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -1024,7 +1024,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || compExactlyDependsOn(InstructionSet_AVX2)) + if ((simdSize != 32) || compExactlyDependsOn(InstructionSet_AVX2)) { var_types simdType = getSIMDTypeForSize(simdSize); @@ -1287,7 +1287,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || compExactlyDependsOn(InstructionSet_AVX2)) + if ((simdSize != 32) || compExactlyDependsOn(InstructionSet_AVX2)) { var_types simdType = getSIMDTypeForSize(simdSize); @@ -1305,7 +1305,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || compExactlyDependsOn(InstructionSet_AVX2)) + if ((simdSize != 32) || compExactlyDependsOn(InstructionSet_AVX2)) { var_types simdType = getSIMDTypeForSize(simdSize); @@ -1339,7 +1339,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || compExactlyDependsOn(InstructionSet_AVX2)) + if ((simdSize != 32) || compExactlyDependsOn(InstructionSet_AVX2)) { var_types simdType = getSIMDTypeForSize(simdSize); @@ -1357,7 +1357,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || compExactlyDependsOn(InstructionSet_AVX2)) + if ((simdSize != 32) || compExactlyDependsOn(InstructionSet_AVX2)) { var_types simdType = getSIMDTypeForSize(simdSize); @@ -1391,7 +1391,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || compExactlyDependsOn(InstructionSet_AVX2)) + if ((simdSize != 32) || compExactlyDependsOn(InstructionSet_AVX2)) { var_types simdType = getSIMDTypeForSize(simdSize); @@ -1409,7 +1409,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || compExactlyDependsOn(InstructionSet_AVX2)) + if ((simdSize != 32) || compExactlyDependsOn(InstructionSet_AVX2)) { var_types simdType = getSIMDTypeForSize(simdSize); @@ -1443,7 +1443,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || compExactlyDependsOn(InstructionSet_AVX2)) + if ((simdSize != 32) || compExactlyDependsOn(InstructionSet_AVX2)) { var_types simdType = getSIMDTypeForSize(simdSize); @@ -1461,7 +1461,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); - if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || compExactlyDependsOn(InstructionSet_AVX2)) + if ((simdSize != 32) || compExactlyDependsOn(InstructionSet_AVX2)) { var_types simdType = getSIMDTypeForSize(simdSize); @@ -2024,7 +2024,12 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, assert(sig->numArgs == 1); var_types simdType = getSIMDTypeForSize(simdSize); - if (varTypeIsFloating(simdBaseType)) + if ((simdSize == 32) && !compOpportunisticallyDependsOn(InstructionSet_AVX2)) + { + // Vector256 for integer types requires AVX2 + break; + } + else if (varTypeIsFloating(simdBaseType)) { if (!compOpportunisticallyDependsOn(InstructionSet_SSE3)) { diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index a6b0ceb91ba95..1331644a0a992 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -3456,7 +3456,7 @@ void Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) // e6, e7, e4, e5 | e2, e3, e0, e1 // e7, e6, e5, e4 | e3, e2, e1, e0 - shuffleConst = 0x4D; + shuffleConst = 0x4E; break; } From 29cc2a2c23ce15469575a0b25c8b8b453a1d975f Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 24 Jan 2022 20:32:43 +0100 Subject: [PATCH 178/308] Don't reference .NETFramework shims in libraries product or test composition (#64193) * Don't reference .NETFramework shims Stop referencing .NETFramework shims in libraries ref or source projects as those are supplementary and shouldn't impact the product composition. --- src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj | 1 - .../System.Formats.Cbor/src/System.Formats.Cbor.csproj | 1 - src/libraries/System.IO.FileSystem/tests/File/EncryptDecrypt.cs | 2 -- .../tests/FunctionalTests/SocketDuplicationTests.cs | 1 - 4 files changed, 5 deletions(-) diff --git a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj index 9cc4d09bf298b..2005ee7715654 100644 --- a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj +++ b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj @@ -176,7 +176,6 @@ System.Data.Odbc.OdbcTransaction - diff --git a/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj b/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj index 29b98e8541577..c4783ca29c167 100644 --- a/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj +++ b/src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj @@ -49,7 +49,6 @@ System.Formats.Cbor.CborWriter - diff --git a/src/libraries/System.IO.FileSystem/tests/File/EncryptDecrypt.cs b/src/libraries/System.IO.FileSystem/tests/File/EncryptDecrypt.cs index c4d34c320668e..d4965d1dbedb6 100644 --- a/src/libraries/System.IO.FileSystem/tests/File/EncryptDecrypt.cs +++ b/src/libraries/System.IO.FileSystem/tests/File/EncryptDecrypt.cs @@ -3,9 +3,7 @@ using Microsoft.DotNet.XUnitExtensions; using System.Diagnostics; -using System.Diagnostics.Eventing.Reader; using System.Security; -using System.ServiceProcess; using Xunit; using Xunit.Abstractions; diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketDuplicationTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketDuplicationTests.cs index 8e257352fd18c..b59c5ebd92a33 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketDuplicationTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketDuplicationTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; -using System.Drawing.Drawing2D; using System.IO; using System.IO.Pipes; using System.Runtime.Serialization.Formatters.Binary; From 1c509934921d6a8b52cc9cb48e983b56da759580 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang <16830051+mdh1418@users.noreply.github.com> Date: Mon, 24 Jan 2022 15:06:56 -0500 Subject: [PATCH 179/308] [Android][libs] Enable Internal.Console.Write in System.Private.CoreLib (#63949) * [Android][libs] Enable Internal.Console.Write in System.Private.CoreLib * [docs] Add debugging System.Private.CoreLib Internal.Console.Write * Elaborate on debugging corelib log * Address feedback --- .../debugging/libraries/debugging-corelib.md | 7 ++++++ .../src/Internal/Console.Android.cs | 24 +++++++++++++++++++ .../System.Private.CoreLib.Shared.projitems | 9 ++++++- 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 docs/workflow/debugging/libraries/debugging-corelib.md create mode 100644 src/libraries/System.Private.CoreLib/src/Internal/Console.Android.cs diff --git a/docs/workflow/debugging/libraries/debugging-corelib.md b/docs/workflow/debugging/libraries/debugging-corelib.md new file mode 100644 index 0000000000000..9dd817d5bf7ff --- /dev/null +++ b/docs/workflow/debugging/libraries/debugging-corelib.md @@ -0,0 +1,7 @@ +Debugging System.Private.CoreLib +========================== + +`System.Console.Write`/`System.Console.WriteLine` cannot be used in `System.Private.CoreLib`. Instead, use `Internal.Console.Write` to add temporary logging for printf-style debugging. + +### Android +The logs can be found through the generated Android Debug Bridge log or viewed directly through ADB logcat. diff --git a/src/libraries/System.Private.CoreLib/src/Internal/Console.Android.cs b/src/libraries/System.Private.CoreLib/src/Internal/Console.Android.cs new file mode 100644 index 0000000000000..a1f427d0af7f1 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/Internal/Console.Android.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. + +using System; +using System.Runtime.InteropServices; + +namespace Internal +{ + public static partial class Console + { + public static unsafe void Write(string s) + { + Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Debug, "DOTNET", s ?? string.Empty); + } + + public static partial class Error + { + public static unsafe void Write(string s) + { + Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Error, "DOTNET", s ?? string.Empty); + } + } + } +} \ No newline at end of file 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 ebbc2d77b6a93..d5ce32af96642 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 @@ -2120,7 +2120,14 @@ Common\System\IO\PathInternal.Unix.cs - + + + + Common\Interop\Android\Interop.Logcat.cs + + + Common\Interop\Android\Interop.Libraries.cs + From ae755ab3c7f838f7dccd2a4c2d5934a9d7d82c69 Mon Sep 17 00:00:00 2001 From: Fan Yang <52458914+fanyang-mono@users.noreply.github.com> Date: Mon, 24 Jan 2022 15:10:22 -0500 Subject: [PATCH 180/308] Install v8 and Prebuild wasm (#64100) --- .devcontainer/Dockerfile | 9 +++++++++ .devcontainer/scripts/onCreateCommand.sh | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 31ff731b02911..2634a9528f1ee 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -10,3 +10,12 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ build-essential python curl git lldb-6.0 liblldb-6.0-dev \ libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev \ libssl-dev libnuma-dev libkrb5-dev zlib1g-dev ninja-build + +# Install V8 Engine +SHELL ["/bin/bash", "-c"] + +RUN curl -sSL "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/linux/chromium-v8/v8-linux64-rel-8.5.183.zip" -o ./v8.zip \ + && unzip ./v8.zip -d /usr/local/v8 \ + && echo $'#!/usr/bin/env bash\n\ +"/usr/local/v8/d8" --snapshot_blob="/usr/local/v8/snapshot_blob.bin" "$@"\n' > /usr/local/bin/v8 \ + && chmod +x /usr/local/bin/v8 \ No newline at end of file diff --git a/.devcontainer/scripts/onCreateCommand.sh b/.devcontainer/scripts/onCreateCommand.sh index faf7cb08d1afa..9a7e6718ba32d 100755 --- a/.devcontainer/scripts/onCreateCommand.sh +++ b/.devcontainer/scripts/onCreateCommand.sh @@ -7,5 +7,10 @@ set -e # restore libs tests so that the project is ready to be loaded by OmniSharp ./build.sh libs.tests -restore +# prebuild for WASM, so it is ready for wasm development +make -C src/mono/wasm provision-wasm +export EMSDK_PATH=$PWD/src/mono/wasm/emsdk +./build.sh mono+libs -os Browser -c release + # save the commit hash of the currently built assemblies, so developers know which version was built git rev-parse HEAD > ./artifacts/prebuild.sha From df69293bdbe75bf5903583c472fcd257119dbda4 Mon Sep 17 00:00:00 2001 From: Jo Shields Date: Mon, 24 Jan 2022 16:29:57 -0500 Subject: [PATCH 181/308] Port Mono to Raspberry Pi, ship as new linux-armv6 RID (#62594) * Initial ARMv6 arch addition. Builds mono runtime, not CoreCLR (Mono already supports the CPU arch subset used by Raspberry Pi, whilst porting CoreCLR to e.g. VFPv2 would be major work) * Build small clr subset on ARMv6, it's needed for SDK and we want to check it works --- Directory.Build.props | 1 + eng/Subsets.props | 2 +- eng/build.sh | 6 +-- eng/native/build-commons.sh | 6 ++- eng/native/configurecompiler.cmake | 19 +++++++++ eng/native/configureplatform.cmake | 13 ++++++ eng/native/configuretools.cmake | 4 +- eng/native/functions.cmake | 6 ++- eng/native/init-os-and-arch.sh | 4 ++ eng/native/tryrun.cmake | 6 +-- eng/pipelines/common/platform-matrix.yml | 25 ++++++++++++ .../libraries/helix-queues-setup.yml | 5 +++ eng/pipelines/runtime-staging.yml | 40 +++++++++++++++++++ eng/targetingpacks.targets | 4 +- src/coreclr/inc/volatile.h | 5 ++- src/coreclr/jit/CMakeLists.txt | 20 +++++++++- src/coreclr/pal/inc/unixasmmacros.inc | 2 + src/coreclr/pal/inc/unixasmmacrosarm.inc | 4 ++ src/coreclr/pal/src/CMakeLists.txt | 3 ++ .../src/arch/arm/callsignalhandlerwrapper.S | 2 + src/coreclr/pal/src/arch/arm/context2.S | 2 + src/coreclr/pal/src/arch/arm/debugbreak.S | 2 + .../pal/src/arch/arm/exceptionhelper.S | 2 + src/coreclr/pal/src/libunwind/CMakeLists.txt | 11 ++++- .../pal/src/libunwind/src/CMakeLists.txt | 10 +++++ .../pkg/projects/netcoreappRIDs.props | 3 ++ .../src/runtime.compatibility.json | 16 +++++++- .../src/runtime.json | 13 +++++- .../src/runtimeGroups.props | 4 +- .../Runtime/InteropServices/Architecture.cs | 3 +- .../RuntimeInformation.ProcessArchitecture.cs | 2 + .../tests/CheckArchitectureTests.cs | 4 ++ .../System.Runtime/ref/System.Runtime.cs | 1 + src/libraries/externals.csproj | 2 +- src/libraries/tests.proj | 2 +- src/mono/CMakeLists.txt | 13 +++++- .../System.Private.CoreLib.csproj | 6 ++- src/mono/mono.proj | 14 ++++++- .../corehost/fxr/standalone/CMakeLists.txt | 4 ++ src/native/corehost/hostmisc/utils.cpp | 2 + .../corehost/test/nativehost/CMakeLists.txt | 4 ++ src/native/eventpipe/ep-event-source.c | 2 + .../System.Native/pal_runtimeinformation.h | 3 +- 43 files changed, 272 insertions(+), 30 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index e9e6fc4e36234..d862ee091fe81 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -29,6 +29,7 @@ <_hostArch>$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant) $(_hostArch) arm + armv6 armel arm64 loongarch64 diff --git a/eng/Subsets.props b/eng/Subsets.props index 5ce5417445136..fbe6f9712686e 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -27,7 +27,7 @@ flavor is used to decide when to build the hosts and installers. --> CoreCLR - Mono + Mono diff --git a/eng/build.sh b/eng/build.sh index ea8e3089e95f4..167f8e2014182 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -17,7 +17,7 @@ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" usage() { echo "Common settings:" - echo " --arch (-a) Target platform: x86, x64, arm, armel, arm64, loongarch64, s390x or wasm." + echo " --arch (-a) Target platform: x86, x64, arm, armv6, armel, arm64, loongarch64, s390x or wasm." echo " [Default: Your machine's architecture.]" echo " --binaryLog (-bl) Output binary log." echo " --cross Optional argument to signify cross compilation." @@ -206,12 +206,12 @@ while [[ $# > 0 ]]; do fi passedArch="$(echo "$2" | tr "[:upper:]" "[:lower:]")" case "$passedArch" in - x64|x86|arm|armel|arm64|loongarch64|s390x|wasm) + x64|x86|arm|armv6|armel|arm64|loongarch64|s390x|wasm) arch=$passedArch ;; *) echo "Unsupported target architecture '$2'." - echo "The allowed values are x86, x64, arm, armel, arm64, loongarch64, s390x, and wasm." + echo "The allowed values are x86, x64, arm, armv6, armel, arm64, loongarch64, s390x, and wasm." exit 1 ;; esac diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh index 373091b13a001..294e9832ad310 100755 --- a/eng/native/build-commons.sh +++ b/eng/native/build-commons.sh @@ -197,7 +197,7 @@ usage() echo "" echo "Common Options:" echo "" - echo "BuildArch can be: -arm, -armel, -arm64, -loongarch64, -s390x, x64, x86, -wasm" + echo "BuildArch can be: -arm, -armv6, -armel, -arm64, -loongarch64, -s390x, x64, x86, -wasm" echo "BuildType can be: -debug, -checked, -release" echo "-os: target OS (defaults to running OS)" echo "-bindir: output directory (defaults to $__ProjectRoot/artifacts)" @@ -270,6 +270,10 @@ while :; do __BuildArch=arm ;; + armv6|-armv6) + __BuildArch=armv6 + ;; + arm64|-arm64) __BuildArch=arm64 ;; diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index fad1ac58d39c8..b67594cb60fb2 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -213,6 +213,9 @@ elseif (CLR_CMAKE_HOST_ARCH_I386) elseif (CLR_CMAKE_HOST_ARCH_ARM) set(ARCH_HOST_NAME arm) add_definitions(-DHOST_ARM) +elseif (CLR_CMAKE_HOST_ARCH_ARMV6) + set(ARCH_HOST_NAME armv6) + add_definitions(-DHOST_ARMV6) elseif (CLR_CMAKE_HOST_ARCH_ARM64) set(ARCH_HOST_NAME arm64) add_definitions(-DHOST_ARM64 -DHOST_64BIT) @@ -238,6 +241,8 @@ if (CLR_CMAKE_HOST_UNIX) message("Detected Linux x86_64") elseif(CLR_CMAKE_HOST_UNIX_ARM) message("Detected Linux ARM") + elseif(CLR_CMAKE_HOST_UNIX_ARMV6) + message("Detected Linux ARMv6") elseif(CLR_CMAKE_HOST_UNIX_ARM64) message("Detected Linux ARM64") elseif(CLR_CMAKE_HOST_UNIX_LOONGARCH64) @@ -301,6 +306,12 @@ elseif (CLR_CMAKE_TARGET_ARCH_ARM) set(ARCH_TARGET_NAME arm) add_compile_definitions($<$>>:TARGET_ARM>) add_compile_definitions($<$>>:TARGET_32BIT>) +elseif (CLR_CMAKE_TARGET_ARCH_ARMV6) + set(ARCH_SOURCES_DIR arm) + set(ARCH_TARGET_NAME armv6) + add_compile_definitions($<$>>:TARGET_ARM>) + add_compile_definitions($<$>>:TARGET_ARMV6>) + add_compile_definitions($<$>>:TARGET_32BIT>) elseif (CLR_CMAKE_TARGET_ARCH_I386) set(ARCH_TARGET_NAME x86) set(ARCH_SOURCES_DIR i386) @@ -507,6 +518,14 @@ if(CLR_CMAKE_HOST_UNIX_ARM) endif(ARM_SOFTFP) endif(CLR_CMAKE_HOST_UNIX_ARM) +if(CLR_CMAKE_HOST_UNIX_ARMV6) + add_compile_options(-mfpu=vfp) + add_definitions(-DCLR_ARM_FPU_CAPABILITY=0x0) + add_compile_options(-march=armv6zk) + add_compile_options(-mcpu=arm1176jzf-s) + add_compile_options(-mfloat-abi=hard) +endif(CLR_CMAKE_HOST_UNIX_ARMV6) + if(CLR_CMAKE_HOST_UNIX_X86) add_compile_options(-msse2) endif() diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake index cdf33430b49f1..ecf10a8d4c39e 100644 --- a/eng/native/configureplatform.cmake +++ b/eng/native/configureplatform.cmake @@ -41,6 +41,8 @@ if(CLR_CMAKE_HOST_OS STREQUAL Linux) set(CLR_CMAKE_HOST_UNIX_ARMV7L 1) 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 armv6 OR CMAKE_SYSTEM_PROCESSOR STREQUAL armv6l) + set(CLR_CMAKE_HOST_UNIX_ARMV6 1) elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL arm64) set(CLR_CMAKE_HOST_UNIX_ARM64 1) elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL loongarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL loongarch64) @@ -217,6 +219,13 @@ if(CLR_CMAKE_HOST_UNIX_ARM) if(CLR_CMAKE_HOST_UNIX_ARMV7L) set(CLR_CMAKE_HOST_ARCH_ARMV7L 1) endif() +elseif(CLR_CMAKE_HOST_UNIX_ARMV6) + set(CLR_CMAKE_HOST_ARCH_ARMV6 1) + set(CLR_CMAKE_HOST_ARCH "armv6") + + if(CLR_CMAKE_HOST_UNIX_ARMV6L) + set(CLR_CMAKE_HOST_ARCH_ARMV6L 1) + endif() elseif(CLR_CMAKE_HOST_UNIX_ARM64) set(CLR_CMAKE_HOST_ARCH_ARM64 1) set(CLR_CMAKE_HOST_ARCH "arm64") @@ -277,6 +286,8 @@ if (CLR_CMAKE_TARGET_ARCH STREQUAL x64) set(CLR_CMAKE_TARGET_ARCH_LOONGARCH64 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL arm) set(CLR_CMAKE_TARGET_ARCH_ARM 1) + elseif(CLR_CMAKE_TARGET_ARCH STREQUAL armv6) + set(CLR_CMAKE_TARGET_ARCH_ARMV6 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL armel) set(CLR_CMAKE_TARGET_ARCH_ARM 1) set(CLR_CMAKE_TARGET_ARCH_ARMV7L 1) @@ -379,6 +390,8 @@ if(CLR_CMAKE_TARGET_UNIX) set(CLR_CMAKE_TARGET_UNIX_ARM 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL arm) set(CLR_CMAKE_TARGET_UNIX_ARM 1) + elseif(CLR_CMAKE_TARGET_ARCH STREQUAL armv6) + set(CLR_CMAKE_TARGET_UNIX_ARMV6 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL arm64) set(CLR_CMAKE_TARGET_UNIX_ARM64 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL loongarch64) diff --git a/eng/native/configuretools.cmake b/eng/native/configuretools.cmake index 136cd67925d0c..ad5dc38107c33 100644 --- a/eng/native/configuretools.cmake +++ b/eng/native/configuretools.cmake @@ -52,8 +52,8 @@ if(NOT WIN32 AND NOT CLR_CMAKE_TARGET_BROWSER) if(CLR_CMAKE_TARGET_ANDROID) set(TOOLSET_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 OR CMAKE_SYSTEM_PROCESSOR STREQUAL s390x)) + elseif(CMAKE_CROSSCOMPILING AND NOT DEFINED CLR_CROSS_COMPONENTS_BUILD AND + CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv7l|armv6l|aarch64|arm|s390x)$") set(TOOLSET_PREFIX "${TOOLCHAIN}-") else() set(TOOLSET_PREFIX "") diff --git a/eng/native/functions.cmake b/eng/native/functions.cmake index c4af68ba7dc61..0c28f75706de1 100644 --- a/eng/native/functions.cmake +++ b/eng/native/functions.cmake @@ -4,7 +4,7 @@ function(clr_unknown_arch) elseif(CLR_CROSS_COMPONENTS_BUILD) 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, LOONGARCH64 and ARM are supported. Found: ${CMAKE_SYSTEM_PROCESSOR}") + message(FATAL_ERROR "Only AMD64, ARMV6, ARM64, LOONGARCH64 and ARM are supported. Found: ${CMAKE_SYSTEM_PROCESSOR}") endif() endfunction() @@ -155,6 +155,10 @@ function(find_unwind_libs UnwindLibs) find_library(UNWIND_ARCH NAMES unwind-arm) endif() + if(CLR_CMAKE_HOST_ARCH_ARMV6) + find_library(UNWIND_ARCH NAMES unwind-arm) + endif() + if(CLR_CMAKE_HOST_ARCH_ARM64) find_library(UNWIND_ARCH NAMES unwind-aarch64) endif() diff --git a/eng/native/init-os-and-arch.sh b/eng/native/init-os-and-arch.sh index 586534be1c8aa..eda07a5feebbd 100644 --- a/eng/native/init-os-and-arch.sh +++ b/eng/native/init-os-and-arch.sh @@ -53,6 +53,10 @@ case "$CPUName" in fi ;; + armv6l) + arch=armv6 + ;; + i[3-6]86) echo "Unsupported CPU $CPUName detected, build might not succeed!" arch=x86 diff --git a/eng/native/tryrun.cmake b/eng/native/tryrun.cmake index e8a04c5698ad3..fca410fcb4b42 100644 --- a/eng/native/tryrun.cmake +++ b/eng/native/tryrun.cmake @@ -68,7 +68,7 @@ if(DARWIN) else() message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only arm64 or x64 is supported for OSX cross build!") endif() -elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|arm64|loongarch64|s390x|x86)$" OR FREEBSD OR ILLUMOS) +elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|armv6|arm64|loongarch64|s390x|x86)$" OR FREEBSD OR ILLUMOS) set_cache_value(FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL_EXITCODE 1) set_cache_value(GETPWUID_R_SETS_ERRNO_EXITCODE 0) set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 0) @@ -146,9 +146,9 @@ elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|arm64|loongarch64|s390x|x86)$" OR F set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES_EXITCODE 0) endif() else() - message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, arm64, loongarch64, s390x and x86 are supported!") + message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, armv6, arm64, loongarch64, s390x and x86 are supported!") endif() -if(TARGET_ARCH_NAME STREQUAL "x86" OR TARGET_ARCH_NAME STREQUAL "s390x" OR TARGET_ARCH_NAME STREQUAL "loongarch64") +if(TARGET_ARCH_NAME STREQUAL "x86" OR TARGET_ARCH_NAME STREQUAL "s390x" OR TARGET_ARCH_NAME STREQUAL "armv6" OR TARGET_ARCH_NAME STREQUAL "loongarch64") set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES_EXITCODE 0) endif() diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index 282fa56755081..0938ee359b4a4 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -52,6 +52,31 @@ jobs: crossrootfsDir: '/crossrootfs/arm' ${{ insert }}: ${{ parameters.jobParameters }} +# Linux armv6 +- ${{ if or(containsValue(parameters.platforms, 'Linux_armv6'), in(parameters.platformGroup, 'all', 'gcstress')) }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + variables: ${{ parameters.variables }} + osGroup: Linux + archType: armv6 + targetRid: linux-armv6 + platform: Linux_armv6 + container: + image: ubuntu-20.04-cross-armv6-raspbian-10-20211208135931-e6e3ac4 + registry: mcr + jobParameters: + runtimeFlavor: ${{ parameters.runtimeFlavor }} + stagedBuild: ${{ parameters.stagedBuild }} + buildConfig: ${{ parameters.buildConfig }} + ${{ if eq(parameters.passPlatforms, true) }}: + platforms: ${{ parameters.platforms }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + crossBuild: true + crossrootfsDir: '/crossrootfs/armv6' + ${{ insert }}: ${{ parameters.jobParameters }} + # Linux arm64 - ${{ if or(containsValue(parameters.platforms, 'Linux_arm64'), in(parameters.platformGroup, 'all', 'gcstress')) }}: diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index dec87138ed456..70161eb7e1968 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -33,6 +33,11 @@ jobs: - (Debian.10.Arm32.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-arm32v7-20210304164340-6616c63 - (Debian.11.Arm32.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-arm32v7-20210304164347-5a7c380 + # Linux armv6 + - ${{ if eq(parameters.platform, 'Linux_armv6') }}: +# - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: + - (Raspbian.10.Armv6.Open)Raspbian.9.Arm32.IoT.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:raspbian-10-helix-arm32v6-20211215185610-60748cc + # Linux arm64 - ${{ if eq(parameters.platform, 'Linux_arm64') }}: - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: diff --git a/eng/pipelines/runtime-staging.yml b/eng/pipelines/runtime-staging.yml index d49ceeed3ef53..e06a9a6344d9b 100644 --- a/eng/pipelines/runtime-staging.yml +++ b/eng/pipelines/runtime-staging.yml @@ -234,6 +234,46 @@ jobs: eq(variables['monoContainsChange'], true), eq(variables['isRollingBuild'], true)) +# +# Build the whole product using Mono and run libraries tests +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: mono + platforms: + - Linux_armv6 + variables: + # map dependencies variables to local variables + - name: librariesContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: monoContainsChange + value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ] + jobParameters: + testScope: innerloop + nameSuffix: AllSubsets_Mono + buildArgs: -s mono+clr+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true + timeoutInMinutes: 120 + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), + eq(variables['isManualOrIsNotPR'], true), + eq(variables['isFullMatrix'], true)) + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Mono_$(_BuildConfig) + condition: >- + or( + eq(variables['librariesContainsChange'], true), + eq(variables['monoContainsChange'], true), + eq(variables['isRollingBuild'], true)) + # # Build the whole product using Mono and run runtime tests with the JIT. # diff --git a/eng/targetingpacks.targets b/eng/targetingpacks.targets index 4213c84e709d9..150ddf7401c9e 100644 --- a/eng/targetingpacks.targets +++ b/eng/targetingpacks.targets @@ -43,13 +43,13 @@ RuntimeFrameworkName="$(LocalFrameworkOverrideName)" LatestRuntimeFrameworkVersion="$(ProductVersion)" RuntimePackNamePatterns="$(LocalFrameworkOverrideName).Runtime.Mono.**RID**" - RuntimePackRuntimeIdentifiers="linux-arm;linux-arm64;linux-musl-arm64;linux-loongarch64;linux-musl-x64;linux-x64;osx-x64;rhel.6-x64;win-arm;win-arm64;win-x64;win-x86;linux-musl-arm;osx-arm64;maccatalyst-x64;maccatalyst-arm64;browser-wasm;ios-arm64;ios-arm;iossimulator-arm64;iossimulator-x64;iossimulator-x86;tvos-arm64;tvossimulator-arm64;tvossimulator-x64;android-arm64;android-arm;android-x64;android-x86" + RuntimePackRuntimeIdentifiers="linux-arm;linux-armv6;linux-arm64;linux-musl-arm64;linux-loongarch64;linux-musl-x64;linux-x64;osx-x64;rhel.6-x64;win-arm;win-arm64;win-x64;win-x86;linux-musl-arm;osx-arm64;maccatalyst-x64;maccatalyst-arm64;browser-wasm;ios-arm64;ios-arm;iossimulator-arm64;iossimulator-x64;iossimulator-x86;tvos-arm64;tvossimulator-arm64;tvossimulator-x64;android-arm64;android-arm;android-x64;android-x86" RuntimePackLabels="Mono" Condition="'@(KnownRuntimePack)' == '' or !@(KnownRuntimePack->AnyHaveMetadataValue('TargetFramework', '$(NetCoreAppCurrent)'))"/> arm + + armv6 + arm64 diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json index 25a7780058844..fc0fb68ac6e7e 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json +++ b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json @@ -3760,6 +3760,14 @@ "any", "base" ], + "linux-armv6": [ + "linux-armv6", + "linux", + "unix-armv6", + "unix", + "any", + "base" + ], "linux-mips64": [ "linux-mips64", "linux", @@ -8248,6 +8256,12 @@ "any", "base" ], + "unix-armv6": [ + "unix-armv6", + "unix", + "any", + "base" + ], "unix-mips64": [ "unix-mips64", "unix", @@ -8902,4 +8916,4 @@ "any", "base" ] -} \ No newline at end of file +} diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json index f8c398707e0bb..0b71f880e893d 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json +++ b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json @@ -1504,6 +1504,12 @@ "unix-loongarch64" ] }, + "linux-armv6": { + "#import": [ + "linux", + "unix-armv6" + ] + }, "linux-mips64": { "#import": [ "linux", @@ -3444,6 +3450,11 @@ "unix" ] }, + "unix-armv6": { + "#import": [ + "unix" + ] + }, "unix-mips64": { "#import": [ "unix" @@ -3788,4 +3799,4 @@ ] } } -} \ No newline at end of file +} diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props b/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props index d1613c4345b31..da7960a1f5785 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props +++ b/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props @@ -3,11 +3,11 @@ any - x64;x86;arm;armel;arm64;loongarch64;mips64;s390x + x64;x86;arm;armv6;armel;arm64;loongarch64;mips64;s390x unix - x64;x86;arm;armel;arm64;loongarch64;mips64;s390x + x64;x86;arm;armv6;armel;arm64;loongarch64;mips64;s390x linux diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Architecture.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Architecture.cs index 225fec28c763a..4dead88ce4c92 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Architecture.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Architecture.cs @@ -11,6 +11,7 @@ public enum Architecture Arm64, Wasm, S390x, - LoongArch64 + LoongArch64, + Armv6, } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.ProcessArchitecture.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.ProcessArchitecture.cs index 0da595b95e074..d11391a001ef9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.ProcessArchitecture.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.ProcessArchitecture.cs @@ -10,6 +10,8 @@ public static Architecture ProcessArchitecture => Architecture.X86; #elif TARGET_AMD64 => Architecture.X64; +#elif TARGET_ARMV6 + => Architecture.Armv6; #elif TARGET_ARM => Architecture.Arm; #elif TARGET_ARM64 diff --git a/src/libraries/System.Runtime.InteropServices.RuntimeInformation/tests/CheckArchitectureTests.cs b/src/libraries/System.Runtime.InteropServices.RuntimeInformation/tests/CheckArchitectureTests.cs index 6f1b289fd00ee..50fe5210c91ad 100644 --- a/src/libraries/System.Runtime.InteropServices.RuntimeInformation/tests/CheckArchitectureTests.cs +++ b/src/libraries/System.Runtime.InteropServices.RuntimeInformation/tests/CheckArchitectureTests.cs @@ -44,6 +44,10 @@ public void VerifyArchitecture() Assert.Equal(Architecture.LoongArch64, processArch); break; + case Architecture.Armv6: + Assert.Equal(Architecture.Armv6, processArch); + break; + default: Assert.False(true, "Unexpected Architecture."); break; diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 57c9f8368994e..ea9cc7ecc0180 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -13452,6 +13452,7 @@ public enum Architecture Wasm = 4, S390x = 5, LoongArch64 = 6, + Armv6 = 7, } public enum CharSet { diff --git a/src/libraries/externals.csproj b/src/libraries/externals.csproj index 54ef0d14897c6..c04d47d9f897e 100644 --- a/src/libraries/externals.csproj +++ b/src/libraries/externals.csproj @@ -9,7 +9,7 @@ true false true - true + true diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 8d6a97b157d41..2e5554df5bc5b 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -47,7 +47,7 @@ Roslyn4.0.Tests.csproj" /> - + diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt index 79d238e6eeb28..909e1f72c19dc 100644 --- a/src/mono/CMakeLists.txt +++ b/src/mono/CMakeLists.txt @@ -9,6 +9,7 @@ project(mono) include(../../eng/native/configurepaths.cmake) include(${CLR_ENG_NATIVE_DIR}/functions.cmake) +set(CROSS_ROOTFS $ENV{ROOTFS_DIR}) set(CMAKE_C_FLAGS_CHECKED "") set(CMAKE_CXX_FLAGS_CHECKED "") set(CMAKE_EXE_LINKER_FLAGS_CHECKED "") @@ -420,8 +421,13 @@ elseif(TARGET_ARCH STREQUAL "arm64") elseif(TARGET_ARCH MATCHES "arm") set(TARGET_ARM 1) set(MONO_ARCHITECTURE "\"arm\"") - # FIXME: - add_definitions("-DARM_FPU_VFP=1") + if(MONO_ARM_FPU STREQUAL "none") + add_definitions("-DARM_FPU_NONE=1") + elseif(MONO_ARM_FPU STREQUAL "vfp-hard") + add_definitions("-DARM_FPU_VFP_HARD=1") + else() + add_definitions("-DARM_FPU_VFP=1") + endif() set(TARGET_SIZEOF_VOID_P 4) set(SIZEOF_REGISTER 4) # fixme: use separate defines for host/target @@ -644,6 +650,9 @@ elseif(HOST_ANDROID) set(HAVE_SYS_ICU 1) elseif(HOST_LINUX) include(FindPkgConfig) + if(CROSS_ROOTFS) + set(ENV{PKG_CONFIG_ICU_UC_INCLUDEDIR} "${CROSS_ROOTFS}/usr/include") + endif(CROSS_ROOTFS) pkg_check_modules(ICU icu-uc) set(ICU_FLAGS "-DTARGET_UNIX -DU_DISABLE_RENAMING -Wno-reserved-id-macro -Wno-documentation -Wno-documentation-unknown-command -Wno-switch-enum -Wno-covered-switch-default -Wno-extra-semi-stmt -Wno-unknown-warning-option -Wno-deprecated-declarations") set(HAVE_SYS_ICU 1) diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index da99b06e81b8e..d952686ac56b8 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -10,7 +10,7 @@ $(RuntimeBinDir)IL/ Debug;Release;Checked - x64;x86;arm;arm64;s390x;wasm + x64;x86;arm;armv6;arm64;s390x;wasm true @@ -56,6 +56,10 @@ x86 $(DefineConstants);TARGET_X86 + + arm + $(DefineConstants);TARGET_ARMV6 + arm $(DefineConstants);TARGET_ARM diff --git a/src/mono/mono.proj b/src/mono/mono.proj index c7febf933f5c9..bff71d03b47e9 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -228,12 +228,23 @@ - + <_MonoCMakeArgs Include="-DCMAKE_TOOLCHAIN_FILE=$(CrossToolchainFile)" /> + <_MonoCMakeArgs Condition="'$(TargetOS)' == 'Linux' and ('$(TargetArchitecture)' == 'arm' or '$(TargetArchitecture)' == 'armv6')" Include="-DMONO_ARM_FPU=vfp-hard" /> <_MonoBuildEnv Condition="'$(Platform)' == 'arm64'" Include="TARGET_BUILD_ARCH=arm64" /> <_MonoBuildEnv Condition="'$(Platform)' == 'arm'" Include="TARGET_BUILD_ARCH=arm" /> + <_MonoBuildEnv Condition="'$(Platform)' == 'armv6'" Include="TARGET_BUILD_ARCH=armv6" /> <_MonoBuildEnv Condition="'$(Platform)' == 'arm64'" Include="PKG_CONFIG_PATH=$(MonoCrossDir)/usr/lib/aarch64-linux-gnu/pkgconfig" /> <_MonoBuildEnv Condition="'$(Platform)' == 'arm'" Include="PKG_CONFIG_PATH=$(MonoCrossDir)/usr/lib/arm-linux-gnueabihf/pkgconfig" /> + <_MonoBuildEnv Condition="'$(Platform)' == 'armv6'" Include="PKG_CONFIG_PATH=$(MonoCrossDir)/usr/lib/arm-linux-gnueabihf/pkgconfig" /> + <_MonoCFLAGS Condition="'$(TargetArchitecture)' == 'armv6'" Include="-march=armv6zk" /> + <_MonoCFLAGS Condition="'$(TargetArchitecture)' == 'armv6'" Include="-mcpu=arm1176jzf-s" /> + <_MonoCFLAGS Condition="'$(TargetArchitecture)' == 'armv6'" Include="-mfpu=vfp" /> + <_MonoCFLAGS Condition="'$(TargetArchitecture)' == 'armv6'" Include="-mfloat-abi=hard" /> + <_MonoCXXFLAGS Condition="'$(TargetArchitecture)' == 'armv6'" Include="-march=armv6zk" /> + <_MonoCXXFLAGS Condition="'$(TargetArchitecture)' == 'armv6'" Include="-mcpu=arm1176jzf-s" /> + <_MonoCXXFLAGS Condition="'$(TargetArchitecture)' == 'armv6'" Include="-mfpu=vfp" /> + <_MonoCXXFLAGS Condition="'$(TargetArchitecture)' == 'armv6'" Include="-mfloat-abi=hard" /> @@ -514,6 +525,7 @@ <_LinuxFloatAbi Condition="'$(TargetsAndroid)' != 'true'">hf <_Objcopy>objcopy <_Objcopy Condition="'$(Platform)' == 'arm'">arm-linux-$(_LinuxAbi)eabi$(_LinuxFloatAbi)-$(_Objcopy) + <_Objcopy Condition="'$(Platform)' == 'armv6'">arm-linux-$(_LinuxAbi)eabi$(_LinuxFloatAbi)-$(_Objcopy) <_Objcopy Condition="'$(Platform)' == 'arm64'">aarch64-linux-$(_LinuxAbi)-$(_Objcopy) <_Objcopy Condition="'$(Platform)' == 's390x'">s390x-linux-$(_LinuxAbi)-$(_Objcopy) <_Objcopy Condition="'$(Platform)' == 'x64'">x86_64-linux-$(_LinuxAbi)-$(_Objcopy) diff --git a/src/native/corehost/fxr/standalone/CMakeLists.txt b/src/native/corehost/fxr/standalone/CMakeLists.txt index 42785ac91d4b6..5e30750ab4a60 100644 --- a/src/native/corehost/fxr/standalone/CMakeLists.txt +++ b/src/native/corehost/fxr/standalone/CMakeLists.txt @@ -56,3 +56,7 @@ else() endif(WIN32) target_link_libraries(hostfxr libhostcommon) + +if (CLR_CMAKE_TARGET_ARCH_ARMV6) + target_link_libraries(${DOTNET_PROJECT_NAME} atomic) +endif() diff --git a/src/native/corehost/hostmisc/utils.cpp b/src/native/corehost/hostmisc/utils.cpp index 7f5fdbca40ab0..18e54a3e6d7f8 100644 --- a/src/native/corehost/hostmisc/utils.cpp +++ b/src/native/corehost/hostmisc/utils.cpp @@ -191,6 +191,8 @@ const pal::char_t* get_arch() return _X("x64"); #elif defined(TARGET_X86) return _X("x86"); +#elif defined(TARGET_ARMV6) + return _X("armv6"); #elif defined(TARGET_ARM) return _X("arm"); #elif defined(TARGET_ARM64) diff --git a/src/native/corehost/test/nativehost/CMakeLists.txt b/src/native/corehost/test/nativehost/CMakeLists.txt index c21e95a1c71d9..d8b23ca12ce56 100644 --- a/src/native/corehost/test/nativehost/CMakeLists.txt +++ b/src/native/corehost/test/nativehost/CMakeLists.txt @@ -58,3 +58,7 @@ endif() if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64)) target_link_libraries(${DOTNET_PROJECT_NAME} Ole32.lib OleAut32.lib) endif() + +if (CLR_CMAKE_TARGET_ARCH_ARMV6) + target_link_libraries(${DOTNET_PROJECT_NAME} atomic) +endif() diff --git a/src/native/eventpipe/ep-event-source.c b/src/native/eventpipe/ep-event-source.c index 78d1c4852b991..0da7ebc50caad 100644 --- a/src/native/eventpipe/ep-event-source.c +++ b/src/native/eventpipe/ep-event-source.c @@ -34,6 +34,8 @@ const ep_char8_t* _ep_os_info = "Unknown"; const ep_char8_t* _ep_arch_info = "x86"; #elif defined(TARGET_AMD64) const ep_char8_t* _ep_arch_info = "x64"; +#elif defined(TARGET_ARMV6) +const ep_char8_t* _ep_arch_info = "arm32"; #elif defined(TARGET_ARM) const ep_char8_t* _ep_arch_info = "arm32"; #elif defined(TARGET_ARM64) diff --git a/src/native/libs/System.Native/pal_runtimeinformation.h b/src/native/libs/System.Native/pal_runtimeinformation.h index adae223d48339..da39ac51d55ac 100644 --- a/src/native/libs/System.Native/pal_runtimeinformation.h +++ b/src/native/libs/System.Native/pal_runtimeinformation.h @@ -23,5 +23,6 @@ enum ARCH_ARM64, ARCH_WASM, ARCH_S390X, - ARCH_LOONGARCH64 + ARCH_LOONGARCH64, + ARCH_ARMV6, }; From 9eb1b0c8e52f3a9899b787d425c99a6ddf0eb391 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 24 Jan 2022 22:58:47 +0100 Subject: [PATCH 182/308] Fix remote unwind (#64220) The _OOP_find_proc_info was setting only a couple of members of the unw_dyn_info_t instance on stack. So the remaining ones had random values. The load_offset was a recently added member to the struct. When we have updated libunwind, this change came in. The load_offset was random and that has broken unwindign as this offset is subtracted from the IP when looking up unwind info. The fix clears the whole struct. I have verified that the issue we had no longer happens with the fix. --- src/coreclr/pal/src/libunwind/src/oop/_OOP_find_proc_info.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/pal/src/libunwind/src/oop/_OOP_find_proc_info.c b/src/coreclr/pal/src/libunwind/src/oop/_OOP_find_proc_info.c index 74d42ffe2abb2..07bd4a73b276c 100644 --- a/src/coreclr/pal/src/libunwind/src/oop/_OOP_find_proc_info.c +++ b/src/coreclr/pal/src/libunwind/src/oop/_OOP_find_proc_info.c @@ -28,6 +28,8 @@ _OOP_find_proc_info ( int ret = 0; unw_dyn_info_t di; + memset(&di, 0, sizeof(di)); + di.start_ip = start_ip; di.end_ip = end_ip; di.gp = pi->gp; From 070b7d80114354ba9ef5dfb8bd175ca832edb638 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 24 Jan 2022 17:05:04 -0500 Subject: [PATCH 183/308] Put back FindCaseSensitivePrefix regex alternation support (#64204) * Put back FindCaseSensitivePrefix alternation support * Fix the bug from the initial version, and add more comments --- .../RegexFindOptimizations.cs | 2 +- .../RegularExpressions/RegexPrefixAnalyzer.cs | 59 ++++++++++++++++++- .../tests/Regex.Match.Tests.cs | 4 ++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs index f3c5552b8404a..e3c760c2728be 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs @@ -50,7 +50,7 @@ public RegexFindOptimizations(RegexTree tree, CultureInfo culture) } // If there's a leading case-sensitive substring, just use IndexOf and inherit all of its optimizations. - string caseSensitivePrefix = RegexPrefixAnalyzer.FindCaseSensitivePrefix(tree); + string caseSensitivePrefix = RegexPrefixAnalyzer.FindCaseSensitivePrefix(tree.Root); if (caseSensitivePrefix.Length > 1) { LeadingCaseSensitivePrefix = caseSensitivePrefix; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs index 869b5cc5aa285..692ee7d5557c1 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs @@ -50,11 +50,11 @@ private RegexPrefixAnalyzer(Span intStack) _skipAllChildren = false; } - /// Computes the leading substring in ; may be empty. - public static string FindCaseSensitivePrefix(RegexTree tree) + /// Computes the leading substring in ; may be empty. + public static string FindCaseSensitivePrefix(RegexNode node) { var vsb = new ValueStringBuilder(stackalloc char[64]); - Process(tree.Root, ref vsb); + Process(node, ref vsb); return vsb.ToString(); // Processes the node, adding any prefix text to the builder. @@ -87,6 +87,59 @@ static bool Process(RegexNode node, ref ValueStringBuilder vsb) return !rtl; } + // Alternation: find a string that's a shared prefix of all branches + case RegexNodeKind.Alternate: + { + int childCount = node.ChildCount(); + + // Store the initial branch into the target builder, keeping track + // of how much was appended. Any of this contents that doesn't overlap + // will every other branch will be removed before returning. + int initialLength = vsb.Length; + Process(node.Child(0), ref vsb); + int addedLength = vsb.Length - initialLength; + + // Then explore the rest of the branches, finding the length + // of prefix they all share in common with the initial branch. + if (addedLength != 0) + { + var alternateSb = new ValueStringBuilder(64); + + // Process each branch. If we reach a point where we've proven there's + // no overlap, we can bail early. + for (int i = 1; i < childCount && addedLength != 0; i++) + { + alternateSb.Length = 0; + + // Process the branch into a temporary builder. + Process(node.Child(i), ref alternateSb); + + // Find how much overlap there is between this branch's prefix + // and the smallest amount of prefix that overlapped with all + // the previously seen branches. + addedLength = Math.Min(addedLength, alternateSb.Length); + for (int j = 0; j < addedLength; j++) + { + if (vsb[initialLength + j] != alternateSb[j]) + { + addedLength = j; + break; + } + } + } + + alternateSb.Dispose(); + + // Then cull back on what was added based on the other branches. + vsb.Length = initialLength + addedLength; + } + + // Don't explore anything after the alternation. We could make this work if desirable, + // but it's currently not worth the extra complication. The entire contents of every + // branch would need to be identical other than zero-width anchors/assertions. + return false; + } + // One character case RegexNodeKind.One when (node.Options & RegexOptions.IgnoreCase) == 0: vsb.Append(node.Ch); diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs index 8fd3ea6e32231..005e9b27bb203 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs @@ -205,6 +205,10 @@ public static IEnumerable Match_MemberData() yield return (@"(^|($|a+))bc", " aabc", RegexOptions.None, 0, 5, true, "aabc"); yield return (@"yz(^|a+)bc", " yzaabc", RegexOptions.None, 0, 7, true, "yzaabc"); yield return (@"(^a|a$) bc", "a bc", RegexOptions.None, 0, 4, true, "a bc"); + yield return (@"(abcdefg|abcdef|abc|a)h", " ah ", RegexOptions.None, 0, 8, true, "ah"); + yield return (@"(^abcdefg|abcdef|^abc|a)h", " abcdefh ", RegexOptions.None, 0, 13, true, "abcdefh"); + yield return (@"(a|^abcdefg|abcdef|^abc)h", " abcdefh ", RegexOptions.None, 0, 13, true, "abcdefh"); + yield return (@"(abcdefg|abcdef)h", " abcdefghij ", RegexOptions.None, 0, 16, true, "abcdefgh"); if (!RegexHelpers.IsNonBacktracking(engine)) { From db21974134ed636c4e6bbd1a24104dd93c1ebc16 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 24 Jan 2022 14:57:42 -0800 Subject: [PATCH 184/308] Update tests to expect RemoteExecutor to check exit code (#64133) --- .../tests/UnitTests/ConsoleLifetimeExitTests.cs | 12 +++++++----- .../tests/FileSystemTests.cs | 3 +-- .../System.Console/tests/CancelKeyPress.Unix.cs | 2 +- .../tests/System/ExitCodeTests.Unix.cs | 1 + .../JsonSerializerContextTests.cs | 5 ++--- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/ConsoleLifetimeExitTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/ConsoleLifetimeExitTests.cs index 55902bd8a3a9b..9788e6684fc01 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/ConsoleLifetimeExitTests.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/ConsoleLifetimeExitTests.cs @@ -105,10 +105,10 @@ await Host.CreateDefaultBuilder() services.AddHostedService(); }) .RunConsoleAsync(); - }); + }, new RemoteInvokeOptions() { ExpectedExitCode = 124 }); + // TODO: Remove once https://github.com/dotnet/arcade/issues/5865 is resolved remoteHandle.Process.WaitForExit(); - Assert.Equal(124, remoteHandle.Process.ExitCode); } @@ -130,6 +130,9 @@ await Task.Run(() => [ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void EnsureEnvironmentExitDoesntHang() { + // SIGTERM is only handled on net6.0+, so the workaround to "clobber" the exit code is still in place on .NET Framework + int expectedExitCode = PlatformDetection.IsNetFramework ? 0 : 125; + using var remoteHandle = RemoteExecutor.Invoke(async () => { await Host.CreateDefaultBuilder() @@ -139,12 +142,11 @@ await Host.CreateDefaultBuilder() services.AddHostedService(); }) .RunConsoleAsync(); - }, new RemoteInvokeOptions() { TimeOut = 30_000 }); // give a 30 second time out, so if this does hang, it doesn't hang for the full timeout + }, new RemoteInvokeOptions() { TimeOut = 30_000, ExpectedExitCode = expectedExitCode }); // give a 30 second time out, so if this does hang, it doesn't hang for the full timeout Assert.True(remoteHandle.Process.WaitForExit(30_000), "The hosted process should have exited within 30 seconds"); - // SIGTERM is only handled on net6.0+, so the workaround to "clobber" the exit code is still in place on NetFramework - int expectedExitCode = PlatformDetection.IsNetFramework ? 0 : 125; + // TODO: Remove once https://github.com/dotnet/arcade/issues/5865 is resolved Assert.Equal(expectedExitCode, remoteHandle.Process.ExitCode); } diff --git a/src/libraries/Microsoft.VisualBasic.Core/tests/FileSystemTests.cs b/src/libraries/Microsoft.VisualBasic.Core/tests/FileSystemTests.cs index d9f981b242598..a2a8e28e8d17b 100644 --- a/src/libraries/Microsoft.VisualBasic.Core/tests/FileSystemTests.cs +++ b/src/libraries/Microsoft.VisualBasic.Core/tests/FileSystemTests.cs @@ -620,8 +620,7 @@ static void remoteWrite(string fileName, string text) } }, fileName, - text, - new RemoteInvokeOptions() { ExpectedExitCode = 0 }).Dispose(); + text).Dispose(); } } diff --git a/src/libraries/System.Console/tests/CancelKeyPress.Unix.cs b/src/libraries/System.Console/tests/CancelKeyPress.Unix.cs index e72522bafc58b..8fd95102c9dba 100644 --- a/src/libraries/System.Console/tests/CancelKeyPress.Unix.cs +++ b/src/libraries/System.Console/tests/CancelKeyPress.Unix.cs @@ -78,7 +78,7 @@ public void ExitDetectionNotBlockedByHandler() // Release CancelKeyPress mre.Set(); - }).Dispose(); + }, new RemoteInvokeOptions() { ExpectedExitCode = 130 }).Dispose(); } private void HandlerInvokedForSignal(int signalOuter, bool redirectStandardInput) diff --git a/src/libraries/System.Runtime/tests/System/ExitCodeTests.Unix.cs b/src/libraries/System.Runtime/tests/System/ExitCodeTests.Unix.cs index 909f700f5c8da..9fd7ab4f461a9 100644 --- a/src/libraries/System.Runtime/tests/System/ExitCodeTests.Unix.cs +++ b/src/libraries/System.Runtime/tests/System/ExitCodeTests.Unix.cs @@ -42,6 +42,7 @@ public void SigTermExitCode(int? exitCodeOnSigterm) RemoteInvokeOptions options = new RemoteInvokeOptions(); options.StartInfo.RedirectStandardOutput = true; + options.CheckExitCode = false; using (RemoteInvokeHandle remoteExecution = RemoteExecutor.Invoke(action, exitCodeOnSigterm?.ToString() ?? string.Empty, options)) { Process process = remoteExecution.Process; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs index 7bc91507d9ad5..a9fa26e3279f1 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs @@ -24,7 +24,7 @@ public static void VariousNestingAndVisibilityLevelsAreSupported() public static void Converters_AndTypeInfoCreator_NotRooted_WhenMetadataNotPresent() { RemoteExecutor.Invoke( - new Action(() => + () => { object[] objArr = new object[] { new MyStruct() }; @@ -56,8 +56,7 @@ static void AssertFieldNull(string fieldName, JsonSerializerOptions? optionsInst Assert.NotNull(fieldInfo); Assert.Null(fieldInfo.GetValue(optionsInstance)); } - }), - new RemoteInvokeOptions() { ExpectedExitCode = 0 }).Dispose(); + }).Dispose(); } [Fact] From 8bfb725d887ff1673652f1d59f8b2a7f071b659e Mon Sep 17 00:00:00 2001 From: Maoni Stephens Date: Mon, 24 Jan 2022 15:21:21 -0800 Subject: [PATCH 185/308] update generation_allocation_size correctly for SIP regions (#64176) SIP regions need to update the corresponding generation's generation_allocation_size and since this can be more than 1 gen older than the region's gen, we need to make all generation's alloc size get updated. --- src/coreclr/gc/gc.cpp | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 9ab892a5ad338..bc4c11771f2b1 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -20423,23 +20423,33 @@ void gc_heap::gc1() if (n < max_generation) { - compute_promoted_allocation (1 + n); + int highest_gen_number = +#ifdef USE_REGIONS + max_generation; +#else //USE_REGIONS + 1 + n; +#endif //USE_REGIONS + + for (int older_gen_idx = (1 + n); older_gen_idx <= highest_gen_number; older_gen_idx++) + { + compute_promoted_allocation (older_gen_idx); - dynamic_data* dd = dynamic_data_of (1 + n); - size_t new_fragmentation = generation_free_list_space (generation_of (1 + n)) + - generation_free_obj_space (generation_of (1 + n)); + dynamic_data* dd = dynamic_data_of (older_gen_idx); + size_t new_fragmentation = generation_free_list_space (generation_of (older_gen_idx)) + + generation_free_obj_space (generation_of (older_gen_idx)); #ifdef BACKGROUND_GC - if (current_c_gc_state != c_gc_state_planning) + if (current_c_gc_state != c_gc_state_planning) #endif //BACKGROUND_GC - { - if (settings.promotion) - { - dd_fragmentation (dd) = new_fragmentation; - } - else { - //assert (dd_fragmentation (dd) == new_fragmentation); + if (settings.promotion) + { + dd_fragmentation (dd) = new_fragmentation; + } + else + { + //assert (dd_fragmentation (dd) == new_fragmentation); + } } } } @@ -30125,6 +30135,11 @@ void gc_heap::sweep_region_in_plan (heap_segment* region, heap_segment_saved_allocated (region) = heap_segment_allocated (region); heap_segment_allocated (region) = last_marked_obj_end; heap_segment_plan_allocated (region) = heap_segment_allocated (region); + + int plan_gen_num = heap_segment_plan_gen_num (region); + generation_allocation_size (generation_of (plan_gen_num)) += heap_segment_survived (region); + dprintf (REGIONS_LOG, ("sip: g%d alloc size is now %Id", plan_gen_num, + generation_allocation_size (generation_of (plan_gen_num)))); } inline From 74d8d0dea0099da8898953b7b094acc3df62741d Mon Sep 17 00:00:00 2001 From: Mitchell Hwang <16830051+mdh1418@users.noreply.github.com> Date: Mon, 24 Jan 2022 18:46:52 -0500 Subject: [PATCH 186/308] Android remove backward timezones (#64028) Fixes #63693 It was discovered that Android produces duplicate TimeZone DisplayNames among all timezone IDs in GetSystemTimeZones. These duplicate DisplayNames occur across TimeZone IDs that are aliases, where all except one are backward timezone IDs. If a name is changed, put its old spelling in the 'backward' file From the Android TimeZone data file tzdata, it isn't obvious which TimeZone IDs are backward (I find it strange that they're included in the first place), however we discovered that on some versions of Android, there is an adjacent file tzlookup.xml that can aid us in determining which TimeZone IDs are "current" (not backward). This PR aims to utilize tzlookup.xml when it exists and post-filter's the Populated TimeZone IDs in the AndroidTzData instance by removing IDs and their associated information (byteoffset and length) from the AndroidTzData instance if it is not found in tzlookup.xml. This is using the assumption that all non-backward TimeZone IDs make it to the tzlookup.xml file. This PR also adds a new TimeZoneInfo Test to check whether or not there are duplicate DisplayNames in GetSystemTimeZones --- .../src/System/TimeZoneInfo.Unix.Android.cs | 92 +++++++++++++++++-- .../tests/System/TimeZoneInfoTests.cs | 14 +++ 2 files changed, 97 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.Android.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.Android.cs index 53baf4eb65111..23c1044e1983c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.Android.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.Android.cs @@ -193,6 +193,7 @@ private sealed class AndroidTzData private string[] _ids; private int[] _byteOffsets; private int[] _lengths; + private bool[] _isBackwards; private string _tzFileDir; private string _tzFilePath; @@ -230,7 +231,7 @@ public AndroidTzData() foreach (var tzFileDir in tzFileDirList) { string tzFilePath = Path.Combine(tzFileDir, TimeZoneFileName); - if (LoadData(tzFilePath)) + if (LoadData(tzFileDir, tzFilePath)) { _tzFileDir = tzFileDir; _tzFilePath = tzFilePath; @@ -241,10 +242,62 @@ public AndroidTzData() throw new TimeZoneNotFoundException(SR.TimeZoneNotFound_ValidTimeZoneFileMissing); } + // On some versions of Android, the tzdata file may still contain backward timezone ids. + // We attempt to use tzlookup.xml, which is available on some versions of Android to help + // validate non-backward timezone ids + // tzlookup.xml is an autogenerated file that contains timezone ids in this form: + // + // + // + // + // Australia/Sydney + // ... + // ... + // Australia/Eucla + // + // + // ... + // ... + // ... + // + // + // + // + // Once the timezone cache is populated with the IDs, we reference tzlookup id tags + // to determine if an id is backwards and label it as such if they are. + private void FilterBackwardIDs(string tzFileDir, out HashSet tzLookupIDs) + { + tzLookupIDs = new HashSet(); + try + { + using (StreamReader sr = File.OpenText(Path.Combine(tzFileDir, "tzlookup.xml"))) + { + string? tzLookupLine; + while (sr.Peek() >= 0) + { + if (!(tzLookupLine = sr.ReadLine())!.AsSpan().TrimStart().StartsWith("') + 1; + int idLength = tzLookupLine.LastIndexOf(" or the end tag are not found + continue; + } + string id = tzLookupLine.Substring(idStart, idLength); + tzLookupIDs.Add(id); + } + } + } + catch {} + } + [MemberNotNullWhen(true, nameof(_ids))] [MemberNotNullWhen(true, nameof(_byteOffsets))] [MemberNotNullWhen(true, nameof(_lengths))] - private bool LoadData(string path) + [MemberNotNullWhen(true, nameof(_isBackwards))] + private bool LoadData(string tzFileDir, string path) { if (!File.Exists(path)) { @@ -254,7 +307,7 @@ private bool LoadData(string path) { using (FileStream fs = File.OpenRead(path)) { - LoadTzFile(fs); + LoadTzFile(tzFileDir, fs); } return true; } @@ -266,7 +319,8 @@ private bool LoadData(string path) [MemberNotNull(nameof(_ids))] [MemberNotNull(nameof(_byteOffsets))] [MemberNotNull(nameof(_lengths))] - private void LoadTzFile(Stream fs) + [MemberNotNull(nameof(_isBackwards))] + private void LoadTzFile(string tzFileDir, Stream fs) { const int HeaderSize = 24; Span buffer = stackalloc byte[HeaderSize]; @@ -274,7 +328,7 @@ private void LoadTzFile(Stream fs) ReadTzDataIntoBuffer(fs, 0, buffer); LoadHeader(buffer, out int indexOffset, out int dataOffset); - ReadIndex(fs, indexOffset, dataOffset); + ReadIndex(tzFileDir, fs, indexOffset, dataOffset); } private void LoadHeader(Span buffer, out int indexOffset, out int dataOffset) @@ -303,16 +357,17 @@ private void LoadHeader(Span buffer, out int indexOffset, out int dataOffs [MemberNotNull(nameof(_ids))] [MemberNotNull(nameof(_byteOffsets))] [MemberNotNull(nameof(_lengths))] - private void ReadIndex(Stream fs, int indexOffset, int dataOffset) + [MemberNotNull(nameof(_isBackwards))] + private void ReadIndex(string tzFileDir, Stream fs, int indexOffset, int dataOffset) { int indexSize = dataOffset - indexOffset; const int entrySize = 52; // Data entry size int entryCount = indexSize / entrySize; - _byteOffsets = new int[entryCount]; _ids = new string[entryCount]; _lengths = new int[entryCount]; - + _isBackwards = new bool[entryCount]; + FilterBackwardIDs(tzFileDir, out HashSet tzLookupIDs); for (int i = 0; i < entryCount; ++i) { LoadEntryAt(fs, indexOffset + (entrySize*i), out string id, out int byteOffset, out int length); @@ -320,6 +375,7 @@ private void ReadIndex(Stream fs, int indexOffset, int dataOffset) _byteOffsets[i] = byteOffset + dataOffset; _ids[i] = id; _lengths[i] = length; + _isBackwards[i] = !tzLookupIDs.Contains(id); if (length < 24) // Header Size { @@ -372,7 +428,25 @@ private void LoadEntryAt(Stream fs, long position, out string id, out int byteOf public string[] GetTimeZoneIds() { - return _ids; + int numTimeZoneIDs = 0; + for (int i = 0; i < _ids.Length; i++) + { + if (!_isBackwards[i]) + { + numTimeZoneIDs++; + } + } + string[] nonBackwardsTZIDs = new string[numTimeZoneIDs]; + var index = 0; + for (int i = 0; i < _ids.Length; i++) + { + if (!_isBackwards[i]) + { + nonBackwardsTZIDs[index] = _ids[i]; + index++; + } + } + return nonBackwardsTZIDs; } public string GetTimeZoneDirectory() diff --git a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs index fb7b8292b03f9..e3e5bdd4564f3 100644 --- a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs +++ b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs @@ -2922,6 +2922,20 @@ public static void AdjustmentRuleBaseUtcOffsetDeltaTest() Assert.Equal(new TimeSpan(2, 0, 0), customTimeZone.GetUtcOffset(new DateTime(2021, 3, 10, 2, 0, 0))); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/64111", TestPlatforms.Linux)] + public static void NoBackwardTimeZones() + { + ReadOnlyCollection tzCollection = TimeZoneInfo.GetSystemTimeZones(); + HashSet tzDisplayNames = new HashSet(); + + foreach (TimeZoneInfo timezone in tzCollection) + { + tzDisplayNames.Add(timezone.DisplayName); + } + Assert.Equal(tzCollection.Count, tzDisplayNames.Count); + } + private static bool IsEnglishUILanguage => CultureInfo.CurrentUICulture.Name.Length == 0 || CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "en"; private static bool IsEnglishUILanguageAndRemoteExecutorSupported => IsEnglishUILanguage && RemoteExecutor.IsSupported; From a5cf724aa2c9a67eb45827b56d6315acd4edea84 Mon Sep 17 00:00:00 2001 From: Santiago Fernandez Madero Date: Mon, 24 Jan 2022 17:28:03 -0800 Subject: [PATCH 187/308] Update main branding to preview2 (#64219) --- eng/Versions.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 6484ee772cec7..e9d607da85bfc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -7,8 +7,8 @@ 0 0 7.0.100 - alpha - 1 + preview + 2 $(MajorVersion).$(MinorVersion).0.0 From 341c3941ad4065686f7a9f627b773b8e4e3c0999 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 24 Jan 2022 21:49:56 -0800 Subject: [PATCH 188/308] Catch UnicodeEncodeErrors (#64251) --- src/coreclr/scripts/jitutil.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/coreclr/scripts/jitutil.py b/src/coreclr/scripts/jitutil.py index 9552869dffa97..5df464da5fc0c 100644 --- a/src/coreclr/scripts/jitutil.py +++ b/src/coreclr/scripts/jitutil.py @@ -85,12 +85,31 @@ def set_pipeline_variable(name, value): print(define_variable_format.format(name, value)) # set variable + ################################################################################ ## ## Helper functions ## ################################################################################ +def decode_string(str_to_decode): + """Decode a UTF-8 encoded bytes to string. + + Args: + str_to_decode (byte stream): Byte stream to decode + + Returns: + String output. If there any encoding/decoding errors, it will replace it with + UnicodeEncodeError. + """ + try: + output = str_to_decode.decode("utf-8", errors='replace') + except UnicodeEncodeError: + output = "UnicodeEncodeError" + except UnicodeDecodeError: + output = "UnicodeDecodeError" + return output + def run_command(command_to_run, _cwd=None, _exit_on_fail=False, _output_file=None): """ Runs the command. @@ -119,15 +138,15 @@ def run_command(command_to_run, _cwd=None, _exit_on_fail=False, _output_file=Non if proc.poll() is not None: break if output: - output_str = output.strip().decode("utf-8", errors='replace') + output_str = decode_string(output.strip()) print(output_str) of.write(output_str + "\n") else: command_stdout, command_stderr = proc.communicate() if len(command_stdout) > 0: - print(command_stdout.decode("utf-8", errors='replace')) + print(decode_string(command_stdout)) if len(command_stderr) > 0: - print(command_stderr.decode("utf-8", errors='replace')) + print(decode_string(command_stderr)) return_code = proc.returncode if _exit_on_fail and return_code != 0: From a5a645313d41332fcb6f90ece69c8c8738c5b93c Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Tue, 25 Jan 2022 08:15:27 +0100 Subject: [PATCH 189/308] Make XmlSerializer.Generator targets incremental (#64191) * Make XmlSerializer.Generator targets incremental Adding inputs and outputs to make XmlSerializer.Generator incremental --- .../src/GenerateNupkgProps.targets | 6 ++++-- .../src/GenerateThisAssemblyCs.targets | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateNupkgProps.targets b/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateNupkgProps.targets index 6a402a0cfeb09..74fd8ebb92b2c 100644 --- a/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateNupkgProps.targets +++ b/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateNupkgProps.targets @@ -10,7 +10,9 @@ Pack="true" /> - + <Project> @@ -25,4 +27,4 @@ Lines="$(PropsFileContents)" Overwrite="true" /> - \ No newline at end of file + diff --git a/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateThisAssemblyCs.targets b/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateThisAssemblyCs.targets index 31fe16ae8c6f1..aa5b94b12c7a6 100644 --- a/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateThisAssemblyCs.targets +++ b/src/libraries/Microsoft.XmlSerializer.Generator/src/GenerateThisAssemblyCs.targets @@ -4,6 +4,8 @@ @@ -44,6 +46,6 @@ namespace Microsoft.XmlSerializer.Generator File="$(IntermediateOutputPath)ThisAssembly.cs" Lines="$(ThisAssemblyCsContents)" Overwrite="true" - Encoding="Unicode"/> + Encoding="Unicode" /> From 9c938f726b7ca6d432114dae0504a5c164e8fbd6 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Tue, 25 Jan 2022 08:15:55 +0100 Subject: [PATCH 190/308] Make sure that shared memory object name meets the length requirements (#64099) Co-authored-by: Stephen Toub --- .../MemoryMappedFile.Unix.cs | 52 +++++++++++++------ .../tests/MemoryMappedFile.CreateNew.Tests.cs | 1 - .../tests/MemoryMappedViewAccessor.Tests.cs | 1 - .../tests/MemoryMappedViewStream.Tests.cs | 1 - .../MemoryMappedViewStreamConformanceTests.cs | 1 - src/native/libs/System.Native/pal_io.c | 6 +++ 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Unix.cs b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Unix.cs index 389ab072d9a6c..6882527cecc8d 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Unix.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Unix.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using Microsoft.Win32.SafeHandles; namespace System.IO.MemoryMappedFiles @@ -173,9 +174,6 @@ private static FileStream CreateSharedBackingObject(Interop.Sys.MemoryMappedProt private static FileStream? CreateSharedBackingObjectUsingMemory( Interop.Sys.MemoryMappedProtections protections, long capacity, HandleInheritability inheritability) { - // The POSIX shared memory object name must begin with '/'. After that we just want something short and unique. - string mapName = string.Create(null, stackalloc char[128], $"/corefx_map_{Guid.NewGuid():N}"); - // Determine the flags to use when creating the shared memory object Interop.Sys.OpenFlags flags = (protections & Interop.Sys.MemoryMappedProtections.PROT_WRITE) != 0 ? Interop.Sys.OpenFlags.O_RDWR : @@ -191,22 +189,32 @@ private static FileStream CreateSharedBackingObject(Interop.Sys.MemoryMappedProt if ((protections & Interop.Sys.MemoryMappedProtections.PROT_EXEC) != 0) perms |= Interop.Sys.Permissions.S_IXUSR; - // Create the shared memory object. - SafeFileHandle fd = Interop.Sys.ShmOpen(mapName, flags, (int)perms); - if (fd.IsInvalid) + string mapName; + SafeFileHandle fd; + + do { - Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); - if (errorInfo.Error == Interop.Error.ENOTSUP) + mapName = GenerateMapName(); + fd = Interop.Sys.ShmOpen(mapName, flags, (int)perms); // Create the shared memory object. + + if (fd.IsInvalid) { - // If ShmOpen is not supported, fall back to file backing object. - // Note that the System.Native shim will force this failure on platforms where - // the result of native shm_open does not work well with our subsequent call - // to mmap. - return null; - } + Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); + fd.Dispose(); - throw Interop.GetExceptionForIoErrno(errorInfo); - } + if (errorInfo.Error == Interop.Error.ENOTSUP) + { + // If ShmOpen is not supported, fall back to file backing object. + // Note that the System.Native shim will force this failure on platforms where + // the result of native shm_open does not work well with our subsequent call to mmap. + return null; + } + else if (errorInfo.Error != Interop.Error.EEXIST) // map with same name already existed + { + throw Interop.GetExceptionForIoErrno(errorInfo); + } + } + } while (fd.IsInvalid); try { @@ -236,6 +244,18 @@ private static FileStream CreateSharedBackingObject(Interop.Sys.MemoryMappedProt fd.Dispose(); throw; } + + static string GenerateMapName() + { + const int MaxSharedMemoryObjectNameLength = 32; // SHM_NAME_MAX on OSX ARM64, on other systems it's equal PATH_MAX (250) + // The POSIX shared memory object name must begin with '/'. After that we just want something short (32) and unique. + return string.Create(MaxSharedMemoryObjectNameLength, 0, (span, state) => + { + Guid.NewGuid().TryFormat(span, out int charsWritten, "N"); + Debug.Assert(charsWritten == MaxSharedMemoryObjectNameLength); + "/dotnet_".CopyTo(span); + }); + } } private static FileStream CreateSharedBackingObjectUsingFile(Interop.Sys.MemoryMappedProtections protections, long capacity, HandleInheritability inheritability) diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFile.CreateNew.Tests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFile.CreateNew.Tests.cs index 4336ce74d6a22..70b82398301d5 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFile.CreateNew.Tests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedFile.CreateNew.Tests.cs @@ -11,7 +11,6 @@ namespace System.IO.MemoryMappedFiles.Tests /// /// Tests for MemoryMappedFile.CreateNew. /// - [ActiveIssue("https://github.com/dotnet/runtime/issues/63240", typeof(PlatformDetection), nameof(PlatformDetection.IsOSX), nameof(PlatformDetection.IsArm64Process), nameof(PlatformDetection.IsNotMonoRuntime))] public class MemoryMappedFileTests_CreateNew : MemoryMappedFilesTestBase { /// diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs index adcfb0e9d4cc4..8fe35396ae804 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs @@ -11,7 +11,6 @@ namespace System.IO.MemoryMappedFiles.Tests /// /// Tests for MemoryMappedViewAccessor. /// - [ActiveIssue("https://github.com/dotnet/runtime/issues/63240", typeof(PlatformDetection), nameof(PlatformDetection.IsOSX), nameof(PlatformDetection.IsArm64Process), nameof(PlatformDetection.IsNotMonoRuntime))] public class MemoryMappedViewAccessorTests : MemoryMappedFilesTestBase { /// diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs index 3a950662e5d49..f279b8c33f98f 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs @@ -11,7 +11,6 @@ namespace System.IO.MemoryMappedFiles.Tests /// /// Tests for MemoryMappedViewStream. /// - [ActiveIssue("https://github.com/dotnet/runtime/issues/63240", typeof(PlatformDetection), nameof(PlatformDetection.IsOSX), nameof(PlatformDetection.IsArm64Process), nameof(PlatformDetection.IsNotMonoRuntime))] public class MemoryMappedViewStreamTests : MemoryMappedFilesTestBase { /// diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStreamConformanceTests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStreamConformanceTests.cs index 1ec0b14fb8a15..c190d329a00fe 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStreamConformanceTests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStreamConformanceTests.cs @@ -45,7 +45,6 @@ private Task CreateStream(byte[] initialData, FileAccess access) } } - [ActiveIssue("https://github.com/dotnet/runtime/issues/63240", typeof(PlatformDetection), nameof(PlatformDetection.IsOSX), nameof(PlatformDetection.IsArm64Process), nameof(PlatformDetection.IsNotMonoRuntime))] public class AnonymousMemoryMappedViewStreamConformanceTests : MemoryMappedViewStreamConformanceTests { protected override MemoryMappedFile CreateFile(int length) => diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index d11ce950f1246..f6cf0d2aa23ea 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -332,6 +332,12 @@ int32_t SystemNative_Unlink(const char* path) intptr_t SystemNative_ShmOpen(const char* name, int32_t flags, int32_t mode) { +#if defined(SHM_NAME_MAX) // macOS + assert(strlen(name) <= SHM_NAME_MAX); +#elif defined(PATH_MAX) // other Unixes + assert(strlen(name) <= PATH_MAX); +#endif + #if HAVE_SHM_OPEN_THAT_WORKS_WELL_ENOUGH_WITH_MMAP flags = ConvertOpenFlags(flags); if (flags == -1) From 0d1049fd11d2e2154ce852970cace53b4b296746 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Tue, 25 Jan 2022 12:00:20 +0200 Subject: [PATCH 191/308] Fix PAL_wprintf for wide characters (#64181) --- src/coreclr/pal/src/cruntime/printfcpp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/pal/src/cruntime/printfcpp.cpp b/src/coreclr/pal/src/cruntime/printfcpp.cpp index d7e992c090a00..fee79c91df12b 100644 --- a/src/coreclr/pal/src/cruntime/printfcpp.cpp +++ b/src/coreclr/pal/src/cruntime/printfcpp.cpp @@ -86,7 +86,7 @@ static int Internal_Convertfwrite(CPalThread *pthrCurrent, const void *buffer, s free(newBuff); return -1; } - ret = InternalFwrite(newBuff, 1, count, stream, &iError); + ret = InternalFwrite(newBuff, 1, nsize, stream, &iError); if (iError != 0) { ERROR("InternalFwrite did not write the whole buffer. Error is %d\n", iError); From 8d0c3d1ab1f16c3a1d15b8d9eb25cc920d936694 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 25 Jan 2022 12:11:58 +0100 Subject: [PATCH 192/308] [main] Update dependencies from dotnet/runtime dotnet/llvm-project (#64205) * Update dependencies from https://github.com/dotnet/runtime build 20220123.5 Microsoft.NETCore.ILAsm , Microsoft.NETCore.DotNetHostPolicy , Microsoft.NETCore.DotNetHost , Microsoft.NETCore.App.Runtime.win-x64 , System.Runtime.CompilerServices.Unsafe , runtime.native.System.IO.Ports , Microsoft.NET.Sdk.IL , System.Text.Json From Version 7.0.0-alpha.1.22066.4 -> To Version 7.0.0-alpha.1.22073.5 * Update dependencies from https://github.com/dotnet/llvm-project build 20220123.1 runtime.win-x64.Microsoft.NETCore.Runtime.ObjWriter , runtime.win-arm64.Microsoft.NETCore.Runtime.ObjWriter , runtime.osx.10.12-x64.Microsoft.NETCore.Runtime.ObjWriter , runtime.osx.11.0-arm64.Microsoft.NETCore.Runtime.ObjWriter , runtime.linux-x64.Microsoft.NETCore.Runtime.ObjWriter , runtime.linux-musl-x64.Microsoft.NETCore.Runtime.ObjWriter , runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.ObjWriter , runtime.linux-arm64.Microsoft.NETCore.Runtime.ObjWriter From Version 1.0.0-alpha.1.22070.1 -> To Version 1.0.0-alpha.1.22073.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 64 ++++++++++++++++++++--------------------- eng/Versions.props | 30 +++++++++---------- global.json | 2 +- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ee709f74031a4..b01aa4c37ed5b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -16,37 +16,37 @@ https://github.com/dotnet/wcf 7f504aabb1988e9a093c1e74d8040bd52feb2f01 - + https://github.com/dotnet/llvm-project - fe77708023f3d8a51c1548b86487a692897227ec + afc9070f64d110ce2bf029a4a624b9dd1c6dbffd - + https://github.com/dotnet/llvm-project - fe77708023f3d8a51c1548b86487a692897227ec + afc9070f64d110ce2bf029a4a624b9dd1c6dbffd - + https://github.com/dotnet/llvm-project - fe77708023f3d8a51c1548b86487a692897227ec + afc9070f64d110ce2bf029a4a624b9dd1c6dbffd - + https://github.com/dotnet/llvm-project - fe77708023f3d8a51c1548b86487a692897227ec + afc9070f64d110ce2bf029a4a624b9dd1c6dbffd - + https://github.com/dotnet/llvm-project - fe77708023f3d8a51c1548b86487a692897227ec + afc9070f64d110ce2bf029a4a624b9dd1c6dbffd - + https://github.com/dotnet/llvm-project - fe77708023f3d8a51c1548b86487a692897227ec + afc9070f64d110ce2bf029a4a624b9dd1c6dbffd - + https://github.com/dotnet/llvm-project - fe77708023f3d8a51c1548b86487a692897227ec + afc9070f64d110ce2bf029a4a624b9dd1c6dbffd - + https://github.com/dotnet/llvm-project - fe77708023f3d8a51c1548b86487a692897227ec + afc9070f64d110ce2bf029a4a624b9dd1c6dbffd @@ -202,37 +202,37 @@ https://github.com/dotnet/llvm-project 79a6d232058e2c2f1d9e833355b72f07fe342a3b - + https://github.com/dotnet/runtime - ae2f60c950cc021921fce83c796cbcb5ff96c658 + 09ff1acdad2e7789908b5db9bb89896144c13042 - + https://github.com/dotnet/runtime - ae2f60c950cc021921fce83c796cbcb5ff96c658 + 09ff1acdad2e7789908b5db9bb89896144c13042 - + https://github.com/dotnet/runtime - ae2f60c950cc021921fce83c796cbcb5ff96c658 + 09ff1acdad2e7789908b5db9bb89896144c13042 - + https://github.com/dotnet/runtime - ae2f60c950cc021921fce83c796cbcb5ff96c658 + 09ff1acdad2e7789908b5db9bb89896144c13042 - + https://github.com/dotnet/runtime - ae2f60c950cc021921fce83c796cbcb5ff96c658 + 09ff1acdad2e7789908b5db9bb89896144c13042 - + https://github.com/dotnet/runtime - ae2f60c950cc021921fce83c796cbcb5ff96c658 + 09ff1acdad2e7789908b5db9bb89896144c13042 - + https://github.com/dotnet/runtime - ae2f60c950cc021921fce83c796cbcb5ff96c658 + 09ff1acdad2e7789908b5db9bb89896144c13042 - + https://github.com/dotnet/runtime - ae2f60c950cc021921fce83c796cbcb5ff96c658 + 09ff1acdad2e7789908b5db9bb89896144c13042 https://github.com/dotnet/linker diff --git a/eng/Versions.props b/eng/Versions.props index e9d607da85bfc..535f0f7e4f01e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -72,20 +72,20 @@ 6.0.0-preview.1.102 - 7.0.0-alpha.1.22066.4 - 7.0.0-alpha.1.22066.4 - 7.0.0-alpha.1.22066.4 + 7.0.0-alpha.1.22073.5 + 7.0.0-alpha.1.22073.5 + 7.0.0-alpha.1.22073.5 3.1.0 - 7.0.0-alpha.1.22066.4 - 1.0.0-alpha.1.22070.1 - 1.0.0-alpha.1.22070.1 - 1.0.0-alpha.1.22070.1 - 1.0.0-alpha.1.22070.1 - 1.0.0-alpha.1.22070.1 - 1.0.0-alpha.1.22070.1 - 1.0.0-alpha.1.22070.1 - 1.0.0-alpha.1.22070.1 + 7.0.0-alpha.1.22073.5 + 1.0.0-alpha.1.22073.1 + 1.0.0-alpha.1.22073.1 + 1.0.0-alpha.1.22073.1 + 1.0.0-alpha.1.22073.1 + 1.0.0-alpha.1.22073.1 + 1.0.0-alpha.1.22073.1 + 1.0.0-alpha.1.22073.1 + 1.0.0-alpha.1.22073.1 5.0.0 4.3.0 @@ -120,11 +120,11 @@ 5.0.0 5.0.0 4.9.0-rc2.21473.1 - 7.0.0-alpha.1.22066.4 - 7.0.0-alpha.1.22066.4 + 7.0.0-alpha.1.22073.5 + 7.0.0-alpha.1.22073.5 4.5.4 4.5.0 - 7.0.0-alpha.1.22066.4 + 7.0.0-alpha.1.22073.5 7.0.0-beta.22060.1 7.0.0-beta.22060.1 diff --git a/global.json b/global.json index e0d86ef423d93..f32ffc29ff09d 100644 --- a/global.json +++ b/global.json @@ -18,6 +18,6 @@ "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.22071.6", "Microsoft.Build.NoTargets": "3.1.0", "Microsoft.Build.Traversal": "3.0.23", - "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.22066.4" + "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.22073.5" } } From 4d16d0934259b2b1b056823986bb0ad08578c5c0 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Tue, 25 Jan 2022 13:09:57 +0100 Subject: [PATCH 193/308] Delete unused ApiCompat baseline files (#64190) * Delete unused ApiCompat baseline files * Delete ApiCompatBaseline.netfx.netstandardOnly.txt * Remove manual .NETFramework baseline validation * Delete ApiCompatBaseline.netcoreapp.netfx461.ignore.txt * Delete ApiCompatBaseline.netcoreapp.netfx461.txt --- src/libraries/shims/ApiCompat.proj | 20 +- ...patBaseline.netcoreapp.netfx461.ignore.txt | 2709 ----------------- .../ApiCompatBaseline.netcoreapp.netfx461.txt | 614 ---- .../ApiCompatBaseline.netfx.netstandard.txt | 102 - ...piCompatBaseline.netfx.netstandardOnly.txt | 870 ------ 5 files changed, 1 insertion(+), 4314 deletions(-) delete mode 100644 src/libraries/shims/ApiCompatBaseline.netcoreapp.netfx461.ignore.txt delete mode 100644 src/libraries/shims/ApiCompatBaseline.netcoreapp.netfx461.txt delete mode 100644 src/libraries/shims/ApiCompatBaseline.netfx.netstandard.txt delete mode 100644 src/libraries/shims/ApiCompatBaseline.netfx.netstandardOnly.txt diff --git a/src/libraries/shims/ApiCompat.proj b/src/libraries/shims/ApiCompat.proj index 3b2c6ceae57c0..e27786ccb1a54 100644 --- a/src/libraries/shims/ApiCompat.proj +++ b/src/libraries/shims/ApiCompat.proj @@ -1,12 +1,5 @@ - - - - - - - @@ -16,8 +9,6 @@ - $(MSBuildThisFileDirectory)ApiCompatBaseline.netcoreapp.netfx461.txt - $(MSBuildThisFileDirectory)ApiCompatBaseline.netcoreapp.netfx461.ignore.txt $(MSBuildThisFileDirectory)ApiCompatBaseline.netcoreapp.netstandard.txt $(MSBuildThisFileDirectory)ApiCompatBaseline.netcoreapp.netstandardOnly.txt $(MSBuildThisFileDirectory)ApiCompatBaseline.PreviousNetCoreApp.txt @@ -32,7 +23,7 @@ @@ -46,15 +37,6 @@ Lines="$(ApiCompatArgs)" Overwrite="true" /> - - - - - $([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)', 'netstandard.library', '$(NetStandardLibraryVersion)', 'build', 'netstandard2.0', 'ref')) diff --git a/src/libraries/shims/ApiCompatBaseline.netcoreapp.netfx461.ignore.txt b/src/libraries/shims/ApiCompatBaseline.netcoreapp.netfx461.ignore.txt deleted file mode 100644 index b0420059f5aae..0000000000000 --- a/src/libraries/shims/ApiCompatBaseline.netcoreapp.netfx461.ignore.txt +++ /dev/null @@ -1,2709 +0,0 @@ -// HttpVersion changed to static class intentionally. See here: https://github.com/dotnet/standard/issues/91 -CannotMakeTypeAbstract : Type 'System.Net.HttpVersion' is abstract in the implementation but is not abstract in the contract. -CannotSealType : Type 'System.Net.HttpVersion' is sealed in the implementation but not sealed in the contract. -MembersMustExist : Member 'System.Net.HttpVersion..ctor()' does not exist in the implementation but it does exist in the contract. - -// RuntimeEnvironment changed to static class intentionally. See here: https://github.com/dotnet/standard/commit/d5fbcbeeeb7f15102fdac111bc8d7d5d72c32036#diff-2856a41639a1f4feb4e95ae667e069b7R10012 -CannotMakeTypeAbstract : Type 'System.Runtime.InteropServices.RuntimeEnvironment' is abstract in the implementation but is not abstract in the contract. -CannotSealType : Type 'System.Runtime.InteropServices.RuntimeEnvironment' is sealed in the implementation but not sealed in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.RuntimeEnvironment..ctor()' does not exist in the implementation but it does exist in the contract. - -// Activator changed to static class intentionally. See here: https://github.com/dotnet/runtime/issues/18630 -CannotMakeTypeAbstract : Type 'System.Activator' is abstract in the implementation but is not abstract in the contract. - -// System.Drawing types changed to static intentionally. Change is source and binary compatible. https://github.com/dotnet/corefx/commit/ad215be2fa28a7d2f19a90c1ba04c50c3b677253 -CannotMakeTypeAbstract : Type 'System.Drawing.Brushes' is abstract in the implementation but is not abstract in the contract. -CannotMakeTypeAbstract : Type 'System.Drawing.Pens' is abstract in the implementation but is not abstract in the contract. -CannotMakeTypeAbstract : Type 'System.Drawing.SystemBrushes' is abstract in the implementation but is not abstract in the contract. -CannotMakeTypeAbstract : Type 'System.Drawing.SystemColors' is abstract in the implementation but is not abstract in the contract. -CannotMakeTypeAbstract : Type 'System.Drawing.SystemFonts' is abstract in the implementation but is not abstract in the contract. -CannotMakeTypeAbstract : Type 'System.Drawing.SystemIcons' is abstract in the implementation but is not abstract in the contract. -CannotMakeTypeAbstract : Type 'System.Drawing.SystemPens' is abstract in the implementation but is not abstract in the contract. -CannotMakeTypeAbstract : Type 'System.Drawing.BufferedGraphicsManager' is abstract in the implementation but is not abstract in the contract. - -// Won't came back into netcoreapp. See here: https://github.com/dotnet/runtime/issues/20974 -MembersMustExist : Member 'System.ComponentModel.DataAnnotations.ValidationContext.ServiceContainer.get()' does not exist in the implementation but it does exist in the contract. - -// Debugger changed to static class intentionally. See here: https://github.com/dotnet/standard/commit/d5fbcbeeeb7f15102fdac111bc8d7d5d72c32036#diff-2856a41639a1f4feb4e95ae667e069b7R10012 -CannotMakeTypeAbstract : Type 'System.Diagnostics.Debugger' is abstract in the implementation but is not abstract in the contract. -MembersMustExist : Member 'System.Diagnostics.Debugger..ctor()' does not exist in the implementation but it does exist in the contract. - -// IRemotingFormatter won't be implemented in netcore20 -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.Formatters.Binary.BinaryFormatter' does not implement interface 'System.Runtime.Remoting.Messaging.IRemotingFormatter' in the implementation but it does in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.IRemotingFormatter' does not exist in the implementation but it does exist in the contract. - -// SchemaImporter won't be implemented in netcore20 -TypesMustExist : Type 'System.Xml.Serialization.SchemaImporter' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSchemaImporter' does not inherit from base type 'System.Xml.Serialization.SchemaImporter' in the implementation but it does in the contract. - -// IServiceProvider won't be implemented by SqlClientFactory. See here: https://github.com/dotnet/runtime/issues/20832 -CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlClient.SqlClientFactory' does not implement interface 'System.IServiceProvider' in the implementation but it does in the contract. - -// DynData Win9x only. Not going to be implemented in any netcore versions. See here: https://github.com/dotnet/runtime/issues/19972 -MembersMustExist : Member 'Microsoft.Win32.RegistryKey Microsoft.Win32.Registry.DynData' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'Microsoft.Win32.RegistryHive Microsoft.Win32.RegistryHive.DynData' does not exist in the implementation but it does exist in the contract. - -// AppDomain.SetupInformation not going to be implemented in netcore20 as no remoting support: -MembersMustExist : Member 'System.AppDomain.SetupInformation.get()' does not exist in the implementation but it does exist in the contract. - -// SetAccessControl in FileStream not going to be implemented in netcore20 as no ACL support: -MembersMustExist : Member 'System.IO.FileStream.SetAccessControl(System.Security.AccessControl.FileSecurity)' does not exist in the implementation but it does exist in the contract. - -// StackTrace ctor deprecated in net472 and won't be implemented in any netcoreapp versions: -MembersMustExist : Member 'System.Diagnostics.StackTrace..ctor(System.Threading.Thread, System.Boolean)' does not exist in the implementation but it does exist in the contract. - -// Dan said there is a reason for those in System.Resrouces to ignore: -MembersMustExist : Member 'System.String System.Resources.ResourceManager.BaseNameField' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Hashtable System.Resources.ResourceSet.Table' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Resources.IResourceReader System.Resources.ResourceSet.Reader' does not exist in the implementation but it does exist in the contract. - -// Thread.CurrentContext is not supported because of remoting: -MembersMustExist : Member 'System.Threading.Thread.CurrentContext.get()' does not exist in the implementation but it does exist in the contract. - -// Debug.Listeners won't be implemented in netstandard20 and netcoreapp20. See here: https://github.com/dotnet/standard/issues/84 -MembersMustExist : Member 'System.Diagnostics.Debug.Listeners.get()' does not exist in the implementation but it does exist in the contract. - -// IsolatedStorage methods won't be implemented in netstandard20 and netcoreapp20. See here: https://github.com/dotnet/runtime/issues/20970 -MembersMustExist : Member 'System.IO.IsolatedStorage.IsolatedStorage.GetPermission(System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.IsolatedStorage.IsolatedStorageFile.GetPermission(System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.IsolatedStorage.IsolatedStorageFile.GetStore(System.IO.IsolatedStorage.IsolatedStorageScope, System.Security.Policy.Evidence, System.Type, System.Security.Policy.Evidence, System.Type)' does not exist in the implementation but it does exist in the contract. - -// Crypto types and members are sealed in netstandard and netcoreapp because they are sealed in Xamarin. https://github.com/dotnet/runtime/issues/20870 -CannotSealType : Type 'System.Security.Cryptography.SHA1Managed' is sealed in the implementation but not sealed in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA1Managed.HashCore(System.Byte[], System.Int32, System.Int32)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA1Managed.HashFinal()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA1Managed.Initialize()' is non-virtual in the implementation but is virtual in the contract. -CannotSealType : Type 'System.Security.Cryptography.SHA256Managed' is sealed in the implementation but not sealed in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA256Managed.HashCore(System.Byte[], System.Int32, System.Int32)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA256Managed.HashFinal()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA256Managed.Initialize()' is non-virtual in the implementation but is virtual in the contract. -CannotSealType : Type 'System.Security.Cryptography.SHA384Managed' is sealed in the implementation but not sealed in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA384Managed.HashCore(System.Byte[], System.Int32, System.Int32)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA384Managed.HashFinal()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA384Managed.Initialize()' is non-virtual in the implementation but is virtual in the contract. -CannotSealType : Type 'System.Security.Cryptography.SHA512Managed' is sealed in the implementation but not sealed in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA512Managed.HashCore(System.Byte[], System.Int32, System.Int32)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA512Managed.HashFinal()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Security.Cryptography.SHA512Managed.Initialize()' is non-virtual in the implementation but is virtual in the contract. - -// Can't build WindowsIdentities or WindowsPrincipals on non-Windows OSes. https://github.com/dotnet/runtime/issues/20972 -MembersMustExist : Member 'System.Security.Principal.IdentityReferenceCollection.IsReadOnly.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WindowsIdentity..ctor(System.Security.Principal.WindowsIdentity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WindowsIdentity..ctor(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WindowsIdentity.DeviceClaims.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WindowsIdentity.Impersonate()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WindowsIdentity.Impersonate(System.IntPtr)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WindowsIdentity.UserClaims.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WindowsPrincipal.DeviceClaims.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WindowsPrincipal.UserClaims.get()' does not exist in the implementation but it does exist in the contract. - -// Reflection.Emit future unclear and won't be implemented till netcoreapp20. See here: https://github.com/dotnet/runtime/issues/20971 -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.AddResourceFile(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.AddResourceFile(System.String, System.String, System.Reflection.ResourceAttributes)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.DefineDynamicModule(System.String, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.DefineDynamicModule(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.DefineDynamicModule(System.String, System.String, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.DefineResource(System.String, System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.DefineResource(System.String, System.String, System.String, System.Reflection.ResourceAttributes)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.DefineUnmanagedResource(System.Byte[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.DefineUnmanagedResource(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.DefineVersionInfoResource()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.DefineVersionInfoResource(System.String, System.String, System.String, System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.Evidence.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.PermissionSet.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.Save(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.Save(System.String, System.Reflection.PortableExecutableKinds, System.Reflection.ImageFileMachine)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.SetEntryPoint(System.Reflection.MethodInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilder.SetEntryPoint(System.Reflection.MethodInfo, System.Reflection.Emit.PEFileKinds)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilderAccess System.Reflection.Emit.AssemblyBuilderAccess.ReflectionOnly' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilderAccess System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.AssemblyBuilderAccess System.Reflection.Emit.AssemblyBuilderAccess.Save' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ConstructorBuilder.AddDeclarativeSecurity(System.Security.Permissions.SecurityAction, System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ConstructorBuilder.GetModule()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ConstructorBuilder.GetToken()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ConstructorBuilder.ReturnType.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ConstructorBuilder.SetMethodBody(System.Byte[], System.Int32, System.Byte[], System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ConstructorBuilder.SetSymCustomAttribute(System.String, System.Byte[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ConstructorBuilder.Signature.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.EnumBuilder.CreateType()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.EnumBuilder.TypeToken.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.EventBuilder.GetEventToken()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.FieldBuilder.GetToken()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.FieldBuilder.SetMarshal(System.Reflection.Emit.UnmanagedMarshal)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ILGenerator.EmitCalli(System.Reflection.Emit.OpCode, System.Runtime.InteropServices.CallingConvention, System.Type, System.Type[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ILGenerator.MarkSequencePoint(System.Diagnostics.SymbolStore.ISymbolDocumentWriter, System.Int32, System.Int32, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.MethodBuilder.AddDeclarativeSecurity(System.Security.Permissions.SecurityAction, System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.MethodBuilder.CreateMethodBody(System.Byte[], System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.MethodBuilder.GetModule()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.MethodBuilder.GetToken()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.MethodBuilder.SetMarshal(System.Reflection.Emit.UnmanagedMarshal)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.MethodBuilder.SetMethodBody(System.Byte[], System.Int32, System.Byte[], System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.MethodBuilder.SetSymCustomAttribute(System.String, System.Byte[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.MethodBuilder.Signature.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.DefineDocument(System.String, System.Guid, System.Guid, System.Guid)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.DefineManifestResource(System.String, System.IO.Stream, System.Reflection.ResourceAttributes)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.DefinePInvokeMethod(System.String, System.String, System.Reflection.MethodAttributes, System.Reflection.CallingConventions, System.Type, System.Type[], System.Runtime.InteropServices.CallingConvention, System.Runtime.InteropServices.CharSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.DefinePInvokeMethod(System.String, System.String, System.String, System.Reflection.MethodAttributes, System.Reflection.CallingConventions, System.Type, System.Type[], System.Runtime.InteropServices.CallingConvention, System.Runtime.InteropServices.CharSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.DefineResource(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.DefineResource(System.String, System.String, System.Reflection.ResourceAttributes)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.DefineUnmanagedResource(System.Byte[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.DefineUnmanagedResource(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetArrayMethodToken(System.Type, System.String, System.Reflection.CallingConventions, System.Type, System.Type[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetConstructorToken(System.Reflection.ConstructorInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetConstructorToken(System.Reflection.ConstructorInfo, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetFieldToken(System.Reflection.FieldInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetMethodToken(System.Reflection.MethodInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetMethodToken(System.Reflection.MethodInfo, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetSignatureToken(System.Byte[], System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetSignatureToken(System.Reflection.Emit.SignatureHelper)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetSignerCertificate()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetStringConstant(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetSymWriter()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetTypeToken(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.GetTypeToken(System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.IsTransient()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.SetSymCustomAttribute(System.String, System.Byte[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ModuleBuilder.SetUserEntryPoint(System.Reflection.MethodInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ParameterBuilder.GetToken()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.ParameterBuilder.SetMarshal(System.Reflection.Emit.UnmanagedMarshal)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.PropertyBuilder.PropertyToken.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.SignatureHelper.GetMethodSigHelper(System.Reflection.Module, System.Runtime.InteropServices.CallingConvention, System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.SignatureHelper.GetMethodSigHelper(System.Runtime.InteropServices.CallingConvention, System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.TypeBuilder.AddDeclarativeSecurity(System.Security.Permissions.SecurityAction, System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.TypeBuilder.DefinePInvokeMethod(System.String, System.String, System.Reflection.MethodAttributes, System.Reflection.CallingConventions, System.Type, System.Type[], System.Runtime.InteropServices.CallingConvention, System.Runtime.InteropServices.CharSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.TypeBuilder.DefinePInvokeMethod(System.String, System.String, System.String, System.Reflection.MethodAttributes, System.Reflection.CallingConventions, System.Type, System.Type[], System.Runtime.InteropServices.CallingConvention, System.Runtime.InteropServices.CharSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.TypeBuilder.DefinePInvokeMethod(System.String, System.String, System.String, System.Reflection.MethodAttributes, System.Reflection.CallingConventions, System.Type, System.Type[], System.Type[], System.Type[], System.Type[][], System.Type[][], System.Runtime.InteropServices.CallingConvention, System.Runtime.InteropServices.CharSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Emit.TypeBuilder.TypeToken.get()' does not exist in the implementation but it does exist in the contract. - -// Consciously are not bringing to core -TypesMustExist : Type 'System.Security.Cryptography.CryptoAPITransform' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.HMACRIPEMD160' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.MACTripleDES' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.RijndaelManagedTransform' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.RIPEMD160' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.RIPEMD160Managed' does not exist in the implementation but it does exist in the contract. - -// Too coupled to ACLs -TypesMustExist : Type 'System.Security.AccessControl.CryptoKeyAccessRule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.AccessControl.CryptoKeyAuditRule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.AccessControl.CryptoKeyRights' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.AccessControl.CryptoKeySecurity' does not exist in the implementation but it does exist in the contract. - -// Interfaces were intentional removals -CannotRemoveBaseTypeOrInterface : Type 'System.Windows.Markup.ValueSerializerAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.DirectoryServicesCOMException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ServiceProcess.ServiceControllerPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ServiceProcess.ServiceProcessDescriptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Microsoft.SqlServer.Server.SqlMethodAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Microsoft.SqlServer.Server.SqlUserDefinedAggregateAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.RegexStringValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Text.RegularExpressions.RegexMatchTimeoutException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Microsoft.SqlServer.Server.InvalidUdtException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'Microsoft.SqlServer.Server.SqlFunctionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ServiceProcess.TimeoutException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.NetworkInformation.PingException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.AccessViolationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Activator' does not implement interface 'System.Runtime.InteropServices._Activator' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.AggregateException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.AppDomain' does not implement interface 'System._AppDomain' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DataMisalignedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DivideByZeroException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DllNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DuplicateWaitObjectException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.EntryPointNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Exception' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ExecutionEngineException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.FieldAccessException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.FlagsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.FormatException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.AppDomainUnloadedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ApplicationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ArgumentException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ArgumentNullException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ArgumentOutOfRangeException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ArithmeticException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ArrayTypeMismatchException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Attribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.AttributeUsageAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.BadImageFormatException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.CannotUnloadAppDomainException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.CLSCompliantAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ContextMarshalException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ContextStaticAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IndexOutOfRangeException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.InsufficientExecutionStackException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.InsufficientMemoryException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.InvalidCastException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.InvalidOperationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.InvalidProgramException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.InvalidTimeZoneException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.LoaderOptimizationAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.MemberAccessException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.MethodAccessException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.MissingFieldException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.MissingMemberException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.MissingMethodException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.MTAThreadAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.MulticastNotSupportedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.NonSerializedAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.NotFiniteNumberException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.NotImplementedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.NotSupportedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.NullReferenceException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ObjectDisposedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ObsoleteAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.OperationCanceledException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.OutOfMemoryException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.OverflowException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ParamArrayAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.PlatformNotSupportedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.RankException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.SerializableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.StackOverflowException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.STAThreadAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.SystemException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ThreadStaticAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.TimeoutException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.TimeZoneNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Type' does not implement interface 'System.Runtime.InteropServices._Type' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.TypeAccessException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.TypeInitializationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.TypeLoadException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.TypeUnloadedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.UnauthorizedAccessException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Collections.Generic.KeyNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.ConditionalAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.DebuggableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.DebuggerBrowsableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.DebuggerDisplayAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.DebuggerHiddenAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.DebuggerNonUserCodeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.DebuggerStepperBoundaryAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.DebuggerStepThroughAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.DebuggerTypeProxyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.DebuggerVisualizerAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.CodeAnalysis.SuppressMessageAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractAbbreviatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractArgumentValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractClassAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractClassForAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractInvariantMethodAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractOptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractPublicPropertyNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractReferenceAssemblyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractRuntimeIgnoredAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.ContractVerificationAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Contracts.PureAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Tracing.EventAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Tracing.EventDataAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Tracing.EventFieldAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Tracing.EventIgnoreAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Tracing.EventSourceAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Tracing.EventSourceException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Tracing.NonEventAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Globalization.CultureNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.DirectoryNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.DriveNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.EndOfStreamException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.FileLoadException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.FileNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.IOException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.PathTooLongException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.IsolatedStorage.IsolatedStorageException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AmbiguousMatchException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Assembly' does not implement interface 'System.Runtime.InteropServices._Assembly' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyAlgorithmIdAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyCompanyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyConfigurationAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyCopyrightAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyCultureAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyDefaultAliasAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyDelaySignAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyDescriptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyFileVersionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyFlagsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyInformationalVersionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyKeyFileAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyKeyNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyMetadataAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyName' does not implement interface 'System.Runtime.InteropServices._AssemblyName' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyProductAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblySignatureKeyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyTitleAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyTrademarkAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.AssemblyVersionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.ConstructorInfo' does not implement interface 'System.Runtime.InteropServices._ConstructorInfo' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.CustomAttributeFormatException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.DefaultMemberAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.EventInfo' does not implement interface 'System.Runtime.InteropServices._EventInfo' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.FieldInfo' does not implement interface 'System.Runtime.InteropServices._FieldInfo' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.InvalidFilterCriteriaException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.MemberInfo' does not implement interface 'System.Runtime.InteropServices._MemberInfo' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.MethodBase' does not implement interface 'System.Runtime.InteropServices._MethodBase' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.MethodInfo' does not implement interface 'System.Runtime.InteropServices._MethodInfo' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Module' does not implement interface 'System.Runtime.InteropServices._Module' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.ObfuscateAssemblyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.ObfuscationAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.ParameterInfo' does not implement interface 'System.Runtime.InteropServices._ParameterInfo' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.PropertyInfo' does not implement interface 'System.Runtime.InteropServices._PropertyInfo' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.ReflectionTypeLoadException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.TargetException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.TargetInvocationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.TargetParameterCountException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.TypeDelegator' does not implement interface 'System.Runtime.InteropServices._Type' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.TypeInfo' does not implement interface 'System.Runtime.InteropServices._Type' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.AssemblyBuilder' does not implement interface 'System.Runtime.InteropServices._AssemblyBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.ConstructorBuilder' does not implement interface 'System.Runtime.InteropServices._ConstructorBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.CustomAttributeBuilder' does not implement interface 'System.Runtime.InteropServices._CustomAttributeBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.DynamicMethod' does not implement interface 'System.Runtime.InteropServices._MethodInfo' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.EventBuilder' does not implement interface 'System.Runtime.InteropServices._EventBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.FieldBuilder' does not implement interface 'System.Runtime.InteropServices._FieldBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.ILGenerator' does not implement interface 'System.Runtime.InteropServices._ILGenerator' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.LocalBuilder' does not implement interface 'System.Runtime.InteropServices._LocalBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.MethodBuilder' does not implement interface 'System.Runtime.InteropServices._MethodBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.ModuleBuilder' does not implement interface 'System.Runtime.InteropServices._ModuleBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.ParameterBuilder' does not implement interface 'System.Runtime.InteropServices._ParameterBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.PropertyBuilder' does not implement interface 'System.Runtime.InteropServices._PropertyBuilder' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.SignatureHelper' does not implement interface 'System.Runtime.InteropServices._SignatureHelper' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Resources.MissingManifestResourceException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Resources.MissingSatelliteAssemblyException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Resources.NeutralResourcesLanguageAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Resources.SatelliteContractVersionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.AssemblyTargetedPatchBandAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.TargetedPatchingOptOutAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.AccessedThroughPropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.CallerFilePathAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.CallerLineNumberAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.CallerMemberNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.CompilationRelaxationsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.CompilerGlobalScopeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.CustomConstantAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.DateTimeConstantAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.DecimalConstantAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.DefaultDependencyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.DependencyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.DisablePrivateReflectionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.DiscardableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.ExtensionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.FixedAddressValueTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.FixedBufferAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.HasCopySemanticsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.IndexerNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.InternalsVisibleToAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.IUnknownConstantAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.MethodImplAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.NativeCppClassAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.ReferenceAssemblyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.RequiredAttributeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.RuntimeCompatibilityAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.RuntimeWrappedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.ScopelessEnumAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.SpecialNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.StateMachineAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.StringFreezingAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.SuppressIldasmAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.TypeForwardedFromAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.TypeForwardedToAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.UnsafeValueTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.ConstrainedExecution.ReliabilityContractAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.AutomationProxyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.BestFitMappingAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ClassInterfaceAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.CoClassAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComAliasNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComCompatibleVersionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComConversionLossAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComDefaultInterfaceAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComEventInterfaceAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.COMException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComImportAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComRegisterFunctionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComSourceInterfacesAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComUnregisterFunctionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComVisibleAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.DefaultCharSetAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.DispIdAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.DllImportAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ExternalException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.FieldOffsetAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.GuidAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.InAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.InterfaceTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.InvalidComObjectException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.InvalidOleVariantTypeException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.LCIDConversionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ManagedToNativeComInteropStubAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.MarshalAsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.MarshalDirectiveException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.OptionalAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.OutAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.PreserveSigAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.PrimaryInteropAssemblyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ProgIdAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.SafeArrayRankMismatchException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.SafeArrayTypeMismatchException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.SEHException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.StructLayoutAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.TypeIdentifierAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.WindowsRuntime.DefaultInterfaceAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.WindowsRuntime.InterfaceImplementedInVersionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.WindowsRuntime.ReadOnlyArrayAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.WindowsRuntime.ReturnValueNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.WindowsRuntime.WriteOnlyArrayAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.OnDeserializedAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.OnDeserializingAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.OnSerializedAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.OnSerializingAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.OptionalFieldAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.SerializationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.Formatters.Binary.BinaryFormatter' does not implement interface 'System.Runtime.Remoting.Messaging.IRemotingFormatter' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Versioning.ComponentGuaranteesAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Versioning.ResourceConsumptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Versioning.ResourceExposureAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Versioning.TargetFrameworkAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.AllowPartiallyTrustedCallersAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.HostProtectionException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.SecurityCriticalAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.SecurityException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.SecurityRulesAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.SecuritySafeCriticalAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.SecurityTransparentAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.SecurityTreatAsSafeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.SuppressUnmanagedCodeSecurityAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.UnverifiableCodeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.VerificationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.XmlSyntaxException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.AccessControl.PrivilegeNotHeldException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Cryptography.CryptographicException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Cryptography.CryptographicUnexpectedOperationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.CodeAccessSecurityAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.EnvironmentPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.FileDialogPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.FileIOPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.GacIdentityPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.HostProtectionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.IsolatedStorageFilePermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.IsolatedStoragePermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.KeyContainerPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.PermissionSetAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.PrincipalPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.PublisherIdentityPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.ReflectionPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.RegistryPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.SecurityAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.SecurityPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.SiteIdentityPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.StrongNameIdentityPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.UIPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.UrlIdentityPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.ZoneIdentityPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Policy.PolicyException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Principal.IdentityNotMappedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Text.DecoderFallbackException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Text.EncoderFallbackException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.AbandonedMutexException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.LockRecursionException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.SemaphoreFullException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.SynchronizationLockException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.Thread' does not implement interface 'System.Runtime.InteropServices._Thread' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.ThreadAbortException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.ThreadInterruptedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.ThreadStartException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.ThreadStateException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.WaitHandleCannotBeOpenedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.Tasks.TaskCanceledException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.Tasks.TaskSchedulerException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.UriFormatException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.CodeDom.Compiler.GeneratedCodeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.AmbientValueAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.AttributeProviderAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.BindableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.BrowsableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.CategoryAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.ComplexBindingPropertiesAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataObjectAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataObjectFieldAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataObjectMethodAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DefaultBindingPropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DefaultEventAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DefaultPropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DefaultValueAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DescriptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DesignerAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DesignerCategoryAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DesignerSerializationVisibilityAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DesignOnlyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DesignTimeVisibleAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DisplayNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.EditorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.EditorBrowsableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.ExtenderProvidedPropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.ImmutableObjectAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.InheritanceAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.InitializationEventAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.InstallerTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.InvalidAsynchronousStateException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.InvalidEnumArgumentException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.LicenseException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.LicenseProviderAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.ListBindableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.LocalizableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.LookupBindingPropertiesAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.MergablePropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.NotifyParentPropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.ParenthesizePropertyNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.PasswordPropertyTextAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.PropertyTabAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.ProvidePropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.ReadOnlyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.RecommendedAsConfigurableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.RefreshPropertiesAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.RunInstallerAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.SettingsBindableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.ToolboxItemAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.ToolboxItemFilterAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.TypeConverterAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.TypeDescriptionProviderAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.WarningException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.Win32Exception' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.Design.CheckoutException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.Design.HelpKeywordAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.Design.Serialization.DefaultSerializationProviderAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.Design.Serialization.DesignerSerializerAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.Design.Serialization.RootDesignerSerializerAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.ApplicationScopedSettingAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.ConfigurationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.DefaultSettingValueAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.NoSettingsVersionUpgradeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingsDescriptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingsGroupDescriptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingsGroupNameAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingsManageabilityAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingsPropertyIsReadOnlyException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingsPropertyNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingsPropertyWrongTypeException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingsProviderAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SettingsSerializeAsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SpecialSettingAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.UserScopedSettingAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.MonitoringDescriptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.SwitchAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.SwitchLevelAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.InternalBufferOverflowException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.InvalidDataException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.CookieException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.HttpListenerException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.ProtocolViolationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.WebException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Mail.SmtpException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Mail.SmtpFailedRecipientException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Mail.SmtpFailedRecipientsException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.NetworkInformation.NetworkInformationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Sockets.SocketException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.WebSockets.WebSocketException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.DefaultParameterValueAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Authentication.AuthenticationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Authentication.InvalidCredentialException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.StorePermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Permissions.TypeDescriptorPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.BarrierPostPhaseException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.SemaphoreFullException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Timers.TimersDescriptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.AssociationAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.CompareAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.ConcurrencyCheckAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.CreditCardAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.CustomValidationAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.DataTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.DisplayAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.DisplayColumnAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.DisplayFormatAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.EditableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.EmailAddressAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.EnumDataTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.FileExtensionsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.FilterUIHintAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.KeyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.MaxLengthAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.MinLengthAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.PhoneAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.RangeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.RegularExpressionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.RequiredAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.ScaffoldColumnAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.StringLengthAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.TimestampAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.UIHintAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.UrlAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.ValidationAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.ValidationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.Schema.ColumnAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.Schema.ComplexTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.Schema.InversePropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.ComponentModel.DataAnnotations.Schema.TableAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.InvalidTimeZoneException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.TimeZoneNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.DynamicAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.ExtensionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ComAwareEventInfo' does not implement interface 'System.Runtime.InteropServices._EventInfo' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.LockRecursionException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.ConstraintException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.DataException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.DataSysDescriptionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.DBConcurrencyException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.DeletedRowInaccessibleException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.DuplicateNameException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.EvaluateException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.InRowChangingEventException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.InvalidConstraintException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.InvalidExpressionException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.MissingPrimaryKeyException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.NoNullAllowedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.OperationAbortedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.ReadOnlyException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.RowNotInTableException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.StrongTypingException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.SyntaxErrorException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.VersionNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.Common.DbException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.Common.DbProviderSpecificTypePropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.Common.DBDataPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.Odbc.OdbcException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlClient.SqlException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlTypes.SqlAlreadyFilledException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlTypes.SqlNotFilledException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlTypes.SqlNullValueException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlTypes.SqlTruncateException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlTypes.SqlTypeException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.CookieException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.WebException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Sockets.SocketException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.CollectionDataContractAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.ContractNamespaceAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.DataContractAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.DataMemberAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.EnumMemberAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.IgnoreDataMemberAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.InvalidDataContractException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.Serialization.KnownTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Transactions.TransactionAbortedException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Transactions.TransactionException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Transactions.TransactionInDoubtException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Transactions.TransactionManagerCommunicationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Transactions.TransactionPromotionException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.XmlException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Schema.XmlSchemaException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Schema.XmlSchemaInferenceException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Schema.XmlSchemaValidationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.SoapAttributeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.SoapElementAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.SoapEnumAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.SoapIgnoreAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.SoapIncludeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.SoapTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlAnyAttributeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlAnyElementAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlArrayAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlArrayItemAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlAttributeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlChoiceIdentifierAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlElementAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlEnumAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlIgnoreAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlIncludeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlNamespaceDeclarationsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlRootAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSchemaProviderAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSerializerAssemblyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSerializerVersionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlTextAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.XPath.XPathException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Xsl.XsltCompileException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Xsl.XsltException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlAnyAttributeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlAnyElementAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlArrayAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlArrayItemAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlAttributeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlChoiceIdentifierAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlElementAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlEnumAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlIgnoreAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlIncludeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlNamespaceDeclarationsAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlRootAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSchemaProviderAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlTextAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.ImportedFromTypeLibAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.TypeLibFuncAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.TypeLibImportClassAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.TypeLibTypeAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.TypeLibVarAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.InteropServices.TypeLibVersionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.PerformanceCounterPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.EventLogPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.DnsPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.SocketPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.WebPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Mail.SmtpPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.NetworkInformation.NetworkInformationPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.Odbc.OdbcPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.Printing.PrintingPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.PeerToPeer.PnrpPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.PeerToPeer.Collaboration.PeerCollaborationPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Transactions.DistributedTransactionPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlClient.SqlClientPermissionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.CallbackValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.ConfigurationCollectionAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.ConfigurationErrorsException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.ConfigurationPropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.ConfigurationValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.IntegerValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.LongValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.PositiveTimeSpanValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.StringValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.SubclassTypeValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.TimeSpanValidatorAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Configuration.Provider.ProviderException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.BitmapSuffixInSameAssemblyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.BitmapSuffixInSatelliteAssemblyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.ToolboxBitmapAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.Printing.InvalidPrinterException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.FileFormatException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectExistsException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectNotFoundException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.ActiveDirectory.ActiveDirectoryOperationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.ActiveDirectory.ActiveDirectoryServerDownException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.ActiveDirectory.ForestTrustCollisionException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.ActiveDirectory.SyncFromAllServersOperationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.DirectoryObjectClassAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.DirectoryPropertyAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.DirectoryRdnPrefixAttribute' does not implement interface 'System.Runtime.InteropServices._Attribute' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.MultipleMatchesException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.NoMatchingPrincipalException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.PasswordException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.PrincipalException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.PrincipalExistsException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.PrincipalOperationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.AccountManagement.PrincipalServerDownException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.Protocols.BerConversionException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.Protocols.DirectoryException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.Protocols.DirectoryOperationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.Protocols.LdapException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.DirectoryServices.Protocols.TlsOperationException' does not implement interface 'System.Runtime.InteropServices._Exception' in the implementation but it does in the contract. - - - -// Types we currently don't plan to port: -TypesMustExist : Type 'System._AppDomain' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ActivationContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.AppDomainInitializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.AppDomainManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.AppDomainManagerInitializationOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.AppDomainSetup' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.CrossAppDomainDelegate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IAppDomainSetup' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Deployment.Internal.InternalActivationContextHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Deployment.Internal.InternalApplicationIdentityHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Contracts.Internal.ContractHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.DesignerServices.WindowsRuntimeDesignerContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Hosting.ActivationArguments' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Hosting.ApplicationActivator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._Activator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._Assembly' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._AssemblyBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._AssemblyName' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._Attribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._ConstructorBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._ConstructorInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._CustomAttributeBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._EnumBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._EventBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._EventInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._Exception' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._FieldBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._FieldInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._ILGenerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._LocalBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._MemberInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._MethodBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._MethodBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._MethodInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._MethodRental' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._Module' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._ModuleBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._ParameterBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._ParameterInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._PropertyBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._PropertyInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._SignatureHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._Thread' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._Type' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices._TypeBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.AssemblyRegistrationFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.BIND_OPTS' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.BINDPTR' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.CALLCONV' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.CONNECTDATA' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.DESCKIND' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.DISPPARAMS' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ELEMDESC' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.EXCEPINFO' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ExporterEventKind' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ExtensibleClassFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.FILETIME' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.FUNCDESC' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.FUNCFLAGS' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.FUNCKIND' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.IDispatchImplAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.IDispatchImplType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.IDLDESC' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.IDLFLAG' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.IMPLTYPEFLAGS' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ImporterEventKind' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.INVOKEKIND' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.IRegistrationServices' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ITypeLibConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ITypeLibExporterNameProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ITypeLibExporterNotifySink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ITypeLibImporterNotifySink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.LIBFLAGS' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ObjectCreationDelegate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.PARAMDESC' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.PARAMFLAG' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.RegistrationClassContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.RegistrationConnectionType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.RegistrationServices' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.SetWin32ContextInIDispatchAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.STATSTG' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.SYSKIND' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TYPEATTR' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TYPEDESC' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TYPEFLAGS' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TYPEKIND' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TYPELIBATTR' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibExporterFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibImporterFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIBindCtx' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIConnectionPoint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIConnectionPointContainer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIEnumConnectionPoints' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIEnumConnections' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIEnumMoniker' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIEnumString' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIEnumVARIANT' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIMoniker' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIPersistFile' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIRunningObjectTable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMIStream' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMITypeComp' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMITypeInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.UCOMITypeLib' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.VARDESC' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.VARFLAGS' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.Expando.IExpando' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.WindowsRuntime.DesignerNamespaceResolveEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.WindowsRuntime.NamespaceResolveEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMetadata' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.ActivatedClientTypeEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.ActivatedServiceTypeEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.CustomErrorsModes' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.IChannelInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.IEnvoyInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.InternalRemotingServices' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.IObjectHandle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.IRemotingTypeInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.ObjectHandle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.ObjRef' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.RemotingConfiguration' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.RemotingException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.RemotingServices' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.RemotingTimeoutException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.ServerException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.SoapServices' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.TypeEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.WellKnownClientTypeEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.WellKnownObjectMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.WellKnownServiceTypeEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Activation.ActivatorLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Activation.IActivator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Activation.IConstructionCallMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Activation.IConstructionReturnMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Activation.UrlAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.BaseChannelObjectWithProperties' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.BaseChannelSinkWithProperties' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.BaseChannelWithProperties' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.ChannelDataStore' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.ChannelServices' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.ClientChannelSinkStack' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IChannel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IChannelDataStore' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IChannelReceiver' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IChannelReceiverHook' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IChannelSender' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IChannelSinkBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IClientChannelSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IClientChannelSinkProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IClientChannelSinkStack' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IClientFormatterSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IClientFormatterSinkProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IClientResponseChannelSinkStack' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.ISecurableChannel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IServerChannelSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IServerChannelSinkProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IServerChannelSinkStack' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IServerFormatterSinkProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.IServerResponseChannelSinkStack' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.ITransportHeaders' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.ServerChannelSinkStack' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.ServerProcessing' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.SinkProviderData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Channels.TransportHeaders' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.Context' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.ContextAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.ContextProperty' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.CrossContextDelegate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IContextAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IContextProperty' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IContextPropertyActivator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IContributeClientContextSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IContributeDynamicSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IContributeEnvoySink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IContributeObjectSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IContributeServerContextSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IDynamicMessageSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.IDynamicProperty' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Contexts.SynchronizationAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Lifetime.ClientSponsor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Lifetime.ILease' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Lifetime.ISponsor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Lifetime.LeaseState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Lifetime.LifetimeServices' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.AsyncResult' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.CallContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.ConstructionCall' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.ConstructionResponse' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.Header' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.HeaderHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.ILogicalThreadAffinative' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.IMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.IMessageCtrl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.IMessageSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.IMethodCallMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.IMethodMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.IMethodReturnMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.InternalMessageWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.LogicalCallContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.MessageSurrogateFilter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.MethodCall' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.MethodCallMessageWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.MethodResponse' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.MethodReturnMessageWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.OneWayAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.RemotingSurrogateSelector' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Messaging.ReturnMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.SoapAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.SoapFieldAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.SoapMethodAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.SoapOption' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.SoapParameterAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.SoapTypeAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.XmlFieldOrderOption' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.ISoapXsd' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapAnyUri' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapBase64Binary' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDay' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDuration' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapEntities' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapEntity' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapId' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapIdref' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapIdrefs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapInteger' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapLanguage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapMonth' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapMonthDay' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapName' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapNcName' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapNegativeInteger' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapNmtoken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapNmtokens' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapNonNegativeInteger' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapNonPositiveInteger' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapNormalizedString' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapNotation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapPositiveInteger' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapQName' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapTime' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapYear' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Metadata.W3cXsd2001.SoapYearMonth' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Proxies.ProxyAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Proxies.RealProxy' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Services.EnterpriseServicesHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Services.ITrackingHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Remoting.Services.TrackingServices' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.ReadOnlyPermissionSet' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Microsoft.Win32.IntranetZoneCredentialPolicy' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Media.SoundPlayer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Media.SystemSound' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Media.SystemSounds' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Web: -TypesMustExist : Type 'System.Web.ApplicationShutdownReason' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.BeginEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.DefaultHttpHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.EndEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.EventHandlerTaskAsyncHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HtmlString' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpApplication' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpApplicationState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpApplicationStateBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpApplicationStateWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpBrowserCapabilities' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpBrowserCapabilitiesBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpBrowserCapabilitiesWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCacheability' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCachePolicy' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCachePolicyBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCachePolicyWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCacheRevalidation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCacheValidateHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCacheVaryByContentEncodings' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCacheVaryByHeaders' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCacheVaryByParams' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpClientCertificate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCompileException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpContextBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpContextWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCookie' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCookieCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpCookieMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpFileCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpFileCollectionBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpFileCollectionWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpModuleCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpParseException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpPostedFile' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpPostedFileBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpPostedFileWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpRequest' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpRequestBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpRequestValidationException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpRequestWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpResponse' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpResponseBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpResponseSubstitutionCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpResponseWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpRuntime' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpServerUtility' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpServerUtilityBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpServerUtilityWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpSessionStateBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpSessionStateWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpStaticObjectsCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpStaticObjectsCollectionBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpStaticObjectsCollectionWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpTaskAsyncHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpUnhandledException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpValidationStatus' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpWorkerRequest' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.HttpWriter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.IHtmlString' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.IHttpAsyncHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.IHttpHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.IHttpHandlerFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.IHttpModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.IisTraceListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.IPartitionResolver' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ISubscriptionToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ITlsTokenBindingInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.MimeMapping' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ParserError' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ParserErrorCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.PreApplicationStartMethodAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ProcessInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ProcessModelInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ProcessShutdownReason' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ProcessStatus' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ReadEntityBodyMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.RequestNotification' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.RequestNotificationStatus' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SiteMap' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SiteMapNode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SiteMapNodeCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SiteMapProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SiteMapProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SiteMapResolveEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SiteMapResolveEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.StaticSiteMapProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.TaskEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.TraceContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.TraceContextEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.TraceContextEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.TraceContextRecord' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.TraceMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UnvalidatedRequestValues' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UnvalidatedRequestValuesBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UnvalidatedRequestValuesWrapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.VirtualPathUtility' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.WebPageTraceListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.XmlSiteMapProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.AggregateCacheDependency' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.Cache' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.CacheDependency' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.CacheItemPriority' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.CacheItemRemovedCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.CacheItemRemovedReason' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.CacheItemUpdateCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.CacheItemUpdateReason' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.DatabaseNotEnabledForNotificationException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.FileResponseElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.HeaderElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.IOutputCacheEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.MemoryResponseElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.OutputCache' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.OutputCacheProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.OutputCacheProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.ResponseElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.SqlCacheDependency' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.SqlCacheDependencyAdmin' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.SubstitutionResponseElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Caching.TableNotEnabledForNotificationException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.AppSettingsExpressionBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.AssemblyBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.BuildDependencySet' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.BuildManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.BuildManagerHostUnloadEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.BuildManagerHostUnloadEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.BuildProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.BuildProviderAppliesTo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.BuildProviderAppliesToAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.BuildProviderResultFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ClientBuildManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ClientBuildManagerCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ClientBuildManagerParameter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.CompilerType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ConnectionStringsExpressionBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ControlBuilderInterceptor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.DesignTimeResourceProviderFactoryAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ExpressionBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ExpressionBuilderContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ExpressionEditorAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ExpressionPrefixAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.FolderLevelBuildProviderAppliesTo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.FolderLevelBuildProviderAppliesToAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.IAssemblyPostProcessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.IImplicitResourceProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ImplicitResourceKey' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.IResourceProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.LinePragmaCodeInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.PrecompilationFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ResourceExpressionBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ResourceExpressionFields' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.ResourceProviderFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.RouteUrlExpressionBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Compilation.RouteValueExpressionBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AdapterDictionary' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AnonymousIdentificationSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AssemblyCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AssemblyInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AsyncPreloadModeFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AuthenticationMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AuthenticationSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AuthorizationRule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AuthorizationRuleAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AuthorizationRuleCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.AuthorizationSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.BrowserCapabilitiesCodeGenerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.BrowserCapabilitiesFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.BrowserCapabilitiesFactoryBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.BufferModesCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.BufferModeSettings' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.BuildProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.BuildProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CacheSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ClientTarget' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ClientTargetCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ClientTargetSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CodeSubDirectoriesCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CodeSubDirectory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CompilationSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.Compiler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CompilerCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CustomError' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CustomErrorCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CustomErrorsMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CustomErrorsRedirectMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.CustomErrorsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.DeploymentSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.EventMappingSettings' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.EventMappingSettingsCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ExpressionBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ExpressionBuilderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FcnMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FolderLevelBuildProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FolderLevelBuildProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FormsAuthenticationConfiguration' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FormsAuthenticationCredentials' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FormsAuthenticationUser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FormsAuthenticationUserCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FormsAuthPasswordFormat' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FormsProtectionEnum' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FullTrustAssembliesSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FullTrustAssembly' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.FullTrustAssemblyCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.GlobalizationSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HealthMonitoringSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HostingEnvironmentSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpCapabilitiesBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpCapabilitiesDefaultProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpCapabilitiesProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpCapabilitiesSectionHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpConfigurationContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpCookiesSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpHandlerAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpHandlerActionCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpHandlersSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpModuleAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpModuleActionCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpModulesSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.HttpRuntimeSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.IConfigMapPath' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.IConfigMapPathFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.IdentitySection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.IgnoreDeviceFilterElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.IgnoreDeviceFilterElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.IRemoteWebConfigurationHostServer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.LowerCaseStringConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.MachineKeyCompatibilityMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.MachineKeySection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.MachineKeyValidation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.MachineKeyValidationConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.MembershipSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.NamespaceCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.NamespaceInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.OutputCacheProfile' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.OutputCacheProfileCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.OutputCacheSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.OutputCacheSettingsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.PagesEnableSessionState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.PagesSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.PartialTrustVisibleAssembliesSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.PartialTrustVisibleAssembly' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.PartialTrustVisibleAssemblyCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.PassportAuthentication' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProcessModelComAuthenticationLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProcessModelComImpersonationLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProcessModelLogLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProcessModelSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProfileGroupSettings' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProfileGroupSettingsCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProfileGuidedOptimizationsFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProfilePropertySettings' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProfilePropertySettingsCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProfileSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProfileSettings' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProfileSettingsCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProtocolCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProtocolElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProtocolsConfigurationHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProtocolsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.ProvidersHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.RegexWorker' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.RemoteWebConfigurationHostServer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.RoleManagerSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.RootProfilePropertySettingsCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.RuleSettings' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.RuleSettingsCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SecurityPolicySection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SerializationMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SessionPageStateSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SessionStateSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SiteMapSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SqlCacheDependencyDatabase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SqlCacheDependencyDatabaseCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SqlCacheDependencySection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SystemWebCachingSectionGroup' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.SystemWebSectionGroup' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TagMapCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TagMapInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TagPrefixCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TagPrefixInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TicketCompatibilityMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TraceDisplayMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TraceSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TransformerInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TransformerInfoCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TrustLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TrustLevelCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.TrustSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.UrlMapping' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.UrlMappingCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.UrlMappingsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.UserMapPath' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.VirtualDirectoryMapping' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.VirtualDirectoryMappingCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.WebApplicationLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.WebConfigurationFileMap' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.WebConfigurationManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.WebContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.WebControlsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.WebPartsPersonalization' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.WebPartsPersonalizationAuthorization' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.WebPartsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.XhtmlConformanceMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.XhtmlConformanceSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Configuration.Internal.IInternalConfigWebHost' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Handlers.AssemblyResourceLoader' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Handlers.TraceHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.AppDomainFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.AppDomainInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.AppDomainInfoEnum' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.AppDomainProtocolHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.ApplicationHost' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.ApplicationInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.ApplicationManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.AppManagerAppDomainFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.HostingEnvironment' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.HostSecurityPolicyResolver' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.HostSecurityPolicyResults' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IAdphManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IAppDomainFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IAppDomainInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IAppDomainInfoEnum' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IApplicationHost' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IApplicationPreloadManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IApplicationPreloadUtil' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IAppManagerAppDomainFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IISAPIRuntime' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IListenerChannelCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IPphManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IProcessHost' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IProcessHostFactoryHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IProcessHostIdleAndHealthCheck' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IProcessHostPreloadClient' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IProcessHostSupportFunctions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IProcessPingCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IRegisteredObject' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.ISAPIRuntime' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.IStopListeningRegisteredObject' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.ISuspendibleRegisteredObject' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.ProcessHost' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.ProcessHostFactoryHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.ProcessProtocolHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.SimpleWorkerRequest' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.VirtualDirectory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.VirtualFile' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.VirtualFileBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Hosting.VirtualPathProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Instrumentation.PageExecutionContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Instrumentation.PageExecutionListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Instrumentation.PageInstrumentationService' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Mail.MailAttachment' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Mail.MailEncoding' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Mail.MailFormat' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Mail.MailMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Mail.MailPriority' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Mail.SmtpMail' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.BufferedWebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.EventLogWebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.EventNotificationType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.IisTraceWebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.IRegiisUtility' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.IWebEventCustomEvaluator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.MailEventNotificationInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.MailWebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.RegiisUtility' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.RuleFiringRecord' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.SessionStateType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.SimpleMailWebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.SqlExecutionException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.SqlFeatures' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.SqlServices' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.SqlWebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.TemplatedMailWebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.TraceWebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebApplicationInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebApplicationLifetimeEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebAuditEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebAuthenticationFailureAuditEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebAuthenticationSuccessAuditEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebBaseErrorEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebBaseEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebBaseEventCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebErrorEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebEventBufferFlushInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebEventCodes' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebEventFormatter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebEventManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebFailureAuditEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebHeartbeatEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebManagementEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebProcessInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebProcessStatistics' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebRequestErrorEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebRequestEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebRequestInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebSuccessAuditEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebThreadInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WebViewStateFailureAuditEvent' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Management.WmiWebEventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ArrayModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ArrayModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.AssociatedMetadataProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.AssociatedValidatorProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.BinaryDataModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.BindingBehavior' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.BindingBehaviorAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.BindNeverAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.BindRequiredAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.CollectionModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.CollectionModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ComplexModel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ComplexModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ComplexModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ComplexModelResult' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ControlAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ControlValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.CookieAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.CookieValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DataAnnotationsModelMetadata' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DataAnnotationsModelMetadataProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DataAnnotationsModelValidationFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DataAnnotationsModelValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DataAnnotationsModelValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DataAnnotationsModelValidatorProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DataAnnotationsValidatableObjectAdapterFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DefaultModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DictionaryModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DictionaryModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.DictionaryValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.EmptyModelMetadataProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ExtensibleModelBinderAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.FormAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.FormValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.GenericModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.IMetadataAware' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.IModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.IModelNameProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.IUnvalidatedValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.IUnvalidatedValueProviderSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.IValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.IValueProviderSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.KeyValuePairModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.KeyValuePairModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBinderDictionary' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBinderErrorMessageProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBinderErrorMessageProviders' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBinderProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBinderProviderOptionsAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBinderProviders' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBinders' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBindingContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelBindingExecutionContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelError' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelErrorCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelMetadata' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelMetadataProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelMetadataProviders' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelStateDictionary' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelValidatedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelValidatingEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelValidationNode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelValidationResult' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelValidatorProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelValidatorProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ModelValidatorProviders' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.MutableObjectModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.MutableObjectModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.NameValueCollectionValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ProfileAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ProfileValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.QueryStringAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.QueryStringValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.RangeAttributeAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.RegularExpressionAttributeAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.RequiredAttributeAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.RouteDataAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.RouteDataValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.SessionAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.SimpleModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.SimpleValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.StringLengthAttributeAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.TypeConverterModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.TypeConverterModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.TypeMatchModelBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.TypeMatchModelBinderProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.UserProfileAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.UserProfileValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ValidatableObjectAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ValueProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ValueProviderResult' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ValueProviderSourceAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ViewStateAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.ModelBinding.ViewStateValueProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.CustomProviderDataAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.DefaultProfile' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileAuthenticationOption' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileAutoSaveEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileAutoSaveEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileGroupBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileInfoCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileMigrateEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileMigrateEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileProviderAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.ProfileProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.SettingsAllowAnonymousAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Profile.SqlProfileProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.HttpMethodConstraint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.IRouteConstraint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.IRouteHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.PageRouteHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.RequestContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.Route' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.RouteBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.RouteCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.RouteData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.RouteDirection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.RouteTable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.RouteValueDictionary' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.StopRoutingHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.UrlRoutingHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.UrlRoutingModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Routing.VirtualPathData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.ActiveDirectoryConnectionProtection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.ActiveDirectoryMembershipProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.ActiveDirectoryMembershipUser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AnonymousIdentificationEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AnonymousIdentificationEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AnonymousIdentificationModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AuthorizationStoreRoleProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.CookieProtection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.DefaultAuthenticationEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.DefaultAuthenticationEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.DefaultAuthenticationModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.FileAuthorizationModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.FormsAuthentication' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.FormsAuthenticationEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.FormsAuthenticationEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.FormsAuthenticationModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.FormsAuthenticationTicket' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.FormsIdentity' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.MachineKey' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.MachineKeyProtection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.Membership' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.MembershipPasswordAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.PassportAuthenticationEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.PassportAuthenticationEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.PassportAuthenticationModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.PassportIdentity' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.PassportPrincipal' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.RoleManagerEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.RoleManagerEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.RoleManagerModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.RolePrincipal' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.RoleProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.Roles' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.SqlMembershipProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.SqlRoleProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.UrlAuthorizationModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.WindowsAuthenticationEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.WindowsAuthenticationEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.WindowsAuthenticationModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.WindowsTokenRoleProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AntiXss.AntiXssEncoder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AntiXss.LowerCodeCharts' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AntiXss.LowerMidCodeCharts' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AntiXss.MidCodeCharts' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AntiXss.UpperCodeCharts' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Security.AntiXss.UpperMidCodeCharts' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.HttpSessionState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.HttpSessionStateContainer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.IHttpSessionState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.IPartialSessionState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.IReadOnlySessionState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.IRequiresSessionState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.ISessionIDManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.ISessionStateItemCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.IStateRuntime' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionIDManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionStateActions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionStateBehavior' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionStateItemCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionStateItemExpireCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionStateMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionStateModule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionStateStoreData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionStateStoreProviderBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.SessionStateUtility' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.SessionState.StateRuntime' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.AttributeCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.BaseParser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.BasePartialCachingControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.BaseTemplateParser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.BindableTemplateBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.BoundPropertyEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.BuilderPropertyEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.BuildMethod' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.BuildTemplateMethod' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ChtmlTextWriter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ClientIDMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ClientScriptManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.CodeBlockType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.CodeConstructType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.CodeStatementBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.CompilationMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.CompiledBindableTemplateBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.CompiledTemplateBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ComplexPropertyEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ConflictOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ConstructorNeedsTagAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.Control' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ControlBuilderAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ControlCachePolicy' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ControlCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ControlSkin' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ControlSkinDelegate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ControlValuePropertyAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.CssClassPropertyAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.CssStyleCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataBinding' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataBindingCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataBindingHandlerAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataBoundLiteralControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataKeyPropertyAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceCacheDurationConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceCacheExpiry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceCapabilities' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceOperation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceSelectArguments' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceViewOperationCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DataSourceViewSelectCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DesignerDataBoundLiteralControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DesignTimeParseData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.DesignTimeTemplateParser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.EmptyControlCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.EventEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ExpressionBinding' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ExpressionBindingCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ExtractTemplateValuesMethod' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.FileLevelControlBuilderAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.FileLevelMasterPageControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.FileLevelPageControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.FileLevelUserControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.FilterableAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HiddenFieldPageStatePersister' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HierarchicalDataSourceControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HierarchicalDataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.Html32TextWriter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlTextWriter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlTextWriterAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlTextWriterStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlTextWriterTag' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IAttributeAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IAutoFieldGenerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IBindableControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IBindableTemplate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ICallbackEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ICheckBoxControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ICodeBlockTypeAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IControlBuilderAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IControlDesignerAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IDataBindingsAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IDataItemContainer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IDataKeysControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IDataSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IDataSourceViewSchemaAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IDReferencePropertyAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IEditableTextControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IExpressionsAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IFilterResolutionService' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IHierarchicalDataSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IHierarchicalEnumerable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IHierarchyData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ImageClickEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ImageClickEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.INamingContainer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.INavigateUIData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IndexedString' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IParserAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IPostBackDataHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IPostBackEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IResourceUrlGenerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IStateFormatter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IStateManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IStyleSheet' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ITemplate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ITextControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IThemeResolutionService' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IUrlResolutionService' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IUserControlDesignerAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IUserControlTypeResolutionService' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.IValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ListSourceHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.LiteralControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.LosFormatter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.MasterPage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.MasterPageControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.NonVisualControlAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ObjectConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ObjectPersistData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ObjectStateFormatter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ObjectTagBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.OutputCacheLocation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.OutputCacheParameters' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.Page' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PageAsyncTask' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PageHandlerFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PageParser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PageParserFilter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PageStatePersister' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PageTheme' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.Pair' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ParseChildrenAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ParseRecorder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PartialCachingAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PartialCachingControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PersistChildrenAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PersistenceMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PersistenceModeAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PostBackOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PropertyConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.PropertyEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.RenderMethod' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.RenderTraceListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.RootBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.SessionPageStatePersister' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.SimplePropertyEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.SimpleWebHandlerParser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.SkinBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.StateBag' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.StateItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.StateManagedCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.StaticPartialCachingControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.SupportsEventValidationAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.TagPrefixAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.TemplateBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.TemplateContainerAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.TemplateControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.TemplateControlParser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.TemplateInstance' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.TemplateInstanceAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.TemplateParser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.TemplatePropertyEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ThemeableAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ThemeProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ToolboxDataAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.Triplet' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.UnobtrusiveValidationMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.UrlPropertyAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.UserControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.UserControlControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ValidateRequestMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ValidationPropertyAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ValidationSettings' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ValidatorCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.VerificationAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.VerificationConditionalOperator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.VerificationReportLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.VerificationRule' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ViewStateEncryptionMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ViewStateException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ViewStateMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.ViewStateModeByIdAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.VirtualReferenceType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebResourceAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebServiceParser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.XhtmlMobileDocType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.XhtmlTextWriter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.XPathBinder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.Adapters.ControlAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.Adapters.PageAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlAnchor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlArea' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlAudio' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlButton' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlContainerControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlEmbed' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlEmptyTagControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlForm' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlGenericControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlHead' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlHeadBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlIframe' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlImage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputButton' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputCheckBox' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputFile' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputGenericControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputHidden' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputImage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputPassword' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputRadioButton' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputReset' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputSubmit' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlInputText' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlLink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlMeta' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlSelect' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlSelectBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlTable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlTableCell' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlTableCellCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlTableRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlTableRowCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlTextArea' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlTitle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlTrack' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.HtmlControls.HtmlVideo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AccessDataSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AccessDataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AdCreatedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AdCreatedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AdRotator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AssociatedControlConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AuthenticateEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AuthenticateEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AutoCompleteType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AutoFieldsGenerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AutoGeneratedField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.AutoGeneratedFieldProperties' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BaseCompareValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BaseDataBoundControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BaseDataList' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BaseValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BorderStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BoundColumn' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BoundField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BulletedList' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BulletedListDisplayMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BulletedListEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BulletedListEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.BulletStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Button' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ButtonColumn' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ButtonColumnType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ButtonField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ButtonFieldBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ButtonType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Calendar' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CalendarDay' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CalendarSelectionMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CallingDataMethodsEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CallingDataMethodsEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ChangePassword' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CheckBox' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CheckBoxField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CheckBoxList' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CircleHotSpot' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CommandEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CommandEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CommandField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CompareValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CompleteWizardStep' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CompositeControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CompositeDataBoundControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Content' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ContentDirection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ContentPlaceHolder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ControlIDConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ControlParameter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ControlPropertyNameConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CookieParameter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CreateUserErrorEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CreateUserErrorEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CreateUserWizard' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CreateUserWizardStep' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CreatingModelDataSourceEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CreatingModelDataSourceEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.CustomValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataBoundControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataBoundControlMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataControlCellType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataControlCommands' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataControlField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataControlFieldCell' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataControlFieldCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataControlFieldHeaderCell' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataControlRowState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataControlRowType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGrid' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridColumn' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridColumnCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridCommandEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridCommandEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridItemCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridItemEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridItemEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridPageChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridPageChangedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridPagerStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridSortCommandEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataGridSortCommandEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataKey' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataKeyArray' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataKeyCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataList' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataListCommandEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataListCommandEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataListItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataListItemCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataListItemEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataListItemEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DataSourceSelectResultProcessingOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DayNameFormat' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DayRenderEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DayRenderEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewCommandEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewCommandEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewDeletedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewDeletedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewDeleteEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewDeleteEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewInsertedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewInsertedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewInsertEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewInsertEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewModeEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewModeEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewPageEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewPageEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewPagerRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewRowCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewRowsGenerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewUpdatedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewUpdatedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewUpdateEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DetailsViewUpdateEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.DropDownList' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.EditCommandColumn' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.EmbeddedMailObject' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.EmbeddedMailObjectsCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FileUpload' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FirstDayOfWeek' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FontInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FontNamesConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FontSize' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FontUnit' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FontUnitConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormParameter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewCommandEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewCommandEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewDeletedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewDeletedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewDeleteEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewDeleteEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewInsertedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewInsertedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewInsertEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewInsertEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewModeEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewModeEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewPageEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewPageEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewPagerRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewUpdatedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewUpdatedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewUpdateEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.FormViewUpdateEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridLines' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewCancelEditEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewCancelEditEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewColumnsGenerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewCommandEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewCommandEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewDeletedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewDeletedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewDeleteEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewDeleteEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewEditEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewEditEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewPageEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewPageEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewRowCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewRowEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewRowEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewSelectEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewSelectEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewSortEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewSortEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewUpdatedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewUpdatedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewUpdateEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.GridViewUpdateEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HiddenField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HierarchicalDataBoundControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HorizontalAlign' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HotSpot' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HotSpotCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HotSpotMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HyperLink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HyperLinkColumn' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HyperLinkControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.HyperLinkField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.IButtonControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ICallbackContainer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ICompositeControlDesignerAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.IDataBoundControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.IDataBoundItemControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.IDataBoundListControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.IFieldControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Image' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ImageAlign' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ImageButton' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ImageField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ImageMap' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ImageMapEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ImageMapEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.IPersistedSelector' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.IPostBackContainer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.IRepeatInfoUser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Label' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LabelControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LinkButton' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LinkButtonControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ListBox' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ListControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ListItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ListItemCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ListItemControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ListItemType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ListSelectionMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Literal' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LiteralControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LiteralMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Localize' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Login' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LoginCancelEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LoginCancelEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LoginFailureAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LoginName' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LoginStatus' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LoginTextLayout' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LoginView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.LogoutAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MailDefinition' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MailMessageEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MailMessageEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Menu' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuItemBinding' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuItemBindingCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuItemCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuItemStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuItemStyleCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuItemTemplateContainer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MenuRenderingMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ModelDataMethodResult' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ModelDataSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ModelDataSourceMethod' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ModelDataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ModelErrorMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ModelMethodContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MonthChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MonthChangedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MultiView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.MultiViewControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.NextPrevFormat' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceDisposingEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceDisposingEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceFilteringEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceFilteringEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceMethodEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceMethodEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceObjectEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceSelectingEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceStatusEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceStatusEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ObjectDataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Orientation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PagedDataSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PagerButtons' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PagerMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PagerPosition' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PagerSettings' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Panel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PanelStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Parameter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ParameterCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ParsingCulture' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PasswordRecovery' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PathDirection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PlaceHolder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PlaceHolderControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.PolygonHotSpot' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ProfileParameter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.QueryExtensions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.QueryStringParameter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RadioButton' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RadioButtonList' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RangeValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RectangleHotSpot' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RegularExpressionValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RepeatDirection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Repeater' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RepeaterCommandEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RepeaterCommandEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RepeaterItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RepeaterItemCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RepeaterItemEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RepeaterItemEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RepeatInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RepeatLayout' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RequiredFieldValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RoleGroup' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RoleGroupCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.RouteParameter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ScrollBars' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SelectedDatesCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SelectResult' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SendMailErrorEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SendMailErrorEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ServerValidateEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ServerValidateEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SessionParameter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SiteMapDataSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SiteMapDataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SiteMapHierarchicalDataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SiteMapNodeItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SiteMapNodeItemEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SiteMapNodeItemEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SiteMapNodeItemType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SiteMapPath' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SortDirection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceCommandEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceCommandEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceCommandType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceFilteringEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceFilteringEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceSelectingEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceSelectingEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceStatusEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceStatusEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SqlDataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.StringArrayConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Style' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.StyleCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SubMenuStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.SubMenuStyleCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Substitution' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Table' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableCaptionAlign' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableCell' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableCellCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableCellControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableFooterRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableHeaderCell' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableHeaderRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableHeaderScope' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableItemStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableRowCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableRowSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableSectionStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TableStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TargetConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TemplateColumn' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TemplatedWizardStep' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TemplateField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TextAlign' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TextBox' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TextBoxControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TextBoxMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TitleFormat' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNodeBinding' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNodeBindingCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNodeCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNodeEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNodeEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNodeSelectAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNodeStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNodeStyleCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeNodeTypes' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.TreeViewImageSet' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Unit' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.UnitConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.UnitType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ValidatedControlConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ValidationCompareOperator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ValidationDataType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ValidationSummary' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ValidationSummaryDisplayMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ValidatorDisplay' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.VerticalAlign' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.View' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.ViewCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebColorConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Wizard' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WizardNavigationEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WizardNavigationEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WizardStep' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WizardStepBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WizardStepCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WizardStepControlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WizardStepType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Xml' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.XmlBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.XmlDataSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.XmlDataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.XmlHierarchicalDataSourceView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Adapters.DataBoundControlAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Adapters.HideDisabledControlAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Adapters.HierarchicalDataBoundControlAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Adapters.MenuAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.Adapters.WebControlAdapter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.AppearanceEditorPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.BehaviorEditorPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.CatalogPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.CatalogPartChrome' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.CatalogPartCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.CatalogZone' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.CatalogZoneBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ConnectionConsumerAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ConnectionInterfaceCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ConnectionPoint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ConnectionProviderAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ConnectionsZone' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ConsumerConnectionPoint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ConsumerConnectionPointCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.DeclarativeCatalogPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.EditorPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.EditorPartChrome' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.EditorPartCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.EditorZone' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.EditorZoneBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ErrorWebPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.FieldCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.GenericWebPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ImportCatalogPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.IPersonalizable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ITrackingPersonalizable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ITransformerConfigurationControl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.IVersioningPersonalizable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.IWebActionable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.IWebEditable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.IWebPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.IWebPartField' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.IWebPartParameters' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.IWebPartRow' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.IWebPartTable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.LayoutEditorPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PageCatalogPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ParametersCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.Part' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PartChromeState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PartChromeType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizableAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationAdministration' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationDictionary' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationProviderCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationScope' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationStateInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationStateInfoCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PersonalizationStateQuery' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.PropertyGridEditorPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ProviderConnectionPoint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ProviderConnectionPointCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ProxyWebPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ProxyWebPartConnectionCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ProxyWebPartManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.RowCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.RowToFieldTransformer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.RowToParametersTransformer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.SharedPersonalizationStateInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.SqlPersonalizationProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.TableCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.TitleStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.ToolZone' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.TransformerTypeCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.UnauthorizedWebPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.UserPersonalizationStateInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebBrowsableAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebDescriptionAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebDisplayNameAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPart' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartAddingEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartAddingEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartAuthorizationEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartAuthorizationEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartCancelEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartCancelEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartChrome' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartConnection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartConnectionCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartConnectionsCancelEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartConnectionsCancelEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartConnectionsEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartConnectionsEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartDescription' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartDescriptionCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartDisplayMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartDisplayModeCancelEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartDisplayModeCancelEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartDisplayModeCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartDisplayModeEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartDisplayModeEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartExportMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartHelpMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartManagerInternals' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartMenuStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartMovingEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartMovingEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartPersonalization' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartTracker' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartTransformer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartTransformerAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartTransformerCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartUserCapability' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartVerb' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartVerbCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartVerbRenderMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartVerbsEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartVerbsEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartZone' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartZoneBase' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebPartZoneCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.UI.WebControls.WebParts.WebZone' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Util.HttpEncoder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Util.IWebObjectFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Util.IWebPropertyAccessor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Util.RequestValidationSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Util.RequestValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Util.TransactedCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Util.Transactions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Util.WorkItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.Util.WorkItemCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.WebSockets.AspNetWebSocket' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.WebSockets.AspNetWebSocketContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Web.WebSockets.AspNetWebSocketOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Markup.ValueSerializerAttribute' does not exist in the implementation but it does exist in the contract. - -// Members can't be added because types are on NS20 and the missing members required types that are not on NS20 and we are ignoring those for netcore20: -MembersMustExist : Member 'System.Activator.CreateComInstanceFrom(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateComInstanceFrom(System.String, System.String, System.Byte[], System.Configuration.Assemblies.AssemblyHashAlgorithm)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstance(System.ActivationContext)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstance(System.ActivationContext, System.String[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstance(System.AppDomain, System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstance(System.AppDomain, System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstance(System.AppDomain, System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstance(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstance(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstance(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstance(System.String, System.String, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstanceFrom(System.AppDomain, System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstanceFrom(System.AppDomain, System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstanceFrom(System.AppDomain, System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstanceFrom(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstanceFrom(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstanceFrom(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.CreateInstanceFrom(System.String, System.String, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.GetObject(System.Type, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Activator.GetObject(System.Type, System.String, System.Object)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.ActivationContext.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.ApplicationIdentity.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.ApplicationTrust.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateComInstanceFrom(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateComInstanceFrom(System.String, System.String, System.Byte[], System.Configuration.Assemblies.AssemblyHashAlgorithm)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateDomain(System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateDomain(System.String, System.Security.Policy.Evidence, System.AppDomainSetup)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateDomain(System.String, System.Security.Policy.Evidence, System.AppDomainSetup, System.Security.PermissionSet, System.Security.Policy.StrongName[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateDomain(System.String, System.Security.Policy.Evidence, System.String, System.String, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateDomain(System.String, System.Security.Policy.Evidence, System.String, System.String, System.Boolean, System.AppDomainInitializer, System.String[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstance(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstance(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstance(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstance(System.String, System.String, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceAndUnwrap(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceAndUnwrap(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceAndUnwrap(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceAndUnwrap(System.String, System.String, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceFrom(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceFrom(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceFrom(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceFrom(System.String, System.String, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceFromAndUnwrap(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceFromAndUnwrap(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceFromAndUnwrap(System.String, System.String, System.Boolean, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.CreateInstanceFromAndUnwrap(System.String, System.String, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.Collections.Generic.IEnumerable, System.Security.SecurityContextSource)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.Security.Policy.Evidence, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String, System.Boolean, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String, System.Security.Policy.Evidence, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String, System.Security.Policy.Evidence, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess, System.String, System.Security.Policy.Evidence, System.Security.PermissionSet, System.Security.PermissionSet, System.Security.PermissionSet, System.Boolean, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DoCallBack(System.CrossAppDomainDelegate)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.DomainManager.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.Evidence.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.ExecuteAssembly(System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.ExecuteAssembly(System.String, System.Security.Policy.Evidence, System.String[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.ExecuteAssembly(System.String, System.Security.Policy.Evidence, System.String[], System.Byte[], System.Configuration.Assemblies.AssemblyHashAlgorithm)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.ExecuteAssemblyByName(System.Reflection.AssemblyName, System.Security.Policy.Evidence, System.String[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.ExecuteAssemblyByName(System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.ExecuteAssemblyByName(System.String, System.Security.Policy.Evidence, System.String[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.Load(System.Byte[], System.Byte[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.Load(System.Reflection.AssemblyName, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.Load(System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.PermissionSet.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.SetAppDomainPolicy(System.Security.Policy.PolicyLevel)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.SetData(System.String, System.Object, System.Security.IPermission)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.AppDomain.SetupInformation.get()' does not exist in the implementation but it does exist in the contract -MembersMustExist : Member 'System.Collections.Hashtable System.Resources.ResourceManager.ResourceSets' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Hashtable System.Resources.ResourceSet.Table' does not exist in the implementation but it does exist in the contract -MembersMustExist : Member 'System.ComponentModel.AsyncCompletedEventArgs..ctor()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.Common.DbProviderFactory.CreatePermission(System.Security.Permissions.PermissionState)' does not exist in the implementation but it does exist in the contract -MembersMustExist : Member 'System.Diagnostics.Debug.Listeners.get()' does not exist in the implementation but it does exist in the contract -MembersMustExist : Member 'System.IO.Directory.CreateDirectory(System.String, System.Security.AccessControl.DirectorySecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Directory.GetAccessControl(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Directory.GetAccessControl(System.String, System.Security.AccessControl.AccessControlSections)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Directory.SetAccessControl(System.String, System.Security.AccessControl.DirectorySecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.Create(System.Security.AccessControl.DirectorySecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.CreateSubdirectory(System.String, System.Security.AccessControl.DirectorySecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.GetAccessControl()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.GetAccessControl(System.Security.AccessControl.AccessControlSections)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.SetAccessControl(System.Security.AccessControl.DirectorySecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.Create(System.String, System.Int32, System.IO.FileOptions, System.Security.AccessControl.FileSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.GetAccessControl(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.GetAccessControl(System.String, System.Security.AccessControl.AccessControlSections)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.SetAccessControl(System.String, System.Security.AccessControl.FileSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.FileInfo.GetAccessControl()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.FileInfo.GetAccessControl(System.Security.AccessControl.AccessControlSections)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.FileInfo.SetAccessControl(System.Security.AccessControl.FileSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.Security.AccessControl.FileSystemRights, System.IO.FileShare, System.Int32, System.IO.FileOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.Security.AccessControl.FileSystemRights, System.IO.FileShare, System.Int32, System.IO.FileOptions, System.Security.AccessControl.FileSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.FileStream.GetAccessControl()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.FileStream.SetAccessControl(System.Security.AccessControl.FileSecurity)' does not exist in the implementation but it does exist in the contract -MembersMustExist : Member 'System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile(System.IO.FileStream, System.String, System.Int64, System.IO.MemoryMappedFiles.MemoryMappedFileAccess, System.IO.MemoryMappedFiles.MemoryMappedFileSecurity, System.IO.HandleInheritability, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.MemoryMappedFiles.MemoryMappedFile.CreateNew(System.String, System.Int64, System.IO.MemoryMappedFiles.MemoryMappedFileAccess, System.IO.MemoryMappedFiles.MemoryMappedFileOptions, System.IO.MemoryMappedFiles.MemoryMappedFileSecurity, System.IO.HandleInheritability)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.MemoryMappedFiles.MemoryMappedFile.CreateOrOpen(System.String, System.Int64, System.IO.MemoryMappedFiles.MemoryMappedFileAccess, System.IO.MemoryMappedFiles.MemoryMappedFileOptions, System.IO.MemoryMappedFiles.MemoryMappedFileSecurity, System.IO.HandleInheritability)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.MemoryMappedFiles.MemoryMappedFile.GetAccessControl()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.MemoryMappedFiles.MemoryMappedFile.SetAccessControl(System.IO.MemoryMappedFiles.MemoryMappedFileSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Pipes.AnonymousPipeServerStream..ctor(System.IO.Pipes.PipeDirection, System.IO.HandleInheritability, System.Int32, System.IO.Pipes.PipeSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Pipes.NamedPipeClientStream..ctor(System.String, System.String, System.IO.Pipes.PipeAccessRights, System.IO.Pipes.PipeOptions, System.Security.Principal.TokenImpersonationLevel, System.IO.HandleInheritability)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Pipes.NamedPipeServerStream..ctor(System.String, System.IO.Pipes.PipeDirection, System.Int32, System.IO.Pipes.PipeTransmissionMode, System.IO.Pipes.PipeOptions, System.Int32, System.Int32, System.IO.Pipes.PipeSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Pipes.NamedPipeServerStream..ctor(System.String, System.IO.Pipes.PipeDirection, System.Int32, System.IO.Pipes.PipeTransmissionMode, System.IO.Pipes.PipeOptions, System.Int32, System.Int32, System.IO.Pipes.PipeSecurity, System.IO.HandleInheritability)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Pipes.NamedPipeServerStream..ctor(System.String, System.IO.Pipes.PipeDirection, System.Int32, System.IO.Pipes.PipeTransmissionMode, System.IO.Pipes.PipeOptions, System.Int32, System.Int32, System.IO.Pipes.PipeSecurity, System.IO.HandleInheritability, System.IO.Pipes.PipeAccessRights)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Pipes.PipeStream.GetAccessControl()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Pipes.PipeStream.SetAccessControl(System.IO.Pipes.PipeSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Linq.Expressions.LambdaExpression.CompileToMethod(System.Reflection.Emit.MethodBuilder)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Linq.Expressions.LambdaExpression.CompileToMethod(System.Reflection.Emit.MethodBuilder, System.Runtime.CompilerServices.DebugInfoGenerator)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.MarshalByRefObject.CreateObjRef(System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpVersion..ctor()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpWebRequest..ctor()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.ServicePointManager.CertificatePolicy.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.ServicePointManager.CertificatePolicy.set(System.Net.ICertificatePolicy)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.SocketAsyncEventArgs.SocketClientAccessPolicyProtocol.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.SocketAsyncEventArgs.SocketClientAccessPolicyProtocol.set(System.Net.Sockets.SocketClientAccessPolicyProtocol)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.SocketFlags System.Net.Sockets.SocketFlags.MaxIOVectorLength' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.TransportContext.GetTlsTokenBindings()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.WebRequest.CreatorInstance.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.WebRequest.RegisterPortableWebRequestCreator(System.Net.IWebRequestCreate)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.Evidence.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.Load(System.Byte[], System.Byte[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.Load(System.Byte[], System.Byte[], System.Security.SecurityContextSource)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.Load(System.Reflection.AssemblyName, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.Load(System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.LoadFile(System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.LoadFrom(System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.LoadFrom(System.String, System.Security.Policy.Evidence, System.Byte[], System.Configuration.Assemblies.AssemblyHashAlgorithm)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.LoadWithPartialName(System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.PermissionSet.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Module.GetSignerCertificate()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Resources.IResourceReader System.Resources.ResourceSet.Reader' does not exist in the implementation but it does exist in the contract -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetActiveObject(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetComInterfaceForObjectInContext(System.Object, System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetComSlotForMethodInfo(System.Reflection.MemberInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetEndComSlot(System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetExceptionPointers()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetIDispatchForObjectInContext(System.Object)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetITypeInfoForType(System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetIUnknownForObjectInContext(System.Object)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetManagedThunkForUnmanagedMethodPtr(System.IntPtr, System.IntPtr, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetMethodInfoForComSlot(System.Type, System.Int32, System.Runtime.InteropServices.ComMemberType)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetThreadFromFiberCookie(System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeForITypeInfo(System.IntPtr)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeInfoName(System.Runtime.InteropServices.UCOMITypeInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeLibGuid(System.Runtime.InteropServices.ComTypes.ITypeLib)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeLibGuid(System.Runtime.InteropServices.UCOMITypeLib)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeLibGuidForAssembly(System.Reflection.Assembly)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeLibLcid(System.Runtime.InteropServices.ComTypes.ITypeLib)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeLibLcid(System.Runtime.InteropServices.UCOMITypeLib)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeLibName(System.Runtime.InteropServices.ComTypes.ITypeLib)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeLibName(System.Runtime.InteropServices.UCOMITypeLib)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetTypeLibVersionForAssembly(System.Reflection.Assembly, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.GetUnmanagedThunkForManagedMethodPtr(System.IntPtr, System.IntPtr, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.IsTypeVisibleFromCom(System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.NumParamBytes(System.Reflection.MethodInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.ReleaseThreadCache()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.RuntimeEnvironment..ctor()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializer..ctor(System.Type, System.Collections.Generic.IEnumerable, System.Int32, System.Boolean, System.Boolean, System.Runtime.Serialization.IDataContractSurrogate)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializer..ctor(System.Type, System.Collections.Generic.IEnumerable, System.Int32, System.Boolean, System.Boolean, System.Runtime.Serialization.IDataContractSurrogate, System.Runtime.Serialization.DataContractResolver)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializer..ctor(System.Type, System.String, System.String, System.Collections.Generic.IEnumerable, System.Int32, System.Boolean, System.Boolean, System.Runtime.Serialization.IDataContractSurrogate)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializer..ctor(System.Type, System.String, System.String, System.Collections.Generic.IEnumerable, System.Int32, System.Boolean, System.Boolean, System.Runtime.Serialization.IDataContractSurrogate, System.Runtime.Serialization.DataContractResolver)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializer..ctor(System.Type, System.Xml.XmlDictionaryString, System.Xml.XmlDictionaryString, System.Collections.Generic.IEnumerable, System.Int32, System.Boolean, System.Boolean, System.Runtime.Serialization.IDataContractSurrogate)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializer..ctor(System.Type, System.Xml.XmlDictionaryString, System.Xml.XmlDictionaryString, System.Collections.Generic.IEnumerable, System.Int32, System.Boolean, System.Boolean, System.Runtime.Serialization.IDataContractSurrogate, System.Runtime.Serialization.DataContractResolver)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializer.DataContractSurrogate.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializerSettings.DataContractSurrogate.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializerSettings.DataContractSurrogate.set(System.Runtime.Serialization.IDataContractSurrogate)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.ExportOptions.DataContractSurrogate.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.ExportOptions.DataContractSurrogate.set(System.Runtime.Serialization.IDataContractSurrogate)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(System.IO.Stream, System.Runtime.Remoting.Messaging.HeaderHandler)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.DeserializeMethodResponse(System.IO.Stream, System.Runtime.Remoting.Messaging.HeaderHandler, System.Runtime.Remoting.Messaging.IMethodCallMessage)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(System.IO.Stream, System.Object, System.Runtime.Remoting.Messaging.Header[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.UnsafeDeserialize(System.IO.Stream, System.Runtime.Remoting.Messaging.HeaderHandler)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.UnsafeDeserializeMethodResponse(System.IO.Stream, System.Runtime.Remoting.Messaging.HeaderHandler, System.Runtime.Remoting.Messaging.IMethodCallMessage)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Json.DataContractJsonSerializer..ctor(System.Type, System.Collections.Generic.IEnumerable, System.Int32, System.Boolean, System.Runtime.Serialization.IDataContractSurrogate, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Json.DataContractJsonSerializer..ctor(System.Type, System.String, System.Collections.Generic.IEnumerable, System.Int32, System.Boolean, System.Runtime.Serialization.IDataContractSurrogate, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Json.DataContractJsonSerializer..ctor(System.Type, System.Xml.XmlDictionaryString, System.Collections.Generic.IEnumerable, System.Int32, System.Boolean, System.Runtime.Serialization.IDataContractSurrogate, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Json.DataContractJsonSerializer.DataContractSurrogate.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Json.DataContractJsonSerializerSettings.DataContractSurrogate.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.Serialization.Json.DataContractJsonSerializerSettings.DataContractSurrogate.set(System.Runtime.Serialization.IDataContractSurrogate)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.CspKeyContainerInfo.CryptoKeySecurity.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.CspParameters..ctor(System.Int32, System.String, System.String, System.Security.AccessControl.CryptoKeySecurity, System.IntPtr)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.CspParameters..ctor(System.Int32, System.String, System.String, System.Security.AccessControl.CryptoKeySecurity, System.Security.SecureString)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.CspParameters.CryptoKeySecurity.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.CspParameters.CryptoKeySecurity.set(System.Security.AccessControl.CryptoKeySecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.SecurityException..ctor(System.String, System.Object, System.Object, System.Reflection.MethodInfo, System.Object, System.Security.IPermission)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.SecurityException..ctor(System.String, System.Reflection.AssemblyName, System.Security.PermissionSet, System.Security.PermissionSet, System.Reflection.MethodInfo, System.Security.Permissions.SecurityAction, System.Object, System.Security.IPermission, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.SecurityException.Action.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.SecurityException.Action.set(System.Security.Permissions.SecurityAction)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.SecurityException.FirstPermissionThatFailed.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.SecurityException.FirstPermissionThatFailed.set(System.Security.IPermission)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.SecurityException.Zone.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.SecurityException.Zone.set(System.Security.SecurityZone)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Thread.CurrentContext.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String System.Resources.ResourceManager.BaseNameField' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.EventWaitHandle..ctor(System.Boolean, System.Threading.EventResetMode, System.String, System.Boolean, System.Security.AccessControl.EventWaitHandleSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.EventWaitHandle.GetAccessControl()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.EventWaitHandle.OpenExisting(System.String, System.Security.AccessControl.EventWaitHandleRights)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.EventWaitHandle.SetAccessControl(System.Security.AccessControl.EventWaitHandleSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.EventWaitHandle.TryOpenExisting(System.String, System.Security.AccessControl.EventWaitHandleRights, System.Threading.EventWaitHandle)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Mutex..ctor(System.Boolean, System.String, System.Boolean, System.Security.AccessControl.MutexSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Mutex.GetAccessControl()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Mutex.OpenExisting(System.String, System.Security.AccessControl.MutexRights)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Mutex.SetAccessControl(System.Security.AccessControl.MutexSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Mutex.TryOpenExisting(System.String, System.Security.AccessControl.MutexRights, System.Threading.Mutex)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Semaphore..ctor(System.Int32, System.Int32, System.String, System.Boolean, System.Security.AccessControl.SemaphoreSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Semaphore.GetAccessControl()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Semaphore.OpenExisting(System.String, System.Security.AccessControl.SemaphoreRights)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Semaphore.SetAccessControl(System.Security.AccessControl.SemaphoreSecurity)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Semaphore.TryOpenExisting(System.String, System.Security.AccessControl.SemaphoreRights, System.Threading.Semaphore)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.XmlMemberMapping.GenerateTypeName(System.CodeDom.Compiler.CodeDomProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeGenerationOptions, System.CodeDom.Compiler.CodeDomProvider, System.Xml.Serialization.ImportContext)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeGenerationOptions, System.Xml.Serialization.ImportContext)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeIdentifiers, System.Xml.Serialization.CodeGenerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer..ctor(System.Type, System.Xml.Serialization.XmlAttributeOverrides, System.Type[], System.Xml.Serialization.XmlRootAttribute, System.String, System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.FromMappings(System.Xml.Serialization.XmlMapping[], System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.GenerateSerializer(System.Type[], System.Xml.Serialization.XmlMapping[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.GenerateSerializer(System.Type[], System.Xml.Serialization.XmlMapping[], System.CodeDom.Compiler.CompilerParameters)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.XmlSerializerFactory.CreateSerializer(System.Type, System.Xml.Serialization.XmlAttributeOverrides, System.Type[], System.Xml.Serialization.XmlRootAttribute, System.String, System.String, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.XmlReaderSettings..ctor(System.Xml.XmlResolver)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.XmlSecureResolver..ctor(System.Xml.XmlResolver, System.Security.PermissionSet)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.XmlSecureResolver..ctor(System.Xml.XmlResolver, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.XmlSecureResolver.CreateEvidenceForUrl(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Xsl.XslCompiledTransform.CompileToType(System.Xml.XmlReader, System.Xml.Xsl.XsltSettings, System.Xml.XmlResolver, System.Boolean, System.Reflection.Emit.TypeBuilder, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Xsl.XslCompiledTransform.TemporaryFiles.get()' does not exist in the implementation but it does exist in the contract -MembersMustExist : Member 'System.Xml.Xsl.XslTransform.Load(System.Xml.XmlReader, System.Xml.XmlResolver, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Xsl.XslTransform.Load(System.Xml.XPath.IXPathNavigable, System.Xml.XmlResolver, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Xsl.XslTransform.Load(System.Xml.XPath.XPathNavigator, System.Xml.XmlResolver, Syste - -// Negligible usage, CAS -TypesMustExist : Type 'System.ServiceProcess.ServiceControllerPermission' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceProcess.ServiceControllerPermissionAccess' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceProcess.ServiceControllerPermissionAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceProcess.ServiceControllerPermissionEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceProcess.ServiceControllerPermissionEntryCollection' does not exist in the implementation but it does exist in the contract. - -// CAS -TypesMustExist : Type 'System.Security.Policy.ApplicationSecurityInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Policy.ApplicationSecurityManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Policy.IApplicationTrustManager' does not exist in the implementation but it does exist in the contract. - -// Undesirable dependencies -TypesMustExist : Type 'System.ServiceProcess.Design.ServiceInstallerDialog' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceProcess.Design.ServiceInstallerDialogResult' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceProcess.ServiceInstaller' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceProcess.ServiceProcessDescriptionAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceProcess.ServiceProcessInstaller' does not exist in the implementation but it does exist in the contract. - -MembersMustExist : Member 'System.Console.Write(System.String, System.Object, System.Object, System.Object, System.Object, __arglist)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Console.WriteLine(System.String, System.Object, System.Object, System.Object, System.Object, __arglist)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Concat(System.Object, System.Object, System.Object, System.Object, __arglist)' does not exist in the implementation but it does exist in the contract. - -// Intentional change in Core -TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'ref struct' in the implementation but is a 'struct' in the contract. -TypeCannotChangeClassification : Type 'System.TypedReference' is a 'ref struct' in the implementation but is a 'struct' in the contract. \ No newline at end of file diff --git a/src/libraries/shims/ApiCompatBaseline.netcoreapp.netfx461.txt b/src/libraries/shims/ApiCompatBaseline.netcoreapp.netfx461.txt deleted file mode 100644 index 4fd3fa2437be4..0000000000000 --- a/src/libraries/shims/ApiCompatBaseline.netcoreapp.netfx461.txt +++ /dev/null @@ -1,614 +0,0 @@ -ApiCompat Error: 0 : Unable to resolve assembly 'Assembly(Name=System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)' referenced by the contract assembly 'Assembly(Name=System.ServiceModel.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)'. -ApiCompat Error: 0 : Unable to resolve assembly 'Assembly(Name=System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)' referenced by the contract assembly 'Assembly(Name=System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a)'. -ApiCompat Error: 0 : Unable to resolve assembly 'Assembly(Name=System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)' referenced by the contract assembly 'Assembly(Name=System.Xml.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)'. -ApiCompat Error: 0 : Unable to resolve assembly 'Assembly(Name=System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)' referenced by the contract assembly 'Assembly(Name=WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)'. -Compat issues with assembly mscorlib: -TypesMustExist : Type 'System.Configuration.Assemblies.AssemblyHash' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.IsolatedStorage.IsolatedStorageSecurityOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.IsolatedStorage.IsolatedStorageSecurityState' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.EventToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.ExceptionHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.FieldToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.MethodRental' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.MethodToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.ParameterToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.PEFileKinds' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.PropertyToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.SignatureToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.StringToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.TypeToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.UnmanagedMarshal' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.ProfileOptimization' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Formatters.InternalRM' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Formatters.InternalST' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Formatters.ISoapMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Formatters.ServerFault' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Formatters.SoapFault' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Formatters.SoapMessage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Principal.WindowsImpersonationContext' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System: -MembersMustExist : Member 'System.CodeDom.Compiler.CompilerParameters.Evidence.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.CodeDom.Compiler.CompilerParameters.Evidence.set(System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.CodeDom.Compiler.CompilerResults.Evidence.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.CodeDom.Compiler.CompilerResults.Evidence.set(System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.ConsoleTraceListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.DiagnosticsConfigurationHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.EventLogTraceListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.XmlWriterTraceListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.IODescriptionAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.ICertificatePolicy' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.AuthenticationModuleElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.AuthenticationModuleElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.AuthenticationModulesSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.BypassElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.BypassElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.ConnectionManagementElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.ConnectionManagementElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.ConnectionManagementSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.DefaultProxySection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.FtpCachePolicyElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.HttpCachePolicyElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.HttpListenerElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.HttpListenerTimeoutsElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.HttpWebRequestElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.Ipv6Element' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.MailSettingsSectionGroup' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.ModuleElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.NetSectionGroup' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.PerformanceCountersElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.ProxyElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.RequestCachingSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.ServicePointManagerElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.SettingsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.SmtpNetworkElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.SmtpSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.SmtpSpecifiedPickupDirectoryElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.SocketElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.UnicodeDecodingConformance' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.UnicodeEncodingConformance' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.WebProxyScriptElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.WebRequestModuleElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.WebRequestModuleElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.WebRequestModulesSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Configuration.WebUtilityElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Sockets.SocketClientAccessPolicyProtocol' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.ICustomTypeProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.StandardOleMarshalObject' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Authentication.ExtendedProtection.TokenBinding' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Authentication.ExtendedProtection.TokenBindingType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Authentication.ExtendedProtection.Configuration.ServiceNameElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Authentication.ExtendedProtection.Configuration.ServiceNameElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Claims.DynamicRoleClaimProvider' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.ComponentModel.DataAnnotations: -TypesMustExist : Type 'System.ComponentModel.DataAnnotations.AssociatedMetadataTypeTypeDescriptionProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.DataAnnotations.BindableTypeAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.DataAnnotations.MetadataTypeAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.DataAnnotations.ScaffoldTableAttribute' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Core: -TypesMustExist : Type 'System.Diagnostics.EventSchemaTraceListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.TraceLogRetentionOption' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.UnescapedXmlDiagnosticData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.EventDescriptor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.EventProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.EventProviderTraceListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventBookmark' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventKeyword' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogConfiguration' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogInvalidDataException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogIsolation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogLink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogNotFoundException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogPropertySelector' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogProviderDisabledException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogQuery' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogReader' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogReadingException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogRecord' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogSession' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogStatus' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventLogWatcher' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventMetadata' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventOpcode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventProperty' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventRecord' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventRecordWrittenEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.EventTask' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.PathType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.ProviderMetadata' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.SessionAuthentication' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.StandardEventKeywords' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.StandardEventLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.StandardEventOpcode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Eventing.Reader.StandardEventTask' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.PerformanceData.CounterData' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.PerformanceData.CounterSet' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.PerformanceData.CounterSetInstance' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.PerformanceData.CounterSetInstanceCounterDataSet' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.PerformanceData.CounterSetInstanceType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.PerformanceData.CounterType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.MemoryMappedFiles.MemoryMappedFileSecurity' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.InstanceNotFoundException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.InstrumentationBaseException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.InstrumentationException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementBindAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementCommitAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementConfigurationAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementConfigurationType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementCreateAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementEntityAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementEnumeratorAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementHostingModel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementKeyAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementMemberAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementNameAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementNewInstanceAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementProbeAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementReferenceAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementRemoveAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.ManagementTaskAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Management.Instrumentation.WmiConfigurationAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.CallSiteOps' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.Closure' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.ExecutionScope' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.RuntimeOps' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.ManifestKinds' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.ManifestSignatureInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.ManifestSignatureInformationCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.MD5Cng' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.SHA1Cng' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.SHA256Cng' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.SHA384Cng' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.SHA512Cng' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.SignatureVerificationResult' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.StrongNameSignatureInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.X509Certificates.AuthenticodeSignatureInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.X509Certificates.TimestampInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.X509Certificates.TrustStatus' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Data: -TypesMustExist : Type 'Microsoft.SqlServer.Server.SqlContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Microsoft.SqlServer.Server.SqlFacetAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Microsoft.SqlServer.Server.SqlPipe' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Microsoft.SqlServer.Server.SqlProcedureAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Microsoft.SqlServer.Server.SqlTriggerAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Microsoft.SqlServer.Server.SqlTriggerContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'Microsoft.SqlServer.Server.TriggerAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.DataSetSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.PropertyAttributes' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.TypedDataSetGenerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.TypedDataSetGeneratorException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.Common.DbProviderConfigurationHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.Common.DbProviderFactoriesConfigurationHandler' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.Common.DbProviderFactory.CreatePermission(System.Security.Permissions.PermissionState)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.Odbc.OdbcConnection.EnlistDistributedTransaction(System.EnterpriseServices.ITransaction)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.Odbc.OdbcFactory.CreatePermission(System.Security.Permissions.PermissionState)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.Sql.SqlDataSourceEnumerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlClient.SqlAuthenticationMethod' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlBulkCopyOptions System.Data.SqlClient.SqlBulkCopyOptions.AllowEncryptedValueModifications' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlClientFactory.CreatePermission(System.Security.Permissions.PermissionState)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlClient.SqlColumnEncryptionCertificateStoreProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlClient.SqlColumnEncryptionCngProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlClient.SqlColumnEncryptionCspProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlClient.SqlColumnEncryptionKeyStoreProvider' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlCommand..ctor(System.String, System.Data.SqlClient.SqlConnection, System.Data.SqlClient.SqlTransaction, System.Data.SqlClient.SqlCommandColumnEncryptionSetting)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlCommand.BeginExecuteReader()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlCommand.BeginExecuteReader(System.AsyncCallback, System.Object)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlCommand.BeginExecuteReader(System.AsyncCallback, System.Object, System.Data.CommandBehavior)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlCommand.BeginExecuteReader(System.Data.CommandBehavior)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlCommand.ColumnEncryptionSetting.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlCommand.EndExecuteReader(System.IAsyncResult)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlCommand.NotificationAutoEnlist.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlCommand.NotificationAutoEnlist.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlClient.SqlCommandColumnEncryptionSetting' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnection.AccessToken.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnection.AccessToken.set(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnection.ColumnEncryptionTrustedMasterKeyPaths.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnection.EnlistDistributedTransaction(System.EnterpriseServices.ITransaction)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnection.RegisterColumnEncryptionKeyStoreProviders(System.Collections.Generic.IDictionary)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlClient.SqlConnectionColumnEncryptionSetting' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.AsynchronousProcessing.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.AsynchronousProcessing.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.Authentication.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.Authentication.set(System.Data.SqlClient.SqlAuthenticationMethod)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.ColumnEncryptionSetting.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.ColumnEncryptionSetting.set(System.Data.SqlClient.SqlConnectionColumnEncryptionSetting)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.ConnectionReset.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.ConnectionReset.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.ContextConnection.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.ContextConnection.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.NetworkLibrary.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.NetworkLibrary.set(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.TransparentNetworkIPResolution.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.TransparentNetworkIPResolution.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlClient.SQLDebugging' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlParameter.ForceColumnEncryption.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlParameter.ForceColumnEncryption.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Data.SqlClient.SqlParameterCollection.Add(System.String, System.Object)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.SqlFileStream' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.SqlTypesSchemaImporterExtensionHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeBigIntSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeBinarySchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeBitSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeCharSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeDateTimeSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeDecimalSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeFloatSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeIntSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeMoneySchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeNCharSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeNTextSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeNumericSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeNVarCharSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeRealSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeSmallDateTimeSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeSmallIntSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeSmallMoneySchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeTextSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeTinyIntSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeUniqueIdentifierSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeVarBinarySchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeVarCharSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Data.SqlTypes.TypeVarImageSchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.XmlDataDocument' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.DirectoryServices: -TypesMustExist : Type 'System.DirectoryServices.DSDescriptionAttribute' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.DirectoryServices.Protocols: -MembersMustExist : Member 'System.DirectoryServices.Protocols.AddRequest.ToXmlNode(System.Xml.XmlDocument)' does not exist in the implementation but it does exist in the contract. -CannotMakeTypeAbstract : Type 'System.DirectoryServices.Protocols.BerConverter' is abstract in the implementation but is not abstract in the contract. -MembersMustExist : Member 'System.DirectoryServices.Protocols.CompareRequest.ToXmlNode(System.Xml.XmlDocument)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DirectoryServices.Protocols.DeleteRequest.ToXmlNode(System.Xml.XmlDocument)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DirectoryServices.Protocols.DirectoryRequest.ToXmlNode(System.Xml.XmlDocument)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DirectoryServices.Protocols.DsmlAuthRequest.ToXmlNode(System.Xml.XmlDocument)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlAuthResponse' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlDirectoryIdentifier' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlDocument' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlDocumentProcessing' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlErrorProcessing' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlErrorResponse' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlInvalidDocumentException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlRequestDocument' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlResponseDocument' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlResponseOrder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlSoapConnection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.DsmlSoapHttpConnection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.ErrorResponseCategory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.DirectoryServices.Protocols.ErrorResponseException' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DirectoryServices.Protocols.ExtendedRequest.ToXmlNode(System.Xml.XmlDocument)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DirectoryServices.Protocols.ModifyDNRequest.ToXmlNode(System.Xml.XmlDocument)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DirectoryServices.Protocols.ModifyRequest.ToXmlNode(System.Xml.XmlDocument)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DirectoryServices.Protocols.SearchRequest..ctor(System.String, System.Xml.XmlDocument, System.DirectoryServices.Protocols.SearchScope, System.String[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DirectoryServices.Protocols.SearchRequest.ToXmlNode(System.Xml.XmlDocument)' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Drawing: -CannotMakeTypeAbstract : Type 'System.Drawing.ColorTranslator' is abstract in the implementation but is not abstract in the contract. -TypesMustExist : Type 'System.Drawing.FontConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.IconConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.ImageConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.ImageFormatConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.IPropertyValueUIService' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.IToolboxItemProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.IToolboxService' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.IToolboxUser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.PaintValueEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.PropertyValueUIHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.PropertyValueUIItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.PropertyValueUIItemInvokeHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.ToolboxComponentsCreatedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.ToolboxComponentsCreatedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.ToolboxComponentsCreatingEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.ToolboxComponentsCreatingEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.ToolboxItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.ToolboxItemCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.ToolboxItemCreatorCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.UITypeEditor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Design.UITypeEditorEditStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.Printing.MarginsConverter' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Net: -TypesMustExist : Type 'System.Net.INetworkProgress' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.IPEndPointCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.IUnsafeWebRequestCreate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.NetworkProgressChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.UiSynchronizationContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Cloud' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.CloudCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.PeerName' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.PeerNameRecord' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.PeerNameRecordCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.PeerNameRegistration' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.PeerNameResolver' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.PeerNameType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.PeerToPeerException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.ResolveCompletedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.ResolveProgressChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.ApplicationChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.ContactManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.CreateContactCompletedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.InviteCompletedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.NameChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.ObjectChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.Peer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerApplication' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerApplicationCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerApplicationLaunchInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerApplicationRegistrationType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerChangeType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerCollaboration' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerContact' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerContactCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerEndPoint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerEndPointCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerInvitationResponse' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerInvitationResponseType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerNearMe' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerNearMeChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerNearMeCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerObject' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerObjectCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerPresenceInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerPresenceStatus' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PeerScope' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.PresenceChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.RefreshDataCompletedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.SubscribeCompletedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.SubscriptionListChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.PeerToPeer.Collaboration.SubscriptionType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Sockets.HttpPolicyDownloaderProtocol' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Sockets.SecurityCriticalAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Sockets.SocketPolicy' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Sockets.UdpAnySourceMulticastClient' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Sockets.UdpSingleSourceMulticastClient' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Runtime.Serialization: -TypesMustExist : Type 'System.Runtime.Serialization.IDataContractSurrogate' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.ImportOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.NetDataContractSerializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.XsdDataContractImporter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Configuration.DataContractSerializerSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Configuration.DeclaredTypeElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Configuration.DeclaredTypeElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Configuration.NetDataContractSerializerSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Configuration.ParameterElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Configuration.ParameterElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Configuration.SerializationSectionGroup' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Configuration.TypeElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.Serialization.Configuration.TypeElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.IXmlMtomReaderInitializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.IXmlMtomWriterInitializer' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Security: -TypesMustExist : Type 'System.Security.Cryptography.DataProtector' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.DpapiDataProtector' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.MemoryProtectionScope' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.ProtectedMemory' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.Pkcs.AlgorithmIdentifier.Parameters.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.Pkcs.AlgorithmIdentifier.Parameters.set(System.Byte[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.Pkcs.EnvelopedCms..ctor(System.Security.Cryptography.Pkcs.SubjectIdentifierType, System.Security.Cryptography.Pkcs.ContentInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.Pkcs.EnvelopedCms..ctor(System.Security.Cryptography.Pkcs.SubjectIdentifierType, System.Security.Cryptography.Pkcs.ContentInfo, System.Security.Cryptography.Pkcs.AlgorithmIdentifier)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.Pkcs.EnvelopedCms.Encrypt()' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.Pkcs.KeyAgreeKeyChoice' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.X509Certificates.X509Certificate2UI' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.X509Certificates.X509SelectionFlag' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.ServiceModel.Web: -TypesMustExist : Type 'System.ServiceModel.WebHttpBinding' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.WebHttpSecurity' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.WebHttpSecurityMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Activation.WebScriptServiceHostFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Activation.WebServiceHostFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Channels.JavascriptCallbackResponseMessageProperty' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Channels.StreamBodyWriter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Channels.WebBodyFormatMessageProperty' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Channels.WebContentFormat' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Channels.WebContentTypeMapper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Channels.WebMessageEncodingBindingElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebHttpBindingCollectionElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebHttpBindingElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebHttpElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebHttpEndpointCollectionElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebHttpEndpointElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebHttpSecurityElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebMessageEncodingElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebScriptEnablingElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebScriptEndpointCollectionElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Configuration.WebScriptEndpointElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Description.JsonFaultDetail' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Description.WebHttpBehavior' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Description.WebHttpEndpoint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Description.WebScriptEnablingBehavior' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Description.WebScriptEndpoint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Description.WebServiceEndpoint' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Dispatcher.JsonQueryStringConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Dispatcher.QueryStringConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Dispatcher.WebHttpDispatchOperationSelector' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.AspNetCacheProfileAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.IncomingWebRequestContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.IncomingWebResponseContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.JavascriptCallbackBehaviorAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.OutgoingWebRequestContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.OutgoingWebResponseContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.WebChannelFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.WebFaultException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.WebFaultException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.WebGetAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.WebInvokeAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.WebMessageBodyStyle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.WebMessageFormat' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.WebOperationContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ServiceModel.Web.WebServiceHost' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.ServiceProcess: -TypesMustExist : Type 'System.ServiceProcess.ServiceAccount' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Transactions: -TypesMustExist : Type 'System.Transactions.Configuration.DefaultSettingsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Transactions.Configuration.MachineSettingsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Transactions.Configuration.TransactionsSectionGroup' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Xml: -TypesMustExist : Type 'System.Xml.XmlXapResolver' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.CodeExporter' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Serialization.SchemaImporter.Extensions.get()' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.SoapCodeExporter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.SoapSchemaExporter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.SoapSchemaImporter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.XmlCodeExporter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.Advanced.SchemaImporterExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.Advanced.SchemaImporterExtensionCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.Configuration.DateTimeSerializationSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.Configuration.RootedPathValidator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.Configuration.SchemaImporterExtensionElement' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.Configuration.SchemaImporterExtensionElementCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.Configuration.SchemaImporterExtensionsSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.Configuration.SerializationSectionGroup' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.Configuration.XmlSerializerSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.XmlConfiguration.XmlReaderSection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.XmlConfiguration.XsltConfigSection' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Xsl.XslCompiledTransform.TemporaryFiles.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Xsl.XslTransform.Load(System.Xml.XPath.XPathNavigator, System.Xml.XmlResolver, System.Security.Policy.Evidence)' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly WindowsBase: -TypesMustExist : Type 'System.Collections.Specialized.CollectionChangedEventManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.CurrentChangedEventManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.CurrentChangingEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.CurrentChangingEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.CurrentChangingEventManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.DependencyPropertyDescriptor' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.ErrorsChangedEventManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.GroupDescription' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.ICollectionView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.ICollectionViewFactory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.ICollectionViewLiveShaping' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.IEditableCollectionView' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.IEditableCollectionViewAddNewItem' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.IItemProperties' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.ItemPropertyInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.NewItemPlaceholderPosition' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.PropertyChangedEventManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.PropertyFilterAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.PropertyFilterOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.SortDescription' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ComponentModel.SortDescriptionCollection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.PresentationTraceLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.PresentationTraceSources' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.CertificateEmbeddingOption' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.EncryptedPackageEnvelope' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.InvalidSignatureEventHandler' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Packaging.Package..ctor(System.IO.FileAccess, System.Boolean)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.PackageDigitalSignature' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.PackageDigitalSignatureManager' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Packaging.PackUriHelper.ComparePackUri(System.Uri, System.Uri)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Packaging.PackUriHelper.Create(System.Uri)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Packaging.PackUriHelper.Create(System.Uri, System.Uri)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Packaging.PackUriHelper.Create(System.Uri, System.Uri, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Packaging.PackUriHelper.GetPackageUri(System.Uri)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Packaging.PackUriHelper.GetPartUri(System.Uri)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.RightsManagementInformation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.SignatureVerificationEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.StorageInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.StreamInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Packaging.VerifyResult' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Permissions.MediaPermission' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Permissions.MediaPermissionAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Permissions.MediaPermissionAudio' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Permissions.MediaPermissionImage' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Permissions.MediaPermissionVideo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Permissions.WebBrowserPermission' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Permissions.WebBrowserPermissionAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Permissions.WebBrowserPermissionLevel' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.AuthenticationType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.ContentGrant' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.ContentRight' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.ContentUser' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.CryptoProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.LocalizedNameDescriptionPair' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.PublishLicense' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.RightsManagementException' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.RightsManagementFailureCode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.SecureEnvironment' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.UnsignedPublishLicense' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.UseLicense' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.RightsManagement.UserActivationMode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.AttachedPropertyBrowsableAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.AttachedPropertyBrowsableForTypeAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.AttachedPropertyBrowsableWhenAttributePresentAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.BaseCompatibilityPreferences' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.CoerceValueCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.DependencyObject' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.DependencyObjectType' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.DependencyProperty' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.DependencyPropertyChangedEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.DependencyPropertyChangedEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.DependencyPropertyKey' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Expression' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.ExpressionConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Freezable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Int32Rect' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Int32RectConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.IWeakEventListener' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.LocalValueEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.LocalValueEnumerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.NameScope' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Point' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.PointConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.PropertyChangedCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.PropertyMetadata' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Rect' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.RectConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Size' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.SizeConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.SplashScreen' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.ValidateValueCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Vector' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.VectorConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.WeakEventManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.WeakEventManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Converters.Int32RectValueSerializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Converters.PointValueSerializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Converters.RectValueSerializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Converters.SizeValueSerializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Converters.VectorValueSerializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Data.DataSourceProvider' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Input.FocusNavigationDirection' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Input.Key' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Input.KeyConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Input.KeyInterop' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Input.KeyValueSerializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Input.ModifierKeys' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Input.ModifierKeysConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Input.ModifierKeysValueSerializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Input.TraversalRequest' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Interop.ComponentDispatcher' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Interop.IKeyboardInputSink' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Interop.IKeyboardInputSite' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Interop.MSG' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Interop.ThreadMessageEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Markup.DesignerSerializationOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Markup.DesignerSerializationOptionsAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Markup.InternalTypeHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Markup.IReceiveMarkupExtension' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Markup.ServiceProviders' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Markup.Primitives.MarkupObject' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Markup.Primitives.MarkupProperty' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Media.DisableDpiAwarenessAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Media.Matrix' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Media.MatrixConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Media.Converters.MatrixValueSerializer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.Dispatcher' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherFrame' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherHookEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherHookEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherHooks' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherObject' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherOperation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherOperation' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherOperationCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherOperationStatus' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherPriority' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherPriorityAwaitable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherPriorityAwaiter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherProcessingDisabled' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherSynchronizationContext' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherTimer' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherUnhandledExceptionEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherUnhandledExceptionEventHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherUnhandledExceptionFilterEventArgs' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Windows.Threading.DispatcherUnhandledExceptionFilterEventHandler' does not exist in the implementation but it does exist in the contract. -Total Issues: 633 diff --git a/src/libraries/shims/ApiCompatBaseline.netfx.netstandard.txt b/src/libraries/shims/ApiCompatBaseline.netfx.netstandard.txt deleted file mode 100644 index e185b0e6f6de7..0000000000000 --- a/src/libraries/shims/ApiCompatBaseline.netfx.netstandard.txt +++ /dev/null @@ -1,102 +0,0 @@ -Compat issues with assembly mscorlib: -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinAccountReadonlyControllersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinApplicationPackageAuthoritySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinAnyPackageSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinCertSvcDComAccessGroup' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinCryptoOperatorsSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinDCOMUsersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinEventLogReadersGroup' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinIUsersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCacheablePrincipalsGroupSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityDocumentsLibrarySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityEnterpriseAuthenticationSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityInternetClientServerSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityInternetClientSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityMusicLibrarySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityPicturesLibrarySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityPrivateNetworkClientServerSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityRemovableStorageSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilitySharedUserCertificatesSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityVideosLibrarySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinConsoleLogonSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCreatorOwnerRightsSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinEnterpriseReadonlyControllersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinHighLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinIUserSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinLocalLogonSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinLowLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinMediumLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinMediumPlusLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinNewEnterpriseReadonlyControllersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinNonCacheablePrincipalsGroupSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinSystemLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinThisOrganizationCertificateSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinUntrustedLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinWriteRestrictedCodeSid' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.ComponentModel.Annotations: -CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.ComponentModel.DataAnnotations.DisplayAttribute' changed from '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple=false)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple=false)]' in the implementation. -MembersMustExist : Member 'System.ComponentModel.DataAnnotations.DisplayFormatAttribute.GetNullDisplayText()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ComponentModel.DataAnnotations.DisplayFormatAttribute.NullDisplayTextResourceType.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ComponentModel.DataAnnotations.DisplayFormatAttribute.NullDisplayTextResourceType.set(System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ComponentModel.DataAnnotations.RangeAttribute.ConvertValueInInvariantCulture.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ComponentModel.DataAnnotations.RangeAttribute.ConvertValueInInvariantCulture.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ComponentModel.DataAnnotations.RangeAttribute.ParseLimitsInInvariantCulture.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ComponentModel.DataAnnotations.RangeAttribute.ParseLimitsInInvariantCulture.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.ComponentModel.Composition: -TypesMustExist : Type 'System.ComponentModel.Composition.AdaptationConstants' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Configuration.ConfigurationManager: -MembersMustExist : Member 'System.Configuration.Internal.DelegatingConfigHost.HasLocalConfig.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Configuration.Internal.DelegatingConfigHost.HasRoamingConfig.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Configuration.Internal.DelegatingConfigHost.IsAppConfigHttp.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Configuration.Internal.DelegatingConfigHost.RefreshConfigPaths()' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Diagnostics.PerformanceCounter: -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Diagnostics.CounterSample' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Diagnostics.CounterSample' is marked as readonly in the contract so it must also be marked readonly in the implementation. -Compat issues with assembly System.Security.Cryptography.OpenSsl: -TypesMustExist : Type 'System.Security.Cryptography.DSAOpenSsl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.ECDsaOpenSsl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.RSAOpenSsl' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.SafeEvpPKeyHandle' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Security.Permissions: -MembersMustExist : Member 'System.Security.Permissions.KeyContainerPermissionAccessEntryCollection..ctor()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Permissions.KeyContainerPermissionAccessEntryCollection.CopyTo(System.Array, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Permissions.KeyContainerPermissionAccessEntryEnumerator..ctor()' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.Security.Principal.Windows: -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinAccountReadonlyControllersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinApplicationPackageAuthoritySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinAnyPackageSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinCertSvcDComAccessGroup' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinCryptoOperatorsSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinDCOMUsersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinEventLogReadersGroup' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinBuiltinIUsersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCacheablePrincipalsGroupSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityDocumentsLibrarySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityEnterpriseAuthenticationSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityInternetClientServerSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityInternetClientSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityMusicLibrarySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityPicturesLibrarySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityPrivateNetworkClientServerSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityRemovableStorageSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilitySharedUserCertificatesSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCapabilityVideosLibrarySid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinConsoleLogonSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinCreatorOwnerRightsSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinEnterpriseReadonlyControllersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinHighLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinIUserSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinLocalLogonSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinLowLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinMediumLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinMediumPlusLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinNewEnterpriseReadonlyControllersSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinNonCacheablePrincipalsGroupSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinSystemLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinThisOrganizationCertificateSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinUntrustedLabelSid' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Principal.WellKnownSidType System.Security.Principal.WellKnownSidType.WinWriteRestrictedCodeSid' does not exist in the implementation but it does exist in the contract. -Compat issues with assembly System.ServiceProcess.ServiceController: -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.ServiceProcess.SessionChangeDescription' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.ServiceProcess.SessionChangeDescription' is marked as readonly in the contract so it must also be marked readonly in the implementation. -Total Issues: 92 diff --git a/src/libraries/shims/ApiCompatBaseline.netfx.netstandardOnly.txt b/src/libraries/shims/ApiCompatBaseline.netfx.netstandardOnly.txt deleted file mode 100644 index f68769e14f081..0000000000000 --- a/src/libraries/shims/ApiCompatBaseline.netfx.netstandardOnly.txt +++ /dev/null @@ -1,870 +0,0 @@ -Compat issues with assembly netstandard: -MembersMustExist : Member 'System.Array.Fill(T[], T)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Array.Fill(T[], T, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Array.Reverse(T[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Array.Reverse(T[], System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.ArraySegment' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.ArraySegment' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.ArraySegment.CopyTo(System.ArraySegment)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.CopyTo(T[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.CopyTo(T[], System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.Empty.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.GetEnumerator()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.Item.get(System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.Item.set(System.Int32, T)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.op_Implicit(T[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.Slice(System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.Slice(System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ArraySegment.ToArray()' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ArraySegment.Enumerator' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.Int32BitsToSingle(System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.SingleToInt32Bits(System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToBoolean(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToChar(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToDouble(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToInt16(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToInt32(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToInt64(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToSingle(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToUInt16(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToUInt32(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.ToUInt64(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.Char)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.Int16)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.Int64)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.UInt16)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.UInt32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.BitConverter.TryWriteBytes(System.Span, System.UInt64)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Boolean' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Boolean' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Boolean.Parse(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Boolean.TryFormat(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Boolean.TryParse(System.ReadOnlySpan, System.Boolean)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Byte' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Byte' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Byte.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Byte.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Byte.TryParse(System.ReadOnlySpan, System.Byte)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Byte.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.Byte)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Char' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Char' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.ConsoleKeyInfo' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.ConsoleKeyInfo' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Convert.ToBase64String(System.ReadOnlySpan, System.Base64FormattingOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Convert.TryFromBase64Chars(System.ReadOnlySpan, System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Convert.TryFromBase64String(System.String, System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Convert.TryToBase64Chars(System.ReadOnlySpan, System.Span, System.Int32, System.Base64FormattingOptions)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.DateTime' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.DateTime' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.DateTime System.DateTime.UnixEpoch' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTime.Parse(System.ReadOnlySpan, System.IFormatProvider, System.Globalization.DateTimeStyles)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTime.ParseExact(System.ReadOnlySpan, System.ReadOnlySpan, System.IFormatProvider, System.Globalization.DateTimeStyles)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTime.ParseExact(System.ReadOnlySpan, System.String[], System.IFormatProvider, System.Globalization.DateTimeStyles)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTime.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTime.TryParse(System.ReadOnlySpan, System.DateTime)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTime.TryParse(System.ReadOnlySpan, System.IFormatProvider, System.Globalization.DateTimeStyles, System.DateTime)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTime.TryParseExact(System.ReadOnlySpan, System.ReadOnlySpan, System.IFormatProvider, System.Globalization.DateTimeStyles, System.DateTime)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTime.TryParseExact(System.ReadOnlySpan, System.String[], System.IFormatProvider, System.Globalization.DateTimeStyles, System.DateTime)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.DateTimeOffset' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.DateTimeOffset' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.DateTimeOffset System.DateTimeOffset.UnixEpoch' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTimeOffset.Parse(System.ReadOnlySpan, System.IFormatProvider, System.Globalization.DateTimeStyles)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTimeOffset.ParseExact(System.ReadOnlySpan, System.ReadOnlySpan, System.IFormatProvider, System.Globalization.DateTimeStyles)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTimeOffset.ParseExact(System.ReadOnlySpan, System.String[], System.IFormatProvider, System.Globalization.DateTimeStyles)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTimeOffset.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTimeOffset.TryParse(System.ReadOnlySpan, System.DateTimeOffset)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTimeOffset.TryParse(System.ReadOnlySpan, System.IFormatProvider, System.Globalization.DateTimeStyles, System.DateTimeOffset)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTimeOffset.TryParseExact(System.ReadOnlySpan, System.ReadOnlySpan, System.IFormatProvider, System.Globalization.DateTimeStyles, System.DateTimeOffset)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.DateTimeOffset.TryParseExact(System.ReadOnlySpan, System.String[], System.IFormatProvider, System.Globalization.DateTimeStyles, System.DateTimeOffset)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Decimal' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Decimal' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Decimal.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Decimal.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Decimal.TryParse(System.ReadOnlySpan, System.Decimal)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Decimal.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.Decimal)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Double' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Double' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Double.IsFinite(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Double.IsNegative(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Double.IsNormal(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Double.IsSubnormal(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Double.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Double.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Double.TryParse(System.ReadOnlySpan, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Double.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Enum.Parse(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Enum.Parse(System.String, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Enum.TryParse(System.Type, System.String, System.Boolean, System.Object)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Enum.TryParse(System.Type, System.String, System.Object)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.GC.GetAllocatedBytesForCurrentThread()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Guid..ctor(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Guid.Parse(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Guid.ParseExact(System.ReadOnlySpan, System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Guid.TryFormat(System.Span, System.Int32, System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Guid.TryParse(System.ReadOnlySpan, System.Guid)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Guid.TryParseExact(System.ReadOnlySpan, System.ReadOnlySpan, System.Guid)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Guid.TryWriteBytes(System.Span)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.HashCode' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IAsyncDisposable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Index' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Int16' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Int16' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Int16.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Int16.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Int16.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.Int16)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Int16.TryParse(System.ReadOnlySpan, System.Int16)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Int32' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Int32' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Int32.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Int32.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Int32.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Int32.TryParse(System.ReadOnlySpan, System.Int32)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Int64' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Int64' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Int64.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Int64.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Int64.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.Int64)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Int64.TryParse(System.ReadOnlySpan, System.Int64)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.IntPtr' in the contract but not the implementation. -CannotRemoveBaseTypeOrInterface : Type 'System.IntPtr' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -TypeCannotChangeClassification : Type 'System.IntPtr' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Lazy..ctor(T)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Acosh(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Asinh(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Atanh(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Cbrt(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.Byte, System.Byte, System.Byte)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.Decimal, System.Decimal, System.Decimal)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.Double, System.Double, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.Int16, System.Int16, System.Int16)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.Int32, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.Int64, System.Int64, System.Int64)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.SByte, System.SByte, System.SByte)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.Single, System.Single, System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.UInt16, System.UInt16, System.UInt16)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.UInt32, System.UInt32, System.UInt32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Math.Clamp(System.UInt64, System.UInt64, System.UInt64)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.MathF' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Memory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.MemoryExtensions' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Random.NextBytes(System.Span)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Range' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ReadOnlyMemory' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.ReadOnlySpan' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsByRefLikeAttribute' exists on 'System.RuntimeArgumentHandle' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'struct' in the implementation but is a 'ref struct' in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.SByte' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.SByte' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.SByte.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.SByte.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.SByte.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.SByte)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.SByte.TryParse(System.ReadOnlySpan, System.SByte)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.SequencePosition' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Single' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Single' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Single.IsFinite(System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Single.IsNegative(System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Single.IsNormal(System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Single.IsSubnormal(System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Single.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Single.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Single.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Single.TryParse(System.ReadOnlySpan, System.Single)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Span' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String..ctor(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Chars.get(System.Index)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Chars.get(System.Range)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Contains(System.Char)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Contains(System.Char, System.StringComparison)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Contains(System.String, System.StringComparison)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Create(System.Int32, TState, System.Buffers.SpanAction)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.EndsWith(System.Char)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.GetHashCode(System.StringComparison)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.IndexOf(System.Char, System.StringComparison)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Join(System.Char, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Join(System.Char, System.String[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Join(System.Char, System.String[], System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Join(System.Char, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.op_Implicit(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Replace(System.String, System.String, System.Boolean, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Replace(System.String, System.String, System.StringComparison)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Split(System.Char, System.Int32, System.StringSplitOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Split(System.Char, System.StringSplitOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Split(System.String, System.Int32, System.StringSplitOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Split(System.String, System.StringSplitOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.StartsWith(System.Char)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Substring(System.Index)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Substring(System.Range)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.Trim(System.Char)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.TrimEnd()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.TrimEnd(System.Char)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.TrimStart()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String.TrimStart(System.Char)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.StringComparer.Create(System.Globalization.CultureInfo, System.Globalization.CompareOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.StringComparer.FromComparison(System.StringComparison)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.TimeSpan' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.TimeSpan' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.TimeSpan.Divide(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.Divide(System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.Multiply(System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.op_Division(System.TimeSpan, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.op_Division(System.TimeSpan, System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.op_Multiply(System.Double, System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.op_Multiply(System.TimeSpan, System.Double)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.Parse(System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.ParseExact(System.ReadOnlySpan, System.ReadOnlySpan, System.IFormatProvider, System.Globalization.TimeSpanStyles)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.ParseExact(System.ReadOnlySpan, System.String[], System.IFormatProvider, System.Globalization.TimeSpanStyles)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.TryParse(System.ReadOnlySpan, System.IFormatProvider, System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.TryParse(System.ReadOnlySpan, System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.TryParseExact(System.ReadOnlySpan, System.ReadOnlySpan, System.IFormatProvider, System.Globalization.TimeSpanStyles, System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.TryParseExact(System.ReadOnlySpan, System.ReadOnlySpan, System.IFormatProvider, System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.TryParseExact(System.ReadOnlySpan, System.String[], System.IFormatProvider, System.Globalization.TimeSpanStyles, System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.TimeSpan.TryParseExact(System.ReadOnlySpan, System.String[], System.IFormatProvider, System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.TimeZoneInfo.TransitionTime' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.TimeZoneInfo.TransitionTime' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Type.GetMethod(System.String, System.Int32, System.Reflection.BindingFlags, System.Reflection.Binder, System.Reflection.CallingConventions, System.Type[], System.Reflection.ParameterModifier[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.GetMethod(System.String, System.Int32, System.Reflection.BindingFlags, System.Reflection.Binder, System.Type[], System.Reflection.ParameterModifier[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.GetMethod(System.String, System.Int32, System.Type[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.GetMethod(System.String, System.Int32, System.Type[], System.Reflection.ParameterModifier[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.GetMethodImpl(System.String, System.Int32, System.Reflection.BindingFlags, System.Reflection.Binder, System.Reflection.CallingConventions, System.Type[], System.Reflection.ParameterModifier[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.IsByRefLike.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.IsGenericMethodParameter.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.IsGenericTypeParameter.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.IsSignatureType.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.IsSZArray.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.IsTypeDefinition.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.IsVariableBoundArray.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Type.MakeGenericMethodParameter(System.Int32)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsByRefLikeAttribute' exists on 'System.TypedReference' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.TypedReference' is a 'struct' in the implementation but is a 'ref struct' in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.UInt16' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.UInt16' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.UInt16.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.UInt16.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.UInt16.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.UInt16)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.UInt16.TryParse(System.ReadOnlySpan, System.UInt16)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.UInt32' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.UInt32' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.UInt32.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.UInt32.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.UInt32.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.UInt32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.UInt32.TryParse(System.ReadOnlySpan, System.UInt32)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.UInt64' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.UInt64' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.UInt64.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.UInt64.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.UInt64.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.UInt64)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.UInt64.TryParse(System.ReadOnlySpan, System.UInt64)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.UIntPtr' in the contract but not the implementation. -CannotRemoveBaseTypeOrInterface : Type 'System.UIntPtr' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -TypeCannotChangeClassification : Type 'System.UIntPtr' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Version.Parse(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Version.TryFormat(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Version.TryFormat(System.Span, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Version.TryParse(System.ReadOnlySpan, System.Version)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.ArrayPool' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.BuffersExtensions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.IBufferWriter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.IMemoryOwner' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.IPinnable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.MemoryHandle' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.MemoryManager' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.MemoryPool' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.OperationStatus' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.ReadOnlySequence' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.ReadOnlySequenceSegment' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.ReadOnlySpanAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.SpanAction' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.StandardFormat' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.Binary.BinaryPrimitives' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.Text.Base64' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.Text.Utf8Formatter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Buffers.Text.Utf8Parser' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.CodeDom.Compiler.IndentedTextWriter' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Collections.BitArray.LeftShift(System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.BitArray.RightShift(System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.DictionaryEntry.Deconstruct(System.Object, System.Object)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Concurrent.ConcurrentBag.Clear()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Concurrent.ConcurrentQueue.Clear()' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Collections.Generic.CollectionExtensions' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Dictionary..ctor(System.Collections.Generic.IEnumerable>)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Dictionary..ctor(System.Collections.Generic.IEnumerable>, System.Collections.Generic.IEqualityComparer)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Dictionary.EnsureCapacity(System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Dictionary.Remove(TKey, TValue)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Dictionary.TrimExcess()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Dictionary.TrimExcess(System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Dictionary.TryAdd(TKey, TValue)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.HashSet.EnsureCapacity(System.Int32)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Collections.Generic.IAsyncEnumerable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Collections.Generic.IAsyncEnumerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Collections.Generic.KeyValuePair' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Collections.Generic.KeyValuePair' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Collections.Generic.KeyValuePair' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Collections.Generic.KeyValuePair.Deconstruct(TKey, TValue)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Queue.TryDequeue(T)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Queue.TryPeek(T)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Stack.TryPeek(T)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.Generic.Stack.TryPop(T)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Collections.ObjectModel.KeyedCollection.TryGetValue(TKey, TItem)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Collections.Specialized.BitVector32.Section' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Collections.Specialized.BitVector32.Section' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.ComponentModel.DefaultValueAttribute..ctor(System.SByte)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ComponentModel.DefaultValueAttribute..ctor(System.UInt16)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ComponentModel.DefaultValueAttribute..ctor(System.UInt32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.ComponentModel.DefaultValueAttribute..ctor(System.UInt64)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.ComponentModel.Design.Serialization.MemberRelationship' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.ComponentModel.Design.Serialization.MemberRelationship' is marked as readonly in the contract so it must also be marked readonly in the implementation. -TypesMustExist : Type 'System.Data.Common.DbProviderFactories' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Diagnostics.ProcessStartInfo.ArgumentList.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Diagnostics.ProcessStartInfo.StandardInputEncoding.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Diagnostics.ProcessStartInfo.StandardInputEncoding.set(System.Text.Encoding)' does not exist in the implementation but it does exist in the contract. -CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute' changed from '[AttributeUsageAttribute(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Struct, Inherited=false, AllowMultiple=false)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Struct, Inherited=false, AllowMultiple=false)]' in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Diagnostics.SymbolStore.SymbolToken' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Diagnostics.SymbolStore.SymbolToken' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveBaseTypeOrInterface : Type 'System.Diagnostics.Tracing.EventCounter' does not implement interface 'System.IDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Diagnostics.Tracing.EventCounter.Dispose()' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Diagnostics.Tracing.EventSourceCreatedEventArgs' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Drawing.Color' in the contract but not the implementation. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.Color' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -TypeCannotChangeClassification : Type 'System.Drawing.Color' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Drawing.Color.Equals(System.Drawing.Color)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.ColorConverter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.KnownColor' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.Point' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Drawing.Point.Equals(System.Drawing.Point)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.PointConverter' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.PointF' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Drawing.PointF.Equals(System.Drawing.PointF)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.Rectangle' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Drawing.Rectangle.Equals(System.Drawing.Rectangle)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.RectangleConverter' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.RectangleF' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Drawing.RectangleF.Equals(System.Drawing.RectangleF)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.Size' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Drawing.Size.Equals(System.Drawing.Size)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Drawing.Size.op_Division(System.Drawing.Size, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Drawing.Size.op_Division(System.Drawing.Size, System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Drawing.Size.op_Multiply(System.Drawing.Size, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Drawing.Size.op_Multiply(System.Drawing.Size, System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Drawing.Size.op_Multiply(System.Int32, System.Drawing.Size)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Drawing.Size.op_Multiply(System.Single, System.Drawing.Size)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.SizeConverter' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Drawing.SizeF' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Drawing.SizeF.Equals(System.Drawing.SizeF)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Drawing.SizeF.op_Division(System.Drawing.SizeF, System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Drawing.SizeF.op_Multiply(System.Drawing.SizeF, System.Single)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Drawing.SizeF.op_Multiply(System.Single, System.Drawing.SizeF)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Drawing.SizeFConverter' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Globalization.CharUnicodeInfo.GetUnicodeCategory(System.Int32)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Globalization.ISOWeek' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.BinaryReader.Read(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.BinaryReader.Read(System.Span)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.BinaryWriter' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.BinaryWriter.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.BinaryWriter.Write(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.BinaryWriter.Write(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.BufferedStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.BufferedStream.BufferSize.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.BufferedStream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.BufferedStream.UnderlyingStream.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Directory.EnumerateDirectories(System.String, System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Directory.EnumerateFiles(System.String, System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Directory.EnumerateFileSystemEntries(System.String, System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Directory.GetDirectories(System.String, System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Directory.GetFiles(System.String, System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Directory.GetFileSystemEntries(System.String, System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.EnumerateDirectories(System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.EnumerateFiles(System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.EnumerateFileSystemInfos(System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.GetDirectories(System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.GetFiles(System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.DirectoryInfo.GetFileSystemInfos(System.String, System.IO.EnumerationOptions)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.EnumerationOptions' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.AppendAllLinesAsync(System.String, System.Collections.Generic.IEnumerable, System.Text.Encoding, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.AppendAllLinesAsync(System.String, System.Collections.Generic.IEnumerable, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.AppendAllTextAsync(System.String, System.String, System.Text.Encoding, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.AppendAllTextAsync(System.String, System.String, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.ReadAllBytesAsync(System.String, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.ReadAllLinesAsync(System.String, System.Text.Encoding, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.ReadAllLinesAsync(System.String, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.ReadAllTextAsync(System.String, System.Text.Encoding, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.ReadAllTextAsync(System.String, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.WriteAllBytesAsync(System.String, System.Byte[], System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.WriteAllLinesAsync(System.String, System.Collections.Generic.IEnumerable, System.Text.Encoding, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.WriteAllLinesAsync(System.String, System.Collections.Generic.IEnumerable, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.WriteAllTextAsync(System.String, System.String, System.Text.Encoding, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.File.WriteAllTextAsync(System.String, System.String, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.FileStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -CannotMakeMemberNonVirtual : Member 'System.IO.FileStream.Name' is non-virtual in the implementation but is virtual in the contract. -MembersMustExist : Member 'System.IO.FileStream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -CannotMakeMemberNonVirtual : Member 'System.IO.FileStream.Name.get()' is non-virtual in the implementation but is virtual in the contract. -TypesMustExist : Type 'System.IO.MatchCasing' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.MatchType' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.MemoryStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.MemoryStream.Read(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.MemoryStream.ReadAsync(System.Memory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.MemoryStream.Write(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.MemoryStream.WriteAsync(System.ReadOnlyMemory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.GetDirectoryName(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.GetExtension(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.GetFileName(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.GetFileNameWithoutExtension(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.GetFullPath(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.GetPathRoot(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.GetRelativePath(System.String, System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.HasExtension(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.IsPathFullyQualified(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.IsPathFullyQualified(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.IsPathRooted(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.Join(System.ReadOnlySpan, System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.Join(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.TryJoin(System.ReadOnlySpan, System.ReadOnlySpan, System.ReadOnlySpan, System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Path.TryJoin(System.ReadOnlySpan, System.ReadOnlySpan, System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.Stream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -CannotMakeMemberNonVirtual : Member 'System.IO.Stream.CopyTo(System.IO.Stream, System.Int32)' is non-virtual in the implementation but is virtual in the contract. -MembersMustExist : Member 'System.IO.Stream.CopyToAsync(System.IO.Stream, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Stream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Stream.Read(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Stream.ReadAsync(System.Memory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Stream.Write(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Stream.WriteAsync(System.ReadOnlyMemory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StreamReader.Read(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StreamReader.ReadAsync(System.Memory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StreamReader.ReadBlock(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StreamReader.ReadBlockAsync(System.Memory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.StreamWriter' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.StreamWriter.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StreamWriter.Write(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StreamWriter.WriteAsync(System.ReadOnlyMemory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StreamWriter.WriteLine(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StreamWriter.WriteLineAsync(System.ReadOnlyMemory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StringReader.Read(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StringReader.ReadAsync(System.Memory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StringReader.ReadBlock(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StringReader.ReadBlockAsync(System.Memory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.StringWriter' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.StringWriter.Write(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StringWriter.WriteAsync(System.ReadOnlyMemory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StringWriter.WriteLine(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.StringWriter.WriteLineAsync(System.ReadOnlyMemory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.TextReader.Read(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.TextReader.ReadAsync(System.Memory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.TextReader.ReadBlock(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.TextReader.ReadBlockAsync(System.Memory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.TextWriter' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.TextWriter.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.TextWriter.Write(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.TextWriter.WriteAsync(System.ReadOnlyMemory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.TextWriter.WriteLine(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.TextWriter.WriteLineAsync(System.ReadOnlyMemory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.UnmanagedMemoryStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.UnmanagedMemoryStream.Read(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.UnmanagedMemoryStream.Write(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Compression.BrotliDecoder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Compression.BrotliEncoder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Compression.BrotliStream' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.Compression.DeflateStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.Compression.DeflateStream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.Compression.GZipStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.Compression.GZipStream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Compression.ZipArchiveEntry.Crc32.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Compression.ZipFile.ExtractToDirectory(System.String, System.String, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Compression.ZipFile.ExtractToDirectory(System.String, System.String, System.Text.Encoding, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.IO.Compression.ZipFileExtensions.ExtractToDirectory(System.IO.Compression.ZipArchive, System.String, System.Boolean)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Enumeration.FileSystemEntry' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Enumeration.FileSystemEnumerable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Enumeration.FileSystemEnumerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.IO.Enumeration.FileSystemName' does not exist in the implementation but it does exist in the contract. -CannotAddAbstractMembers : Member 'System.IO.IsolatedStorage.IsolatedStorage.GetPermission(System.Security.PermissionSet)' is abstract in the implementation but is missing in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.IsolatedStorage.IsolatedStorageFileStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.IsolatedStorage.IsolatedStorageFileStream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.MemoryMappedFiles.MemoryMappedViewStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.Pipes.AnonymousPipeClientStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.Pipes.AnonymousPipeServerStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.Pipes.NamedPipeClientStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.Pipes.NamedPipeServerStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.IO.Pipes.PipeOptions System.IO.Pipes.PipeOptions.CurrentUserOnly' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.IO.Pipes.PipeStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Linq.Enumerable.SkipLast(System.Collections.Generic.IEnumerable, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Linq.Enumerable.TakeLast(System.Collections.Generic.IEnumerable, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Linq.Queryable.Append(System.Linq.IQueryable, TSource)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Linq.Queryable.Prepend(System.Linq.IQueryable, TSource)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Linq.Queryable.SkipLast(System.Linq.IQueryable, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Linq.Queryable.TakeLast(System.Linq.IQueryable, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.AlreadyReported' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.EarlyHints' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.FailedDependency' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.IMUsed' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.InsufficientStorage' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.Locked' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.LoopDetected' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.MisdirectedRequest' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.MultiStatus' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.NetworkAuthenticationRequired' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.NotExtended' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.PermanentRedirect' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.PreconditionRequired' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.Processing' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.RequestHeaderFieldsTooLarge' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.TooManyRequests' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.UnavailableForLegalReasons' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.UnprocessableEntity' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.HttpStatusCode System.Net.HttpStatusCode.VariantAlsoNegotiates' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Version System.Net.HttpVersion.Unknown' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Version System.Net.HttpVersion.Version20' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.IPAddress..ctor(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.IPAddress..ctor(System.ReadOnlySpan, System.Int64)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.IPAddress.Parse(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.IPAddress.TryFormat(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.IPAddress.TryParse(System.ReadOnlySpan, System.Net.IPAddress)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.IPAddress.TryWriteBytes(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Http.HttpClient.PatchAsync(System.String, System.Net.Http.HttpContent)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Http.HttpClient.PatchAsync(System.String, System.Net.Http.HttpContent, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Http.HttpClient.PatchAsync(System.Uri, System.Net.Http.HttpContent)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Http.HttpClient.PatchAsync(System.Uri, System.Net.Http.HttpContent, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Http.HttpMethod.Patch.get()' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Http.ReadOnlyMemoryContent' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String System.Net.Mime.MediaTypeNames.Application.Json' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.String System.Net.Mime.MediaTypeNames.Application.Xml' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Security.AuthenticatedStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Net.Security.AuthenticatedStream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Security.NegotiateStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Net.Security.NegotiateStream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Security.ServerCertificateSelectionCallback' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Security.SslApplicationProtocol' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Security.SslClientAuthenticationOptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Security.SslServerAuthenticationOptions' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Security.SslStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Net.Security.SslStream.AuthenticateAsClientAsync(System.Net.Security.SslClientAuthenticationOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Security.SslStream.AuthenticateAsServerAsync(System.Net.Security.SslServerAuthenticationOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Security.SslStream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Security.SslStream.NegotiatedApplicationProtocol.get()' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Net.Sockets.NetworkStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Net.Sockets.Socket.Receive(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.Socket.Receive(System.Span, System.Net.Sockets.SocketFlags)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.Socket.Receive(System.Span, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.Socket.Send(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.Socket.Send(System.ReadOnlySpan, System.Net.Sockets.SocketFlags)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.Socket.Send(System.ReadOnlySpan, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.SocketAsyncEventArgs.MemoryBuffer.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.SocketAsyncEventArgs.SetBuffer(System.Memory)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.SocketTaskExtensions.ReceiveAsync(System.Net.Sockets.Socket, System.Memory, System.Net.Sockets.SocketFlags, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.Sockets.SocketTaskExtensions.SendAsync(System.Net.Sockets.Socket, System.ReadOnlyMemory, System.Net.Sockets.SocketFlags, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.Sockets.UnixDomainSocketEndPoint' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.WebSockets.ClientWebSocketOptions.RemoteCertificateValidationCallback.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.WebSockets.ClientWebSocketOptions.RemoteCertificateValidationCallback.set(System.Net.Security.RemoteCertificateValidationCallback)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Net.WebSockets.ValueWebSocketReceiveResult' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.WebSockets.WebSocket.CreateFromStream(System.IO.Stream, System.Boolean, System.String, System.TimeSpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.WebSockets.WebSocket.ReceiveAsync(System.Memory, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Net.WebSockets.WebSocket.SendAsync(System.ReadOnlyMemory, System.Net.WebSockets.WebSocketMessageType, System.Boolean, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Numerics.BigInteger' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Numerics.BigInteger' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Numerics.BigInteger..ctor(System.ReadOnlySpan, System.Boolean, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Numerics.BigInteger.GetByteCount(System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Numerics.BigInteger.Parse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Numerics.BigInteger.ToByteArray(System.Boolean, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Numerics.BigInteger.TryFormat(System.Span, System.Int32, System.ReadOnlySpan, System.IFormatProvider)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Numerics.BigInteger.TryParse(System.ReadOnlySpan, System.Globalization.NumberStyles, System.IFormatProvider, System.Numerics.BigInteger)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Numerics.BigInteger.TryParse(System.ReadOnlySpan, System.Numerics.BigInteger)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Numerics.BigInteger.TryWriteBytes(System.Span, System.Int32, System.Boolean, System.Boolean)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Numerics.Matrix3x2' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Numerics.Matrix4x4' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Numerics.Plane' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Numerics.Quaternion' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Numerics.Vector' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Numerics.Vector' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Numerics.Vector2' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Numerics.Vector3' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Numerics.Vector4' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.Assembly.GetForwardedTypes()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.BindingFlags System.Reflection.BindingFlags.DoNotWrapExceptions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.DispatchProxy' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.MemberInfo.HasSameMetadataDefinitionAs(System.Reflection.MemberInfo)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.MethodBase.IsConstructedGenericMethod.get()' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Reflection.ParameterModifier' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Reflection.ParameterModifier' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Reflection.TypeDelegator.IsByRefLike.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.TypeDelegator.IsGenericMethodParameter.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.TypeDelegator.IsGenericTypeParameter.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.TypeDelegator.IsSZArray.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.TypeDelegator.IsTypeDefinition.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Reflection.TypeDelegator.IsVariableBoundArray.get()' does not exist in the implementation but it does exist in the contract. -CannotSealType : Type 'System.Reflection.TypeInfo' is effectively (has a private constructor) sealed in the implementation but not sealed in the contract. -MembersMustExist : Member 'System.Reflection.TypeInfo..ctor()' does not exist in the implementation but it does exist in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredConstructors' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredEvents' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredFields' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredMembers' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredMethods' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredNestedTypes' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredProperties' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.GenericTypeParameters' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.ImplementedInterfaces' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.AsType()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredConstructors.get()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredEvents.get()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredFields.get()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredMembers.get()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredMethods.get()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredNestedTypes.get()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.DeclaredProperties.get()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.GenericTypeParameters.get()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.GetDeclaredEvent(System.String)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.GetDeclaredField(System.String)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.GetDeclaredMethod(System.String)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.GetDeclaredMethods(System.String)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.GetDeclaredNestedType(System.String)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.GetDeclaredProperty(System.String)' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.ImplementedInterfaces.get()' is non-virtual in the implementation but is virtual in the contract. -CannotMakeMemberNonVirtual : Member 'System.Reflection.TypeInfo.IsAssignableFrom(System.Reflection.TypeInfo)' is non-virtual in the implementation but is virtual in the contract. -TypesMustExist : Type 'System.Reflection.Emit.AssemblyBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.AssemblyBuilderAccess' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.ConstructorBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.CustomAttributeBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.DynamicILInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.DynamicMethod' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.EnumBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.EventBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.EventToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.ExceptionHandler' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.FieldBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.FieldToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.GenericTypeParameterBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.ILGenerator' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.Label' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.LocalBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.MethodBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.MethodToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.ModuleBuilder' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Reflection.Emit.OpCode' in the contract but not the implementation. -CannotRemoveBaseTypeOrInterface : Type 'System.Reflection.Emit.OpCode' does not implement interface 'System.IEquatable' in the implementation but it does in the contract. -TypeCannotChangeClassification : Type 'System.Reflection.Emit.OpCode' is marked as readonly in the contract so it must also be marked readonly in the implementation. -TypesMustExist : Type 'System.Reflection.Emit.ParameterBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.ParameterToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.PropertyBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.PropertyToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.SignatureHelper' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.SignatureToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.StringToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.TypeBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Reflection.Emit.TypeToken' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.AsyncIteratorMethodBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.AsyncIteratorStateMachineAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.AsyncMethodBuilderAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Runtime.CompilerServices.ConditionalWeakTable' does not implement interface 'System.Collections.Generic.IEnumerable>' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Runtime.CompilerServices.ConditionalWeakTable.AddOrUpdate(TKey, TValue)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.CompilerServices.ConditionalWeakTable.Clear()' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.ConfiguredAsyncDisposable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.CompilerServices.ConfiguredTaskAwaitable' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.CompilerServices.ConfiguredTaskAwaitable' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.CompilerServices.ConfiguredTaskAwaitable' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.CompilerServices.ConfiguredTaskAwaitable' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter' is marked as readonly in the contract so it must also be marked readonly in the implementation. -TypesMustExist : Type 'System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.IsByRefLikeAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.IsReadOnlyAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.ITuple' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.RuntimeFeature' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray(T[], System.Range)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject(System.Type)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.CompilerServices.RuntimeHelpers.TryEnsureSufficientExecutionStack()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.CompilerServices.RuntimeWrappedException..ctor(System.Object)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.SwitchExpressionException' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.CompilerServices.TaskAwaiter' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.CompilerServices.TaskAwaiter' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.CompilerServices.TaskAwaiter' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.CompilerServices.TaskAwaiter' is marked as readonly in the contract so it must also be marked readonly in the implementation. -TypesMustExist : Type 'System.Runtime.CompilerServices.ValueTaskAwaiter' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.CompilerServices.ValueTaskAwaiter' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.CompilerServices.YieldAwaitable' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.CompilerServices.YieldAwaitable' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw(System.Exception)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.AutomationProxyAttribute' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.InteropServices.HandleRef' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.InteropServices.HandleRef' is marked as readonly in the contract so it must also be marked readonly in the implementation. -TypesMustExist : Type 'System.Runtime.InteropServices.ImportedFromTypeLibAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.ManagedToNativeComInteropStubAttribute' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.PtrToStringUTF8(System.IntPtr)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.PtrToStringUTF8(System.IntPtr, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.StringToCoTaskMemUTF8(System.String)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Runtime.InteropServices.Marshal.ZeroFreeCoTaskMemUTF8(System.IntPtr)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.MemoryMarshal' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.InteropServices.OSPlatform' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.InteropServices.OSPlatform' is marked as readonly in the contract so it must also be marked readonly in the implementation. -TypesMustExist : Type 'System.Runtime.InteropServices.SequenceMarshal' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibFuncAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibFuncFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibImportClassAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibTypeAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibTypeFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibVarAttribute' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibVarFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Runtime.InteropServices.TypeLibVersionAttribute' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.Serialization.SerializationEntry' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.Serialization.SerializationEntry' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Runtime.Serialization.StreamingContext' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Runtime.Serialization.StreamingContext' is marked as readonly in the contract so it must also be marked readonly in the implementation. -TypesMustExist : Type 'System.Runtime.Serialization.Formatters.IFieldInfo' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.CryptographicOperations' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Security.Cryptography.CryptoStream' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Security.Cryptography.CryptoStream.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.DSA.TryCreateSignature(System.ReadOnlySpan, System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.DSA.TryHashData(System.ReadOnlySpan, System.Span, System.Security.Cryptography.HashAlgorithmName, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.DSA.TrySignData(System.ReadOnlySpan, System.Span, System.Security.Cryptography.HashAlgorithmName, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.DSA.VerifyData(System.ReadOnlySpan, System.ReadOnlySpan, System.Security.Cryptography.HashAlgorithmName)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.DSA.VerifySignature(System.ReadOnlySpan, System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.ECDiffieHellman' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.ECDsa.TryHashData(System.ReadOnlySpan, System.Span, System.Security.Cryptography.HashAlgorithmName, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.ECDsa.TrySignData(System.ReadOnlySpan, System.Span, System.Security.Cryptography.HashAlgorithmName, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.ECDsa.TrySignHash(System.ReadOnlySpan, System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.ECDsa.VerifyData(System.ReadOnlySpan, System.ReadOnlySpan, System.Security.Cryptography.HashAlgorithmName)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.ECDsa.VerifyHash(System.ReadOnlySpan, System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HashAlgorithm.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HashAlgorithm.TryComputeHash(System.ReadOnlySpan, System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HashAlgorithm.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Security.Cryptography.HashAlgorithmName' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Security.Cryptography.HashAlgorithmName' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Security.Cryptography.HMAC.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMAC.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACMD5.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACMD5.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACSHA1.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACSHA1.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACSHA256.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACSHA256.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACSHA384.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACSHA384.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACSHA512.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.HMACSHA512.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.IncrementalHash.AppendData(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.IncrementalHash.TryGetHashAndReset(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RandomNumberGenerator.Fill(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RandomNumberGenerator.GetBytes(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RandomNumberGenerator.GetInt32(System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RandomNumberGenerator.GetInt32(System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RandomNumberGenerator.GetNonZeroBytes(System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.Rfc2898DeriveBytes.HashAlgorithm.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RSA.TryDecrypt(System.ReadOnlySpan, System.Span, System.Security.Cryptography.RSAEncryptionPadding, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RSA.TryEncrypt(System.ReadOnlySpan, System.Span, System.Security.Cryptography.RSAEncryptionPadding, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RSA.TryHashData(System.ReadOnlySpan, System.Span, System.Security.Cryptography.HashAlgorithmName, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RSA.TrySignData(System.ReadOnlySpan, System.Span, System.Security.Cryptography.HashAlgorithmName, System.Security.Cryptography.RSASignaturePadding, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RSA.TrySignHash(System.ReadOnlySpan, System.Span, System.Security.Cryptography.HashAlgorithmName, System.Security.Cryptography.RSASignaturePadding, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RSA.VerifyData(System.ReadOnlySpan, System.ReadOnlySpan, System.Security.Cryptography.HashAlgorithmName, System.Security.Cryptography.RSASignaturePadding)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.RSA.VerifyHash(System.ReadOnlySpan, System.ReadOnlySpan, System.Security.Cryptography.HashAlgorithmName, System.Security.Cryptography.RSASignaturePadding)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.SHA1Managed.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.SHA1Managed.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.SHA256Managed.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.SHA256Managed.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.SHA384Managed.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.SHA384Managed.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.SHA512Managed.HashCore(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.SHA512Managed.TryHashFinal(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.X509Certificates.CertificateRequest' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.X509Certificates.DSACertificateExtensions' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.X509Certificates.SubjectAlternativeNameBuilder' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.X509Certificates.X509Certificate.GetCertHash(System.Security.Cryptography.HashAlgorithmName)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.X509Certificates.X509Certificate.GetCertHashString(System.Security.Cryptography.HashAlgorithmName)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.X509Certificates.X509Certificate.TryGetCertHash(System.Security.Cryptography.HashAlgorithmName, System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Security.Cryptography.X509Certificates.X509SignatureGenerator' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.X509Certificates.X509Store..ctor(System.Security.Cryptography.X509Certificates.StoreName, System.Security.Cryptography.X509Certificates.StoreLocation, System.Security.Cryptography.X509Certificates.OpenFlags)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.X509Certificates.X509Store..ctor(System.String, System.Security.Cryptography.X509Certificates.StoreLocation, System.Security.Cryptography.X509Certificates.OpenFlags)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Security.Cryptography.X509Certificates.X509Store.IsOpen.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Decoder.Convert(System.ReadOnlySpan, System.Span, System.Boolean, System.Int32, System.Int32, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Decoder.GetCharCount(System.ReadOnlySpan, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Decoder.GetChars(System.ReadOnlySpan, System.Span, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoder.Convert(System.ReadOnlySpan, System.Span, System.Boolean, System.Int32, System.Int32, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoder.GetByteCount(System.ReadOnlySpan, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoder.GetBytes(System.ReadOnlySpan, System.Span, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoding.GetByteCount(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoding.GetByteCount(System.String, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoding.GetBytes(System.ReadOnlySpan, System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoding.GetBytes(System.String, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoding.GetCharCount(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoding.GetChars(System.ReadOnlySpan, System.Span)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoding.GetString(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.Encoding.Preamble.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.Append(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.Append(System.Text.StringBuilder)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.Append(System.Text.StringBuilder, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.AppendJoin(System.Char, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.AppendJoin(System.Char, System.String[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.AppendJoin(System.String, System.Object[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.AppendJoin(System.String, System.String[])' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.AppendJoin(System.Char, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.AppendJoin(System.String, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.CopyTo(System.Int32, System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.Equals(System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Text.StringBuilder.Insert(System.Int32, System.ReadOnlySpan)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Text.RegularExpressions.CaptureCollection' does not implement interface 'System.Collections.Generic.ICollection' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Text.RegularExpressions.CaptureCollection.CopyTo(System.Text.RegularExpressions.Capture[], System.Int32)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Text.RegularExpressions.GroupCollection' does not implement interface 'System.Collections.Generic.ICollection' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Text.RegularExpressions.GroupCollection.CopyTo(System.Text.RegularExpressions.Group[], System.Int32)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Text.RegularExpressions.MatchCollection' does not implement interface 'System.Collections.Generic.ICollection' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Text.RegularExpressions.MatchCollection.CopyTo(System.Text.RegularExpressions.Match[], System.Int32)' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Threading.AsyncLocalValueChangedArgs' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Threading.AsyncLocalValueChangedArgs' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Threading.CancellationToken' in the contract but not the implementation. -TypeCannotChangeClassification : Type 'System.Threading.CancellationToken' is marked as readonly in the contract so it must also be marked readonly in the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'System.Threading.CancellationTokenRegistration' in the contract but not the implementation. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.CancellationTokenRegistration' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -TypeCannotChangeClassification : Type 'System.Threading.CancellationTokenRegistration' is marked as readonly in the contract so it must also be marked readonly in the implementation. -MembersMustExist : Member 'System.Threading.CancellationTokenRegistration.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.CancellationTokenRegistration.Token.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Interlocked.MemoryBarrierProcessWide()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.LazyInitializer.EnsureInitialized(T, System.Object, System.Func)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Thread.GetCurrentProcessorId()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.ThreadPool.QueueUserWorkItem(System.Action, TState, System.Boolean)' does not exist in the implementation but it does exist in the contract. -CannotRemoveBaseTypeOrInterface : Type 'System.Threading.Timer' does not implement interface 'System.IAsyncDisposable' in the implementation but it does in the contract. -MembersMustExist : Member 'System.Threading.Timer.DisposeAsync()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Tasks.Task.IsCompletedSuccessfully.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Tasks.TaskCanceledException..ctor(System.String, System.Exception, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Tasks.TaskExtensions.ConfigureAwait(System.IAsyncDisposable, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Tasks.TaskExtensions.ConfigureAwait(System.Collections.Generic.IAsyncEnumerable, System.Boolean)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Threading.Tasks.TaskExtensions.WithCancellation(System.Collections.Generic.IAsyncEnumerable, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Threading.Tasks.ValueTask' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Threading.Tasks.ValueTask' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Threading.Tasks.Sources.IValueTaskSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Threading.Tasks.Sources.IValueTaskSource' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Threading.Tasks.Sources.ValueTaskSourceStatus' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XCData.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XComment.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XDocument.LoadAsync(System.IO.Stream, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XDocument.LoadAsync(System.IO.TextReader, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XDocument.LoadAsync(System.Xml.XmlReader, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XDocument.SaveAsync(System.IO.Stream, System.Xml.Linq.SaveOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XDocument.SaveAsync(System.IO.TextWriter, System.Xml.Linq.SaveOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XDocument.SaveAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XDocument.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XDocumentType.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XElement.LoadAsync(System.IO.Stream, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XElement.LoadAsync(System.IO.TextReader, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XElement.LoadAsync(System.Xml.XmlReader, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XElement.SaveAsync(System.IO.Stream, System.Xml.Linq.SaveOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XElement.SaveAsync(System.IO.TextWriter, System.Xml.Linq.SaveOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XElement.SaveAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XElement.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XNode.ReadFromAsync(System.Xml.XmlReader, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XNode.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XProcessingInstruction.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'System.Xml.Linq.XText.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'System.Xml.Serialization.SchemaImporter' does not exist in the implementation but it does exist in the contract. -CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.Xml.Serialization.XmlAnyAttributeAttribute' changed from '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple=false)]' in the implementation. -CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.Xml.Serialization.XmlNamespaceDeclarationsAttribute' changed from '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple=false)]' in the implementation. -Total Issues: 868 From 9e2a8a6042f82fd73eb4e5f0dc0e68a99ed8e7fa Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 25 Jan 2022 09:30:24 -0500 Subject: [PATCH 194/308] Improve Regex handling of anchors (#64177) * Improve Regex handling of anchors - Extend search for leading anchor to support alternations. This means that an expression like `^abc|^def` will now observe the leading `^` whereas previously it didn't. - Add a FindFirstChar optimization that jumps to the right position for a pattern that matches a computeable max length and ends with an end anchor. * Address PR feedback --- .../gen/RegexGenerator.Emitter.cs | 153 ++++++---- .../System/Text/RegularExpressions/Match.cs | 3 - .../Text/RegularExpressions/RegexCode.cs | 2 +- .../Text/RegularExpressions/RegexCompiler.cs | 261 ++++++++++-------- .../RegexFindOptimizations.cs | 78 +++++- .../Text/RegularExpressions/RegexNode.cs | 178 ++++++++++-- .../Text/RegularExpressions/RegexNodeKind.cs | 10 +- .../RegularExpressions/RegexPrefixAnalyzer.cs | 163 ++++++----- .../tests/Regex.Match.Tests.cs | 38 ++- .../tests/RegexReductionTests.cs | 158 +++++++---- 10 files changed, 700 insertions(+), 344 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index fabe62f5262ec..820490c500298 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -392,68 +392,111 @@ private static RequiredHelperFunctions EmitFindFirstChar(IndentedTextWriter writ // searching is required; otherwise, false. bool EmitAnchors() { - // Generate anchor checks. - if ((code.FindOptimizations.LeadingAnchor & (RegexPrefixAnalyzer.Beginning | RegexPrefixAnalyzer.Start | RegexPrefixAnalyzer.EndZ | RegexPrefixAnalyzer.End | RegexPrefixAnalyzer.Bol)) != 0) + // Anchors that fully implement FindFirstChar, with a check that leads to immediate success or failure determination. + switch (code.FindOptimizations.FindMode) { - switch (code.FindOptimizations.LeadingAnchor) - { - case RegexPrefixAnalyzer.Beginning: - writer.WriteLine("// Beginning \\A anchor"); - additionalDeclarations.Add("int beginning = base.runtextbeg;"); - using (EmitBlock(writer, "if (pos > beginning)")) - { - writer.WriteLine($"goto {NoStartingPositionFound};"); - } - writer.WriteLine("return true;"); - return true; + case FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Beginning: + writer.WriteLine("// Beginning \\A anchor"); + additionalDeclarations.Add("int beginning = base.runtextbeg;"); + using (EmitBlock(writer, "if (pos > beginning)")) + { + writer.WriteLine($"goto {NoStartingPositionFound};"); + } + writer.WriteLine("return true;"); + return true; + + case FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Start: + writer.WriteLine("// Start \\G anchor"); + using (EmitBlock(writer, "if (pos > base.runtextstart)")) + { + writer.WriteLine($"goto {NoStartingPositionFound};"); + } + writer.WriteLine("return true;"); + return true; + + case FindNextStartingPositionMode.LeadingAnchor_LeftToRight_EndZ: + writer.WriteLine("// Leading end \\Z anchor"); + using (EmitBlock(writer, "if (pos < end - 1)")) + { + writer.WriteLine("base.runtextpos = end - 1;"); + } + writer.WriteLine("return true;"); + return true; + + case FindNextStartingPositionMode.LeadingAnchor_LeftToRight_End: + writer.WriteLine("// Leading end \\z anchor"); + using (EmitBlock(writer, "if (pos < end)")) + { + writer.WriteLine("base.runtextpos = end;"); + } + writer.WriteLine("return true;"); + return true; - case RegexPrefixAnalyzer.Start: - writer.WriteLine("// Start \\G anchor"); - using (EmitBlock(writer, "if (pos > base.runtextstart)")) + case FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_EndZ: + // Jump to the end, minus the min required length, which in this case is actually the fixed length, minus 1 (for a possible ending \n). + writer.WriteLine("// Trailing end \\Z anchor with fixed-length match"); + using (EmitBlock(writer, $"if (pos < end - {code.Tree.MinRequiredLength + 1})")) + { + writer.WriteLine($"base.runtextpos = end - {code.Tree.MinRequiredLength + 1};"); + } + writer.WriteLine("return true;"); + return true; + + case FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_End: + // Jump to the end, minus the min required length, which in this case is actually the fixed length. + writer.WriteLine("// Trailing end \\z anchor with fixed-length match"); + using (EmitBlock(writer, $"if (pos < end - {code.Tree.MinRequiredLength})")) + { + writer.WriteLine($"base.runtextpos = end - {code.Tree.MinRequiredLength};"); + } + writer.WriteLine("return true;"); + return true; + } + + // Now handle anchors that boost the position but may not determine immediate success or failure. + + switch (code.FindOptimizations.LeadingAnchor) + { + case RegexNodeKind.Bol: + // Optimize the handling of a Beginning-Of-Line (BOL) anchor. BOL is special, in that unlike + // other anchors like Beginning, there are potentially multiple places a BOL can match. So unlike + // the other anchors, which all skip all subsequent processing if found, with BOL we just use it + // to boost our position to the next line, and then continue normally with any searches. + writer.WriteLine("// Beginning-of-line anchor"); + additionalDeclarations.Add("global::System.ReadOnlySpan inputSpan = base.runtext;"); + additionalDeclarations.Add("int beginning = base.runtextbeg;"); + using (EmitBlock(writer, "if (pos > beginning && inputSpan[pos - 1] != '\\n')")) + { + writer.WriteLine("int newlinePos = global::System.MemoryExtensions.IndexOf(inputSpan.Slice(pos), '\\n');"); + using (EmitBlock(writer, "if (newlinePos < 0 || newlinePos + pos + 1 > end)")) { writer.WriteLine($"goto {NoStartingPositionFound};"); } - writer.WriteLine("return true;"); - return true; + writer.WriteLine("pos = newlinePos + pos + 1;"); + } + writer.WriteLine(); + break; + } - case RegexPrefixAnalyzer.EndZ: - writer.WriteLine("// End \\Z anchor"); - using (EmitBlock(writer, "if (pos < end - 1)")) - { - writer.WriteLine("base.runtextpos = end - 1;"); - } - writer.WriteLine("return true;"); - return true; + switch (code.FindOptimizations.TrailingAnchor) + { + case RegexNodeKind.End when code.FindOptimizations.MaxPossibleLength is int maxLength: + writer.WriteLine("// End \\z anchor with maximum-length match"); + using (EmitBlock(writer, $"if (pos < end - {maxLength})")) + { + writer.WriteLine($"pos = end - {maxLength};"); + } + writer.WriteLine(); + break; - case RegexPrefixAnalyzer.End: - writer.WriteLine("// End \\z anchor"); - using (EmitBlock(writer, "if (pos < end)")) - { - writer.WriteLine("base.runtextpos = end;"); - } - writer.WriteLine("return true;"); - return true; - - case RegexPrefixAnalyzer.Bol: - // Optimize the handling of a Beginning-Of-Line (BOL) anchor. BOL is special, in that unlike - // other anchors like Beginning, there are potentially multiple places a BOL can match. So unlike - // the other anchors, which all skip all subsequent processing if found, with BOL we just use it - // to boost our position to the next line, and then continue normally with any searches. - writer.WriteLine("// Beginning-of-line anchor"); - additionalDeclarations.Add("global::System.ReadOnlySpan inputSpan = base.runtext;"); - additionalDeclarations.Add("int beginning = base.runtextbeg;"); - using (EmitBlock(writer, "if (pos > beginning && inputSpan[pos - 1] != '\\n')")) - { - writer.WriteLine("int newlinePos = global::System.MemoryExtensions.IndexOf(inputSpan.Slice(pos), '\\n');"); - using (EmitBlock(writer, "if (newlinePos < 0 || newlinePos + pos + 1 > end)")) - { - writer.WriteLine($"goto {NoStartingPositionFound};"); - } - writer.WriteLine("pos = newlinePos + pos + 1;"); - } - writer.WriteLine(); - break; - } + case RegexNodeKind.EndZ when code.FindOptimizations.MaxPossibleLength is int maxLength: + writer.WriteLine("// End \\Z anchor with maximum-length match"); + using (EmitBlock(writer, $"if (pos < end - {maxLength + 1})")) + { + writer.WriteLine($"pos = end - {maxLength + 1};"); + } + writer.WriteLine(); + break; } return false; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Match.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Match.cs index b7f2f032e78a8..b941d1ad8d7a2 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Match.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Match.cs @@ -61,9 +61,6 @@ internal Match(Regex? regex, int capcount, string text, int begpos, int len, int _textend = begpos + len; _textstart = startpos; _balancing = false; - - Debug.Assert(!(_textbeg < 0 || _textstart < _textbeg || _textend < _textstart || Text.Length < _textend), - "The parameters are out of range."); } /// Returns an empty Match object. diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs index d51ca826fd71c..76caec6647ad2 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs @@ -401,7 +401,7 @@ public override string ToString() var sb = new StringBuilder(); sb.AppendLine($"Direction: {(RightToLeft ? "right-to-left" : "left-to-right")}"); - sb.AppendLine($"Anchor: {RegexPrefixAnalyzer.AnchorDescription(FindOptimizations.LeadingAnchor)}"); + sb.AppendLine($"Anchor: {FindOptimizations.LeadingAnchor}"); sb.AppendLine(); for (int i = 0; i < Codes.Length; i += OpcodeSize(Codes[i])) { diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs index 2145a5dec334d..1c03616ef3793 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs @@ -465,134 +465,173 @@ FindNextStartingPositionMode.FixedSets_LeftToRight_CaseInsensitive or // searching is required; otherwise, false. bool GenerateAnchors() { - // Generate anchor checks. - if ((_code.FindOptimizations.LeadingAnchor & (RegexPrefixAnalyzer.Beginning | RegexPrefixAnalyzer.Start | RegexPrefixAnalyzer.EndZ | RegexPrefixAnalyzer.End | RegexPrefixAnalyzer.Bol)) != 0) + Label label; + + // Anchors that fully implement FindFirstChar, with a check that leads to immediate success or failure determination. + switch (_code.FindOptimizations.FindMode) { - switch (_code.FindOptimizations.LeadingAnchor) - { - case RegexPrefixAnalyzer.Beginning: - { - Label l1 = DefineLabel(); - Ldloc(pos); - Ldthisfld(s_runtextbegField); - Ble(l1); - Br(returnFalse); - MarkLabel(l1); - } + case FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Beginning: + label = DefineLabel(); + Ldloc(pos); + Ldthisfld(s_runtextbegField); + Ble(label); + Br(returnFalse); + MarkLabel(label); + Ldc(1); + Ret(); + return true; + + case FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Start: + label = DefineLabel(); + Ldloc(pos); + Ldthisfld(s_runtextstartField); + Ble(label); + Br(returnFalse); + MarkLabel(label); + Ldc(1); + Ret(); + return true; + + case FindNextStartingPositionMode.LeadingAnchor_LeftToRight_EndZ: + label = DefineLabel(); + Ldloc(pos); + Ldloc(end); + Ldc(1); + Sub(); + Bge(label); + Ldthis(); + Ldloc(end); + Ldc(1); + Sub(); + Stfld(s_runtextposField); + MarkLabel(label); + Ldc(1); + Ret(); + return true; + + case FindNextStartingPositionMode.LeadingAnchor_LeftToRight_End: + label = DefineLabel(); + Ldloc(pos); + Ldloc(end); + Bge(label); + Ldthis(); + Ldloc(end); + Stfld(s_runtextposField); + MarkLabel(label); + Ldc(1); + Ret(); + return true; + + case FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_End: + case FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_EndZ: + // Jump to the end, minus the min required length, which in this case is actually the fixed length. + { + int extraNewlineBump = _code.FindOptimizations.FindMode == FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_EndZ ? 1 : 0; + label = DefineLabel(); + Ldloc(pos); + Ldloc(end); + Ldc(_code.Tree.MinRequiredLength + extraNewlineBump); + Sub(); + Bge(label); + Ldthis(); + Ldloc(end); + Ldc(_code.Tree.MinRequiredLength + extraNewlineBump); + Sub(); + Stfld(s_runtextposField); + MarkLabel(label); Ldc(1); Ret(); return true; + } + } - case RegexPrefixAnalyzer.Start: - { - Label l1 = DefineLabel(); - Ldloc(pos); - Ldthisfld(s_runtextstartField); - Ble(l1); - Br(returnFalse); - MarkLabel(l1); - } + // Now handle anchors that boost the position but don't determine immediate success or failure. + + switch (_code.FindOptimizations.LeadingAnchor) + { + case RegexNodeKind.Bol: + { + // Optimize the handling of a Beginning-Of-Line (BOL) anchor. BOL is special, in that unlike + // other anchors like Beginning, there are potentially multiple places a BOL can match. So unlike + // the other anchors, which all skip all subsequent processing if found, with BOL we just use it + // to boost our position to the next line, and then continue normally with any prefix or char class searches. + + label = DefineLabel(); + + // if (pos > runtextbeg... + Ldloc(pos!); + Ldthisfld(s_runtextbegField); + Ble(label); + + // ... && inputSpan[pos - 1] != '\n') { ... } + Ldloca(inputSpan); + Ldloc(pos); Ldc(1); - Ret(); - return true; + Sub(); + Call(s_spanGetItemMethod); + LdindU2(); + Ldc('\n'); + Beq(label); - case RegexPrefixAnalyzer.EndZ: + // int tmp = inputSpan.Slice(pos).IndexOf('\n'); + Ldloca(inputSpan); + Ldloc(pos); + Call(s_spanSliceIntMethod); + Ldc('\n'); + Call(s_spanIndexOfChar); + using (RentedLocalBuilder newlinePos = RentInt32Local()) { - Label l1 = DefineLabel(); + Stloc(newlinePos); + + // if (newlinePos < 0 || newlinePos + pos + 1 > end) + // { + // base.runtextpos = end; + // return false; + // } + Ldloc(newlinePos); + Ldc(0); + Blt(returnFalse); + Ldloc(newlinePos); Ldloc(pos); - Ldloc(end); + Add(); Ldc(1); - Sub(); - Bge(l1); - Ldthis(); + Add(); Ldloc(end); - Ldc(1); - Sub(); - Stfld(s_runtextposField); - MarkLabel(l1); - } - Ldc(1); - Ret(); - return true; + Bgt(returnFalse); - case RegexPrefixAnalyzer.End: - { - Label l1 = DefineLabel(); + // pos += newlinePos + 1; Ldloc(pos); - Ldloc(end); - Bge(l1); - Ldthis(); - Ldloc(end); - Stfld(s_runtextposField); - MarkLabel(l1); + Ldloc(newlinePos); + Add(); + Ldc(1); + Add(); + Stloc(pos); } - Ldc(1); - Ret(); - return true; - - case RegexPrefixAnalyzer.Bol: - { - // Optimize the handling of a Beginning-Of-Line (BOL) anchor. BOL is special, in that unlike - // other anchors like Beginning, there are potentially multiple places a BOL can match. So unlike - // the other anchors, which all skip all subsequent processing if found, with BOL we just use it - // to boost our position to the next line, and then continue normally with any prefix or char class searches. - Label atBeginningOfLine = DefineLabel(); - - // if (pos > runtextbeg... - Ldloc(pos!); - Ldthisfld(s_runtextbegField); - Ble(atBeginningOfLine); + MarkLabel(label); + } + break; + } - // ... && inputSpan[pos - 1] != '\n') { ... } - Ldloca(inputSpan); - Ldloc(pos); - Ldc(1); - Sub(); - Call(s_spanGetItemMethod); - LdindU2(); - Ldc('\n'); - Beq(atBeginningOfLine); - - // int tmp = inputSpan.Slice(pos).IndexOf('\n'); - Ldloca(inputSpan); - Ldloc(pos); - Call(s_spanSliceIntMethod); - Ldc('\n'); - Call(s_spanIndexOfChar); - using (RentedLocalBuilder newlinePos = RentInt32Local()) - { - Stloc(newlinePos); - - // if (newlinePos < 0 || newlinePos + pos + 1 > end) - // { - // base.runtextpos = end; - // return false; - // } - Ldloc(newlinePos); - Ldc(0); - Blt(returnFalse); - Ldloc(newlinePos); - Ldloc(pos); - Add(); - Ldc(1); - Add(); - Ldloc(end); - Bgt(returnFalse); - - // pos += newlinePos + 1; - Ldloc(pos); - Ldloc(newlinePos); - Add(); - Ldc(1); - Add(); - Stloc(pos); - } - - MarkLabel(atBeginningOfLine); - } + switch (_code.FindOptimizations.TrailingAnchor) + { + case RegexNodeKind.End or RegexNodeKind.EndZ when _code.FindOptimizations.MaxPossibleLength is int maxLength: + // Jump to the end, minus the max allowed length. + { + int extraNewlineBump = _code.FindOptimizations.FindMode == FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_EndZ ? 1 : 0; + label = DefineLabel(); + Ldloc(pos); + Ldloc(end); + Ldc(maxLength + extraNewlineBump); + Sub(); + Bge(label); + Ldloc(end); + Ldc(maxLength + extraNewlineBump); + Sub(); + Stloc(pos); + MarkLabel(label); break; - } + } } return false; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs index e3c760c2728be..ee96e7e5cc847 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFindOptimizations.cs @@ -10,7 +10,8 @@ namespace System.Text.RegularExpressions /// Contains state and provides operations related to finding the next location a match could possibly begin. internal sealed class RegexFindOptimizations { - /// The minimum required length an input need be to match the pattern. May be 0. + /// The minimum required length an input need be to match the pattern. + /// 0 is a valid minimum length. This value may also be the max (and hence fixed) length of the expression. private readonly int _minRequiredLength; /// True if the input should be processed right-to-left rather than left-to-right. private readonly bool _rightToLeft; @@ -27,28 +28,48 @@ public RegexFindOptimizations(RegexTree tree, CultureInfo culture) // Compute any anchor starting the expression. If there is one, we won't need to search for anything, // as we can just match at that single location. - LeadingAnchor = RegexPrefixAnalyzer.FindLeadingAnchor(tree); - if (_rightToLeft) + LeadingAnchor = RegexPrefixAnalyzer.FindLeadingAnchor(tree.Root); + if (_rightToLeft && LeadingAnchor == RegexNodeKind.Bol) { // Filter out Bol for RightToLeft, as we don't currently optimize for it. - LeadingAnchor &= ~RegexPrefixAnalyzer.Bol; + LeadingAnchor = RegexNodeKind.Unknown; } - if ((LeadingAnchor & (RegexPrefixAnalyzer.Beginning | RegexPrefixAnalyzer.Start | RegexPrefixAnalyzer.EndZ | RegexPrefixAnalyzer.End)) != 0) + if (LeadingAnchor is RegexNodeKind.Beginning or RegexNodeKind.Start or RegexNodeKind.EndZ or RegexNodeKind.End) { FindMode = (LeadingAnchor, _rightToLeft) switch { - (RegexPrefixAnalyzer.Beginning, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Beginning, - (RegexPrefixAnalyzer.Beginning, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_Beginning, - (RegexPrefixAnalyzer.Start, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Start, - (RegexPrefixAnalyzer.Start, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_Start, - (RegexPrefixAnalyzer.End, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_End, - (RegexPrefixAnalyzer.End, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_End, + (RegexNodeKind.Beginning, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Beginning, + (RegexNodeKind.Beginning, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_Beginning, + (RegexNodeKind.Start, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_Start, + (RegexNodeKind.Start, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_Start, + (RegexNodeKind.End, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_End, + (RegexNodeKind.End, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_End, (_, false) => FindNextStartingPositionMode.LeadingAnchor_LeftToRight_EndZ, (_, true) => FindNextStartingPositionMode.LeadingAnchor_RightToLeft_EndZ, }; return; } + // Compute any anchor trailing the expression. If there is one, and we can also compute a fixed length + // for the whole expression, we can use that to quickly jump to the right location in the input. + if (!_rightToLeft) // haven't added FindNextStartingPositionMode support for RTL + { + TrailingAnchor = RegexPrefixAnalyzer.FindTrailingAnchor(tree.Root); + if (TrailingAnchor is RegexNodeKind.End or RegexNodeKind.EndZ && + tree.Root.ComputeMaxLength() is int maxLength) + { + Debug.Assert(maxLength >= _minRequiredLength, $"{maxLength} should have been greater than {_minRequiredLength} minimum"); + MaxPossibleLength = maxLength; + if (_minRequiredLength == maxLength) + { + FindMode = TrailingAnchor == RegexNodeKind.End ? + FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_End : + FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_EndZ; + return; + } + } + } + // If there's a leading case-sensitive substring, just use IndexOf and inherit all of its optimizations. string caseSensitivePrefix = RegexPrefixAnalyzer.FindCaseSensitivePrefix(tree.Root); if (caseSensitivePrefix.Length > 1) @@ -183,8 +204,18 @@ public RegexFindOptimizations(RegexTree tree, CultureInfo culture) /// Gets the selected mode for performing the next operation public FindNextStartingPositionMode FindMode { get; } = FindNextStartingPositionMode.NoSearch; - /// Gets the leading anchor, if one exists (RegexPrefixAnalyzer.Bol, etc). - public int LeadingAnchor { get; } + /// Gets the leading anchor (e.g. RegexNodeKind.Bol) if one exists and was computed. + public RegexNodeKind LeadingAnchor { get; } + + /// Gets the trailing anchor (e.g. RegexNodeKind.Bol) if one exists and was computed. + public RegexNodeKind TrailingAnchor { get; } + + /// The maximum possible length an input could be to match the pattern. + /// + /// This is currently only set when is found to be an end anchor. + /// That can be expanded in the future as needed. + /// + public int? MaxPossibleLength { get; } /// Gets the leading prefix. May be an empty string. public string LeadingCaseSensitivePrefix { get; } = string.Empty; @@ -230,7 +261,7 @@ public bool TryFindNextStartingPosition(ReadOnlySpan textSpan, ref int pos // other anchors like Beginning, there are potentially multiple places a BOL can match. So unlike // the other anchors, which all skip all subsequent processing if found, with BOL we just use it // to boost our position to the next line, and then continue normally with any searches. - if (LeadingAnchor == RegexPrefixAnalyzer.Bol) + if (LeadingAnchor == RegexNodeKind.Bol) { // If we're not currently positioned at the beginning of a line (either // the beginning of the string or just after a line feed), find the next @@ -315,6 +346,20 @@ public bool TryFindNextStartingPosition(ReadOnlySpan textSpan, ref int pos } return true; + case FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_EndZ: + if (pos < end - _minRequiredLength - 1) + { + pos = end - _minRequiredLength - 1; + } + return true; + + case FindNextStartingPositionMode.TrailingAnchor_FixedLength_LeftToRight_End: + if (pos < end - _minRequiredLength) + { + pos = end - _minRequiredLength; + } + return true; + // There's a case-sensitive prefix. Search for it with ordinal IndexOf. case FindNextStartingPositionMode.LeadingPrefix_LeftToRight_CaseSensitive: @@ -698,6 +743,11 @@ internal enum FindNextStartingPositionMode /// An "end" anchor at the beginning of the right-to-left pattern. This is rare. LeadingAnchor_RightToLeft_End, + /// An "end" anchor at the end of the pattern, with the pattern always matching a fixed-length expression. + TrailingAnchor_FixedLength_LeftToRight_End, + /// An "endz" anchor at the end of the pattern, with the pattern always matching a fixed-length expression. + TrailingAnchor_FixedLength_LeftToRight_EndZ, + /// A case-sensitive multi-character substring at the beginning of the pattern. LeadingPrefix_LeftToRight_CaseSensitive, /// A case-sensitive multi-character substring at the beginning of the right-to-left pattern. diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index ad760e95e3914..945f9ac2b4f2d 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -232,7 +232,7 @@ private void ValidateFinalTreeInvariants() case RegexNodeKind.Setloopatomic: case RegexNodeKind.Start: case RegexNodeKind.UpdateBumpalong: - Debug.Assert(childCount == 0, $"Expected zero children for {node.TypeName}, got {childCount}."); + Debug.Assert(childCount == 0, $"Expected zero children for {node.Kind}, got {childCount}."); break; case RegexNodeKind.Atomic: @@ -241,20 +241,20 @@ private void ValidateFinalTreeInvariants() case RegexNodeKind.Loop: case RegexNodeKind.NegativeLookaround: case RegexNodeKind.PositiveLookaround: - Debug.Assert(childCount == 1, $"Expected one and only one child for {node.TypeName}, got {childCount}."); + Debug.Assert(childCount == 1, $"Expected one and only one child for {node.Kind}, got {childCount}."); break; case RegexNodeKind.BackreferenceConditional: - Debug.Assert(childCount == 2, $"Expected two children for {node.TypeName}, got {childCount}"); + Debug.Assert(childCount == 2, $"Expected two children for {node.Kind}, got {childCount}"); break; case RegexNodeKind.ExpressionConditional: - Debug.Assert(childCount == 3, $"Expected three children for {node.TypeName}, got {childCount}"); + Debug.Assert(childCount == 3, $"Expected three children for {node.Kind}, got {childCount}"); break; case RegexNodeKind.Concatenate: case RegexNodeKind.Alternate: - Debug.Assert(childCount >= 2, $"Expected at least two children for {node.TypeName}, got {childCount}."); + Debug.Assert(childCount >= 2, $"Expected at least two children for {node.Kind}, got {childCount}."); break; default: @@ -274,11 +274,11 @@ private void ValidateFinalTreeInvariants() case RegexNodeKind.Setloop: case RegexNodeKind.Setloopatomic: case RegexNodeKind.Setlazy: - Debug.Assert(!string.IsNullOrEmpty(node.Str), $"Expected non-null, non-empty string for {node.TypeName}."); + Debug.Assert(!string.IsNullOrEmpty(node.Str), $"Expected non-null, non-empty string for {node.Kind}."); break; default: - Debug.Assert(node.Str is null, $"Expected null string for {node.TypeName}, got \"{node.Str}\"."); + Debug.Assert(node.Str is null, $"Expected null string for {node.Kind}, got \"{node.Str}\"."); break; } } @@ -2125,7 +2125,7 @@ public int ComputeMinLength() case RegexNodeKind.Lazyloop: case RegexNodeKind.Loop: // A node graph repeated at least M times. - return (int)Math.Min(int.MaxValue, (long)M * Child(0).ComputeMinLength()); + return (int)Math.Min(int.MaxValue - 1, (long)M * Child(0).ComputeMinLength()); case RegexNodeKind.Alternate: // The minimum required length for any of the alternation's branches. @@ -2157,7 +2157,7 @@ public int ComputeMinLength() { sum += Child(i).ComputeMinLength(); } - return (int)Math.Min(int.MaxValue, sum); + return (int)Math.Min(int.MaxValue - 1, sum); } case RegexNodeKind.Atomic: @@ -2170,9 +2170,9 @@ public int ComputeMinLength() case RegexNodeKind.Empty: case RegexNodeKind.Nothing: case RegexNodeKind.UpdateBumpalong: - // Nothing to match. In the future, we could potentially use Nothing to say that the min length - // is infinite, but that would require a different structure, as that would only apply if the - // Nothing match is required in all cases (rather than, say, as one branch of an alternation). + // Nothing to match. In the future, we could potentially use Nothing to say that the min length + // is infinite, but that would require a different structure, as that would only apply if the + // Nothing match is required in all cases (rather than, say, as one branch of an alternation). case RegexNodeKind.Beginning: case RegexNodeKind.Bol: case RegexNodeKind.Boundary: @@ -2183,20 +2183,154 @@ public int ComputeMinLength() case RegexNodeKind.NonBoundary: case RegexNodeKind.NonECMABoundary: case RegexNodeKind.Start: - // Difficult to glean anything meaningful from boundaries or results only known at run time. case RegexNodeKind.NegativeLookaround: case RegexNodeKind.PositiveLookaround: - // Lookaheads/behinds could potentially be included in the future, but that will require - // a different structure, as they can't be added as part of a concatenation, since they overlap - // with what comes after. + // Zero-width case RegexNodeKind.Backreference: - // Constructs requiring data at runtime from the matching pattern can't influence min length. + // Requires matching data available only at run-time. In the future, we could choose to find + // and follow the capture group this aligns with, while being careful not to end up in an + // infinite cycle. return 0; default: -#if DEBUG - Debug.Fail($"Unknown node: {TypeName}"); -#endif + Debug.Fail($"Unknown node: {Kind}"); + goto case RegexNodeKind.Empty; + } + } + + /// Computes a maximum length of any string that could possibly match. + /// The maximum length of any string that could possibly match, or null if the length may not always be the same. + /// + /// e.g. abc[def](gh|ijklmnop) => 12 + /// + public int? ComputeMaxLength() + { + if (!StackHelper.TryEnsureSufficientExecutionStack()) + { + // If we can't recur further, assume there's no minimum we can enforce. + return null; + } + + switch (Kind) + { + case RegexNodeKind.One: + case RegexNodeKind.Notone: + case RegexNodeKind.Set: + // Single character. + return 1; + + case RegexNodeKind.Multi: + // Every character in the string needs to match. + return Str!.Length; + + case RegexNodeKind.Notonelazy or RegexNodeKind.Notoneloop or RegexNodeKind.Notoneloopatomic or + RegexNodeKind.Onelazy or RegexNodeKind.Oneloop or RegexNodeKind.Oneloopatomic or + RegexNodeKind.Setlazy or RegexNodeKind.Setloop or RegexNodeKind.Setloopatomic: + // Return the max number of iterations if there's an upper bound, or null if it's infinite + return N == int.MaxValue ? null : N; + + case RegexNodeKind.Loop or RegexNodeKind.Lazyloop: + if (N != int.MaxValue) + { + // A node graph repeated a fixed number of times + if (Child(0).ComputeMaxLength() is int childMaxLength) + { + long maxLength = (long)N * childMaxLength; + if (maxLength < int.MaxValue) + { + return (int)maxLength; + } + } + } + return null; + + case RegexNodeKind.Alternate: + // The maximum length of any child branch, as long as they all have one. + { + int childCount = ChildCount(); + Debug.Assert(childCount >= 2); + if (Child(0).ComputeMaxLength() is not int maxLength) + { + return null; + } + + for (int i = 1; i < childCount; i++) + { + if (Child(i).ComputeMaxLength() is not int next) + { + return null; + } + + maxLength = Math.Max(maxLength, next); + } + + return maxLength; + } + + case RegexNodeKind.BackreferenceConditional: + case RegexNodeKind.ExpressionConditional: + // The maximum length of either child branch, as long as they both have one.. The condition for an expression conditional is a zero-width assertion. + { + int i = Kind == RegexNodeKind.BackreferenceConditional ? 0 : 1; + return Child(i).ComputeMaxLength() is int yes && Child(i + 1).ComputeMaxLength() is int no ? + Math.Max(yes, no) : + null; + } + + case RegexNodeKind.Concatenate: + // The sum of all of the concatenation's children's max lengths, as long as they all have one. + { + long sum = 0; + int childCount = ChildCount(); + for (int i = 0; i < childCount; i++) + { + if (Child(i).ComputeMaxLength() is not int length) + { + return null; + } + sum += length; + } + + if (sum < int.MaxValue) + { + return (int)sum; + } + + return null; + } + + case RegexNodeKind.Atomic: + case RegexNodeKind.Capture: + // For groups, we just delegate to the sole child. + Debug.Assert(ChildCount() == 1); + return Child(0).ComputeMaxLength(); + + case RegexNodeKind.Empty: + case RegexNodeKind.Nothing: + case RegexNodeKind.UpdateBumpalong: + case RegexNodeKind.Beginning: + case RegexNodeKind.Bol: + case RegexNodeKind.Boundary: + case RegexNodeKind.ECMABoundary: + case RegexNodeKind.End: + case RegexNodeKind.EndZ: + case RegexNodeKind.Eol: + case RegexNodeKind.NonBoundary: + case RegexNodeKind.NonECMABoundary: + case RegexNodeKind.Start: + case RegexNodeKind.PositiveLookaround: + case RegexNodeKind.NegativeLookaround: + // Zero-width + return 0; + + case RegexNodeKind.Backreference: + // Requires matching data available only at run-time. In the future, we could choose to find + // and follow the capture group this aligns with, while being careful not to end up in an + // infinite cycle. + return null; + + default: + Debug.Fail($"Unknown node: {Kind}"); goto case RegexNodeKind.Empty; } } @@ -2416,12 +2550,10 @@ public bool IsInLoop() } #if DEBUG - private string TypeName => Kind.ToString(); - [ExcludeFromCodeCoverage] public string Description() { - var sb = new StringBuilder(TypeName); + var sb = new StringBuilder(Kind.ToString()); if ((Options & RegexOptions.ExplicitCapture) != 0) sb.Append("-C"); if ((Options & RegexOptions.IgnoreCase) != 0) sb.Append("-I"); diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNodeKind.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNodeKind.cs index ab4ea881087c5..dcf1097ea3ec7 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNodeKind.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNodeKind.cs @@ -1,17 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Threading; - namespace System.Text.RegularExpressions { /// Specifies the kind of a . internal enum RegexNodeKind { + /// Unknown node type. + /// This should never occur on an actual node, and instead is used as a sentinel. + Unknown = 0, + // The following are leaves (no children) and correspond to primitive operations in the regular expression. /// A specific character, e.g. `a`. diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs index 692ee7d5557c1..c3e80fc991371 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Threading; @@ -17,16 +16,6 @@ internal ref struct RegexPrefixAnalyzer private const RegexNodeKind BeforeChild = (RegexNodeKind)64; private const RegexNodeKind AfterChild = (RegexNodeKind)128; - // where the regex can be pegged - public const int Beginning = 0x0001; - public const int Bol = 0x0002; - public const int Start = 0x0004; - public const int Eol = 0x0008; - public const int EndZ = 0x0010; - public const int End = 0x0020; - public const int Boundary = 0x0040; - public const int ECMABoundary = 0x0080; - private readonly List _fcStack; private ValueListBuilder _intStack; // must not be readonly private bool _skipAllChildren; // don't process any more children at the current level @@ -654,94 +643,116 @@ public static (RegexNode LoopNode, (char Char, string? String, char[]? Chars) Li return null; } - /// Takes a RegexTree and computes the leading anchor that it encounters. - public static int FindLeadingAnchor(RegexTree tree) + /// Computes the leading anchor of a node. + public static RegexNodeKind FindLeadingAnchor(RegexNode node) => + FindLeadingOrTrailingAnchor(node, leading: true); + + /// Computes the leading anchor of a node. + public static RegexNodeKind FindTrailingAnchor(RegexNode node) => + FindLeadingOrTrailingAnchor(node, leading: false); + + /// Computes the leading or trailing anchor of a node. + private static RegexNodeKind FindLeadingOrTrailingAnchor(RegexNode node, bool leading) { - RegexNode curNode = tree.Root; - RegexNode? concatNode = null; - int nextChild = 0; + if (!StackHelper.TryEnsureSufficientExecutionStack()) + { + // We only recur for alternations, but with a really deep nesting of alternations we could potentially overflow. + // In such a case, simply stop searching for an anchor. + return RegexNodeKind.Unknown; + } while (true) { - switch (curNode.Kind) + switch (node.Kind) { case RegexNodeKind.Bol: - return Bol; - case RegexNodeKind.Eol: - return Eol; - - case RegexNodeKind.Boundary: - return Boundary; - - case RegexNodeKind.ECMABoundary: - return ECMABoundary; - case RegexNodeKind.Beginning: - return Beginning; - case RegexNodeKind.Start: - return Start; - case RegexNodeKind.EndZ: - return EndZ; - case RegexNodeKind.End: - return End; + case RegexNodeKind.Boundary: + case RegexNodeKind.ECMABoundary: + // Return any anchor found. + return node.Kind; + + case RegexNodeKind.Atomic: + case RegexNodeKind.Capture: + // For groups, continue exploring the sole child. + node = node.Child(0); + continue; case RegexNodeKind.Concatenate: - if (curNode.ChildCount() > 0) + // For concatenations, we expect primarily to explore its first (for leading) or last (for trailing) child, + // but we can also skip over certain kinds of nodes (e.g. Empty), and thus iterate through its children backward + // looking for the last we shouldn't skip. { - concatNode = curNode; - nextChild = 0; + int childCount = node.ChildCount(); + RegexNode? child = null; + if (leading) + { + for (int i = 0; i < childCount; i++) + { + if (node.Child(i).Kind is not (RegexNodeKind.Empty or RegexNodeKind.PositiveLookaround or RegexNodeKind.NegativeLookaround)) + { + child = node.Child(i); + break; + } + } + } + else + { + for (int i = childCount - 1; i >= 0; i--) + { + if (node.Child(i).Kind is not (RegexNodeKind.Empty or RegexNodeKind.PositiveLookaround or RegexNodeKind.NegativeLookaround)) + { + child = node.Child(i); + break; + } + } + } + + if (child is not null) + { + node = child; + continue; + } + + goto default; } - break; - case RegexNodeKind.Atomic: - case RegexNodeKind.Capture: - curNode = curNode.Child(0); - concatNode = null; - continue; + case RegexNodeKind.Alternate: + // For alternations, every branch needs to lead or trail with the same anchor. + { + // Get the leading/trailing anchor of the first branch. If there isn't one, bail. + RegexNodeKind anchor = FindLeadingOrTrailingAnchor(node.Child(0), leading); + if (anchor == RegexNodeKind.Unknown) + { + return RegexNodeKind.Unknown; + } - case RegexNodeKind.Empty: - case RegexNodeKind.PositiveLookaround: - case RegexNodeKind.NegativeLookaround: - break; + // Look at each subsequent branch and validate it has the same leading or trailing + // anchor. If any doesn't, bail. + int childCount = node.ChildCount(); + for (int i = 1; i < childCount; i++) + { + if (FindLeadingOrTrailingAnchor(node.Child(i), leading) != anchor) + { + return RegexNodeKind.Unknown; + } + } - default: - return 0; - } + // All branches have the same leading/trailing anchor. Return it. + return anchor; + } - if (concatNode == null || nextChild >= concatNode.ChildCount()) - { - return 0; + default: + // For everything else, we couldn't find an anchor. + return RegexNodeKind.Unknown; } - - curNode = concatNode.Child(nextChild++); } } -#if DEBUG - [ExcludeFromCodeCoverage] - public static string AnchorDescription(int anchors) - { - var sb = new StringBuilder(); - - if ((anchors & Beginning) != 0) sb.Append(", Beginning"); - if ((anchors & Start) != 0) sb.Append(", Start"); - if ((anchors & Bol) != 0) sb.Append(", Bol"); - if ((anchors & Boundary) != 0) sb.Append(", Boundary"); - if ((anchors & ECMABoundary) != 0) sb.Append(", ECMABoundary"); - if ((anchors & Eol) != 0) sb.Append(", Eol"); - if ((anchors & End) != 0) sb.Append(", End"); - if ((anchors & EndZ) != 0) sb.Append(", EndZ"); - - return sb.Length >= 2 ? - sb.ToString(2, sb.Length - 2) : - "None"; - } -#endif - /// /// To avoid recursion, we use a simple integer stack. /// diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs index 005e9b27bb203..e3e466dd64ece 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs @@ -284,8 +284,42 @@ public static IEnumerable Match_MemberData() // Using beginning/end of string chars \A, \Z: Actual - "\\Aaaa\\w+zzz\\Z" yield return (@"\Aaaa\w+zzz\Z", "aaaasdfajsdlfjzzza", RegexOptions.None, 0, 18, false, string.Empty); + // Anchors + foreach (RegexOptions anchorOptions in new[] { RegexOptions.None, RegexOptions.Multiline }) + { + yield return (@"^abc", "abc", anchorOptions, 0, 3, true, "abc"); + yield return (@"^abc", " abc", anchorOptions, 0, 4, false, ""); + yield return (@"^abc|^def", "def", anchorOptions, 0, 3, true, "def"); + yield return (@"^abc|^def", " abc", anchorOptions, 0, 4, false, ""); + yield return (@"^abc|^def", " def", anchorOptions, 0, 4, false, ""); + yield return (@"abc|^def", " abc", anchorOptions, 0, 4, true, "abc"); + yield return (@"abc|^def|^efg", " abc", anchorOptions, 0, 4, true, "abc"); + yield return (@"^abc|def|^efg", " def", anchorOptions, 0, 4, true, "def"); + yield return (@"^abc|def", " def", anchorOptions, 0, 4, true, "def"); + yield return (@"abcd$", "1234567890abcd", anchorOptions, 0, 14, true, "abcd"); + yield return (@"abc{1,4}d$", "1234567890abcd", anchorOptions, 0, 14, true, "abcd"); + yield return (@"abc{1,4}d$", "1234567890abccccd", anchorOptions, 0, 17, true, "abccccd"); + } + if (!RegexHelpers.IsNonBacktracking(engine)) + { + yield return (@"\Gabc", "abc", RegexOptions.None, 0, 3, true, "abc"); + yield return (@"\Gabc", " abc", RegexOptions.None, 0, 4, false, ""); + yield return (@"\Gabc", " abc", RegexOptions.None, 1, 3, true, "abc"); + yield return (@"\Gabc|\Gdef", "def", RegexOptions.None, 0, 3, true, "def"); + yield return (@"\Gabc|\Gdef", " abc", RegexOptions.None, 0, 4, false, ""); + yield return (@"\Gabc|\Gdef", " def", RegexOptions.None, 0, 4, false, ""); + yield return (@"\Gabc|\Gdef", " abc", RegexOptions.None, 1, 3, true, "abc"); + yield return (@"\Gabc|\Gdef", " def", RegexOptions.None, 1, 3, true, "def"); + yield return (@"abc|\Gdef", " abc", RegexOptions.None, 0, 4, true, "abc"); + yield return (@"\Gabc|def", " def", RegexOptions.None, 0, 4, true, "def"); + } + // Anchors and multiline - yield return (@"^A$", "ABC\n", RegexOptions.Multiline, 0, 2, false, string.Empty); + yield return (@"^A$", "A\n", RegexOptions.Multiline, 0, 2, true, "A"); + yield return (@"^A$", "ABC\n", RegexOptions.Multiline, 0, 4, false, string.Empty); + yield return (@"^A$", "123\nA", RegexOptions.Multiline, 0, 5, true, "A"); + yield return (@"^A$", "123\nA\n456", RegexOptions.Multiline, 0, 9, true, "A"); + yield return (@"^A$|^B$", "123\nB\n456", RegexOptions.Multiline, 0, 9, true, "B"); // Using beginning/end of string chars \A, \Z: Actual - "\\Aaaa\\w+zzz\\Z" yield return (@"\A(line2\n)line3\Z", "line2\nline3\n", RegexOptions.Multiline, 0, 12, true, "line2\nline3"); @@ -905,7 +939,7 @@ private async Task Match_TestThatTimeoutHappens(RegexEngine engine) } string input = new string(chars); - Regex re = await RegexHelpers.GetRegexAsync(engine, @"a.{20}$", RegexOptions.None, TimeSpan.FromMilliseconds(10)); + Regex re = await RegexHelpers.GetRegexAsync(engine, @"a.{20}^", RegexOptions.None, TimeSpan.FromMilliseconds(10)); Assert.Throws(() => { re.Match(input); }); } diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs index 38cf72a3f5238..65ef818124a42 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs @@ -18,6 +18,8 @@ public class RegexReductionTests private static readonly FieldInfo s_regexCode; private static readonly FieldInfo s_regexCodeCodes; private static readonly FieldInfo s_regexCodeTree; + private static readonly FieldInfo s_regexCodeFindOptimizations; + private static readonly PropertyInfo s_regexCodeFindOptimizationsMaxPossibleLength; private static readonly FieldInfo s_regexCodeTreeMinRequiredLength; static RegexReductionTests() @@ -31,6 +33,12 @@ static RegexReductionTests() s_regexCode = typeof(Regex).GetField("_code", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(s_regexCode); + s_regexCodeFindOptimizations = s_regexCode.FieldType.GetField("FindOptimizations", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(s_regexCodeFindOptimizations); + + s_regexCodeFindOptimizationsMaxPossibleLength = s_regexCodeFindOptimizations.FieldType.GetProperty("MaxPossibleLength", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(s_regexCodeFindOptimizationsMaxPossibleLength); + s_regexCodeCodes = s_regexCode.FieldType.GetField("Codes", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(s_regexCodeCodes); @@ -71,6 +79,20 @@ private static int GetMinRequiredLength(Regex r) return (int)minRequiredLength; } + private static int? GetMaxPossibleLength(Regex r) + { + object code = s_regexCode.GetValue(r); + Assert.NotNull(code); + + object findOpts = s_regexCodeFindOptimizations.GetValue(code); + Assert.NotNull(findOpts); + + object maxPossibleLength = s_regexCodeFindOptimizationsMaxPossibleLength.GetValue(findOpts); + Assert.True(maxPossibleLength is null || maxPossibleLength is int); + + return (int?)maxPossibleLength; + } + [Theory] [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Many of these optimizations don't exist in .NET Framework.")] // Two greedy one loops @@ -535,70 +557,100 @@ public void PatternsReduceDifferently(string pattern1, string pattern2) [Theory] [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Not computed in netfx")] - [InlineData(@"a", 1)] - [InlineData(@"[^a]", 1)] - [InlineData(@"[abcdefg]", 1)] - [InlineData(@"abcd", 4)] - [InlineData(@"a*", 0)] - [InlineData(@"a*?", 0)] - [InlineData(@"a?", 0)] - [InlineData(@"a??", 0)] - [InlineData(@"a+", 1)] - [InlineData(@"a+?", 1)] - [InlineData(@"a{2}", 2)] - [InlineData(@"a{2}?", 2)] - [InlineData(@"a{3,17}", 3)] - [InlineData(@"a{3,17}?", 3)] - [InlineData(@"(abcd){5}", 20)] - [InlineData(@"(abcd|ef){2,6}", 4)] - [InlineData(@"abcef|de", 2)] - [InlineData(@"abc(def|ghij)k", 7)] - [InlineData(@"\d{1,2}-\d{1,2}-\d{2,4}", 6)] - [InlineData(@"1(?=9)\d", 2)] - [InlineData(@"1(?!\d)\w", 2)] - [InlineData(@"a*a*a*a*a*a*a*b*", 0)] - [InlineData(@"((a{1,2}){4}){3,7}", 12)] - [InlineData(@"\b\w{4}\b", 4)] - [InlineData(@"abcd(?=efgh)efgh", 8)] - [InlineData(@"abcd(?<=cd)efgh", 8)] - [InlineData(@"abcd(?!ab)efgh", 8)] - [InlineData(@"abcd(?\d{1,2})-\d{2,4}", RegexOptions.None, 6, 10)] + [InlineData(@"1(?=9)\d", RegexOptions.None, 2, 2)] + [InlineData(@"1(?!\d)\w", RegexOptions.None, 2, 2)] + [InlineData(@"a*a*a*a*a*a*a*b*", RegexOptions.None, 0, null)] + [InlineData(@"((a{1,2}){4}){3,7}", RegexOptions.None, 12, 56)] + [InlineData(@"((a{1,2}){4}?){3,7}", RegexOptions.None, 12, 56)] + [InlineData(@"\b\w{4}\b", RegexOptions.None, 4, 4)] + [InlineData(@"\b\w{4}\b", RegexOptions.ECMAScript, 4, 4)] + [InlineData(@"abcd(?=efgh)efgh", RegexOptions.None, 8, 8)] + [InlineData(@"abcd(?<=cd)efgh", RegexOptions.None, 8, 8)] + [InlineData(@"abcd(?!ab)efgh", RegexOptions.None, 8, 8)] + [InlineData(@"abcd(? Date: Tue, 25 Jan 2022 17:35:28 +0300 Subject: [PATCH 195/308] Add the exception set for `ObjGetType` (#64106) * Model NRE for ObjGetType * Add tests --- src/coreclr/jit/gentree.cpp | 18 +++------ src/coreclr/jit/namedintrinsiclist.h | 5 ++- src/coreclr/jit/valuenum.cpp | 3 +- .../JIT/opt/ValueNumbering/ExceptionSets.cs | 37 +++++++++++++++++++ .../opt/ValueNumbering/ExceptionSets.csproj | 13 +++++++ 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSets.cs create mode 100644 src/tests/JIT/opt/ValueNumbering/ExceptionSets.csproj diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 8c9450cfbf564..68a7b49d74dbb 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -5226,7 +5226,7 @@ bool GenTree::OperRequiresCallFlag(Compiler* comp) // Return Value: // True if the given node contains an implicit indirection // -// Note that for the GT_HWINTRINSIC node we have to examine the +// Note that for the [HW]INTRINSIC nodes we have to examine the // details of the node to determine its result. // @@ -5250,6 +5250,8 @@ bool GenTree::OperIsImplicitIndir() const case GT_ARR_ELEM: case GT_ARR_OFFSET: return true; + case GT_INTRINSIC: + return AsIntrinsic()->gtIntrinsicName == NI_System_Object_GetType; #ifdef FEATURE_SIMD case GT_SIMD: { @@ -5306,18 +5308,8 @@ bool GenTree::OperMayThrow(Compiler* comp) case GT_INTRINSIC: // If this is an intrinsic that represents the object.GetType(), it can throw an NullReferenceException. - // Report it as may throw. - // Note: Some of the rest of the existing intrinsics could potentially throw an exception (for example - // the array and string element access ones). They are handled differently than the GetType intrinsic - // and are not marked with GTF_EXCEPT. If these are revisited at some point to be marked as - // GTF_EXCEPT, - // the code below might need to be specialized to handle them properly. - if ((this->gtFlags & GTF_EXCEPT) != 0) - { - return true; - } - - break; + // Currently, this is the only intrinsic that can throw an exception. + return AsIntrinsic()->gtIntrinsicName == NI_System_Object_GetType; case GT_CALL: diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 7b2108d3edd05..68ea721ae4818 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -4,7 +4,10 @@ #ifndef _NAMEDINTRINSICLIST_H_ #define _NAMEDINTRINSICLIST_H_ -// Named jit intrinsics +// Named jit intrinsics. + +// When adding a new intrinsic that will use the GT_INTRINSIC node and can throw, make sure +// to update the "OperMayThrow" and "fgValueNumberAddExceptionSet" methods to account for that. enum NamedIntrinsic : unsigned short { diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 356124ab00e5c..3faa6efc7ace9 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -10992,7 +10992,8 @@ void Compiler::fgValueNumberAddExceptionSet(GenTree* tree) break; case GT_INTRINSIC: - // ToDo: model the exceptions for Intrinsics + assert(tree->AsIntrinsic()->gtIntrinsicName == NI_System_Object_GetType); + fgValueNumberAddExceptionSetForIndirection(tree, tree->AsIntrinsic()->gtGetOp1()); break; case GT_IND: diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSets.cs b/src/tests/JIT/opt/ValueNumbering/ExceptionSets.cs new file mode 100644 index 0000000000000..6a413303ad194 --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSets.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. + +using System; +using System.Runtime.CompilerServices; + +#pragma warning disable CS0253 // Possible unintended reference comparison + +class ExceptionSets +{ + public static int Main() + { + try + { + TestObjGetType(null, 0); + return 101; + } + catch (NullReferenceException) { } + + return 100; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool TestObjGetType(object a, int i) + { + var fls = false; + var c1 = i == 0; + var c2 = c1; + + if (((a.GetType() == a) & fls) | (i == 0)) + { + return true; + } + + return c2; + } +} diff --git a/src/tests/JIT/opt/ValueNumbering/ExceptionSets.csproj b/src/tests/JIT/opt/ValueNumbering/ExceptionSets.csproj new file mode 100644 index 0000000000000..5d8fe22529764 --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ExceptionSets.csproj @@ -0,0 +1,13 @@ + + + Exe + 1 + + + None + True + + + + + From 902db7e364422b9918d3d9d4ee2c1e6362359cf7 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 25 Jan 2022 06:37:01 -0800 Subject: [PATCH 196/308] [ILVerify] Fix casting check for arrays of generic parameters with class constraints (#64259) Fixes #63999 --- .../Common/TypeSystem/Common/CastingHelper.cs | 28 +++++++++++++++++-- .../CastingTests.cs | 15 ++++++++++ .../CoreTestAssembly/Casting.cs | 4 +++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.cs b/src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.cs index 1b067af21b476..03a59a840e1de 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.cs @@ -263,7 +263,7 @@ private static bool CanCastParamTo(this ParameterizedType thisType, TypeDesc par else if (curTypesParm.IsGenericParameter) { var genericVariableFromParam = (GenericParameterDesc)curTypesParm; - if (genericVariableFromParam.HasReferenceTypeConstraint) + if (genericVariableFromParam.HasReferenceTypeConstraint || IsConstrainedAsGCPointer(genericVariableFromParam)) { return genericVariableFromParam.CanCastToInternal(paramType, protect); } @@ -281,6 +281,30 @@ private static bool CanCastParamTo(this ParameterizedType thisType, TypeDesc par return false; } + private static bool IsConstrainedAsGCPointer(GenericParameterDesc type) + { + foreach (var typeConstraint in type.TypeConstraints) + { + if (typeConstraint.IsGenericParameter) + { + if (IsConstrainedAsGCPointer((GenericParameterDesc)typeConstraint)) + return true; + } + + if (!typeConstraint.IsInterface && typeConstraint.IsGCPointer) + { + // Object, ValueType, and Enum are GCPointers but they do not constrain the type to GCPointer! + if (!typeConstraint.IsWellKnownType(WellKnownType.Object) && + !typeConstraint.IsWellKnownType(WellKnownType.ValueType) && + !typeConstraint.IsWellKnownType(WellKnownType.Enum)) + { + return true; + } + } + } + return false; + } + private static TypeFlags GetNormalizedIntegralArrayElementType(TypeDesc type) { Debug.Assert(!type.IsEnum); @@ -502,7 +526,7 @@ private static bool IsBoxedAndCanCastTo(this TypeDesc thisType, TypeDesc otherTy else if (thisType.IsGenericParameter) { var genericVariableFromParam = (GenericParameterDesc)thisType; - if (genericVariableFromParam.HasReferenceTypeConstraint) + if (genericVariableFromParam.HasReferenceTypeConstraint || IsConstrainedAsGCPointer(genericVariableFromParam)) { return genericVariableFromParam.CanCastToInternal(otherType, protect); } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CastingTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CastingTests.cs index f6cd2e187d46c..4bcf3432f522f 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CastingTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CastingTests.cs @@ -202,6 +202,21 @@ public void TestNullableCasting() Assert.True(intType.CanCastTo(nullableOfIntType)); } + [Fact] + public void TestGenericParameterArrayCasting() + { + TypeDesc baseArrayType = _testModule.GetType("Casting", "Base").MakeArrayType(); + TypeDesc iFooArrayType = _testModule.GetType("Casting", "IFoo").MakeArrayType(); + + TypeDesc paramArrayWithBaseClassConstraint = + _testModule.GetType("Casting", "ClassWithBaseClassConstraint`1").Instantiation[0].MakeArrayType(); + TypeDesc paramArrayWithInterfaceConstraint = + _testModule.GetType("Casting", "ClassWithInterfaceConstraint`1").Instantiation[0].MakeArrayType(); + + Assert.True(paramArrayWithBaseClassConstraint.CanCastTo(baseArrayType)); + Assert.False(paramArrayWithInterfaceConstraint.CanCastTo(iFooArrayType)); + } + [Fact] public void TestRecursiveCanCast() { diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Casting.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Casting.cs index a6ae700e942a1..03ce4ae4332cd 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Casting.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Casting.cs @@ -3,6 +3,8 @@ namespace Casting { + class Base { } + interface IFoo { } interface IContravariant { } @@ -21,6 +23,8 @@ class ClassWithNoConstraint { } class ClassWithValueTypeConstraint where T : struct { } + class ClassWithBaseClassConstraint where T : Base { } + class ClassWithInterfaceConstraint where T : IFoo { } class ClassWithRecursiveImplementation : IContravariant> { } From 802dc689fdcca6e52e17604048465a50203371b1 Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Tue, 25 Jan 2022 06:47:22 -0800 Subject: [PATCH 197/308] Use lower call count threshold for tiering in debug builds (#60945) * Use lower call count threshold for tiering in debug builds To exercise more paths during tests, see https://github.com/dotnet/runtime/pull/60886 --- src/coreclr/inc/clrconfigvalues.h | 33 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 28b1010666369..e1edb2466e65c 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -562,21 +562,36 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_HillClimbing_GainExponent, /// Tiered Compilation /// #ifdef FEATURE_TIERED_COMPILATION +#ifdef _DEBUG +// Use lower values to exercise more paths sooner +#define TC_BackgroundWorkerTimeoutMs (100) +#define TC_CallCountThreshold (2) +#define TC_CallCountingDelayMs (1) +#define TC_DelaySingleProcMultiplier (2) +#define TC_DeleteCallCountingStubsAfter (1) +#else // !_DEBUG +#define TC_BackgroundWorkerTimeoutMs (4000) +#define TC_CallCountThreshold (30) +#define TC_CallCountingDelayMs (100) +#define TC_DelaySingleProcMultiplier (10) +#define TC_DeleteCallCountingStubsAfter (4096) +#endif // _DEBUG RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TieredCompilation, W("TieredCompilation"), 1, "Enables tiered compilation") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TC_QuickJit, W("TC_QuickJit"), 1, "For methods that would be jitted, enable using quick JIT when appropriate.") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TC_QuickJitForLoops, W("TC_QuickJitForLoops"), 0, "When quick JIT is enabled, quick JIT may also be used for methods that contain loops.") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TC_AggressiveTiering, W("TC_AggressiveTiering"), 0, "Transition through tiers aggressively.") -RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_BackgroundWorkerTimeoutMs, W("TC_BackgroundWorkerTimeoutMs"), 4000, "How long in milliseconds the background worker thread may remain idle before exiting.") -RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCountThreshold, W("TC_CallCountThreshold"), 30, "Number of times a method must be called in tier 0 after which it is promoted to the next tier.") -RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCountingDelayMs, W("TC_CallCountingDelayMs"), 100, "A perpetual delay in milliseconds that is applied call counting in tier 0 and jitting at higher tiers, while there is startup-like activity.") -RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_DelaySingleProcMultiplier, W("TC_DelaySingleProcMultiplier"), 10, "Multiplier for TC_CallCountingDelayMs that is applied on a single-processor machine or when the process is affinitized to a single processor.") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_BackgroundWorkerTimeoutMs, W("TC_BackgroundWorkerTimeoutMs"), TC_BackgroundWorkerTimeoutMs, "How long in milliseconds the background worker thread may remain idle before exiting.") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCountThreshold, W("TC_CallCountThreshold"), TC_CallCountThreshold, "Number of times a method must be called in tier 0 after which it is promoted to the next tier.") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCountingDelayMs, W("TC_CallCountingDelayMs"), TC_CallCountingDelayMs, "A perpetual delay in milliseconds that is applied call counting in tier 0 and jitting at higher tiers, while there is startup-like activity.") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_DelaySingleProcMultiplier, W("TC_DelaySingleProcMultiplier"), TC_DelaySingleProcMultiplier, "Multiplier for TC_CallCountingDelayMs that is applied on a single-processor machine or when the process is affinitized to a single processor.") RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCounting, W("TC_CallCounting"), 1, "Enabled by default (only activates when TieredCompilation is also enabled). If disabled immediately backpatches prestub, and likely prevents any promotion to higher tiers") RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_UseCallCountingStubs, W("TC_UseCallCountingStubs"), 1, "Uses call counting stubs for faster call counting.") -#ifdef _DEBUG -RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_DeleteCallCountingStubsAfter, W("TC_DeleteCallCountingStubsAfter"), 1, "Deletes call counting stubs after this many have completed. Zero to disable deleting.") -#else -RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_DeleteCallCountingStubsAfter, W("TC_DeleteCallCountingStubsAfter"), 4096, "Deletes call counting stubs after this many have completed. Zero to disable deleting.") -#endif +RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_DeleteCallCountingStubsAfter, W("TC_DeleteCallCountingStubsAfter"), TC_DeleteCallCountingStubsAfter, "Deletes call counting stubs after this many have completed. Zero to disable deleting.") +#undef TC_BackgroundWorkerTimeoutMs +#undef TC_CallCountThreshold +#undef TC_CallCountingDelayMs +#undef TC_DelaySingleProcMultiplier +#undef TC_DeleteCallCountingStubsAfter #endif // FEATURE_TIERED_COMPILATION /// From d910ce301fad2f8e8a4ff82ec7da658d7852b034 Mon Sep 17 00:00:00 2001 From: Steve Pfister Date: Tue, 25 Jan 2022 07:37:06 -0800 Subject: [PATCH 198/308] Skip tests using AsyncIO in FileSystemAclExtensionsTests where it's not supported (#64212) The mono runtime does not yet support AsyncIO on Windows and there were some tests failing on CI because of it. Fixes #64221 --- .../tests/FileSystemAclExtensionsTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs b/src/libraries/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs index 80eb1805310b5..5a525cf5f60e3 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs +++ b/src/libraries/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs @@ -409,7 +409,8 @@ from options in Enum.GetValues() where !(rights == FileSystemRights.CreateFiles && (mode == FileMode.Append || mode == FileMode.Create || mode == FileMode.CreateNew)) && !(mode == FileMode.Truncate && rights != FileSystemRights.Write) && - options != FileOptions.Encrypted // Using FileOptions.Encrypted throws UnauthorizedAccessException when attempting to read the created file + (options != FileOptions.Encrypted && // Using FileOptions.Encrypted throws UnauthorizedAccessException when attempting to read the created file + !(options == FileOptions.Asynchronous && !PlatformDetection.IsAsyncFileIOSupported))// Async IO not supported on Windows using Mono runtime https://github.com/dotnet/runtime/issues/34582 select new object[] { mode, rights, share, options }; [Theory] @@ -432,7 +433,8 @@ public static IEnumerable ReadRights_AllArguments_Data() => from rights in s_readableRights from share in Enum.GetValues() from options in Enum.GetValues() - where options != FileOptions.Encrypted // Using FileOptions.Encrypted throws UnauthorizedAccessException when attempting to read the created file + where options != FileOptions.Encrypted && // Using FileOptions.Encrypted throws UnauthorizedAccessException when attempting to read the created file + !(options == FileOptions.Asynchronous && !PlatformDetection.IsAsyncFileIOSupported) // Async IO not supported on Windows using Mono runtime https://github.com/dotnet/runtime/issues/34582 select new object[] { mode, rights, share, options }; [Theory] From 722ecced8963c83c315104513babd78620502db2 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Tue, 25 Jan 2022 10:40:34 -0600 Subject: [PATCH 199/308] Correct JsonNode.Root doc (#64238) --- .../System.Text.Json/src/System/Text/Json/Nodes/JsonNode.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.cs index cfe4a1130db3a..dc34dcfba8276 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.cs @@ -140,8 +140,10 @@ public string GetPath() /// /// Gets the root . - /// If the current is a root, is returned. /// + /// + /// The current node is returned if it is a root. + /// public JsonNode Root { get From 233c0644a472d95ac6f0418c2ee3020c1afd4187 Mon Sep 17 00:00:00 2001 From: Jo Shields Date: Tue, 25 Jan 2022 11:50:09 -0500 Subject: [PATCH 200/308] Take ARMv6 out of PlatformGroup All (#64267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Take ARMv6 out of PlatformGroup All, CoreCLR assumes this means full support Co-authored-by: Alexander Köplinger --- eng/pipelines/common/platform-matrix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index 0938ee359b4a4..4f0200380bc9f 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -53,7 +53,7 @@ jobs: ${{ insert }}: ${{ parameters.jobParameters }} # Linux armv6 -- ${{ if or(containsValue(parameters.platforms, 'Linux_armv6'), in(parameters.platformGroup, 'all', 'gcstress')) }}: +- ${{ if or(containsValue(parameters.platforms, 'Linux_armv6'), or(and(ne(parameters.runtimeFlavor, 'mono'), in(parameters.platformGroup, 'gcstress')), and(eq(parameters.runtimeFlavor, 'mono'), in(parameters.platformGroup, 'all', 'gcstress')))) }}: - template: xplat-setup.yml parameters: jobTemplate: ${{ parameters.jobTemplate }} From 74f5ca5a81e03accbaa571018350e781e093acdc Mon Sep 17 00:00:00 2001 From: Jo Shields Date: Tue, 25 Jan 2022 12:52:36 -0500 Subject: [PATCH 201/308] Only send to Helix for rolling build, due to small Helix queue (#64274) --- eng/pipelines/runtime-staging.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/eng/pipelines/runtime-staging.yml b/eng/pipelines/runtime-staging.yml index e06a9a6344d9b..c51d639d29f0f 100644 --- a/eng/pipelines/runtime-staging.yml +++ b/eng/pipelines/runtime-staging.yml @@ -261,18 +261,13 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true), eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isManualOrIsNotPR'], true), - eq(variables['isFullMatrix'], true)) - # extra steps, run tests - extraStepsTemplate: /eng/pipelines/libraries/helix.yml - extraStepsParameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - condition: >- - or( - eq(variables['librariesContainsChange'], true), - eq(variables['monoContainsChange'], true), eq(variables['isRollingBuild'], true)) + ${{ if eq(variables['isRollingBuild'], true) }}: + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Mono_$(_BuildConfig) # # Build the whole product using Mono and run runtime tests with the JIT. From aa1b4f8e4a029cea54e2a87c1ff027d5a20e323c Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Tue, 25 Jan 2022 13:15:47 -0500 Subject: [PATCH 202/308] Add ref field runtime feature indication (#64167) * Add ref field runtime feature indication Co-authored-by: Stephen Toub --- .../src/System/Runtime/CompilerServices/RuntimeFeature.cs | 6 ++++++ src/libraries/System.Runtime/ref/System.Runtime.cs | 1 + 2 files changed, 7 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs index a94a0e19d0176..9e0a5ed29e42e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs @@ -27,6 +27,11 @@ public static partial class RuntimeFeature /// public const string CovariantReturnsOfClasses = nameof(CovariantReturnsOfClasses); + /// + /// Represents a runtime feature where types can define ref fields. + /// + public const string ByRefFields = nameof(ByRefFields); + /// /// Indicates that this version of runtime supports virtual static members of interfaces. /// @@ -42,6 +47,7 @@ public static bool IsSupported(string feature) { case PortablePdb: case CovariantReturnsOfClasses: + case ByRefFields: case UnmanagedSignatureCallingConvention: case DefaultImplementationsOfInterfaces: #pragma warning disable CA2252 diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index ea9cc7ecc0180..b8b136aeb3b5a 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -13209,6 +13209,7 @@ public RuntimeCompatibilityAttribute() { } } public static partial class RuntimeFeature { + public const string ByRefFields = "ByRefFields"; public const string CovariantReturnsOfClasses = "CovariantReturnsOfClasses"; public const string DefaultImplementationsOfInterfaces = "DefaultImplementationsOfInterfaces"; public const string PortablePdb = "PortablePdb"; From 442a42147ef23c3b9742abcd8b997e8f472af68a Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Tue, 25 Jan 2022 21:54:35 +0300 Subject: [PATCH 203/308] Faster IndexOf for substrings (#63285) * Improve "lastChar == firstChar" case, also, use IndexOf directly if value.Length == 1 * Try plain IndexOf first, to optimize cases where even first char of value is never met * add 1-byte implementation * copyrights * fix copy-paste mistake * Initial LastIndexOf impl * More efficient LastIndexOf * fix bug in Char version (we need two clear two lowest bits in the mask) & temporarily remove AdvSimd impl * use ResetLowestSetBit * Fix bug * Add two-byte LastIndexOf * Fix build * Minor optimizations * optimize cases with two-byte/two-char values * Remove gotos, fix build * fix bug in LastIndexOf * Make sure String.LastIndexOf is optimized * Use xplat simd helpers - implicit ARM support * fix arm * Delete \ * Use Vector128.IsHardwareAccelerated * Fix build * Use IsAllZero * Address feedback * Address feedback * micro-optimization, do-while is better here since mask is guaranteed to be non-zero * Address feedabc * Use clever trick I borrowed from IndexOfAny for trailing elements * give up on +1 bump for SequenceCompare * Clean up * Clean up * fix build * Add debug asserts * Clean up: give up on the unrolled trick - too little value from code bloat * Add a test * Fix build * Add byte-specific test * Fix build * Update IndexOfSequence.byte.cs --- THIRD-PARTY-NOTICES.TXT | 29 ++ .../tests/Span/IndexOfSequence.byte.cs | 101 ++++++ .../tests/Span/IndexOfSequence.char.cs | 101 ++++++ .../src/System/MemoryExtensions.cs | 25 +- .../src/System/Numerics/BitOperations.cs | 20 ++ .../src/System/SpanHelpers.Byte.cs | 310 +++++++++++++++--- .../src/System/SpanHelpers.Char.cs | 299 ++++++++++++++++- .../src/System/SpanHelpers.T.cs | 10 +- 8 files changed, 833 insertions(+), 62 deletions(-) diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT index e38f6ef907d43..55329a8b02294 100644 --- a/THIRD-PARTY-NOTICES.TXT +++ b/THIRD-PARTY-NOTICES.TXT @@ -697,6 +697,35 @@ License for fastmod (https://github.com/lemire/fastmod) and ibm-fpgen (https://g See the License for the specific language governing permissions and limitations under the License. +License for sse4-strstr (https://github.com/WojciechMula/sse4-strstr) +-------------------------------------- + + Copyright (c) 2008-2016, Wojciech Muła + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + License notice for The C++ REST SDK ----------------------------------- diff --git a/src/libraries/System.Memory/tests/Span/IndexOfSequence.byte.cs b/src/libraries/System.Memory/tests/Span/IndexOfSequence.byte.cs index 33250569da2da..1a9027d0fc744 100644 --- a/src/libraries/System.Memory/tests/Span/IndexOfSequence.byte.cs +++ b/src/libraries/System.Memory/tests/Span/IndexOfSequence.byte.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using Xunit; +using System.Collections.Generic; +using System.Runtime.InteropServices; namespace System.SpanTests { @@ -115,5 +117,104 @@ public static void IndexOfSequenceLengthOneValueJustPasttVeryEnd_Byte() int index = span.IndexOf(value); Assert.Equal(-1, index); } + + public static IEnumerable IndexOfSubSeqData_Byte() + { + // searchSpace, value, expected IndexOf value, expected LastIndexOf value + yield return new object[] { new byte[]{0,0,0,0,0},new byte[]{0,0,0}, 0, 2}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0},new byte[]{0,71,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0},new byte[]{0,0,0}, 0, 7}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0},new byte[]{0,71,0,1,0}, 10, 10}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0},new byte[]{0,0,0,1,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0},new byte[]{0,0,0,1,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0},new byte[]{0,0,0,1,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0},new byte[]{0,71,1,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0},new byte[]{0,0,1,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0},new byte[]{0,0,1,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0},new byte[]{0,0,1,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0},new byte[]{0,1,0,0,0}, 12, 12}; + yield return new object[] { new byte[]{0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0},new byte[]{0,1,0,0,0}, 11, 11}; + yield return new object[] { new byte[]{0,0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0},new byte[]{0,1,0,0,0}, 6, 6}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,0,0,1,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,0,0,1,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,0,0,0,1,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,0,0,0,0,1,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,0,0,0,0,1,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,0,0,0,0,1,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,1,0,0,1,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,1,0,0,0,0,0}, 5, 5}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,1,0,0,0,0,0}, 5, 5}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1},new byte[]{0,1,0,0,0,0,0}, 5, 5}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0}, 0, 44}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0}, 0, 43}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0}, 7, 42}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0}, 7, 41}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0}, 7, 11}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,0}, 7, 10}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,0,0}, 7, 9}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,0,0,0,0}, 7, 7}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,1,0,0}, 5, 48}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,1,0}, 44, 44}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,1,0,0,0,0}, 5, 19}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,1,0,0,0,1,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0}, 7, 11}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,1,0,0,1,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,1,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,1,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,1,0,0,0,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{0,0,0,0,71,0,1,0,0,0,0,0,0,0,0,0,0,0,71,0,1,0,0,0,0,1,1,0,2,0,1,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,1,0},new byte[]{0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0}, -1, -1}; + yield return new object[] { new byte[]{159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133},new byte[]{159,133,159,133,159,133}, 0, 22}; + yield return new object[] { new byte[]{159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133},new byte[]{159,133,255,159,133}, -1, -1}; + yield return new object[] { new byte[]{159,133,159,133,159,133,159,133,159,133,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,160,86,160,86,160,86,160,86,160,80},new byte[]{160,86,160,86,160,86,160,86,160,80}, 40, 40}; + yield return new object[] { new byte[]{159,133,159,133,159,133,159,133,159,133,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,159,127,160,86,160,86,160,86,160,86,160,80,160,80,160,80,160,80,160,80,160,80,160,80,160,86,160,86,160,86,160,86},new byte[]{160,86,160,86,160,86,160,86}, 40, 62}; + yield return new object[] { new byte[]{159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133,159,133},new byte[]{0,0,0,1}, -1, -1}; + yield return new object[] { new byte[]{255,160,82,159,134,159,127,255,159,141,160,85,160,82,160,88,255,159,141,159,127,159,134,255,160,88,160,85,160,82,159,141,159,127,159,134,160,88,160,85,160,82,159,141,255,159,127,159,134,160,88,160,85,160,82,159,141,159,127,159,134,160,88,159,141,160,85,255,160,82,159,134,159,141,159,134,160,85,160,82,159,141,159,127,159,134,160,82,159,141,160,85,159,134,255,160,88,159,127,160,82,160,85,159,134,255,159,141,159,127,159,134,160,85,159,141},new byte[]{255,159,141,159,127,159,134,255}, 16, 16}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49,50},new byte[]{49,49}, 29, 29}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49},new byte[]{49,49}, 29, 29}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49,50},new byte[]{49,49}, 29, 29}; + yield return new object[] { new byte[]{49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,50},new byte[]{49,49}, -1, -1}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49,49},new byte[]{49,49,49}, 29, 29}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49,49,50},new byte[]{49,49,49}, 29, 29}; + yield return new object[] { new byte[]{49,49,49,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,50},new byte[]{49,49,49}, 0, 1}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49,50},new byte[]{48,48}, -1, -1}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49},new byte[]{48,48}, -1, -1}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49,50},new byte[]{48,48}, -1, -1}; + yield return new object[] { new byte[]{49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,50},new byte[]{48,48}, -1, -1}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49,49},new byte[]{48,48,48}, -1, -1}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49,49,50},new byte[]{48,48,48}, -1, -1}; + yield return new object[] { new byte[]{49,49,49,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,50},new byte[]{48,48,48}, -1, -1}; + yield return new object[] { new byte[]{48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,49,50},new byte[]{48,49,48,48}, -1, -1}; + yield return new object[] { new byte[]{49,48,49,49,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,50},new byte[]{49,48,49,49}, 0, 0}; + yield return new object[] { new byte[]{49,48,49,49,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,48,49,50},new byte[]{160,80,48,160,80,160,80}, -1, -1}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,48,49,49,49,49,49,49,49,49,49,49,49,49}, 0, 0}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,48,49,49,49,49,49,49,49,49,49,49,49,49}, 0, 15}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,48,49,49,49,49,49,49,49,49,49,49,49,49}, 0, 17}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,48,49,49,49,49,49,49,49,49,49,49,49,49}, 18, 32}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,49,49,49,49,49,49,49,49,49,49,49,49}, 20, 20}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49}, 0, 0}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49}, 0, 0}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49}, -1, -1}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49}, 0, 0}; + yield return new object[] { new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49},new byte[]{49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49}, 0, 0}; + yield return new object[] { new byte[]{71,71,71,71,71,71,71,71,71,71,71,71,71,71,49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71},new byte[]{71,71,71,71,71,71,71,71,71,71,71,71,71,71,71}, 60, 60}; + yield return new object[] { new byte[]{71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,49,48,49,49,49,49,49,49,71,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,49,48,49,49,49,49,49,49,49,49,49,49,49,49,71,71,71,71,71,71,71,71,71,71,71,71,71,71},new byte[]{71,71,71,71,71,71,71,71,71,71,71,71,71,71,71}, 0, 0}; + } + + [Theory] + [MemberData(nameof(IndexOfSubSeqData_Byte))] + public static void ValueStartsAndEndsWithTheSameBytes(byte[] searchSpace, byte[] value, int expectedIndexOfValue, int expectedLastIndexOfValue) + { + Assert.Equal(expectedIndexOfValue, searchSpace.AsSpan().IndexOf(value)); + Assert.Equal(expectedLastIndexOfValue, searchSpace.AsSpan().LastIndexOf(value)); + } } } diff --git a/src/libraries/System.Memory/tests/Span/IndexOfSequence.char.cs b/src/libraries/System.Memory/tests/Span/IndexOfSequence.char.cs index bda626153a5d0..b341a79c9b1f3 100644 --- a/src/libraries/System.Memory/tests/Span/IndexOfSequence.char.cs +++ b/src/libraries/System.Memory/tests/Span/IndexOfSequence.char.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using Xunit; +using System.Collections.Generic; +using System.Runtime.InteropServices; namespace System.SpanTests { @@ -115,5 +117,104 @@ public static void IndexOfSequenceLengthOneValueJustPasttVeryEnd_Char() int index = span.IndexOf(value); Assert.Equal(-1, index); } + + public static IEnumerable IndexOfSubSeqData_Char() + { + // searchSpace, value, expected IndexOf value, expected LastIndexOf value + yield return new object[] { "11111", "111", 0, 2 }; + yield return new object[] { "1111111111", "1x1", -1, -1 }; + yield return new object[] { "1111111111", "111", 0, 7 }; + yield return new object[] { "11111111111x12111", "1x121", 10, 10 }; + yield return new object[] { "11111111111x12111", "11121", -1, -1 }; + yield return new object[] { "1111111111x121111", "11121", -1, -1 }; + yield return new object[] { "11111x12111111111", "11121", -1, -1 }; + yield return new object[] { "11111111111x12111", "1x211", -1, -1 }; + yield return new object[] { "11111111111x12111", "11211", -1, -1 }; + yield return new object[] { "1111111111x121111", "11211", -1, -1 }; + yield return new object[] { "11111x12111111111", "11211", -1, -1 }; + yield return new object[] { "11111111111x12111", "12111", 12, 12 }; + yield return new object[] { "1111111111x121111", "12111", 11, 11 }; + yield return new object[] { "11111x12111111111", "12111", 6, 6 }; + yield return new object[] { "1111x1211111111111x12", "11121", -1, -1 }; + yield return new object[] { "1111x1211111111111x12", "11121", -1, -1 }; + yield return new object[] { "1111x1211111111111x12", "111121", -1, -1 }; + yield return new object[] { "1111x1211111111111x12", "1111121", -1, -1 }; + yield return new object[] { "1111x1211111111111x12", "1111121", -1, -1 }; + yield return new object[] { "1111x1211111111111x12", "1111121", -1, -1 }; + yield return new object[] { "1111x1211111111111x12", "1211211", -1, -1 }; + yield return new object[] { "1111x1211111111111x12", "1211111", 5, 5 }; + yield return new object[] { "1111x1211111111111x12", "1211111", 5, 5 }; + yield return new object[] { "1111x1211111111111x12", "1211111", 5, 5 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "111", 0, 44 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1111", 0, 43 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "11111", 7, 42 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "111111", 7, 41 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1111111", 7, 11 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "11111111", 7, 10 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "111111111", 7, 9 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "11111111111", 7, 7 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "111111111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1111111111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "11111111111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "111111111111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "11111111111111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "111111111111111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1211", 5, 48 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "11121", 44, 44 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "121111", 5, 19 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "12111211", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1111111", 7, 11 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1121121111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1111211111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "111111211111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1121111111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "11122111112111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1111111211111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "111211111111111111", -1, -1 }; + yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "11111211111121111111", -1, -1 }; + yield return new object[] { "жжжжжжжжжжжжжж", "жжж", 0, 11 }; + yield return new object[] { "жжжжжжжжжжжжжжжжжжжжжжжжжжжж", "ж0ж", -1, -1 }; + yield return new object[] { "жжжжжаааааааааааааааччччс", "ччччс", 20, 20 }; + yield return new object[] { "жжжжжаааааааааааааааччччсссссссчччч", "чччч", 20, 31 }; + yield return new object[] { "жжжжжжжжжжжжжжжжжжжжжжжжжжжж", "1112", -1, -1 }; + yield return new object[] { "0уза0оцущ0оаз0щцуоазщцуо0азщцуоазщоц0узозцуоазуоцз0щауцз0оазцо", "0оаз0", 9, 9 }; + yield return new object[] { "abababababababababababababababbc", "bb", 29, 29 }; + yield return new object[] { "abababababababababababababababb", "bb", 29, 29 }; + yield return new object[] { "abababababababababababababababbc", "bb", 29, 29 }; + yield return new object[] { "babababababababababababababababc", "bb", -1, -1 }; + yield return new object[] { "abababababababababababababababbb", "bbb", 29, 29 }; + yield return new object[] { "abababababababababababababababbbc", "bbb", 29, 29 }; + yield return new object[] { "bbbbabababababababababababababababc", "bbb", 0, 1 }; + yield return new object[] { "abababababababababababababababbc", "aa", -1, -1 }; + yield return new object[] { "abababababababababababababababb", "aa", -1, -1 }; + yield return new object[] { "abababababababababababababababbc", "aa", -1, -1 }; + yield return new object[] { "babababababababababababababababc", "aa", -1, -1 }; + yield return new object[] { "abababababababababababababababbb", "aaa", -1, -1 }; + yield return new object[] { "abababababababababababababababbbc", "aaa", -1, -1 }; + yield return new object[] { "bbbbabababababababababababababababc", "aaa", -1, -1 }; + yield return new object[] { "ababababababababababababababababbc", "abaa", -1, -1 }; + yield return new object[] { "babbbabababababababababababababababc", "babb", 0, 0 }; + yield return new object[] { "babbbabababababababababababababababc", "сaсс", -1, -1 }; + yield return new object[] { "babbbbbbbbbbbbb", "babbbbbbbbbbbb", 0, 0 }; + yield return new object[] { "babbbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbbbbbbb", 0, 15 }; + yield return new object[] { "babbbbbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbbbbbbb", 0, 17 }; + yield return new object[] { "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbbbbbbb", 18, 32 }; + yield return new object[] { "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbb", "bbbbbbbbbbbbb", 20, 20 }; + yield return new object[] { "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbb", 0, 0 }; + yield return new object[] { "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbb", 0, 0 }; + yield return new object[] { "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbbb", -1, -1 }; + yield return new object[] { "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbb", 0, 0 }; + yield return new object[] { "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbb", 0, 0 }; + yield return new object[] { "xxxxxxxxxxxxxxbabbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbbxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxx", 60, 60 }; + yield return new object[] { "xxxxxxxxxxxxxxxbabbbbbbxbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbbbbbbxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxx", 0, 0 }; + } + + [Theory] + [MemberData(nameof(IndexOfSubSeqData_Char))] + public static void ValueStartsAndEndsWithTheSameChars(string searchSpace, string value, int expectedIndexOfValue, int expectedLastIndexOfValue) + { + Assert.Equal(expectedIndexOfValue, searchSpace.AsSpan().IndexOf(value)); + Assert.Equal(expectedLastIndexOfValue, searchSpace.AsSpan().LastIndexOf(value)); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs index b49dea6f3638a..3c7c13fa645f0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs @@ -580,12 +580,25 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LastIndexOf(this ReadOnlySpan span, ReadOnlySpan value) where T : IEquatable { - if (Unsafe.SizeOf() == sizeof(byte) && RuntimeHelpers.IsBitwiseEquatable()) - return SpanHelpers.LastIndexOf( - ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - span.Length, - ref Unsafe.As(ref MemoryMarshal.GetReference(value)), - value.Length); + if (RuntimeHelpers.IsBitwiseEquatable()) + { + if (Unsafe.SizeOf() == sizeof(byte)) + { + return SpanHelpers.LastIndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + } + if (Unsafe.SizeOf() == sizeof(char)) + { + return SpanHelpers.LastIndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + } + } return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs index 6a7141cd01cd4..419a1c9f5f114 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs @@ -708,5 +708,25 @@ public static nuint RotateRight(nuint value, int offset) return (nuint)RotateRight((uint)value, offset); #endif } + + /// + /// Reset the lowest significant bit in the given value + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static uint ResetLowestSetBit(uint value) + { + // It's lowered to BLSR on x86 + return value & (value - 1); + } + + /// + /// Reset specific bit in the given value + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static uint ResetBit(uint value, int bitPos) + { + // TODO: Recognize BTR on x86 and LSL+BIC on ARM + return value & ~(uint)(1 << bitPos); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs index e94b1dfe672b2..3a3bc586912ae 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs @@ -22,12 +22,21 @@ public static int IndexOf(ref byte searchSpace, int searchSpaceLength, ref byte if (valueLength == 0) return 0; // A zero-length sequence is always treated as "found" at the start of the search space. - byte valueHead = value; - ref byte valueTail = ref Unsafe.Add(ref value, 1); int valueTailLength = valueLength - 1; - int remainingSearchSpaceLength = searchSpaceLength - valueTailLength; + if (valueTailLength == 0) + return IndexOf(ref searchSpace, value, searchSpaceLength); // for single-byte values use plain IndexOf int offset = 0; + byte valueHead = value; + int searchSpaceMinusValueTailLength = searchSpaceLength - valueTailLength; + if (Vector128.IsHardwareAccelerated && searchSpaceMinusValueTailLength >= Vector128.Count) + { + goto SEARCH_TWO_BYTES; + } + + ref byte valueTail = ref Unsafe.Add(ref value, 1); + int remainingSearchSpaceLength = searchSpaceMinusValueTailLength; + while (remainingSearchSpaceLength > 0) { // Do a quick search for the first element of "value". @@ -42,13 +51,264 @@ public static int IndexOf(ref byte searchSpace, int searchSpaceLength, ref byte break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. // Found the first element of "value". See if the tail matches. - if (SequenceEqual(ref Unsafe.Add(ref searchSpace, offset + 1), ref valueTail, (nuint)valueTailLength)) // The (nuint)-cast is necessary to pick the correct overload + if (SequenceEqual( + ref Unsafe.Add(ref searchSpace, offset + 1), + ref valueTail, (nuint)(uint)valueTailLength)) // The (nuint)-cast is necessary to pick the correct overload return offset; // The tail matched. Return a successful find. remainingSearchSpaceLength--; offset++; } return -1; + + // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Muła + // Some details about the implementation can also be found in https://github.com/dotnet/runtime/pull/63285 + SEARCH_TWO_BYTES: + if (Avx2.IsSupported && searchSpaceMinusValueTailLength - Vector256.Count >= 0) + { + // Find the last unique (which is not equal to ch1) byte + // the algorithm is fine if both are equal, just a little bit less efficient + byte ch2Val = Unsafe.Add(ref value, valueTailLength); + int ch1ch2Distance = valueTailLength; + while (ch2Val == value && ch1ch2Distance > 1) + ch2Val = Unsafe.Add(ref value, --ch1ch2Distance); + + Vector256 ch1 = Vector256.Create(value); + Vector256 ch2 = Vector256.Create(ch2Val); + + do + { + Debug.Assert(offset >= 0); + // Make sure we don't go out of bounds + Debug.Assert(offset + ch1ch2Distance + Vector256.Count <= searchSpaceLength); + + Vector256 cmpCh1 = Vector256.Equals(ch1, Vector256.LoadUnsafe(ref searchSpace, (nuint)offset)); + Vector256 cmpCh2 = Vector256.Equals(ch2, Vector256.LoadUnsafe(ref searchSpace, (nuint)(offset + ch1ch2Distance))); + Vector256 cmpAnd = (cmpCh1 & cmpCh2).AsByte(); + + // Early out: cmpAnd is all zeros + if (cmpAnd != Vector256.Zero) + { + uint mask = cmpAnd.ExtractMostSignificantBits(); + do + { + int bitPos = BitOperations.TrailingZeroCount(mask); + if (valueLength == 2 || // we already matched two bytes + SequenceEqual( + ref Unsafe.Add(ref searchSpace, offset + bitPos), + ref value, (nuint)(uint)valueLength)) // The (nuint)-cast is necessary to pick the correct overload + { + return offset + bitPos; + } + mask = BitOperations.ResetLowestSetBit(mask); // Clear the lowest set bit + } while (mask != 0); + } + offset += Vector256.Count; + + if (offset == searchSpaceMinusValueTailLength) + return -1; + + // Overlap with the current chunk for trailing elements + if (offset > searchSpaceMinusValueTailLength - Vector256.Count) + offset = searchSpaceMinusValueTailLength - Vector256.Count; + } while (true); + } + else // 128bit vector path (SSE2 or AdvSimd) + { + // Find the last unique (which is not equal to ch1) byte + // the algorithm is fine if both are equal, just a little bit less efficient + byte ch2Val = Unsafe.Add(ref value, valueTailLength); + int ch1ch2Distance = valueTailLength; + while (ch2Val == value && ch1ch2Distance > 1) + ch2Val = Unsafe.Add(ref value, --ch1ch2Distance); + + Vector128 ch1 = Vector128.Create(value); + Vector128 ch2 = Vector128.Create(ch2Val); + + do + { + Debug.Assert(offset >= 0); + // Make sure we don't go out of bounds + Debug.Assert(offset + ch1ch2Distance + Vector128.Count <= searchSpaceLength); + + Vector128 cmpCh1 = Vector128.Equals(ch1, Vector128.LoadUnsafe(ref searchSpace, (nuint)offset)); + Vector128 cmpCh2 = Vector128.Equals(ch2, Vector128.LoadUnsafe(ref searchSpace, (nuint)(offset + ch1ch2Distance))); + Vector128 cmpAnd = (cmpCh1 & cmpCh2).AsByte(); + + // Early out: cmpAnd is all zeros + if (cmpAnd != Vector128.Zero) + { + uint mask = cmpAnd.ExtractMostSignificantBits(); + do + { + int bitPos = BitOperations.TrailingZeroCount(mask); + if (valueLength == 2 || // we already matched two bytes + SequenceEqual( + ref Unsafe.Add(ref searchSpace, offset + bitPos), + ref value, (nuint)(uint)valueLength)) // The (nuint)-cast is necessary to pick the correct overload + { + return offset + bitPos; + } + // Clear the lowest set bit + mask = BitOperations.ResetLowestSetBit(mask); + } while (mask != 0); + } + offset += Vector128.Count; + + if (offset == searchSpaceMinusValueTailLength) + return -1; + + // Overlap with the current chunk for trailing elements + if (offset > searchSpaceMinusValueTailLength - Vector128.Count) + offset = searchSpaceMinusValueTailLength - Vector128.Count; + } while (true); + } + } + + public static int LastIndexOf(ref byte searchSpace, int searchSpaceLength, ref byte value, int valueLength) + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return searchSpaceLength; // A zero-length sequence is always treated as "found" at the end of the search space. + + int valueTailLength = valueLength - 1; + if (valueTailLength == 0) + return LastIndexOf(ref searchSpace, value, searchSpaceLength); // for single-byte values use plain LastIndexOf + + int offset = 0; + byte valueHead = value; + int searchSpaceMinusValueTailLength = searchSpaceLength - valueTailLength; + if (Vector128.IsHardwareAccelerated && searchSpaceMinusValueTailLength >= Vector128.Count) + { + goto SEARCH_TWO_BYTES; + } + + ref byte valueTail = ref Unsafe.Add(ref value, 1); + + while (true) + { + Debug.Assert(0 <= offset && offset <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". + int remainingSearchSpaceLength = searchSpaceLength - offset - valueTailLength; + if (remainingSearchSpaceLength <= 0) + break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. + + // Do a quick search for the first element of "value". + int relativeIndex = LastIndexOf(ref searchSpace, valueHead, remainingSearchSpaceLength); + if (relativeIndex < 0) + break; + + // Found the first element of "value". See if the tail matches. + if (SequenceEqual( + ref Unsafe.Add(ref searchSpace, relativeIndex + 1), + ref valueTail, (nuint)(uint)valueTailLength)) // The (nuint)-cast is necessary to pick the correct overload + return relativeIndex; // The tail matched. Return a successful find. + + offset += remainingSearchSpaceLength - relativeIndex; + } + return -1; + + // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Muła + // Some details about the implementation can also be found in https://github.com/dotnet/runtime/pull/63285 + SEARCH_TWO_BYTES: + if (Avx2.IsSupported && searchSpaceMinusValueTailLength >= Vector256.Count) + { + offset = searchSpaceMinusValueTailLength - Vector256.Count; + + // Find the last unique (which is not equal to ch1) byte + // the algorithm is fine if both are equal, just a little bit less efficient + byte ch2Val = Unsafe.Add(ref value, valueTailLength); + int ch1ch2Distance = valueTailLength; + while (ch2Val == value && ch1ch2Distance > 1) + ch2Val = Unsafe.Add(ref value, --ch1ch2Distance); + + Vector256 ch1 = Vector256.Create(value); + Vector256 ch2 = Vector256.Create(ch2Val); + do + { + Vector256 cmpCh1 = Vector256.Equals(ch1, Vector256.LoadUnsafe(ref searchSpace, (nuint)offset)); + Vector256 cmpCh2 = Vector256.Equals(ch2, Vector256.LoadUnsafe(ref searchSpace, (nuint)(offset + ch1ch2Distance))); + Vector256 cmpAnd = (cmpCh1 & cmpCh2).AsByte(); + + // Early out: cmpAnd is all zeros + if (cmpAnd != Vector256.Zero) + { + uint mask = cmpAnd.ExtractMostSignificantBits(); + do + { + // unlike IndexOf, here we use LZCNT to process matches starting from the end + int bitPos = 31 - BitOperations.LeadingZeroCount(mask); + if (valueLength == 2 || // we already matched two bytes + SequenceEqual( + ref Unsafe.Add(ref searchSpace, offset + bitPos), + ref value, (nuint)(uint)valueLength)) // The (nuint)-cast is necessary to pick the correct overload + { + return bitPos + offset; + } + // Clear the highest set bit. + mask = BitOperations.ResetBit(mask, bitPos); + } while (mask != 0); + } + + offset -= Vector256.Count; + if (offset == -Vector256.Count) + return -1; + // Overlap with the current chunk if there is not enough room for the next one + if (offset < 0) + offset = 0; + } while (true); + } + else // 128bit vector path (SSE2 or AdvSimd) + { + offset = searchSpaceMinusValueTailLength - Vector128.Count; + + // Find the last unique (which is not equal to ch1) byte + // the algorithm is fine if both are equal, just a little bit less efficient + byte ch2Val = Unsafe.Add(ref value, valueTailLength); + int ch1ch2Distance = valueTailLength; + while (ch2Val == value && ch1ch2Distance > 1) + ch2Val = Unsafe.Add(ref value, --ch1ch2Distance); + + Vector128 ch1 = Vector128.Create(value); + Vector128 ch2 = Vector128.Create(ch2Val); + + do + { + Vector128 cmpCh1 = Vector128.Equals(ch1, Vector128.LoadUnsafe(ref searchSpace, (nuint)offset)); + Vector128 cmpCh2 = Vector128.Equals(ch2, Vector128.LoadUnsafe(ref searchSpace, (nuint)(offset + ch1ch2Distance))); + Vector128 cmpAnd = (cmpCh1 & cmpCh2).AsByte(); + + // Early out: cmpAnd is all zeros + // it's especially important for ARM where ExtractMostSignificantBits is not cheap + if (cmpAnd != Vector128.Zero) + { + uint mask = cmpAnd.ExtractMostSignificantBits(); + do + { + // unlike IndexOf, here we use LZCNT to process matches starting from the end + int bitPos = 31 - BitOperations.LeadingZeroCount(mask); + if (valueLength == 2 || // we already matched two bytes + SequenceEqual( + ref Unsafe.Add(ref searchSpace, offset + bitPos), + ref value, (nuint)(uint)valueLength)) // The (nuint)-cast is necessary to pick the correct overload + { + return bitPos + offset; + } + // Clear the highest set bit. + mask = BitOperations.ResetBit(mask, bitPos); + } while (mask != 0); + } + + offset -= Vector128.Count; + if (offset == -Vector128.Count) + return -1; + // Overlap with the current chunk if there is not enough room for the next one + if (offset < 0) + offset = 0; + + } while (true); + } } // Adapted from IndexOf(...) @@ -408,40 +668,6 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) return (int)(offset + 7); } - public static int LastIndexOf(ref byte searchSpace, int searchSpaceLength, ref byte value, int valueLength) - { - Debug.Assert(searchSpaceLength >= 0); - Debug.Assert(valueLength >= 0); - - if (valueLength == 0) - return searchSpaceLength; // A zero-length sequence is always treated as "found" at the end of the search space. - - byte valueHead = value; - ref byte valueTail = ref Unsafe.Add(ref value, 1); - int valueTailLength = valueLength - 1; - - int offset = 0; - while (true) - { - Debug.Assert(0 <= offset && offset <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". - int remainingSearchSpaceLength = searchSpaceLength - offset - valueTailLength; - if (remainingSearchSpaceLength <= 0) - break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. - - // Do a quick search for the first element of "value". - int relativeIndex = LastIndexOf(ref searchSpace, valueHead, remainingSearchSpaceLength); - if (relativeIndex < 0) - break; - - // Found the first element of "value". See if the tail matches. - if (SequenceEqual(ref Unsafe.Add(ref searchSpace, relativeIndex + 1), ref valueTail, (nuint)(uint)valueTailLength)) // The (nunit)-cast is necessary to pick the correct overload - return relativeIndex; // The tail matched. Return a successful find. - - offset += remainingSearchSpaceLength - relativeIndex; - } - return -1; - } - [MethodImpl(MethodImplOptions.AggressiveOptimization)] public static int LastIndexOf(ref byte searchSpace, byte value, int length) { @@ -1564,13 +1790,11 @@ public static unsafe bool SequenceEqual(ref byte first, ref byte second, nuint l // This becomes a conditional jmp foward to not favor it. goto NotEqual; } - // Use Vector128.Size as Vector128.Count doesn't inline at R2R time - // https://github.com/dotnet/runtime/issues/32714 - else if (length >= Vector128.Size) + else if (length >= (nuint)Vector128.Count) { Vector128 vecResult; nuint offset = 0; - nuint lengthToExamine = length - Vector128.Size; + nuint lengthToExamine = length - (nuint)Vector128.Count; // Unsigned, so it shouldn't have overflowed larger than length (rather than negative) Debug.Assert(lengthToExamine < length); if (lengthToExamine != 0) @@ -1584,7 +1808,7 @@ public static unsafe bool SequenceEqual(ref byte first, ref byte second, nuint l { goto NotEqual; } - offset += Vector128.Size; + offset += (nuint)Vector128.Count; } while (lengthToExamine > offset); } diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs index 753e5301b503b..fb00b062538f2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs @@ -22,38 +22,315 @@ public static int IndexOf(ref char searchSpace, int searchSpaceLength, ref char if (valueLength == 0) return 0; // A zero-length sequence is always treated as "found" at the start of the search space. - char valueHead = value; - ref char valueTail = ref Unsafe.Add(ref value, 1); int valueTailLength = valueLength - 1; - int remainingSearchSpaceLength = searchSpaceLength - valueTailLength; + if (valueTailLength == 0) + { + // for single-char values use plain IndexOf + return IndexOf(ref searchSpace, value, searchSpaceLength); + } + + int offset = 0; + char valueHead = value; + int searchSpaceMinusValueTailLength = searchSpaceLength - valueTailLength; + if (Vector128.IsHardwareAccelerated && searchSpaceMinusValueTailLength >= Vector128.Count) + { + goto SEARCH_TWO_CHARS; + } + + ref byte valueTail = ref Unsafe.As(ref Unsafe.Add(ref value, 1)); + int remainingSearchSpaceLength = searchSpaceMinusValueTailLength; - int index = 0; while (remainingSearchSpaceLength > 0) { // Do a quick search for the first element of "value". - int relativeIndex = IndexOf(ref Unsafe.Add(ref searchSpace, index), valueHead, remainingSearchSpaceLength); + int relativeIndex = IndexOf(ref Unsafe.Add(ref searchSpace, offset), valueHead, remainingSearchSpaceLength); if (relativeIndex < 0) break; remainingSearchSpaceLength -= relativeIndex; - index += relativeIndex; + offset += relativeIndex; if (remainingSearchSpaceLength <= 0) break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. // Found the first element of "value". See if the tail matches. if (SequenceEqual( - ref Unsafe.As(ref Unsafe.Add(ref searchSpace, index + 1)), - ref Unsafe.As(ref valueTail), - (nuint)(uint)valueTailLength * 2)) + ref Unsafe.As(ref Unsafe.Add(ref searchSpace, offset + 1)), + ref valueTail, + (nuint)(uint)valueTailLength * 2)) { - return index; // The tail matched. Return a successful find. + return offset; // The tail matched. Return a successful find. } remainingSearchSpaceLength--; - index++; + offset++; } return -1; + + // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Muła + // Some details about the implementation can also be found in https://github.com/dotnet/runtime/pull/63285 + SEARCH_TWO_CHARS: + if (Avx2.IsSupported && searchSpaceMinusValueTailLength - Vector256.Count >= 0) + { + // Find the last unique (which is not equal to ch1) character + // the algorithm is fine if both are equal, just a little bit less efficient + ushort ch2Val = Unsafe.Add(ref value, valueTailLength); + int ch1ch2Distance = valueTailLength; + while (ch2Val == valueHead && ch1ch2Distance > 1) + ch2Val = Unsafe.Add(ref value, --ch1ch2Distance); + + Vector256 ch1 = Vector256.Create((ushort)valueHead); + Vector256 ch2 = Vector256.Create(ch2Val); + + do + { + // Make sure we don't go out of bounds + Debug.Assert(offset + ch1ch2Distance + Vector256.Count <= searchSpaceLength); + + Vector256 cmpCh1 = Vector256.Equals(ch1, LoadVector256(ref searchSpace, offset)); + Vector256 cmpCh2 = Vector256.Equals(ch2, LoadVector256(ref searchSpace, offset + ch1ch2Distance)); + Vector256 cmpAnd = (cmpCh1 & cmpCh2).AsByte(); + + // Early out: cmpAnd is all zeros + if (cmpAnd != Vector256.Zero) + { + uint mask = cmpAnd.ExtractMostSignificantBits(); + do + { + int bitPos = BitOperations.TrailingZeroCount(mask); + // div by 2 (shr) because we work with 2-byte chars + int charPos = (int)((uint)bitPos / 2); + if (valueLength == 2 || // we already matched two chars + SequenceEqual( + ref Unsafe.As(ref Unsafe.Add(ref searchSpace, offset + charPos)), + ref Unsafe.As(ref value), (nuint)(uint)valueLength * 2)) + { + return offset + charPos; + } + + // Clear two the lowest set bits + if (Bmi1.IsSupported) + mask = Bmi1.ResetLowestSetBit(Bmi1.ResetLowestSetBit(mask)); + else + mask &= ~(uint)(0b11 << bitPos); + } while (mask != 0); + } + offset += Vector256.Count; + + if (offset == searchSpaceMinusValueTailLength) + return -1; + + // Overlap with the current chunk for trailing elements + if (offset > searchSpaceMinusValueTailLength - Vector256.Count) + offset = searchSpaceMinusValueTailLength - Vector256.Count; + } while (true); + } + else // 128bit vector path (SSE2 or AdvSimd) + { + // Find the last unique (which is not equal to ch1) character + // the algorithm is fine if both are equal, just a little bit less efficient + ushort ch2Val = Unsafe.Add(ref value, valueTailLength); + int ch1ch2Distance = valueTailLength; + while (ch2Val == valueHead && ch1ch2Distance > 1) + ch2Val = Unsafe.Add(ref value, --ch1ch2Distance); + + Vector128 ch1 = Vector128.Create((ushort)valueHead); + Vector128 ch2 = Vector128.Create(ch2Val); + + do + { + // Make sure we don't go out of bounds + Debug.Assert(offset + ch1ch2Distance + Vector128.Count <= searchSpaceLength); + + Vector128 cmpCh1 = Vector128.Equals(ch1, LoadVector128(ref searchSpace, offset)); + Vector128 cmpCh2 = Vector128.Equals(ch2, LoadVector128(ref searchSpace, offset + ch1ch2Distance)); + Vector128 cmpAnd = (cmpCh1 & cmpCh2).AsByte(); + + // Early out: cmpAnd is all zeros + if (cmpAnd != Vector128.Zero) + { + uint mask = cmpAnd.ExtractMostSignificantBits(); + do + { + int bitPos = BitOperations.TrailingZeroCount(mask); + // div by 2 (shr) because we work with 2-byte chars + int charPos = (int)((uint)bitPos / 2); + if (valueLength == 2 || // we already matched two chars + SequenceEqual( + ref Unsafe.As(ref Unsafe.Add(ref searchSpace, offset + charPos)), + ref Unsafe.As(ref value), (nuint)(uint)valueLength * 2)) + { + return offset + charPos; + } + + // Clear two lowest set bits + if (Bmi1.IsSupported) + mask = Bmi1.ResetLowestSetBit(Bmi1.ResetLowestSetBit(mask)); + else + mask &= ~(uint)(0b11 << bitPos); + } while (mask != 0); + } + offset += Vector128.Count; + + if (offset == searchSpaceMinusValueTailLength) + return -1; + + // Overlap with the current chunk for trailing elements + if (offset > searchSpaceMinusValueTailLength - Vector128.Count) + offset = searchSpaceMinusValueTailLength - Vector128.Count; + } while (true); + } + } + + public static int LastIndexOf(ref char searchSpace, int searchSpaceLength, ref char value, int valueLength) + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return searchSpaceLength; // A zero-length sequence is always treated as "found" at the end of the search space. + + int valueTailLength = valueLength - 1; + if (valueTailLength == 0) + return LastIndexOf(ref searchSpace, value, searchSpaceLength); // for single-char values use plain LastIndexOf + + int offset = 0; + char valueHead = value; + int searchSpaceMinusValueTailLength = searchSpaceLength - valueTailLength; + if (Vector128.IsHardwareAccelerated && searchSpaceMinusValueTailLength >= Vector128.Count) + { + goto SEARCH_TWO_CHARS; + } + + ref byte valueTail = ref Unsafe.As(ref Unsafe.Add(ref value, 1)); + + while (true) + { + Debug.Assert(0 <= offset && offset <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". + int remainingSearchSpaceLength = searchSpaceLength - offset - valueTailLength; + if (remainingSearchSpaceLength <= 0) + break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. + + // Do a quick search for the first element of "value". + int relativeIndex = LastIndexOf(ref searchSpace, valueHead, remainingSearchSpaceLength); + if (relativeIndex == -1) + break; + + // Found the first element of "value". See if the tail matches. + if (SequenceEqual( + ref Unsafe.As(ref Unsafe.Add(ref searchSpace, relativeIndex + 1)), + ref valueTail, (nuint)(uint)valueTailLength * 2)) + { + return relativeIndex; // The tail matched. Return a successful find. + } + + offset += remainingSearchSpaceLength - relativeIndex; + } + return -1; + + // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Muła + // Some details about the implementation can also be found in https://github.com/dotnet/runtime/pull/63285 + SEARCH_TWO_CHARS: + if (Avx2.IsSupported && searchSpaceMinusValueTailLength >= Vector256.Count) + { + offset = searchSpaceMinusValueTailLength - Vector256.Count; + + // Find the last unique (which is not equal to ch1) char + // the algorithm is fine if both are equal, just a little bit less efficient + char ch2Val = Unsafe.Add(ref value, valueTailLength); + int ch1ch2Distance = valueTailLength; + while (ch2Val == valueHead && ch1ch2Distance > 1) + ch2Val = Unsafe.Add(ref value, --ch1ch2Distance); + + Vector256 ch1 = Vector256.Create((ushort)valueHead); + Vector256 ch2 = Vector256.Create((ushort)ch2Val); + + do + { + + Vector256 cmpCh1 = Vector256.Equals(ch1, LoadVector256(ref searchSpace, (nuint)offset)); + Vector256 cmpCh2 = Vector256.Equals(ch2, LoadVector256(ref searchSpace, (nuint)(offset + ch1ch2Distance))); + Vector256 cmpAnd = (cmpCh1 & cmpCh2).AsByte(); + + // Early out: cmpAnd is all zeros + if (cmpAnd != Vector256.Zero) + { + uint mask = cmpAnd.ExtractMostSignificantBits(); + do + { + // unlike IndexOf, here we use LZCNT to process matches starting from the end + int bitPos = 30 - BitOperations.LeadingZeroCount(mask); + int charPos = (int)((uint)bitPos / 2); + + if (valueLength == 2 || // we already matched two chars + SequenceEqual( + ref Unsafe.As(ref Unsafe.Add(ref searchSpace, offset + charPos)), + ref Unsafe.As(ref value), (nuint)(uint)valueLength * 2)) + { + return charPos + offset; + } + mask &= ~(uint)(0b11 << bitPos); // clear two highest set bits. + } while (mask != 0); + } + + offset -= Vector256.Count; + if (offset == -Vector256.Count) + return -1; + // Overlap with the current chunk if there is not enough room for the next one + if (offset < 0) + offset = 0; + } while (true); + } + else // 128bit vector path (SSE2 or AdvSimd) + { + offset = searchSpaceMinusValueTailLength - Vector128.Count; + + // Find the last unique (which is not equal to ch1) char + // the algorithm is fine if both are equal, just a little bit less efficient + char ch2Val = Unsafe.Add(ref value, valueTailLength); + int ch1ch2Distance = valueTailLength; + while (ch2Val == value && ch1ch2Distance > 1) + ch2Val = Unsafe.Add(ref value, --ch1ch2Distance); + + Vector128 ch1 = Vector128.Create((ushort)value); + Vector128 ch2 = Vector128.Create((ushort)ch2Val); + + do + { + Vector128 cmpCh1 = Vector128.Equals(ch1, LoadVector128(ref searchSpace, (nuint)offset)); + Vector128 cmpCh2 = Vector128.Equals(ch2, LoadVector128(ref searchSpace, (nuint)(offset + ch1ch2Distance))); + Vector128 cmpAnd = (cmpCh1 & cmpCh2).AsByte(); + + // Early out: cmpAnd is all zeros + // it's especially important for ARM where ExtractMostSignificantBits is not cheap + if (cmpAnd != Vector128.Zero) + { + uint mask = cmpAnd.ExtractMostSignificantBits(); + do + { + // unlike IndexOf, here we use LZCNT to process matches starting from the end + int bitPos = 30 - BitOperations.LeadingZeroCount(mask); + int charPos = (int)((uint)bitPos / 2); + + if (valueLength == 2 || // we already matched two chars + SequenceEqual( + ref Unsafe.As(ref Unsafe.Add(ref searchSpace, offset + charPos)), + ref Unsafe.As(ref value), (nuint)(uint)valueLength * 2)) + { + return charPos + offset; + } + mask &= ~(uint)(0b11 << bitPos); // clear two the highest set bits. + } while (mask != 0); + } + + offset -= Vector128.Count; + if (offset == -Vector128.Count) + return -1; + // Overlap with the current chunk if there is not enough room for the next one + if (offset < 0) + offset = 0; + } while (true); + } } [MethodImpl(MethodImplOptions.AggressiveOptimization)] diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs index 91d2a34a47796..27944aff4876c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs @@ -774,11 +774,17 @@ public static int LastIndexOf(ref T searchSpace, int searchSpaceLength, ref T if (valueLength == 0) return searchSpaceLength; // A zero-length sequence is always treated as "found" at the end of the search space. - T valueHead = value; - ref T valueTail = ref Unsafe.Add(ref value, 1); int valueTailLength = valueLength - 1; + if (valueTailLength == 0) + { + return LastIndexOf(ref searchSpace, value, searchSpaceLength); + } int index = 0; + + T valueHead = value; + ref T valueTail = ref Unsafe.Add(ref value, 1); + while (true) { Debug.Assert(0 <= index && index <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". From 4e165d3cc623282baa627ae468220c00f71626c6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 25 Jan 2022 14:46:37 -0500 Subject: [PATCH 204/308] [main] Update dependencies from dotnet/arcade dotnet/xharness dotnet/icu dotnet/hotreload-utils dotnet/llvm-project (#64265) * Update dependencies from https://github.com/dotnet/arcade build 20220124.13 Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.ApiCompat , Microsoft.DotNet.XUnitExtensions , Microsoft.DotNet.GenAPI , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.GenFacades , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.Helix.Sdk From Version 2.5.1-beta.22071.6 -> To Version 2.5.1-beta.22074.13 * Update dependencies from https://github.com/dotnet/xharness build 20220124.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 1.0.0-prerelease.22071.1 -> To Version 1.0.0-prerelease.22074.1 * Update dependencies from https://github.com/dotnet/icu build 20220124.5 Microsoft.NETCore.Runtime.ICU.Transport From Version 7.0.0-preview.2.22071.2 -> To Version 7.0.0-preview.2.22074.5 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20220124.1 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 1.0.2-alpha.0.22069.1 -> To Version 1.0.2-alpha.0.22074.1 * Update dependencies from https://github.com/dotnet/llvm-project build 20220124.2 runtime.win-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools , runtime.win-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk , runtime.linux-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk , runtime.linux-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools , runtime.linux-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk , runtime.linux-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools , runtime.osx.10.12-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk , runtime.osx.10.12-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools From Version 11.1.0-alpha.1.22067.2 -> To Version 11.1.0-alpha.1.22074.2 Co-authored-by: dotnet-maestro[bot] --- .config/dotnet-tools.json | 2 +- eng/Version.Details.xml | 128 +++++++++--------- eng/Versions.props | 56 ++++---- eng/common/templates/job/execute-sdl.yml | 10 +- eng/common/templates/job/onelocbuild.yml | 19 ++- eng/common/templates/jobs/jobs.yml | 10 +- .../templates/post-build/post-build.yml | 42 ++++-- .../post-build/setup-maestro-vars.yml | 1 + global.json | 8 +- 9 files changed, 162 insertions(+), 114 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 26dc5ae6a75f4..f6ec0a4e1da7e 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "1.0.0-prerelease.22071.1", + "version": "1.0.0-prerelease.22074.1", "commands": [ "xharness" ] diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b01aa4c37ed5b..0e09fa1f297b3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/icu - 8a4a45cc99e7d6e5244c16f581171633091b96b3 + 80a658fa6aa6601d67bfe5a294e0d1b7e1184a5c https://github.com/dotnet/msquic @@ -50,77 +50,77 @@ - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 https://github.com/microsoft/vstest @@ -170,37 +170,37 @@ https://github.com/dotnet/runtime-assets a597df23119faf540d95cebab14b82f084c47384 - + https://github.com/dotnet/llvm-project - 79a6d232058e2c2f1d9e833355b72f07fe342a3b + 44adf6c047663fe20c388bfb769e18dd3c91f7e0 - + https://github.com/dotnet/llvm-project - 79a6d232058e2c2f1d9e833355b72f07fe342a3b + 44adf6c047663fe20c388bfb769e18dd3c91f7e0 - + https://github.com/dotnet/llvm-project - 79a6d232058e2c2f1d9e833355b72f07fe342a3b + 44adf6c047663fe20c388bfb769e18dd3c91f7e0 - + https://github.com/dotnet/llvm-project - 79a6d232058e2c2f1d9e833355b72f07fe342a3b + 44adf6c047663fe20c388bfb769e18dd3c91f7e0 - + https://github.com/dotnet/llvm-project - 79a6d232058e2c2f1d9e833355b72f07fe342a3b + 44adf6c047663fe20c388bfb769e18dd3c91f7e0 - + https://github.com/dotnet/llvm-project - 79a6d232058e2c2f1d9e833355b72f07fe342a3b + 44adf6c047663fe20c388bfb769e18dd3c91f7e0 - + https://github.com/dotnet/llvm-project - 79a6d232058e2c2f1d9e833355b72f07fe342a3b + 44adf6c047663fe20c388bfb769e18dd3c91f7e0 - + https://github.com/dotnet/llvm-project - 79a6d232058e2c2f1d9e833355b72f07fe342a3b + 44adf6c047663fe20c388bfb769e18dd3c91f7e0 https://github.com/dotnet/runtime @@ -238,21 +238,21 @@ https://github.com/dotnet/linker e485816b48273d03bd6266a64dad9bea97f861d5 - + https://github.com/dotnet/xharness - bd2a12f9cc6c93c249f987b42c1c761550369674 + 0137095821e2e5a9e030d97248503387b8d72a18 - + https://github.com/dotnet/xharness - bd2a12f9cc6c93c249f987b42c1c761550369674 + 0137095821e2e5a9e030d97248503387b8d72a18 - + https://github.com/dotnet/xharness - bd2a12f9cc6c93c249f987b42c1c761550369674 + 0137095821e2e5a9e030d97248503387b8d72a18 - + https://github.com/dotnet/arcade - e1ea8873d2e0175c1d1e49b3884cd2e9c6ef5007 + b6483cac5832aa5207692517f9a49ce1741a3041 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -270,9 +270,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 91d6b3c1f51888d166701510189505f35714665c - + https://github.com/dotnet/hotreload-utils - b6504c8dca937ff1a59d3283374241eacf26684a + d3e96c2e8ed4d58de217c44423c9ba3b90333724 https://github.com/dotnet/runtime-assets diff --git a/eng/Versions.props b/eng/Versions.props index 535f0f7e4f01e..5beaf9c02f194 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -54,21 +54,21 @@ 2.0.0-alpha.1.21525.11 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 2.5.1-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 - 7.0.0-beta.22071.6 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 2.5.1-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 + 7.0.0-beta.22074.13 6.0.0-preview.1.102 @@ -160,10 +160,10 @@ 1.0.1-prerelease-00006 16.9.0-preview-20201201-01 - 1.0.0-prerelease.22071.1 - 1.0.0-prerelease.22071.1 - 1.0.0-prerelease.22071.1 - 1.0.2-alpha.0.22069.1 + 1.0.0-prerelease.22074.1 + 1.0.0-prerelease.22074.1 + 1.0.0-prerelease.22074.1 + 1.0.2-alpha.0.22074.1 2.4.2-pre.22 0.12.0-pre.20 2.4.2 @@ -180,18 +180,18 @@ 7.0.100-1.22063.2 $(MicrosoftNETILLinkTasksVersion) - 7.0.0-preview.2.22071.2 + 7.0.0-preview.2.22074.5 7.0.0-alpha.1.21529.3 - 11.1.0-alpha.1.22067.2 - 11.1.0-alpha.1.22067.2 - 11.1.0-alpha.1.22067.2 - 11.1.0-alpha.1.22067.2 - 11.1.0-alpha.1.22067.2 - 11.1.0-alpha.1.22067.2 - 11.1.0-alpha.1.22067.2 - 11.1.0-alpha.1.22067.2 + 11.1.0-alpha.1.22074.2 + 11.1.0-alpha.1.22074.2 + 11.1.0-alpha.1.22074.2 + 11.1.0-alpha.1.22074.2 + 11.1.0-alpha.1.22074.2 + 11.1.0-alpha.1.22074.2 + 11.1.0-alpha.1.22074.2 + 11.1.0-alpha.1.22074.2 7.0.0-alpha.2.22071.3 $(MicrosoftNETWorkloadEmscriptenManifest70100Version) diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml index a4837c32c3869..24cec0424e5d6 100644 --- a/eng/common/templates/job/execute-sdl.yml +++ b/eng/common/templates/job/execute-sdl.yml @@ -47,8 +47,14 @@ jobs: - name: GuardianVersion value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals Build.Server.Amd64.VS2019 + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - checkout: self clean: true diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index 0b93fd5b490eb..9d1e3042d8a6c 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -3,10 +3,8 @@ parameters: dependsOn: '' # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool - pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals Build.Server.Amd64.VS2019 - + pool: '' + CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex GithubPat: $(BotAccount-dotnet-bot-repo-PAT) @@ -32,7 +30,18 @@ jobs: displayName: OneLocBuild - pool: ${{ parameters.pool }} + ${{ if ne(parameters.pool, '') }}: + pool: ${{ parameters.pool }} + ${{ if eq(parameters.pool, '') }}: + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 variables: - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml index dafa603dc5d90..554e71cfc436d 100644 --- a/eng/common/templates/jobs/jobs.yml +++ b/eng/common/templates/jobs/jobs.yml @@ -83,8 +83,14 @@ jobs: - ${{ if eq(parameters.enableSourceBuild, true) }}: - Source_Build_Complete pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals Build.Server.Amd64.VS2019 + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 runAsPublic: ${{ parameters.runAsPublic }} publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index 9583d27dbbf89..2f176571f020c 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -94,8 +94,14 @@ stages: displayName: NuGet Validation condition: eq( ${{ parameters.enableNugetValidation }}, 'true') pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals Build.Server.Amd64.VS2019 + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - template: setup-maestro-vars.yml @@ -125,8 +131,14 @@ stages: displayName: Signing Validation condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true')) pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals Build.Server.Amd64.VS2019 + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - template: setup-maestro-vars.yml parameters: @@ -179,8 +191,14 @@ stages: displayName: SourceLink Validation condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true') pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals Build.Server.Amd64.VS2019 + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - template: setup-maestro-vars.yml parameters: @@ -230,14 +248,22 @@ stages: displayName: Publish Using Darc timeoutInMinutes: 120 pool: - name: NetCore1ESPool-Internal - demands: ImageOverride -equals Build.Server.Amd64.VS2019 + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - template: setup-maestro-vars.yml parameters: BARBuildId: ${{ parameters.BARBuildId }} PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + - task: NuGetAuthenticate@0 + - task: PowerShell@2 displayName: Publish Using Darc inputs: diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml index 826d3ed5f74c2..0c87f149a4ad7 100644 --- a/eng/common/templates/post-build/setup-maestro-vars.yml +++ b/eng/common/templates/post-build/setup-maestro-vars.yml @@ -16,6 +16,7 @@ steps: displayName: Set Release Configs Vars inputs: targetType: inline + pwsh: true script: | try { if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { diff --git a/global.json b/global.json index f32ffc29ff09d..c6832999bdb02 100644 --- a/global.json +++ b/global.json @@ -12,10 +12,10 @@ "python3": "3.7.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.22071.6", - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22071.6", - "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22071.6", - "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.22071.6", + "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.22074.13", + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22074.13", + "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22074.13", + "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.22074.13", "Microsoft.Build.NoTargets": "3.1.0", "Microsoft.Build.Traversal": "3.0.23", "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.22073.5" From 7483b24b73a962bdf8e7be8426a7b43ba4ff09de Mon Sep 17 00:00:00 2001 From: Bradley Grainger Date: Tue, 25 Jan 2022 12:02:24 -0800 Subject: [PATCH 205/308] Add CancellationToken to TextReader.ReadXAsync (#61898) Co-authored-by: Adam Sitnik Co-authored-by: Stephen Toub --- .../src/System/IO/SyncTextReader.cs | 15 ++++ .../tests/StreamReader/StreamReaderTests.cs | 59 ++++++++++++++ .../StringReader/StringReader.CtorTests.cs | 27 +++++++ .../tests/TextReader/TextReaderTests.cs | 21 +++++ .../src/System/IO/File.cs | 2 +- .../src/System/IO/StreamReader.cs | 81 ++++++++++++++++--- .../src/System/IO/StringReader.cs | 63 +++++++++++++++ .../src/System/IO/TextReader.cs | 56 +++++++++++-- .../System.Runtime/ref/System.Runtime.cs | 6 ++ 9 files changed, 311 insertions(+), 19 deletions(-) diff --git a/src/libraries/System.Console/src/System/IO/SyncTextReader.cs b/src/libraries/System.Console/src/System/IO/SyncTextReader.cs index 7a2661691e624..33ef898edb688 100644 --- a/src/libraries/System.Console/src/System/IO/SyncTextReader.cs +++ b/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; +using System.Threading; using System.Threading.Tasks; namespace System.IO @@ -95,11 +96,25 @@ public override string ReadToEnd() return Task.FromResult(ReadLine()); } + public override ValueTask ReadLineAsync(CancellationToken cancellationToken) + { + return cancellationToken.IsCancellationRequested ? + ValueTask.FromCanceled(cancellationToken) : + new ValueTask(ReadLine()); + } + public override Task ReadToEndAsync() { return Task.FromResult(ReadToEnd()); } + public override Task ReadToEndAsync(CancellationToken cancellationToken) + { + return cancellationToken.IsCancellationRequested ? + Task.FromCanceled(cancellationToken) : + Task.FromResult(ReadToEnd()); + } + public override Task ReadBlockAsync(char[] buffer, int index, int count) { if (buffer == null) diff --git a/src/libraries/System.IO/tests/StreamReader/StreamReaderTests.cs b/src/libraries/System.IO/tests/StreamReader/StreamReaderTests.cs index 4a2b91f8862b5..fccc269868ed7 100644 --- a/src/libraries/System.IO/tests/StreamReader/StreamReaderTests.cs +++ b/src/libraries/System.IO/tests/StreamReader/StreamReaderTests.cs @@ -110,6 +110,44 @@ public async Task ReadToEndAsync() Assert.Equal(5000, result.Length); } + [Fact] + public async Task ReadToEndAsync_WithCancellationToken() + { + using var sw = new StreamReader(GetLargeStream()); + var result = await sw.ReadToEndAsync(default); + + Assert.Equal(5000, result.Length); + } + + [Fact] + public async Task ReadToEndAsync_WithCanceledCancellationToken() + { + using var sw = new StreamReader(GetLargeStream()); + using var cts = new CancellationTokenSource(); + cts.Cancel(); + var token = cts.Token; + + var ex = await Assert.ThrowsAnyAsync(async () => await sw.ReadToEndAsync(token)); + Assert.Equal(token, ex.CancellationToken); + } + + [Fact] + [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser.")] + public async Task ReadToEndAsync_WithCancellation() + { + string path = GetTestFilePath(); + + // create large (~100MB) file + File.WriteAllLines(path, Enumerable.Repeat("A very large file used for testing StreamReader cancellation. 0123456789012345678901234567890123456789.", 1_000_000)); + + using StreamReader reader = File.OpenText(path); + using CancellationTokenSource cts = new (TimeSpan.FromMilliseconds(50)); + var token = cts.Token; + + var ex = await Assert.ThrowsAnyAsync(async () => await reader.ReadToEndAsync(token)); + Assert.Equal(token, ex.CancellationToken); + } + [Fact] public void GetBaseStream() { @@ -301,6 +339,27 @@ public void VanillaReadLines2() Assert.Equal(valueString.Substring(1, valueString.IndexOf('\r') - 1), data); } + [Fact] + public async Task VanillaReadLineAsync() + { + var baseInfo = GetCharArrayStream(); + var sr = baseInfo.Item2; + + string valueString = new string(baseInfo.Item1); + + var data = await sr.ReadLineAsync(); + Assert.Equal(valueString.Substring(0, valueString.IndexOf('\r')), data); + + data = await sr.ReadLineAsync(default); + Assert.Equal(valueString.Substring(valueString.IndexOf('\r') + 1, 3), data); + + data = await sr.ReadLineAsync(); + Assert.Equal(valueString.Substring(valueString.IndexOf('\n') + 1, 2), data); + + data = await sr.ReadLineAsync(default); + Assert.Equal((valueString.Substring(valueString.LastIndexOf('\n') + 1)), data); + } + [Fact] public async Task ContinuousNewLinesAndTabsAsync() { diff --git a/src/libraries/System.IO/tests/StringReader/StringReader.CtorTests.cs b/src/libraries/System.IO/tests/StringReader/StringReader.CtorTests.cs index 9e500923164f3..3c4446f07f47a 100644 --- a/src/libraries/System.IO/tests/StringReader/StringReader.CtorTests.cs +++ b/src/libraries/System.IO/tests/StringReader/StringReader.CtorTests.cs @@ -68,6 +68,23 @@ public static void ReadLine() } } + [Fact] + public static async Task ReadLineAsync() + { + string str1 = "Hello\0\t\v \\ World"; + string str2 = str1 + Environment.NewLine + str1; + + using (StringReader sr = new StringReader(str1)) + { + Assert.Equal(str1, await sr.ReadLineAsync()); + } + using (StringReader sr = new StringReader(str2)) + { + Assert.Equal(str1, await sr.ReadLineAsync(default)); + Assert.Equal(str1, await sr.ReadLineAsync(default)); + } + } + [Fact] public static void ReadPseudoRandomString() { @@ -155,6 +172,14 @@ public static void ReadToEndPseudoRandom() { Assert.Equal(str1, sr.ReadToEnd()); } + [Fact] + public static async Task ReadToEndAsyncString() + { + string str1 = "Hello\0\t\v \\ World"; + StringReader sr = new StringReader(str1); + Assert.Equal(str1, await sr.ReadToEndAsync(default)); + } + [Fact] public static void Closed_DisposedExceptions() { @@ -278,6 +303,8 @@ public async Task Precanceled_ThrowsException() await Assert.ThrowsAnyAsync(() => reader.ReadAsync(Memory.Empty, new CancellationToken(true)).AsTask()); await Assert.ThrowsAnyAsync(() => reader.ReadBlockAsync(Memory.Empty, new CancellationToken(true)).AsTask()); + await Assert.ThrowsAnyAsync(() => reader.ReadLineAsync(new CancellationToken(true)).AsTask()); + await Assert.ThrowsAnyAsync(() => reader.ReadToEndAsync(new CancellationToken(true))); } private static void ValidateDisposedExceptions(StringReader sr) diff --git a/src/libraries/System.IO/tests/TextReader/TextReaderTests.cs b/src/libraries/System.IO/tests/TextReader/TextReaderTests.cs index e6ba6d818f286..48f83d7108e53 100644 --- a/src/libraries/System.IO/tests/TextReader/TextReaderTests.cs +++ b/src/libraries/System.IO/tests/TextReader/TextReaderTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Threading; using System.Threading.Tasks; using Xunit; @@ -54,6 +55,26 @@ public async Task ReadToEndAsync() } } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + public async Task ReadToEndAsync_WithCancellationToken() + { + using var tr = new CharArrayTextReader(TestDataProvider.LargeData); + var result = await tr.ReadToEndAsync(default); + Assert.Equal(5000, result.Length); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + public async Task ReadToEndAsync_WithCanceledCancellationToken() + { + using var tr = new CharArrayTextReader(TestDataProvider.LargeData); + using var cts = new CancellationTokenSource(); + cts.Cancel(); + var token = cts.Token; + + var ex = await Assert.ThrowsAnyAsync(async () => await tr.ReadToEndAsync(token)); + Assert.Equal(token, ex.CancellationToken); + } + [Fact] public void TestRead() { diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/File.cs b/src/libraries/System.Private.CoreLib/src/System/IO/File.cs index 2b4c61f1eb0ba..007a16d590b0a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/File.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/File.cs @@ -649,7 +649,7 @@ private static async Task InternalReadAllLinesAsync(string path, Encod cancellationToken.ThrowIfCancellationRequested(); string? line; List lines = new List(); - while ((line = await sr.ReadLineAsync().ConfigureAwait(false)) != null) + while ((line = await sr.ReadLineAsync(cancellationToken).ConfigureAwait(false)) != null) { lines.Add(line); cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs b/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs index 3b3e03a806ff5..b5aca3d1dfbcf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @@ -845,7 +845,37 @@ private int ReadBuffer(Span userBuffer, out bool readToUserBuffer) return sb.ToString(); } - public override Task ReadLineAsync() + public override Task ReadLineAsync() => + ReadLineAsync(default).AsTask(); + + /// + /// Reads a line of characters asynchronously from the current stream and returns the data as a string. + /// + /// The token to monitor for cancellation requests. + /// A value task that represents the asynchronous read operation. The value of the TResult + /// parameter contains the next line from the stream, or is if all of the characters have been read. + /// The number of characters in the next line is larger than . + /// The stream reader has been disposed. + /// The reader is currently in use by a previous read operation. + /// + /// The following example shows how to read and print all lines from the file until the end of the file is reached or the operation timed out. + /// + /// using CancellationTokenSource tokenSource = new (TimeSpan.FromSeconds(1)); + /// using StreamReader reader = File.OpenText("existingfile.txt"); + /// + /// string line; + /// while ((line = await reader.ReadLineAsync(tokenSource.Token)) is not null) + /// { + /// Console.WriteLine(line); + /// } + /// + /// + /// + /// If this method is canceled via , some data + /// that has been read from the current but not stored (by the + /// ) or returned (to the caller) may be lost. + /// + public override ValueTask ReadLineAsync(CancellationToken cancellationToken) { // If we have been inherited into a subclass, the following implementation could be incorrect // since it does not call through to Read() which a subclass might have overridden. @@ -853,21 +883,21 @@ private int ReadBuffer(Span userBuffer, out bool readToUserBuffer) // and delegate to our base class (which will call into Read) when we are not sure. if (GetType() != typeof(StreamReader)) { - return base.ReadLineAsync(); + return base.ReadLineAsync(cancellationToken); } ThrowIfDisposed(); CheckAsyncTaskInProgress(); - Task task = ReadLineAsyncInternal(); + Task task = ReadLineAsyncInternal(cancellationToken); _asyncReadTask = task; - return task; + return new ValueTask(task); } - private async Task ReadLineAsyncInternal() + private async Task ReadLineAsyncInternal(CancellationToken cancellationToken) { - if (_charPos == _charLen && (await ReadBufferAsync(CancellationToken.None).ConfigureAwait(false)) == 0) + if (_charPos == _charLen && (await ReadBufferAsync(cancellationToken).ConfigureAwait(false)) == 0) { return null; } @@ -903,7 +933,7 @@ private int ReadBuffer(Span userBuffer, out bool readToUserBuffer) _charPos = tmpCharPos = i + 1; - if (ch == '\r' && (tmpCharPos < tmpCharLen || (await ReadBufferAsync(CancellationToken.None).ConfigureAwait(false)) > 0)) + if (ch == '\r' && (tmpCharPos < tmpCharLen || (await ReadBufferAsync(cancellationToken).ConfigureAwait(false)) > 0)) { tmpCharPos = _charPos; if (_charBuffer[tmpCharPos] == '\n') @@ -921,12 +951,37 @@ private int ReadBuffer(Span userBuffer, out bool readToUserBuffer) i = tmpCharLen - tmpCharPos; sb ??= new StringBuilder(i + 80); sb.Append(tmpCharBuffer, tmpCharPos, i); - } while (await ReadBufferAsync(CancellationToken.None).ConfigureAwait(false) > 0); + } while (await ReadBufferAsync(cancellationToken).ConfigureAwait(false) > 0); return sb.ToString(); } - public override Task ReadToEndAsync() + public override Task ReadToEndAsync() => ReadToEndAsync(default); + + /// + /// Reads all characters from the current position to the end of the stream asynchronously and returns them as one string. + /// + /// The token to monitor for cancellation requests. + /// A task that represents the asynchronous read operation. The value of the TResult parameter contains + /// a string with the characters from the current position to the end of the stream. + /// The number of characters is larger than . + /// The stream reader has been disposed. + /// The reader is currently in use by a previous read operation. + /// + /// The following example shows how to read the contents of a file by using the method. + /// + /// using CancellationTokenSource tokenSource = new (TimeSpan.FromSeconds(1)); + /// using StreamReader reader = File.OpenText("existingfile.txt"); + /// + /// Console.WriteLine(await reader.ReadToEndAsync(tokenSource.Token)); + /// + /// + /// + /// If this method is canceled via , some data + /// that has been read from the current but not stored (by the + /// ) or returned (to the caller) may be lost. + /// + public override Task ReadToEndAsync(CancellationToken cancellationToken) { // If we have been inherited into a subclass, the following implementation could be incorrect // since it does not call through to Read() which a subclass might have overridden. @@ -934,19 +989,19 @@ public override Task ReadToEndAsync() // and delegate to our base class (which will call into Read) when we are not sure. if (GetType() != typeof(StreamReader)) { - return base.ReadToEndAsync(); + return base.ReadToEndAsync(cancellationToken); } ThrowIfDisposed(); CheckAsyncTaskInProgress(); - Task task = ReadToEndAsyncInternal(); + Task task = ReadToEndAsyncInternal(cancellationToken); _asyncReadTask = task; return task; } - private async Task ReadToEndAsyncInternal() + private async Task ReadToEndAsyncInternal(CancellationToken cancellationToken) { // Call ReadBuffer, then pull data out of charBuffer. StringBuilder sb = new StringBuilder(_charLen - _charPos); @@ -955,7 +1010,7 @@ private async Task ReadToEndAsyncInternal() int tmpCharPos = _charPos; sb.Append(_charBuffer, tmpCharPos, _charLen - tmpCharPos); _charPos = _charLen; // We consumed these characters - await ReadBufferAsync(CancellationToken.None).ConfigureAwait(false); + await ReadBufferAsync(cancellationToken).ConfigureAwait(false); } while (_charLen > 0); return sb.ToString(); diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/StringReader.cs b/src/libraries/System.Private.CoreLib/src/System/IO/StringReader.cs index 3d50897ec7f38..a8e07ad382d15 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/StringReader.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/StringReader.cs @@ -224,11 +224,74 @@ public override string ReadToEnd() return Task.FromResult(ReadLine()); } + /// + /// Reads a line of characters asynchronously from the current string and returns the data as a string. + /// + /// The token to monitor for cancellation requests. + /// A value task that represents the asynchronous read operation. The value of the TResult + /// parameter contains the next line from the string reader, or is if all of the characters have been read. + /// The number of characters in the next line is larger than . + /// The string reader has been disposed. + /// The reader is currently in use by a previous read operation. + /// + /// The following example shows how to read one line at a time from a string asynchronously. + /// + /// using System.Text; + /// + /// StringBuilder stringToRead = new(); + /// stringToRead.AppendLine("Characters in 1st line to read"); + /// stringToRead.AppendLine("and 2nd line"); + /// stringToRead.AppendLine("and the end"); + /// + /// string readText; + /// using CancellationTokenSource tokenSource = new (TimeSpan.FromSeconds(1)); + /// using StringReader reader = new (stringToRead.ToString()); + /// while ((readText = await reader.ReadLineAsync(tokenSource.Token)) is not null) + /// { + /// Console.WriteLine(readText); + /// } + /// + /// + public override ValueTask ReadLineAsync(CancellationToken cancellationToken) => + cancellationToken.IsCancellationRequested + ? ValueTask.FromCanceled(cancellationToken) + : new ValueTask(ReadLine()); + public override Task ReadToEndAsync() { return Task.FromResult(ReadToEnd()); } + /// + /// Reads all characters from the current position to the end of the string asynchronously and returns them as a single string. + /// + /// The token to monitor for cancellation requests. + /// A task that represents the asynchronous read operation. The value of the TResult parameter contains + /// a string with the characters from the current position to the end of the string. + /// The number of characters is larger than . + /// The string reader has been disposed. + /// The reader is currently in use by a previous read operation. + /// + /// The following example shows how to read an entire string asynchronously. + /// + /// using System.Text; + /// + /// StringBuilder stringToRead = new(); + /// stringToRead.AppendLine("Characters in 1st line to read"); + /// stringToRead.AppendLine("and 2nd line"); + /// stringToRead.AppendLine("and the end"); + /// + /// using CancellationTokenSource tokenSource = new (TimeSpan.FromSeconds(1)); + /// using StringReader reader = new (stringToRead.ToString()); + /// var readText = await reader.ReadToEndAsync(tokenSource.Token); + /// Console.WriteLine(readText); + /// + /// + public override Task ReadToEndAsync(CancellationToken cancellationToken) => + cancellationToken.IsCancellationRequested + ? Task.FromCanceled(cancellationToken) + : Task.FromResult(ReadToEnd()); + public override Task ReadBlockAsync(char[] buffer, int index, int count) { if (buffer == null) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/TextReader.cs b/src/libraries/System.Private.CoreLib/src/System/IO/TextReader.cs index 05211d6dc7a33..583fb3c2652ae 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/TextReader.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/TextReader.cs @@ -203,18 +203,56 @@ public virtual int ReadBlock(Span buffer) } #region Task based Async APIs - public virtual Task ReadLineAsync() => + public virtual Task ReadLineAsync() => ReadLineCoreAsync(default); + + /// + /// Reads a line of characters asynchronously and returns the data as a string. + /// + /// The token to monitor for cancellation requests. + /// A value task that represents the asynchronous read operation. The value of the TResult + /// parameter contains the next line from the text reader, or is if all of the characters have been read. + /// The number of characters in the next line is larger than . + /// The text reader has been disposed. + /// The reader is currently in use by a previous read operation. + /// + /// The class is an abstract class. Therefore, you do not instantiate it in + /// your code. For an example of using the method, see the + /// method. + /// If the current represents the standard input stream returned by + /// the Console.In property, the method + /// executes synchronously rather than asynchronously. + /// + public virtual ValueTask ReadLineAsync(CancellationToken cancellationToken) => + new ValueTask(ReadLineCoreAsync(cancellationToken)); + + private Task ReadLineCoreAsync(CancellationToken cancellationToken) => Task.Factory.StartNew(static state => ((TextReader)state!).ReadLine(), this, - CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); - - public virtual async Task ReadToEndAsync() + cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + + public virtual Task ReadToEndAsync() => ReadToEndAsync(default); + + /// + /// Reads all characters from the current position to the end of the text reader asynchronously and returns them as one string. + /// + /// The token to monitor for cancellation requests. + /// A task that represents the asynchronous read operation. The value of the TResult parameter contains + /// a string with the characters from the current position to the end of the text reader. + /// The number of characters is larger than . + /// The text reader has been disposed. + /// The reader is currently in use by a previous read operation. + /// + /// The class is an abstract class. Therefore, you do not instantiate it in + /// your code. For an example of using the method, see the + /// method. + /// + public virtual async Task ReadToEndAsync(CancellationToken cancellationToken) { var sb = new StringBuilder(4096); char[] chars = ArrayPool.Shared.Rent(4096); try { int len; - while ((len = await ReadAsyncInternal(chars, default).ConfigureAwait(false)) != 0) + while ((len = await ReadAsyncInternal(chars, cancellationToken).ConfigureAwait(false)) != 0) { sb.Append(chars, 0, len); } @@ -368,9 +406,17 @@ protected override void Dispose(bool disposing) [MethodImpl(MethodImplOptions.Synchronized)] public override Task ReadLineAsync() => Task.FromResult(ReadLine()); + [MethodImpl(MethodImplOptions.Synchronized)] + public override ValueTask ReadLineAsync(CancellationToken cancellationToken) + => cancellationToken.IsCancellationRequested ? ValueTask.FromCanceled(cancellationToken) : new ValueTask(ReadLine()); + [MethodImpl(MethodImplOptions.Synchronized)] public override Task ReadToEndAsync() => Task.FromResult(ReadToEnd()); + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task ReadToEndAsync(CancellationToken cancellationToken) + => cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.FromResult(ReadToEnd()); + [MethodImpl(MethodImplOptions.Synchronized)] public override Task ReadBlockAsync(char[] buffer, int index, int count) { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index b8b136aeb3b5a..82211a2cca7c8 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -10868,8 +10868,10 @@ protected override void Dispose(bool disposing) { } public override System.Threading.Tasks.ValueTask ReadBlockAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public override string? ReadLine() { throw null; } public override System.Threading.Tasks.Task ReadLineAsync() { throw null; } + public override System.Threading.Tasks.ValueTask ReadLineAsync(System.Threading.CancellationToken cancellationToken) { throw null; } public override string ReadToEnd() { throw null; } public override System.Threading.Tasks.Task ReadToEndAsync() { throw null; } + public override System.Threading.Tasks.Task ReadToEndAsync(System.Threading.CancellationToken cancellationToken) { throw null; } } public partial class StreamWriter : System.IO.TextWriter { @@ -10933,8 +10935,10 @@ protected override void Dispose(bool disposing) { } public override System.Threading.Tasks.ValueTask ReadBlockAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public override string? ReadLine() { throw null; } public override System.Threading.Tasks.Task ReadLineAsync() { throw null; } + public override System.Threading.Tasks.ValueTask ReadLineAsync(System.Threading.CancellationToken cancellationToken) { throw null; } public override string ReadToEnd() { throw null; } public override System.Threading.Tasks.Task ReadToEndAsync() { throw null; } + public override System.Threading.Tasks.Task ReadToEndAsync(System.Threading.CancellationToken cancellationToken) { throw null; } } public partial class StringWriter : System.IO.TextWriter { @@ -10985,8 +10989,10 @@ protected virtual void Dispose(bool disposing) { } public virtual System.Threading.Tasks.ValueTask ReadBlockAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual string? ReadLine() { throw null; } public virtual System.Threading.Tasks.Task ReadLineAsync() { throw null; } + public virtual System.Threading.Tasks.ValueTask ReadLineAsync(System.Threading.CancellationToken cancellationToken) { throw null; } public virtual string ReadToEnd() { throw null; } public virtual System.Threading.Tasks.Task ReadToEndAsync() { throw null; } + public virtual System.Threading.Tasks.Task ReadToEndAsync(System.Threading.CancellationToken cancellationToken) { throw null; } public static System.IO.TextReader Synchronized(System.IO.TextReader reader) { throw null; } } public abstract partial class TextWriter : System.MarshalByRefObject, System.IAsyncDisposable, System.IDisposable From fb284a84f4175bbcc88a89cef72a63a39d73f64e Mon Sep 17 00:00:00 2001 From: Jo Shields Date: Tue, 25 Jan 2022 15:09:34 -0500 Subject: [PATCH 206/308] Restrict parallelism in LLVM FullAOT compile, to prevent OOM (#63800) * Restrict parallelism in FullAOT compile, to prevent OOM * Reduce parallelism further, due to more OOM --- eng/pipelines/common/templates/runtimes/run-test-job.yml | 2 +- eng/pipelines/runtime.yml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml index 6aa8a54f24c0f..f944ad47ba203 100644 --- a/eng/pipelines/common/templates/runtimes/run-test-job.yml +++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml @@ -319,7 +319,7 @@ jobs: - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(logRootNameArg)MonoAot $(monoAotBuildshCommand) $(buildConfig) $(archType) $(runtimeVariantArg) displayName: "LLVM AOT compile CoreCLR tests" - ${{ if eq(parameters.archType, 'arm64') }}: - - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(logRootNameArg)MonoAot $(monoAotBuildshCommand) $(buildConfig) $(archType) cross $(runtimeVariantArg) + - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(logRootNameArg)MonoAot $(monoAotBuildshCommand) $(buildConfig) $(archType) cross $(runtimeVariantArg) -maxcpucount:2 displayName: "LLVM AOT cross-compile CoreCLR tests" env: __MonoToolPrefix: aarch64-linux-gnu- diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 7fb2493bac479..1c376cad61b93 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -1110,8 +1110,7 @@ jobs: runtimeFlavor: mono platforms: - Linux_x64 - # Disabled pending outcome of https://github.com/dotnet/runtime/issues/60234 investigation - #- Linux_arm64 + - Linux_arm64 helixQueueGroup: pr helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml jobParameters: From 33940e671a16ca558cc9d145369e16fd0ae2132e Mon Sep 17 00:00:00 2001 From: Vladimir Sadov Date: Tue, 25 Jan 2022 13:10:05 -0800 Subject: [PATCH 207/308] Moved AssemblyName helpers to managed (#62866) * Moved ComputePublicKeyToken to managed * Managed assembly name parsing (adapted from nativeaot) * Fix for HostActivation failures. * PR feedback (RuntimeAssemblyName is back to CoreRT + other comments) * remove AssemblyNameNative::Init form the .hpp * remove AppX compat ifdef * renamed instance fields to convention used in C# * `Argument_InvalidAssemblyName` should be `InvalidAssemblyName`. Majority of use is `FileLoadException`. * remove `this.` * PR feedback (assign to fileds, bypass properties) * missed this change in the rebase * "low-hanging fruit" perf tweaks. * move one-user helpers to where they are used. * removed ActiveIssue for #45032 * remove AssemblyNameHelpers.cs form corelib * Remove the List when detecting duplicates. Support PublicKey. * whitespace * Fix managed implementation to match the new tests. * Some minor cleanup. * Do not validate culture too early * PR feedback * use SR.InvalidAssemblyName * Report the input string when throwing FileLoadException * tweaked couple comments --- .../System/Reflection/AssemblyName.CoreCLR.cs | 18 - .../Runtime/Augments/RuntimeAugments.cs | 5 + .../src/System.Private.CoreLib.csproj | 6 +- .../System/Reflection/AssemblyName.CoreRT.cs | 19 - .../System/Reflection/AssemblyNameHelpers.cs | 47 +- .../System/Reflection/AssemblyNameLexer.cs | 136 ------ .../System/Reflection/AssemblyNameParser.cs | 230 ---------- .../Reflection/AssemblyRuntimeNameHelpers.cs | 52 +++ .../System/Reflection/RuntimeAssemblyName.cs | 27 +- .../Core/Execution/ExecutionDomain.cs | 2 +- .../Runtime/TypeParsing/TypeLexer.cs | 4 +- src/coreclr/vm/assembly.cpp | 2 +- src/coreclr/vm/assemblyname.cpp | 73 +-- src/coreclr/vm/assemblyname.hpp | 2 - src/coreclr/vm/assemblynative.cpp | 5 +- src/coreclr/vm/assemblyspec.cpp | 174 +++---- src/coreclr/vm/assemblyspec.hpp | 4 +- src/coreclr/vm/ecalllist.h | 2 - .../src/Resources/Strings.resx | 7 +- .../System.Private.CoreLib.Shared.projitems | 4 +- .../src/System/Reflection/AssemblyName.cs | 30 +- .../AssemblyNameHelpers.StrongName.cs | 3 +- .../System/Reflection/AssemblyNameParser.cs | 427 ++++++++++++++++++ .../src/System/ThrowHelper.cs | 6 + .../tests/AssemblyNameTests.cs | 1 - .../System/Reflection/AssemblyName.Mono.cs | 50 -- src/mono/mono/metadata/icall-decl.h | 1 - src/mono/mono/metadata/icall-def-netcore.h | 2 - src/mono/mono/metadata/icall.c | 15 - 29 files changed, 628 insertions(+), 726 deletions(-) delete mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameLexer.cs delete mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs create mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyRuntimeNameHelpers.cs rename src/{coreclr/nativeaot => libraries}/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs (98%) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs index f45b3837abdd9..0a3cd42ba900a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreCLR.cs @@ -11,18 +11,6 @@ namespace System.Reflection { public sealed partial class AssemblyName : ICloneable, IDeserializationCallback, ISerializable { - public AssemblyName(string assemblyName) - { - if (assemblyName == null) - throw new ArgumentNullException(nameof(assemblyName)); - if ((assemblyName.Length == 0) || - (assemblyName[0] == '\0')) - throw new ArgumentException(SR.Format_StringZeroLength); - - _name = assemblyName; - nInit(); - } - internal AssemblyName(string? name, byte[]? publicKey, byte[]? publicKeyToken, @@ -44,9 +32,6 @@ internal AssemblyName(string? name, _flags = flags; } - [MethodImpl(MethodImplOptions.InternalCall)] - internal extern void nInit(); - // This call opens and closes the file, but does not add the // assembly to the domain. [MethodImpl(MethodImplOptions.InternalCall)] @@ -58,9 +43,6 @@ internal static AssemblyName GetFileInformationCore(string assemblyFile) return nGetFileInformation(fullPath); } - [MethodImpl(MethodImplOptions.InternalCall)] - private extern byte[]? ComputePublicKeyToken(); - internal void SetProcArchIndex(PortableExecutableKinds pek, ImageFileMachine ifm) { #pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs index 2cc2f40a841f8..198172362464a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs @@ -1091,5 +1091,10 @@ public static bool IsPrimitive(RuntimeTypeHandle typeHandle) { return typeHandle.ToEETypePtr().IsPrimitive && !typeHandle.ToEETypePtr().IsEnum; } + + public static byte[] ComputePublicKeyToken(byte[] publicKey) + { + return System.Reflection.AssemblyNameHelpers.ComputePublicKeyToken(publicKey); + } } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index cf0cab0700eba..bc79d83f0d476 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -123,12 +123,10 @@ - - - - + + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreRT.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreRT.cs index bc3ef37804315..7efcf64288a62 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreRT.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyName.CoreRT.cs @@ -7,25 +7,6 @@ namespace System.Reflection { public sealed partial class AssemblyName : ICloneable, IDeserializationCallback, ISerializable { - public AssemblyName(string assemblyName) - : this() - { - if (assemblyName == null) - throw new ArgumentNullException(nameof(assemblyName)); - if ((assemblyName.Length == 0) || - (assemblyName[0] == '\0')) - throw new ArgumentException(SR.Format_StringZeroLength); - - _name = assemblyName; - RuntimeAssemblyName runtimeAssemblyName = AssemblyNameParser.Parse(_name); - runtimeAssemblyName.CopyToAssemblyName(this); - } - - private byte[] ComputePublicKeyToken() - { - return AssemblyNameHelpers.ComputePublicKeyToken(_publicKey); - } - private static AssemblyName GetFileInformationCore(string assemblyFile) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_AssemblyName_GetAssemblyName); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.cs index b259e2b6bfbdc..a79f9f7f65307 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.cs @@ -9,41 +9,8 @@ namespace System.Reflection { - [System.Runtime.CompilerServices.ReflectionBlocked] - public static partial class AssemblyNameHelpers + internal static partial class AssemblyNameHelpers { - // - // Converts an AssemblyName to a RuntimeAssemblyName that is free from any future mutations on the AssemblyName. - // - public static RuntimeAssemblyName ToRuntimeAssemblyName(this AssemblyName assemblyName) - { - if (assemblyName.Name == null) - throw new ArgumentException(); - - AssemblyNameFlags flags = assemblyName.Flags; - AssemblyContentType contentType = assemblyName.ContentType; -#pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete - ProcessorArchitecture processorArchitecture = assemblyName.ProcessorArchitecture; -#pragma warning restore SYSLIB0037 - AssemblyNameFlags combinedFlags = CombineAssemblyNameFlags(flags, contentType, processorArchitecture); - byte[]? pkOriginal; - if (0 != (flags & AssemblyNameFlags.PublicKey)) - pkOriginal = assemblyName.GetPublicKey(); - else - pkOriginal = assemblyName.GetPublicKeyToken(); - - // AssemblyName's PKT property getters do NOT copy the array before giving it out. Make our own copy - // as the original is wide open to tampering by anyone. - byte[]? pkCopy = null; - if (pkOriginal != null) - { - pkCopy = new byte[pkOriginal.Length]; - ((ICollection)pkOriginal).CopyTo(pkCopy, 0); - } - - return new RuntimeAssemblyName(assemblyName.Name, assemblyName.Version, assemblyName.CultureName, combinedFlags, pkCopy); - } - // // These helpers convert between the combined flags+contentType+processorArchitecture value and the separated parts. // @@ -55,19 +22,9 @@ internal static AssemblyContentType ExtractAssemblyContentType(this AssemblyName return (AssemblyContentType)((((int)flags) >> 9) & 0x7); } - internal static ProcessorArchitecture ExtractProcessorArchitecture(this AssemblyNameFlags flags) - { - return (ProcessorArchitecture)((((int)flags) >> 4) & 0x7); - } - - public static AssemblyNameFlags ExtractAssemblyNameFlags(this AssemblyNameFlags combinedFlags) + internal static AssemblyNameFlags ExtractAssemblyNameFlags(this AssemblyNameFlags combinedFlags) { return combinedFlags & unchecked((AssemblyNameFlags)0xFFFFF10F); } - - internal static AssemblyNameFlags CombineAssemblyNameFlags(AssemblyNameFlags flags, AssemblyContentType contentType, ProcessorArchitecture processorArchitecture) - { - return (AssemblyNameFlags)(((int)flags) | (((int)contentType) << 9) | ((int)processorArchitecture << 4)); - } } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameLexer.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameLexer.cs deleted file mode 100644 index 84555ab310d45..0000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameLexer.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.IO; -using System.Text; -using System.Globalization; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace System.Reflection -{ - // - // A simple lexer for assembly display names. - // - internal struct AssemblyNameLexer - { - internal AssemblyNameLexer(string s) - { - // Convert string to char[] with NUL terminator. (An actual NUL terminator in the input string will be treated - // as an actual end of string: this is compatible with desktop behavior.) - char[] chars = new char[s.Length + 1]; - s.CopyTo(0, chars, 0, s.Length); - _chars = chars; - _index = 0; - } - - // - // Return the next token in assembly name. If you expect the result to be DisplayNameToken.String, - // use GetNext(out String) instead. - // - internal Token GetNext() - { - return GetNext(out _); - } - - // - // Return the next token in assembly name. If the result is DisplayNameToken.String, - // sets "tokenString" to the tokenized string. - // - internal Token GetNext(out string tokenString) - { - tokenString = null; - while (char.IsWhiteSpace(_chars[_index])) - _index++; - - char c = _chars[_index++]; - if (c == 0) - return Token.End; - if (c == ',') - return Token.Comma; - if (c == '=') - return Token.Equals; - - StringBuilder sb = new StringBuilder(); - - char quoteChar = (char)0; - if (c == '\'' || c == '\"') - { - quoteChar = c; - c = _chars[_index++]; - } - - for (;;) - { - if (c == 0) - { - _index--; - break; // Terminate: End of string (desktop compat: if string was quoted, permitted to terminate without end-quote.) - } - - if (quoteChar != 0 && c == quoteChar) - break; // Terminate: Found closing quote of quoted string. - - if (quoteChar == 0 && (c == ',' || c == '=')) - { - _index--; - break; // Terminate: Found start of a new ',' or '=' token. - } - - if (quoteChar == 0 && (c == '\'' || c == '\"')) - throw new FileLoadException(); // Desktop compat: Unescaped quote illegal unless entire string is quoted. - - if (c == '\\') - { - c = _chars[_index++]; - - switch (c) - { - case '\\': - case ',': - case '=': - case '\'': - case '"': - sb.Append(c); - break; - case 't': - sb.Append('\t'); - break; - case 'r': - sb.Append('\r'); - break; - case 'n': - sb.Append('\n'); - break; - default: - throw new FileLoadException(); // Unrecognized escape - } - } - else - { - sb.Append(c); - } - - c = _chars[_index++]; - } - - tokenString = sb.ToString(); - if (quoteChar == 0) - tokenString = tokenString.Trim(); // Unless quoted, whitespace at beginning or end doesn't count. - return Token.String; - } - - // Token categories for display name lexer. - internal enum Token - { - Equals = 1, - Comma = 2, - String = 3, - End = 4, - } - - private readonly char[] _chars; - private int _index; - } -} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs deleted file mode 100644 index 5d8f2ef1c34b0..0000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs +++ /dev/null @@ -1,230 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.IO; -using System.Text; -using System.Diagnostics; -using System.Globalization; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace System.Reflection -{ - // - // Parses an assembly name. - // - [System.Runtime.CompilerServices.ReflectionBlocked] - public static class AssemblyNameParser - { - public static void Parse(AssemblyName blank, string s) - { - if (s == null) - throw new ArgumentNullException(nameof(s)); - RuntimeAssemblyName runtimeAssemblyName = Parse(s); - runtimeAssemblyName.CopyToAssemblyName(blank); - } - - public static RuntimeAssemblyName Parse(string s) - { - Debug.Assert(s != null); - - int indexOfNul = s.IndexOf((char)0); - if (indexOfNul != -1) - s = s.Substring(0, indexOfNul); - if (s.Length == 0) - throw new ArgumentException(SR.Format_StringZeroLength); - - AssemblyNameLexer lexer = new AssemblyNameLexer(s); - - // Name must come first. - string name; - AssemblyNameLexer.Token token = lexer.GetNext(out name); - if (token != AssemblyNameLexer.Token.String) - throw new FileLoadException(SR.InvalidAssemblyName); - - if (name == string.Empty || name.IndexOfAny(s_illegalCharactersInSimpleName) != -1) - throw new FileLoadException(SR.InvalidAssemblyName); - - Version? version = null; - string? cultureName = null; - byte[]? pkt = null; - AssemblyNameFlags flags = 0; - - LowLevelList alreadySeen = new LowLevelList(); - token = lexer.GetNext(); - while (token != AssemblyNameLexer.Token.End) - { - if (token != AssemblyNameLexer.Token.Comma) - throw new FileLoadException(SR.InvalidAssemblyName); - string attributeName; - - token = lexer.GetNext(out attributeName); - if (token != AssemblyNameLexer.Token.String) - throw new FileLoadException(SR.InvalidAssemblyName); - token = lexer.GetNext(); - - // Compat note: Inside AppX apps, the desktop CLR's AssemblyName parser skips past any elements that don't follow the "=" pattern. - // (when running classic Windows apps, such an illegal construction throws an exception as expected.) - // Naturally, at least one app unwittingly takes advantage of this. - if (token == AssemblyNameLexer.Token.Comma || token == AssemblyNameLexer.Token.End) - continue; - - if (token != AssemblyNameLexer.Token.Equals) - throw new FileLoadException(SR.InvalidAssemblyName); - string attributeValue; - token = lexer.GetNext(out attributeValue); - if (token != AssemblyNameLexer.Token.String) - throw new FileLoadException(SR.InvalidAssemblyName); - - if (attributeName == string.Empty) - throw new FileLoadException(SR.InvalidAssemblyName); - - for (int i = 0; i < alreadySeen.Count; i++) - { - if (alreadySeen[i].Equals(attributeName, StringComparison.OrdinalIgnoreCase)) - throw new FileLoadException(SR.InvalidAssemblyName); // Cannot specify the same attribute twice. - } - alreadySeen.Add(attributeName); - - if (attributeName.Equals("Version", StringComparison.OrdinalIgnoreCase)) - { - version = ParseVersion(attributeValue); - } - - if (attributeName.Equals("Culture", StringComparison.OrdinalIgnoreCase)) - { - cultureName = ParseCulture(attributeValue); - } - - if (attributeName.Equals("PublicKeyToken", StringComparison.OrdinalIgnoreCase)) - { - pkt = ParsePKT(attributeValue); - } - - if (attributeName.Equals("ProcessorArchitecture", StringComparison.OrdinalIgnoreCase)) - { - flags |= (AssemblyNameFlags)(((int)ParseProcessorArchitecture(attributeValue)) << 4); - } - - if (attributeName.Equals("Retargetable", StringComparison.OrdinalIgnoreCase)) - { - if (attributeValue.Equals("Yes", StringComparison.OrdinalIgnoreCase)) - flags |= AssemblyNameFlags.Retargetable; - else if (attributeValue.Equals("No", StringComparison.OrdinalIgnoreCase)) - { - // nothing to do - } - else - throw new FileLoadException(SR.InvalidAssemblyName); - } - - if (attributeName.Equals("ContentType", StringComparison.OrdinalIgnoreCase)) - { - if (attributeValue.Equals("WindowsRuntime", StringComparison.OrdinalIgnoreCase)) - flags |= (AssemblyNameFlags)(((int)AssemblyContentType.WindowsRuntime) << 9); - else - throw new FileLoadException(SR.InvalidAssemblyName); - } - - // Desktop compat: If we got here, the attribute name is unknown to us. Ignore it (as long it's not duplicated.) - token = lexer.GetNext(); - } - return new RuntimeAssemblyName(name, version, cultureName, flags, pkt); - } - - private static Version ParseVersion(string attributeValue) - { - string[] parts = attributeValue.Split('.'); - if (parts.Length > 4) - throw new FileLoadException(SR.InvalidAssemblyName); - ushort[] versionNumbers = new ushort[4]; - for (int i = 0; i < versionNumbers.Length; i++) - { - if (i >= parts.Length) - versionNumbers[i] = ushort.MaxValue; - else - { - // Desktop compat: TryParse is a little more forgiving than Fusion. - for (int j = 0; j < parts[i].Length; j++) - { - if (!char.IsDigit(parts[i][j])) - throw new FileLoadException(SR.InvalidAssemblyName); - } - if (!(ushort.TryParse(parts[i], out versionNumbers[i]))) - { - throw new FileLoadException(SR.InvalidAssemblyName); - } - } - } - - if (versionNumbers[0] == ushort.MaxValue || versionNumbers[1] == ushort.MaxValue) - throw new FileLoadException(SR.InvalidAssemblyName); - if (versionNumbers[2] == ushort.MaxValue) - return new Version(versionNumbers[0], versionNumbers[1]); - if (versionNumbers[3] == ushort.MaxValue) - return new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2]); - return new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2], versionNumbers[3]); - } - - private static string ParseCulture(string attributeValue) - { - if (attributeValue.Equals("Neutral", StringComparison.OrdinalIgnoreCase)) - { - return ""; - } - else - { - CultureInfo culture = CultureInfo.GetCultureInfo(attributeValue); // Force a CultureNotFoundException if not a valid culture. - return culture.Name; - } - } - - private static byte[] ParsePKT(string attributeValue) - { - if (attributeValue.Equals("null", StringComparison.OrdinalIgnoreCase) || attributeValue == string.Empty) - return Array.Empty(); - - if (attributeValue.Length != 8 * 2) - throw new FileLoadException(SR.InvalidAssemblyName); - - byte[] pkt = new byte[8]; - int srcIndex = 0; - for (int i = 0; i < 8; i++) - { - char hi = attributeValue[srcIndex++]; - char lo = attributeValue[srcIndex++]; - pkt[i] = (byte)((ParseHexNybble(hi) << 4) | ParseHexNybble(lo)); - } - return pkt; - } - - private static ProcessorArchitecture ParseProcessorArchitecture(string attributeValue) - { - if (attributeValue.Equals("msil", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.MSIL; - if (attributeValue.Equals("x86", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.X86; - if (attributeValue.Equals("ia64", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.IA64; - if (attributeValue.Equals("amd64", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.Amd64; - if (attributeValue.Equals("arm", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.Arm; - throw new FileLoadException(SR.InvalidAssemblyName); - } - - private static byte ParseHexNybble(char c) - { - if (c >= '0' && c <= '9') - return (byte)(c - '0'); - if (c >= 'a' && c <= 'f') - return (byte)(c - 'a' + 10); - if (c >= 'A' && c <= 'F') - return (byte)(c - 'A' + 10); - throw new FileLoadException(SR.InvalidAssemblyName); - } - - private static readonly char[] s_illegalCharactersInSimpleName = { '/', '\\', ':' }; - } -} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyRuntimeNameHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyRuntimeNameHelpers.cs new file mode 100644 index 0000000000000..fc4ed2816e580 --- /dev/null +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyRuntimeNameHelpers.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Globalization; +using System.IO; +using System.Text; +using System.Collections.Generic; + +namespace System.Reflection +{ + [System.Runtime.CompilerServices.ReflectionBlocked] + public static class AssemblyRuntimeNameHelpers + { + // + // Converts an AssemblyName to a RuntimeAssemblyName that is free from any future mutations on the AssemblyName. + // + public static RuntimeAssemblyName ToRuntimeAssemblyName(this AssemblyName assemblyName) + { + if (assemblyName.Name == null) + throw new ArgumentException(SR.InvalidAssemblyName); + + AssemblyNameFlags flags = assemblyName.Flags; + AssemblyContentType contentType = assemblyName.ContentType; +#pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete + ProcessorArchitecture processorArchitecture = assemblyName.ProcessorArchitecture; +#pragma warning restore SYSLIB0037 + AssemblyNameFlags combinedFlags = CombineAssemblyNameFlags(flags, contentType, processorArchitecture); + byte[]? pkOriginal; + if (0 != (flags & AssemblyNameFlags.PublicKey)) + pkOriginal = assemblyName.GetPublicKey(); + else + pkOriginal = assemblyName.GetPublicKeyToken(); + + // AssemblyName's PKT property getters do NOT copy the array before giving it out. Make our own copy + // as the original is wide open to tampering by anyone. + byte[]? pkCopy = null; + if (pkOriginal != null) + { + pkCopy = new byte[pkOriginal.Length]; + Array.Copy(pkOriginal, pkCopy, pkOriginal.Length); + } + + return new RuntimeAssemblyName(assemblyName.Name, assemblyName.Version, assemblyName.CultureName, combinedFlags, pkCopy); + } + + internal static AssemblyNameFlags CombineAssemblyNameFlags(AssemblyNameFlags flags, AssemblyContentType contentType, ProcessorArchitecture processorArchitecture) + { + return (AssemblyNameFlags)(((int)flags) | (((int)contentType) << 9) | ((int)processorArchitecture << 4)); + } + } +} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeAssemblyName.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeAssemblyName.cs index 90c0fe5ff824a..f4dbc0d667140 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeAssemblyName.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeAssemblyName.cs @@ -16,7 +16,7 @@ namespace System.Reflection // public sealed class RuntimeAssemblyName : IEquatable { - public RuntimeAssemblyName(string name, Version version, string cultureName, AssemblyNameFlags flags, byte[] publicKeyOrToken) + public RuntimeAssemblyName(string name, Version? version, string? cultureName, AssemblyNameFlags flags, byte[]? publicKeyOrToken) { Debug.Assert(name != null); this.Name = name; @@ -34,20 +34,26 @@ public RuntimeAssemblyName(string name, Version version, string cultureName, Ass this.PublicKeyOrToken = publicKeyOrToken; } + public static RuntimeAssemblyName Parse(string name) + { + AssemblyNameParser.AssemblyNameParts parts = AssemblyNameParser.Parse(name); + return new RuntimeAssemblyName(parts._name, parts._version, parts._cultureName, parts._flags, parts._publicKeyOrToken); + } + // Simple name. public string Name { get; } // Optional version. - public Version Version { get; } + public Version? Version { get; } // Optional culture name. - public string CultureName { get; } + public string? CultureName { get; } // Optional flags (this is actually an OR of the classic flags and the ContentType.) public AssemblyNameFlags Flags { get; } // Optional public key (if Flags.PublicKey == true) or public key token. - public byte[] PublicKeyOrToken { get; } + public byte[]? PublicKeyOrToken { get; } // Equality - this compares every bit of data in the RuntimeAssemblyName which is acceptable for use as keys in a cache // where semantic duplication is permissible. This method is *not* meant to define ref->def binding rules or @@ -73,8 +79,8 @@ public bool Equals(RuntimeAssemblyName? other) if (this.Flags != other.Flags) return false; - byte[] thisPK = this.PublicKeyOrToken; - byte[] otherPK = other.PublicKeyOrToken; + byte[]? thisPK = this.PublicKeyOrToken; + byte[]? otherPK = other.PublicKeyOrToken; if (thisPK == null) { if (otherPK != null) @@ -139,7 +145,7 @@ public void CopyToAssemblyName(AssemblyName blank) blank.Flags = this.Flags.ExtractAssemblyNameFlags(); blank.ContentType = this.Flags.ExtractAssemblyContentType(); #pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete - blank.ProcessorArchitecture = this.Flags.ExtractProcessorArchitecture(); + blank.ProcessorArchitecture = ExtractProcessorArchitecture(this.Flags); #pragma warning restore SYSLIB0037 if (this.PublicKeyOrToken != null) @@ -162,9 +168,14 @@ public string FullName { get { - byte[] pkt = (0 != (Flags & AssemblyNameFlags.PublicKey)) ? AssemblyNameHelpers.ComputePublicKeyToken(PublicKeyOrToken) : PublicKeyOrToken; + byte[]? pkt = (0 != (Flags & AssemblyNameFlags.PublicKey)) ? AssemblyNameHelpers.ComputePublicKeyToken(PublicKeyOrToken) : PublicKeyOrToken; return AssemblyNameFormatter.ComputeDisplayName(Name, Version, CultureName, pkt, Flags.ExtractAssemblyNameFlags(), Flags.ExtractAssemblyContentType()); } } + + internal static ProcessorArchitecture ExtractProcessorArchitecture(AssemblyNameFlags flags) + { + return (ProcessorArchitecture)((((int)flags) >> 4) & 0x7); + } } } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs index 53edc6a6ec5e4..2227d4a59682b 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs @@ -89,7 +89,7 @@ private static CoreTypeResolver CreateCoreTypeResolver(FuncVerifyIsAssembly(); AssemblySpec spec; - spec.InitializeSpec(TokenFromRid(mdtAssembly,1),pImage->GetMDImport(),NULL); + spec.InitializeSpec(TokenFromRid(1,mdtAssembly),pImage->GetMDImport(),NULL); spec.AssemblyNameInit(&gc.result, pImage); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(gc.result); } FCIMPLEND - -FCIMPL1(Object*, AssemblyNameNative::GetPublicKeyToken, Object* refThisUNSAFE) -{ - FCALL_CONTRACT; - - U1ARRAYREF orOutputArray = NULL; - OBJECTREF refThis = (OBJECTREF) refThisUNSAFE; - HELPER_METHOD_FRAME_BEGIN_RET_1(refThis); - - if (refThis == NULL) - COMPlusThrow(kNullReferenceException, W("NullReference_This")); - - ASSEMBLYNAMEREF orThis = (ASSEMBLYNAMEREF)refThis; - U1ARRAYREF orPublicKey = orThis->GetPublicKey(); - - if (orPublicKey != NULL) { - DWORD cb = orPublicKey->GetNumComponents(); - StrongNameBufferHolder pbToken; - - if (cb) { - CQuickBytes qb; - BYTE *pbKey = (BYTE*) qb.AllocThrows(cb); - memcpy(pbKey, orPublicKey->GetDataPtr(), cb); - - { - GCX_PREEMP(); - IfFailThrow(StrongNameTokenFromPublicKey(pbKey, cb, &pbToken, &cb)); - } - } - - orOutputArray = (U1ARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_U1, cb); - memcpyNoGCRefs(orOutputArray->m_Array, pbToken, cb); - } - - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(orOutputArray); -} -FCIMPLEND - - -FCIMPL1(void, AssemblyNameNative::Init, Object * refThisUNSAFE) -{ - FCALL_CONTRACT; - - ASSEMBLYNAMEREF pThis = (ASSEMBLYNAMEREF) (OBJECTREF) refThisUNSAFE; - HRESULT hr = S_OK; - - HELPER_METHOD_FRAME_BEGIN_1(pThis); - - if (pThis == NULL) - COMPlusThrow(kNullReferenceException, W("NullReference_This")); - - ACQUIRE_STACKING_ALLOCATOR(pStackingAllocator); - - AssemblySpec spec; - hr = spec.InitializeSpec(pStackingAllocator, (ASSEMBLYNAMEREF *) &pThis, TRUE); - - if (SUCCEEDED(hr)) - { - spec.AssemblyNameInit(&pThis,NULL); - } - else - { - ThrowHR(hr); - } - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - - diff --git a/src/coreclr/vm/assemblyname.hpp b/src/coreclr/vm/assemblyname.hpp index 9e818fc1a9f7c..a336cfaf9ae70 100644 --- a/src/coreclr/vm/assemblyname.hpp +++ b/src/coreclr/vm/assemblyname.hpp @@ -19,8 +19,6 @@ class AssemblyNameNative { public: static FCDECL1(Object*, GetFileInformation, StringObject* filenameUNSAFE); - static FCDECL1(Object*, GetPublicKeyToken, Object* refThisUNSAFE); - static FCDECL1(void, Init, Object * refThisUNSAFE); }; #endif // _AssemblyName_H diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp index a51280e21e4a3..19a5d62c0b9ed 100644 --- a/src/coreclr/vm/assemblynative.cpp +++ b/src/coreclr/vm/assemblynative.cpp @@ -86,9 +86,8 @@ extern "C" void QCALLTYPE AssemblyNative_InternalLoad(QCall::ObjectHandleOnStack } // Initialize spec - spec.InitializeSpec(pStackingAllocator, - &assemblyNameRef, - FALSE); + spec.InitializeSpec(pStackingAllocator, &assemblyNameRef); + GCPROTECT_END(); spec.SetCodeBase(NULL); diff --git a/src/coreclr/vm/assemblyspec.cpp b/src/coreclr/vm/assemblyspec.cpp index 0cea7dc712107..5bdb2cbd65259 100644 --- a/src/coreclr/vm/assemblyspec.cpp +++ b/src/coreclr/vm/assemblyspec.cpp @@ -250,8 +250,7 @@ void AssemblySpec::InitializeSpec(PEAssembly * pFile) // This uses thread storage to allocate space. Please use Checkpoint and release it. -HRESULT AssemblySpec::InitializeSpec(StackingAllocator* alloc, ASSEMBLYNAMEREF* pName, - BOOL fParse /*=TRUE*/) +void AssemblySpec::InitializeSpec(StackingAllocator* alloc, ASSEMBLYNAMEREF* pName) { CONTRACTL { @@ -271,11 +270,6 @@ HRESULT AssemblySpec::InitializeSpec(StackingAllocator* alloc, ASSEMBLYNAMEREF* WCHAR* pString; int iString; ((STRINGREF) (*pName)->GetSimpleName())->RefInterpretGetStringValuesDangerousForGC(&pString, &iString); - - // we will not parse names that contain nulls - if (fParse && (wcslen(pString) != (size_t)iString)) - ThrowHR(FUSION_E_INVALID_NAME); - DWORD lgth = WszWideCharToMultiByte(CP_UTF8, 0, pString, iString, NULL, 0, NULL, NULL); if (lgth + 1 < lgth) ThrowHR(E_INVALIDARG); @@ -295,108 +289,86 @@ HRESULT AssemblySpec::InitializeSpec(StackingAllocator* alloc, ASSEMBLYNAMEREF* SetName(lpName); } - if (fParse) - { - HRESULT hr = ParseName(); - // Sometimes Fusion flags invalid characters in the name, sometimes it doesn't - // depending on where the invalid characters are - // We want to Raise the assembly resolve event on all invalid characters - // but calling ParseName before checking for invalid characters gives Fusion a chance to - // parse the rest of the name (to get a public key token, etc.) - if ((hr == FUSION_E_INVALID_NAME) || (!IsValidAssemblyName())) { - // This is the only case where we do not throw on an error - // We don't want to throw so as to give the caller a chance to call RaiseAssemblyResolveEvent - // The only caller that cares is System.Reflection.Assembly.InternalLoad which calls us through - // AssemblyNameNative::Init - return FUSION_E_INVALID_NAME; - } - else - IfFailThrow(hr); + AssemblyMetaDataInternal asmInfo; + // Flags + DWORD dwFlags = (*pName)->GetFlags(); + + // Version + VERSIONREF version = (VERSIONREF) (*pName)->GetVersion(); + if(version == NULL) { + asmInfo.usMajorVersion = (USHORT)-1; + asmInfo.usMinorVersion = (USHORT)-1; + asmInfo.usBuildNumber = (USHORT)-1; + asmInfo.usRevisionNumber = (USHORT)-1; } else { - AssemblyMetaDataInternal asmInfo; - // Flags - DWORD dwFlags = (*pName)->GetFlags(); - - // Version - VERSIONREF version = (VERSIONREF) (*pName)->GetVersion(); - if(version == NULL) { - asmInfo.usMajorVersion = (USHORT)-1; - asmInfo.usMinorVersion = (USHORT)-1; - asmInfo.usBuildNumber = (USHORT)-1; - asmInfo.usRevisionNumber = (USHORT)-1; - } - else { - asmInfo.usMajorVersion = (USHORT)version->GetMajor(); - asmInfo.usMinorVersion = (USHORT)version->GetMinor(); - asmInfo.usBuildNumber = (USHORT)version->GetBuild(); - asmInfo.usRevisionNumber = (USHORT)version->GetRevision(); - } + asmInfo.usMajorVersion = (USHORT)version->GetMajor(); + asmInfo.usMinorVersion = (USHORT)version->GetMinor(); + asmInfo.usBuildNumber = (USHORT)version->GetBuild(); + asmInfo.usRevisionNumber = (USHORT)version->GetRevision(); + } - asmInfo.szLocale = 0; + asmInfo.szLocale = 0; - if ((*pName)->GetCultureInfo() != NULL) - { - struct _gc { - OBJECTREF cultureinfo; - STRINGREF pString; - } gc; - - gc.cultureinfo = (*pName)->GetCultureInfo(); - gc.pString = NULL; - - GCPROTECT_BEGIN(gc); - - MethodDescCallSite getName(METHOD__CULTURE_INFO__GET_NAME, &gc.cultureinfo); - - ARG_SLOT args[] = { - ObjToArgSlot(gc.cultureinfo) - }; - gc.pString = getName.Call_RetSTRINGREF(args); - if (gc.pString != NULL) { - WCHAR* pString; - int iString; - gc.pString->RefInterpretGetStringValuesDangerousForGC(&pString, &iString); - DWORD lgth = WszWideCharToMultiByte(CP_UTF8, 0, pString, iString, NULL, 0, NULL, NULL); - S_UINT32 lengthWillNull = S_UINT32(lgth) + S_UINT32(1); - LPSTR lpLocale = (LPSTR) alloc->Alloc(lengthWillNull); - if (lengthWillNull.IsOverflow()) - { - COMPlusThrowHR(COR_E_OVERFLOW); - } - WszWideCharToMultiByte(CP_UTF8, 0, pString, iString, - lpLocale, lengthWillNull.Value(), NULL, NULL); - lpLocale[lgth] = '\0'; - asmInfo.szLocale = lpLocale; - } - GCPROTECT_END(); - } + if ((*pName)->GetCultureInfo() != NULL) + { + struct _gc { + OBJECTREF cultureinfo; + STRINGREF pString; + } gc; - // Strong name - DWORD cbPublicKeyOrToken=0; - BYTE* pbPublicKeyOrToken=NULL; - // Note that we prefer to take a public key token if present, - // even if flags indicate a full public key - if ((*pName)->GetPublicKeyToken() != NULL) { - dwFlags &= ~afPublicKey; - PBYTE pArray = NULL; - pArray = (*pName)->GetPublicKeyToken()->GetDirectPointerToNonObjectElements(); - cbPublicKeyOrToken = (*pName)->GetPublicKeyToken()->GetNumComponents(); - pbPublicKeyOrToken = pArray; - } - else if ((*pName)->GetPublicKey() != NULL) { - dwFlags |= afPublicKey; - PBYTE pArray = NULL; - pArray = (*pName)->GetPublicKey()->GetDirectPointerToNonObjectElements(); - cbPublicKeyOrToken = (*pName)->GetPublicKey()->GetNumComponents(); - pbPublicKeyOrToken = pArray; + gc.cultureinfo = (*pName)->GetCultureInfo(); + gc.pString = NULL; + + GCPROTECT_BEGIN(gc); + + MethodDescCallSite getName(METHOD__CULTURE_INFO__GET_NAME, &gc.cultureinfo); + + ARG_SLOT args[] = { + ObjToArgSlot(gc.cultureinfo) + }; + gc.pString = getName.Call_RetSTRINGREF(args); + if (gc.pString != NULL) { + WCHAR* pString; + int iString; + gc.pString->RefInterpretGetStringValuesDangerousForGC(&pString, &iString); + DWORD lgth = WszWideCharToMultiByte(CP_UTF8, 0, pString, iString, NULL, 0, NULL, NULL); + S_UINT32 lengthWillNull = S_UINT32(lgth) + S_UINT32(1); + LPSTR lpLocale = (LPSTR) alloc->Alloc(lengthWillNull); + if (lengthWillNull.IsOverflow()) + { + COMPlusThrowHR(COR_E_OVERFLOW); + } + WszWideCharToMultiByte(CP_UTF8, 0, pString, iString, + lpLocale, lengthWillNull.Value(), NULL, NULL); + lpLocale[lgth] = '\0'; + asmInfo.szLocale = lpLocale; } - BaseAssemblySpec::Init(GetName(),&asmInfo,pbPublicKeyOrToken,cbPublicKeyOrToken,dwFlags); - } + GCPROTECT_END(); + } + + // Strong name + DWORD cbPublicKeyOrToken=0; + BYTE* pbPublicKeyOrToken=NULL; + // Note that we prefer to take a public key token if present, + // even if flags indicate a full public key + if ((*pName)->GetPublicKeyToken() != NULL) { + dwFlags &= ~afPublicKey; + PBYTE pArray = NULL; + pArray = (*pName)->GetPublicKeyToken()->GetDirectPointerToNonObjectElements(); + cbPublicKeyOrToken = (*pName)->GetPublicKeyToken()->GetNumComponents(); + pbPublicKeyOrToken = pArray; + } + else if ((*pName)->GetPublicKey() != NULL) { + dwFlags |= afPublicKey; + PBYTE pArray = NULL; + pArray = (*pName)->GetPublicKey()->GetDirectPointerToNonObjectElements(); + cbPublicKeyOrToken = (*pName)->GetPublicKey()->GetNumComponents(); + pbPublicKeyOrToken = pArray; + } + BaseAssemblySpec::Init(GetName(),&asmInfo,pbPublicKeyOrToken,cbPublicKeyOrToken,dwFlags); CloneFieldsToStackingAllocator(alloc); - - return S_OK; } void AssemblySpec::AssemblyNameInit(ASSEMBLYNAMEREF* pAsmName, PEImage* pImageInfo) diff --git a/src/coreclr/vm/assemblyspec.hpp b/src/coreclr/vm/assemblyspec.hpp index d6ce12300170e..9f49c1d78cf75 100644 --- a/src/coreclr/vm/assemblyspec.hpp +++ b/src/coreclr/vm/assemblyspec.hpp @@ -103,9 +103,7 @@ class AssemblySpec : public BaseAssemblySpec void InitializeSpec(PEAssembly* pPEAssembly); - HRESULT InitializeSpec(StackingAllocator* alloc, - ASSEMBLYNAMEREF* pName, - BOOL fParse); + void InitializeSpec(StackingAllocator* alloc, ASSEMBLYNAMEREF* pName); void AssemblyNameInit(ASSEMBLYNAMEREF* pName, PEImage* pImageInfo); //[in,out], [in] diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index f3ada145b6839..8a11c4fb930ab 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -292,8 +292,6 @@ FCFuncStart(gAssemblyLoadContextFuncs) FCFuncEnd() FCFuncStart(gAssemblyNameFuncs) - FCFuncElement("nInit", AssemblyNameNative::Init) - FCFuncElement("ComputePublicKeyToken", AssemblyNameNative::GetPublicKeyToken) FCFuncElement("nGetFileInformation", AssemblyNameNative::GetFileInformation) FCFuncEnd() diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index e9d5e447ee90f..8564b3894fa41 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -1104,8 +1104,8 @@ Target array type is not compatible with the type of items in the collection. - - Assembly names may not begin with whitespace or contain the characters '/', or '\\' or ':'. + + The given assembly name or codebase was invalid. Not a valid calendar for the given culture. @@ -3877,9 +3877,6 @@ A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property. - - The given assembly name or codebase was invalid - Invalid assembly public key. 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 d5ce32af96642..8cf5cf0dda601 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 @@ -562,6 +562,8 @@ + + @@ -2369,4 +2371,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs index 198c6804b7e4f..a1822fbe83a1a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs @@ -25,6 +25,32 @@ public sealed partial class AssemblyName : ICloneable, IDeserializationCallback, private AssemblyVersionCompatibility _versionCompatibility; private AssemblyNameFlags _flags; + public AssemblyName(string assemblyName) + : this() + { + if (assemblyName == null) + throw new ArgumentNullException(nameof(assemblyName)); + if ((assemblyName.Length == 0) || + (assemblyName[0] == '\0')) + throw new ArgumentException(SR.Format_StringZeroLength); + + AssemblyNameParser.AssemblyNameParts parts = AssemblyNameParser.Parse(assemblyName); + _name = parts._name; + _version = parts._version; + _flags = parts._flags; + if ((parts._flags & AssemblyNameFlags.PublicKey) != 0) + { + _publicKey = parts._publicKeyOrToken; + } + else + { + _publicKeyToken = parts._publicKeyOrToken; + } + + if (parts._cultureName != null) + _cultureInfo = new CultureInfo(parts._cultureName); + } + public AssemblyName() { _versionCompatibility = AssemblyVersionCompatibility.SameMachine; @@ -166,7 +192,7 @@ public void SetPublicKey(byte[]? publicKey) // The compressed version of the public key formed from a truncated hash. // Will throw a SecurityException if _publicKey is invalid - public byte[]? GetPublicKeyToken() => _publicKeyToken ??= ComputePublicKeyToken(); + public byte[]? GetPublicKeyToken() => _publicKeyToken ??= AssemblyNameHelpers.ComputePublicKeyToken(_publicKey); public void SetPublicKeyToken(byte[]? publicKeyToken) { @@ -219,7 +245,7 @@ public string FullName return string.Empty; // Do not call GetPublicKeyToken() here - that latches the result into AssemblyName which isn't a side effect we want. - byte[]? pkt = _publicKeyToken ?? ComputePublicKeyToken(); + byte[]? pkt = _publicKeyToken ?? AssemblyNameHelpers.ComputePublicKeyToken(_publicKey); return AssemblyNameFormatter.ComputeDisplayName(Name, Version, CultureName, pkt, Flags, ContentType); } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs rename to src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs index 85e437548102e..ef05ef39f8a7e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers.Binary; -using System.Runtime; using System.Security; namespace System.Reflection { - public static partial class AssemblyNameHelpers + internal static partial class AssemblyNameHelpers { public static byte[]? ComputePublicKeyToken(byte[]? publicKey) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs new file mode 100644 index 0000000000000..ab3be2c8f06d2 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs @@ -0,0 +1,427 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Text; + +namespace System.Reflection +{ + // + // Parses an assembly name. + // + internal ref struct AssemblyNameParser + { + public struct AssemblyNameParts + { + public AssemblyNameParts(string name, Version? version, string? cultureName, AssemblyNameFlags flags, byte[]? publicKeyOrToken) + { + _name = name; + _version = version; + _cultureName = cultureName; + _flags = flags; + _publicKeyOrToken = publicKeyOrToken; + } + + public string _name; + public Version? _version; + public string? _cultureName; + public AssemblyNameFlags _flags; + public byte[]? _publicKeyOrToken; + } + + // Token categories for the lexer. + private enum Token + { + Equals = 1, + Comma = 2, + String = 3, + End = 4, + } + + private enum AttributeKind + { + Version = 1, + Culture = 2, + PublicKeyOrToken = 4, + ProcessorArchitecture = 8, + Retargetable = 16, + ContentType = 32 + } + + private static readonly char[] s_illegalCharactersInSimpleName = { '/', '\\', ':' }; + private string _input; + private int _index; + + private AssemblyNameParser(string input) + { + Debug.Assert(input != null); + if (input.Length == 0) + throw new ArgumentException(SR.Format_StringZeroLength); + + _input = input; + _index = 0; + } + + public static AssemblyNameParts Parse(string s) + { + return new AssemblyNameParser(s).Parse(); + } + + private void RecordNewSeenOrThrow(ref AttributeKind seenAttributes, AttributeKind newAttribute) + { + if ((seenAttributes & newAttribute) != 0) + { + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + } + else + { + seenAttributes |= newAttribute; + } + } + + private AssemblyNameParts Parse() + { + // Name must come first. + string name; + Token token = GetNextToken(out name); + if (token != Token.String) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + + if (name == string.Empty || name.IndexOfAny(s_illegalCharactersInSimpleName) != -1) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + + Version? version = null; + string? cultureName = null; + byte[]? pkt = null; + AssemblyNameFlags flags = 0; + + AttributeKind alreadySeen = default; + token = GetNextToken(); + while (token != Token.End) + { + if (token != Token.Comma) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + string attributeName; + + token = GetNextToken(out attributeName); + if (token != Token.String) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + token = GetNextToken(); + + if (token != Token.Equals) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + string attributeValue; + token = GetNextToken(out attributeValue); + if (token != Token.String) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + + if (attributeName == string.Empty) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + + if (attributeName.Equals("Version", StringComparison.OrdinalIgnoreCase)) + { + RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.Version); + version = ParseVersion(attributeValue); + } + + if (attributeName.Equals("Culture", StringComparison.OrdinalIgnoreCase)) + { + RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.Culture); + cultureName = ParseCulture(attributeValue); + } + + if (attributeName.Equals("PublicKey", StringComparison.OrdinalIgnoreCase)) + { + RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.PublicKeyOrToken); + pkt = ParsePKT(attributeValue, isToken: false); + flags |= AssemblyNameFlags.PublicKey; + } + + if (attributeName.Equals("PublicKeyToken", StringComparison.OrdinalIgnoreCase)) + { + RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.PublicKeyOrToken); + pkt = ParsePKT(attributeValue, isToken: true); + } + + if (attributeName.Equals("ProcessorArchitecture", StringComparison.OrdinalIgnoreCase)) + { + RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.ProcessorArchitecture); + flags |= (AssemblyNameFlags)(((int)ParseProcessorArchitecture(attributeValue)) << 4); + } + + if (attributeName.Equals("Retargetable", StringComparison.OrdinalIgnoreCase)) + { + RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.Retargetable); + if (attributeValue.Equals("Yes", StringComparison.OrdinalIgnoreCase)) + flags |= AssemblyNameFlags.Retargetable; + else if (attributeValue.Equals("No", StringComparison.OrdinalIgnoreCase)) + { + // nothing to do + } + else + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + } + + if (attributeName.Equals("ContentType", StringComparison.OrdinalIgnoreCase)) + { + RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.ContentType); + if (attributeValue.Equals("WindowsRuntime", StringComparison.OrdinalIgnoreCase)) + flags |= (AssemblyNameFlags)(((int)AssemblyContentType.WindowsRuntime) << 9); + else + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + } + + // Desktop compat: If we got here, the attribute name is unknown to us. Ignore it. + token = GetNextToken(); + } + + return new AssemblyNameParts(name, version, cultureName, flags, pkt); + } + + private Version ParseVersion(string attributeValue) + { + string[] parts = attributeValue.Split('.'); + if (parts.Length > 4) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + ushort[] versionNumbers = new ushort[4]; + for (int i = 0; i < versionNumbers.Length; i++) + { + if (i >= parts.Length) + versionNumbers[i] = ushort.MaxValue; + else + { + // Desktop compat: TryParse is a little more forgiving than Fusion. + for (int j = 0; j < parts[i].Length; j++) + { + if (!char.IsDigit(parts[i][j])) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + } + if (!(ushort.TryParse(parts[i], out versionNumbers[i]))) + { + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + } + } + } + + if (versionNumbers[0] == ushort.MaxValue || versionNumbers[1] == ushort.MaxValue) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + if (versionNumbers[2] == ushort.MaxValue) + return new Version(versionNumbers[0], versionNumbers[1]); + if (versionNumbers[3] == ushort.MaxValue) + return new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2]); + return new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2], versionNumbers[3]); + } + + private string ParseCulture(string attributeValue) + { + if (attributeValue.Equals("Neutral", StringComparison.OrdinalIgnoreCase)) + { + return ""; + } + + return attributeValue; + } + + private byte[] ParsePKT(string attributeValue, bool isToken) + { + if (attributeValue.Equals("null", StringComparison.OrdinalIgnoreCase) || attributeValue == string.Empty) + return Array.Empty(); + + if (isToken && attributeValue.Length != 8 * 2) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + + byte[] pkt = new byte[attributeValue.Length / 2]; + int srcIndex = 0; + for (int i = 0; i < pkt.Length; i++) + { + char hi = attributeValue[srcIndex++]; + char lo = attributeValue[srcIndex++]; + pkt[i] = (byte)((ParseHexNybble(hi) << 4) | ParseHexNybble(lo)); + } + return pkt; + } + + private ProcessorArchitecture ParseProcessorArchitecture(string attributeValue) + { + if (attributeValue.Equals("msil", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.MSIL; + if (attributeValue.Equals("x86", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.X86; + if (attributeValue.Equals("ia64", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.IA64; + if (attributeValue.Equals("amd64", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.Amd64; + if (attributeValue.Equals("arm", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.Arm; + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + return default; // unreachable + } + + private byte ParseHexNybble(char c) + { + if (c >= '0' && c <= '9') + return (byte)(c - '0'); + if (c >= 'a' && c <= 'f') + return (byte)(c - 'a' + 10); + if (c >= 'A' && c <= 'F') + return (byte)(c - 'A' + 10); + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + return default; // unreachable + } + + // + // Return the next token in assembly name. If you expect the result to be Token.String, + // use GetNext(out String) instead. + // + private Token GetNextToken() + { + return GetNextToken(out _); + } + + private static bool IsWhiteSpace(char ch) + { + switch (ch) + { + case '\n': + case '\r': + case ' ': + case '\t': + return true; + default: + return false; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private char GetNextChar() + { + char ch; + if (_index < _input.Length) + { + ch = _input[_index++]; + if (ch == '\0') + { + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + } + } + else + { + ch = '\0'; + } + + return ch; + } + + // + // Return the next token in assembly name. If the result is Token.String, + // sets "tokenString" to the tokenized string. + // + private Token GetNextToken(out string tokenString) + { + tokenString = string.Empty; + char c; + + while (true) + { + c = GetNextChar(); + switch (c) + { + case ',': + return Token.Comma; + case '=': + return Token.Equals; + case '\0': + return Token.End; + } + + if (!IsWhiteSpace(c)) + { + break; + } + } + + ValueStringBuilder sb = new ValueStringBuilder(stackalloc char[64]); + + char quoteChar = '\0'; + if (c == '\'' || c == '\"') + { + quoteChar = c; + c = GetNextChar(); + } + + for (; ; ) + { + if (c == 0) + { + if (quoteChar != 0) + { + // EOS and unclosed quotes is an error + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + } + else + { + // Reached end of input and therefore of string + break; + } + } + + if (quoteChar != 0 && c == quoteChar) + break; // Terminate: Found closing quote of quoted string. + + if (quoteChar == 0 && (c == ',' || c == '=')) + { + _index--; + break; // Terminate: Found start of a new ',' or '=' token. + } + + if (quoteChar == 0 && (c == '\'' || c == '\"')) + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + + if (c == '\\') + { + c = GetNextChar(); + + switch (c) + { + case '\\': + case ',': + case '=': + case '\'': + case '"': + sb.Append(c); + break; + case 't': + sb.Append('\t'); + break; + case 'r': + sb.Append('\r'); + break; + case 'n': + sb.Append('\n'); + break; + default: + ThrowHelper.ThrowFileLoadException_InvalidAssemblyName(_input); + return default; //unreachable + } + } + else + { + sb.Append(c); + } + + c = GetNextChar(); + } + + + if (quoteChar == 0) + { + while (sb.Length > 0 && IsWhiteSpace(sb[sb.Length - 1])) + sb.Length--; + } + + tokenString = sb.ToString(); + return Token.String; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs index 01e4a44dfc19d..781cd38aaadb3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs @@ -494,6 +494,12 @@ internal static void ThrowFormatException_BadFormatSpecifier() throw new FormatException(SR.Argument_BadFormatSpecifier); } + [DoesNotReturn] + internal static void ThrowFileLoadException_InvalidAssemblyName(string name) + { + throw new FileLoadException(SR.InvalidAssemblyName, name); + } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException_PrecisionTooLarge() { diff --git a/src/libraries/System.Reflection/tests/AssemblyNameTests.cs b/src/libraries/System.Reflection/tests/AssemblyNameTests.cs index 7e9b8c5849b22..34a7023e2e607 100644 --- a/src/libraries/System.Reflection/tests/AssemblyNameTests.cs +++ b/src/libraries/System.Reflection/tests/AssemblyNameTests.cs @@ -124,7 +124,6 @@ public void Ctor_String_Invalid_Legacy(string assemblyName, Type exceptionType) [InlineData("na=me", typeof(FileLoadException))] [InlineData("na\'me", typeof(FileLoadException))] [InlineData("na\"me", typeof(FileLoadException))] - [ActiveIssue ("https://github.com/dotnet/runtime/issues/45032", TestRuntimes.Mono)] public void Ctor_String_Invalid_Issue(string assemblyName, Type exceptionType) { Assert.Throws(exceptionType, () => new AssemblyName(assemblyName)); diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/AssemblyName.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/AssemblyName.Mono.cs index 12b2a5936c3de..67ff341eec5df 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/AssemblyName.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/AssemblyName.Mono.cs @@ -12,50 +12,6 @@ namespace System.Reflection { public partial class AssemblyName { - public AssemblyName(string assemblyName) - { - if (assemblyName == null) - throw new ArgumentNullException(nameof(assemblyName)); - if (assemblyName.Length == 0 || assemblyName[0] == '\0') - throw new ArgumentException(SR.Format_StringZeroLength); - - if (assemblyName.Contains('\0')) - throw new FileLoadException("The assembly name is invalid."); - - using (SafeStringMarshal name = RuntimeMarshal.MarshalString(assemblyName)) - { - // TODO: Should use CoreRT AssemblyNameParser - if (!ParseAssemblyName(name.Value, out MonoAssemblyName nativeName, out bool isVersionDefined, out bool isTokenDefined)) - throw new FileLoadException("The assembly name is invalid."); - - try - { - unsafe - { - FillName(&nativeName, null, isVersionDefined, false, isTokenDefined); - } - } - finally - { - RuntimeMarshal.FreeAssemblyName(ref nativeName, false); - } - } - } - - private unsafe byte[]? ComputePublicKeyToken() - { - if (_publicKey == null) - return null; - if (_publicKey.Length == 0) - return Array.Empty(); - - var token = new byte[8]; - fixed (byte* pkt = token) - fixed (byte* pk = _publicKey) - get_public_token(pkt, pk, _publicKey.Length); - return token; - } - internal static AssemblyName Create(IntPtr monoAssembly, string? codeBase) { AssemblyName aname = new AssemblyName(); @@ -141,13 +97,7 @@ private static AssemblyName GetFileInformationCore(string assemblyFile) } } - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe void get_public_token(byte* token, byte* pubkey, int len); - [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern unsafe MonoAssemblyName* GetNativeName(IntPtr assemblyPtr); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool ParseAssemblyName(IntPtr name, out MonoAssemblyName aname, out bool is_version_definited, out bool is_token_defined); } } diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h index 5b75710e6456a..1a960fdaa8655 100644 --- a/src/mono/mono/metadata/icall-decl.h +++ b/src/mono/mono/metadata/icall-decl.h @@ -60,7 +60,6 @@ typedef enum { // This is sorted. // grep ICALL_EXPORT | sort | uniq ICALL_EXPORT MonoAssemblyName* ves_icall_System_Reflection_AssemblyName_GetNativeName (MonoAssembly*); -ICALL_EXPORT MonoBoolean ves_icall_System_Reflection_AssemblyName_ParseAssemblyName (const char*, MonoAssemblyName*, MonoBoolean*, MonoBoolean* is_token_defined_arg); ICALL_EXPORT MonoBoolean ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_SufficientExecutionStack (void); ICALL_EXPORT MonoBoolean ves_icall_System_Threading_Thread_YieldInternal (void); ICALL_EXPORT MonoThread *ves_icall_System_Threading_Thread_GetCurrentThread (void); diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index 45c65207a0849..ae7984fada9b0 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -176,8 +176,6 @@ HANDLES(ASSEM_7, "InternalLoad", ves_icall_System_Reflection_Assembly_InternalLo ICALL_TYPE(ASSEMN, "System.Reflection.AssemblyName", ASSEMN_0) NOHANDLES(ICALL(ASSEMN_0, "GetNativeName", ves_icall_System_Reflection_AssemblyName_GetNativeName)) -NOHANDLES(ICALL(ASSEMN_3, "ParseAssemblyName", ves_icall_System_Reflection_AssemblyName_ParseAssemblyName)) -NOHANDLES(ICALL(ASSEMN_2, "get_public_token", mono_digest_get_public_token)) ICALL_TYPE(MCATTR, "System.Reflection.CustomAttribute", MCATTR_1) HANDLES(MCATTR_1, "GetCustomAttributesDataInternal", ves_icall_MonoCustomAttrs_GetCustomAttributesDataInternal, MonoArray, 1, (MonoObject)) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 39806dd249178..92e0526e1c2b4 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -5379,21 +5379,6 @@ gint32 ves_icall_AssemblyExtensions_ApplyUpdateEnabled (gint32 just_component_ch return mono_metadata_update_available () && (just_component_check || mono_metadata_update_enabled (NULL)); } -MonoBoolean -ves_icall_System_Reflection_AssemblyName_ParseAssemblyName (const char *name, MonoAssemblyName *aname, MonoBoolean *is_version_defined_arg, MonoBoolean *is_token_defined_arg) -{ - gboolean is_version_defined = FALSE; - gboolean is_token_defined = FALSE; - gboolean result = FALSE; - - result = mono_assembly_name_parse_full (name, aname, TRUE, &is_version_defined, &is_token_defined); - - *is_version_defined_arg = (MonoBoolean)is_version_defined; - *is_token_defined_arg = (MonoBoolean)is_token_defined; - - return result; -} - MonoReflectionTypeHandle ves_icall_System_Reflection_RuntimeModule_GetGlobalType (MonoImage *image, MonoError *error) { From ca1340bb034fca163375a6da88f22b1843d633ef Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 25 Jan 2022 18:01:02 -0500 Subject: [PATCH 208/308] Disable RegexReductionTests tests on browser --- .../System.Text.RegularExpressions/tests/RegexReductionTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs index 65ef818124a42..f4fcbf92dadf1 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs @@ -6,6 +6,7 @@ namespace System.Text.RegularExpressions.Tests { + [ActiveIssue("https://github.com/dotnet/runtime/issues/64300", TestPlatforms.Browser)] public class RegexReductionTests { // These tests depend on using reflection to access internals of Regex in order to validate From bdc0d1a409a24d4092e7b108c13fc4ff1c643d1f Mon Sep 17 00:00:00 2001 From: Roman Marusyk Date: Wed, 26 Jan 2022 01:08:51 +0200 Subject: [PATCH 209/308] Fix formatting of resource string where excess arguments are passed (#63824) * Fix formatting of resource string where excess arguments are passed. #63607 * Fix BuildCharExceptionArgs and ECCurve.Validate * Fix CA2208 * Fix CA2208. Remove paramName becaus it is in error message * Code review fixes * Code review fixes --- .../Microsoft/VisualBasic/FileIO/TextFieldParser.vb | 8 ++++---- .../src/Microsoft/Win32/Registry.cs | 2 +- .../AccessControl/RegistrySecurity.Windows.cs | 2 +- .../src/System/Drawing/RectangleConverter.cs | 2 +- .../BasicEventSourceTest/TestsManifestNegative.cs | 12 ++++++------ .../src/System/Drawing/RectangleConverter.cs | 1 - .../src/System/IO/IsolatedStorage/IsolatedStorage.cs | 2 +- .../System.IO.Packaging/src/Resources/Strings.resx | 4 ++-- .../System.Net.NameResolution/src/System/Net/Dns.cs | 6 +++--- .../src/System/Net/Sockets/SocketAsyncEventArgs.cs | 8 ++++---- .../src/System/Collections/Hashtable.cs | 2 +- .../src/System/Diagnostics/Tracing/EventSource.cs | 6 +++--- .../src/System/IO/UnmanagedMemoryAccessor.cs | 4 ++-- .../System.Private.CoreLib/src/System/Random.cs | 2 +- .../src/System/Text/DecoderReplacementFallback.cs | 2 +- .../src/System/Text/EncoderReplacementFallback.cs | 2 +- .../tests/Xslt/XslTransformApi/CXslTransform.cs | 2 +- .../System/Reflection/Metadata/Internal/BlobHeap.cs | 2 +- .../src/System/Numerics/BigNumber.cs | 2 +- .../src/Resources/Strings.resx | 2 +- .../Cryptography/CspKeyContainerInfo.Windows.cs | 4 ++-- .../Cryptography/X509Certificates/X509Chain.cs | 4 ++-- .../src/Resources/Strings.resx | 2 +- .../src/System/Security/Cryptography/ECCurve.cs | 4 ++-- .../Fallback/DecoderReplacementFallbackTests.cs | 12 ++++++------ .../Fallback/EncoderReplacementFallbackTests.cs | 12 ++++++------ 26 files changed, 55 insertions(+), 56 deletions(-) diff --git a/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/TextFieldParser.vb b/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/TextFieldParser.vb index 77219110807c4..d97358dcd5a5b 100644 --- a/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/TextFieldParser.vb +++ b/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/FileIO/TextFieldParser.vb @@ -375,7 +375,7 @@ Namespace Microsoft.VisualBasic.FileIO Public Function PeekChars(ByVal numberOfChars As Integer) As String If numberOfChars <= 0 Then - Throw GetArgumentExceptionWithArgName("numberOfChars", SR.TextFieldParser_NumberOfCharsMustBePositive, "numberOfChars") + Throw GetArgumentExceptionWithArgName("numberOfChars", SR.TextFieldParser_NumberOfCharsMustBePositive) End If If m_Reader Is Nothing Or m_Buffer Is Nothing Then @@ -1151,7 +1151,7 @@ Namespace Microsoft.VisualBasic.FileIO Dim Bound As Integer = Widths.Length - 1 For i As Integer = 0 To Bound - 1 If Widths(i) < 1 Then - Throw GetArgumentExceptionWithArgName("FieldWidths", SR.TextFieldParser_FieldWidthsMustPositive, "FieldWidths") + Throw GetArgumentExceptionWithArgName("FieldWidths", SR.TextFieldParser_FieldWidthsMustPositive) End If Next End Sub @@ -1163,11 +1163,11 @@ Namespace Microsoft.VisualBasic.FileIO ''' Private Sub ValidateAndEscapeDelimiters() If m_Delimiters Is Nothing Then - Throw GetArgumentExceptionWithArgName("Delimiters", SR.TextFieldParser_DelimitersNothing, "Delimiters") + Throw GetArgumentExceptionWithArgName("Delimiters", SR.TextFieldParser_DelimitersNothing) End If If m_Delimiters.Length = 0 Then - Throw GetArgumentExceptionWithArgName("Delimiters", SR.TextFieldParser_DelimitersNothing, "Delimiters") + Throw GetArgumentExceptionWithArgName("Delimiters", SR.TextFieldParser_DelimitersNothing) End If Dim Length As Integer = m_Delimiters.Length diff --git a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/Registry.cs b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/Registry.cs index 56cbc26afe977..49eeecff31ab0 100644 --- a/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/Registry.cs +++ b/src/libraries/Microsoft.Win32.Registry/src/Microsoft/Win32/Registry.cs @@ -64,7 +64,7 @@ private static RegistryKey GetBaseKeyFromKeyName(string keyName, out string subK return baseKey; } - throw new ArgumentException(SR.Format(SR.Arg_RegInvalidKeyName, nameof(keyName)), nameof(keyName)); + throw new ArgumentException(SR.Arg_RegInvalidKeyName, nameof(keyName)); } public static object? GetValue(string keyName, string? valueName, object? defaultValue) diff --git a/src/libraries/Microsoft.Win32.Registry/src/System/Security/AccessControl/RegistrySecurity.Windows.cs b/src/libraries/Microsoft.Win32.Registry/src/System/Security/AccessControl/RegistrySecurity.Windows.cs index f5ff293848ffa..f16e03965ed18 100644 --- a/src/libraries/Microsoft.Win32.Registry/src/System/Security/AccessControl/RegistrySecurity.Windows.cs +++ b/src/libraries/Microsoft.Win32.Registry/src/System/Security/AccessControl/RegistrySecurity.Windows.cs @@ -19,7 +19,7 @@ public sealed partial class RegistrySecurity : NativeObjectSecurity break; case Interop.Errors.ERROR_INVALID_NAME: - exception = new ArgumentException(SR.Format(SR.Arg_RegInvalidKeyName, nameof(name))); + exception = new ArgumentException(SR.Arg_RegInvalidKeyName, nameof(name)); break; case Interop.Errors.ERROR_INVALID_HANDLE: diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/Drawing/RectangleConverter.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/Drawing/RectangleConverter.cs index 9037db5175274..9c0393da53ab3 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/Drawing/RectangleConverter.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/Drawing/RectangleConverter.cs @@ -50,7 +50,7 @@ public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destina if (values.Length != 4) { - throw new ArgumentException(SR.Format(SR.TextParseFailedFormat, "text", text, "x, y, width, height")); + throw new ArgumentException(SR.Format(SR.TextParseFailedFormat, text, "x, y, width, height")); } return new Rectangle(values[0], values[1], values[2], values[3]); diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestNegative.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestNegative.cs index 2ee59adf59464..012a03bcad1c1 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestNegative.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestNegative.cs @@ -82,13 +82,13 @@ public void Test_GenerateManifest_InvalidEventSources() Assert.NotNull(EventSource.GenerateManifest(typeof(Sdt.EventWithReturnEventSource), string.Empty, EventManifestOptions.AllowEventSourceOverride)); e = AssertExtensions.Throws(null, () => EventSource.GenerateManifest(typeof(Sdt.NegativeEventIdEventSource), string.Empty)); - AsserExceptionStringsEqual(() => GetResourceString("EventSource_NeedPositiveId", "WriteInteger"), e); + AsserExceptionStringsEqual(() => GetResourceString("EventSource_NeedPositiveId"), e); e = AssertExtensions.Throws(null, () => EventSource.GenerateManifest(typeof(Sdt.NegativeEventIdEventSource), string.Empty, strictOptions)); - AsserExceptionStringsEqual(() => GetResourceString("EventSource_NeedPositiveId", "WriteInteger"), e); + AsserExceptionStringsEqual(() => GetResourceString("EventSource_NeedPositiveId"), e); e = AssertExtensions.Throws(null, () => EventSource.GenerateManifest(typeof(Sdt.NegativeEventIdEventSource), string.Empty, EventManifestOptions.AllowEventSourceOverride)); - AsserExceptionStringsEqual(() => GetResourceString("EventSource_NeedPositiveId", "WriteInteger"), e); + AsserExceptionStringsEqual(() => GetResourceString("EventSource_NeedPositiveId"), e); e = AssertExtensions.Throws(null, () => EventSource.GenerateManifest(typeof(Sdt.OutOfRangeKwdEventSource), string.Empty, strictOptions)); AsserExceptionStringsEqual(() => string.Join(Environment.NewLine, @@ -124,7 +124,7 @@ public void Test_GenerateManifest_InvalidEventSources() e = AssertExtensions.Throws(null, () => EventSource.GenerateManifest(typeof(Sdt.EnumKindMismatchEventSource), string.Empty, strictOptions)); AsserExceptionStringsEqual(() => string.Join(Environment.NewLine, - GetResourceString("EventSource_EnumKindMismatch", "Op1", "EventKeywords", "Opcodes"), + GetResourceString("EventSource_EnumKindMismatch", "EventKeywords", "Opcodes"), GetResourceString("EventSource_UndefinedKeyword", "0x1", "WriteInteger")), e); @@ -144,14 +144,14 @@ public void Test_GenerateManifest_InvalidEventSources() e = AssertExtensions.Throws(null, () => EventSource.GenerateManifest(typeof(Sdt.EventIdReusedEventSource), string.Empty, strictOptions)); AsserExceptionStringsEqual(() => string.Join(Environment.NewLine, - GetResourceString("EventSource_EventIdReused", "WriteInteger2", 1, "WriteInteger1"), + GetResourceString("EventSource_EventIdReused", "WriteInteger2", 1), GetResourceString("EventSource_TaskOpcodePairReused", "WriteInteger2", 1, "WriteInteger1", 1)), e); e = AssertExtensions.Throws(null, () => EventSource.GenerateManifest(typeof(Sdt.EventIdReusedEventSource), string.Empty, strictOptions)); AsserExceptionStringsEqual(() => string.Join(Environment.NewLine, - GetResourceString("EventSource_EventIdReused", "WriteInteger2", 1, "WriteInteger1"), + GetResourceString("EventSource_EventIdReused", "WriteInteger2", 1), GetResourceString("EventSource_TaskOpcodePairReused", "WriteInteger2", 1, "WriteInteger1", 1)), e); diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/RectangleConverter.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/RectangleConverter.cs index 445d7c72c6dd4..098830cbf4a61 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/RectangleConverter.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/RectangleConverter.cs @@ -83,7 +83,6 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c } else { throw new ArgumentException(SR.Format(SR.TextParseFailedFormat, - "text", text, "x, y, width, height")); } diff --git a/src/libraries/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorage.cs b/src/libraries/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorage.cs index 6171cce6d9a34..78dab30883812 100644 --- a/src/libraries/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorage.cs +++ b/src/libraries/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorage.cs @@ -55,7 +55,7 @@ public virtual ulong CurrentSize { get { - throw new InvalidOperationException(SR.Format(SR.IsolatedStorage_CurrentSizeUndefined, nameof(CurrentSize))); + throw new InvalidOperationException(SR.IsolatedStorage_CurrentSizeUndefined); } } diff --git a/src/libraries/System.IO.Packaging/src/Resources/Strings.resx b/src/libraries/System.IO.Packaging/src/Resources/Strings.resx index 668094559fa96..a2ffa3af1ed3d 100644 --- a/src/libraries/System.IO.Packaging/src/Resources/Strings.resx +++ b/src/libraries/System.IO.Packaging/src/Resources/Strings.resx @@ -106,7 +106,7 @@ Invalid file format. - Invalid file format. + File '{0}' has an invalid file format. PackagePart subclass must implement GetContentTypeCore method if passing a null value for the content type when PackagePart object is constructed. @@ -375,4 +375,4 @@ File contains corrupted data. - \ No newline at end of file + diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs index 5da904a7c6f9d..a0127f539bc6c 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/Dns.cs @@ -47,7 +47,7 @@ public static IPHostEntry GetHostEntry(IPAddress address) if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) { if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(address, $"Invalid address '{address}'"); - throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(address))); + throw new ArgumentException(SR.net_invalid_ip_addr, nameof(address)); } IPHostEntry ipHostEntry = GetHostEntryCore(address, AddressFamily.Unspecified); @@ -81,7 +81,7 @@ public static IPHostEntry GetHostEntry(string hostNameOrAddress, AddressFamily f if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) { if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(address, $"Invalid address '{address}'"); - throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(hostNameOrAddress))); + throw new ArgumentException(SR.net_invalid_ip_addr, nameof(hostNameOrAddress)); } ipHostEntry = GetHostEntryCore(address, family); @@ -207,7 +207,7 @@ public static IPAddress[] GetHostAddresses(string hostNameOrAddress, AddressFami if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)) { if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(address, $"Invalid address '{address}'"); - throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(hostNameOrAddress))); + throw new ArgumentException(SR.net_invalid_ip_addr, nameof(hostNameOrAddress)); } addresses = (family == AddressFamily.Unspecified || address.AddressFamily == family) ? new IPAddress[] { address } : Array.Empty(); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs index 6c79043631eb7..faf0d9f204c7c 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs @@ -153,7 +153,7 @@ public IList>? BufferList if (!_buffer.Equals(default)) { // Can't have both set - throw new ArgumentException(SR.Format(SR.net_ambiguousbuffers, nameof(Buffer))); + throw new ArgumentException(SR.net_ambiguousbuffers); } // Copy the user-provided list into our internal buffer list, @@ -358,7 +358,7 @@ public void SetBuffer(byte[]? buffer, int offset, int count) // Can't have both Buffer and BufferList. if (_bufferList != null) { - throw new ArgumentException(SR.Format(SR.net_ambiguousbuffers, nameof(BufferList))); + throw new ArgumentException(SR.net_ambiguousbuffers); } // Offset and count can't be negative and the @@ -391,7 +391,7 @@ public void SetBuffer(Memory buffer) { if (buffer.Length != 0 && _bufferList != null) { - throw new ArgumentException(SR.Format(SR.net_ambiguousbuffers, nameof(BufferList))); + throw new ArgumentException(SR.net_ambiguousbuffers); } _buffer = buffer; @@ -559,7 +559,7 @@ internal void StartOperationAccept() // Caller specified a buffer - see if it is large enough if (_count < _acceptAddressBufferCount) { - throw new ArgumentException(SR.Format(SR.net_buffercounttoosmall, nameof(Count))); + throw new ArgumentException(SR.net_buffercounttoosmall, nameof(Count)); } } else diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Hashtable.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Hashtable.cs index 01b9cdb3c737a..d311cd0c94bbd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Hashtable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Hashtable.cs @@ -260,7 +260,7 @@ public Hashtable(int capacity, float loadFactor) if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_NeedNonNegNum); if (!(loadFactor >= 0.1f && loadFactor <= 1.0f)) - throw new ArgumentOutOfRangeException(nameof(loadFactor), SR.Format(SR.ArgumentOutOfRange_HashtableLoadFactor, .1, 1.0)); + throw new ArgumentOutOfRangeException(nameof(loadFactor), SR.ArgumentOutOfRange_HashtableLoadFactor); // Based on perf work, .72 is the optimal load factor for this table. _loadFactor = 0.72f * loadFactor; diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index f8d6e9c6ff114..b54a5a50ba62e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -3280,7 +3280,7 @@ private static bool AttributeTypeNamesMatch(Type attributeType, Type reflectedAt } else if (eventAttribute.EventId <= 0) { - manifest.ManifestError(SR.Format(SR.EventSource_NeedPositiveId, method.Name), true); + manifest.ManifestError(SR.EventSource_NeedPositiveId, true); continue; // don't validate anything else for this event } if (method.Name.LastIndexOf('.') >= 0) @@ -3501,7 +3501,7 @@ private static void AddProviderEnumKind(ManifestBuilder manifest, FieldInfo stat #endif return; Error: - manifest.ManifestError(SR.Format(SR.EventSource_EnumKindMismatch, staticField.Name, staticField.FieldType.Name, providerEnumKind)); + manifest.ManifestError(SR.Format(SR.EventSource_EnumKindMismatch, staticField.FieldType.Name, providerEnumKind)); } // Helper used by code:CreateManifestAndDescriptors to add a code:EventData descriptor for a method @@ -3630,7 +3630,7 @@ private static void DebugCheckEvent(ref Dictionary? eventsByName if (evtId < eventData.Length && eventData[evtId].Descriptor.EventId != 0) { - manifest.ManifestError(SR.Format(SR.EventSource_EventIdReused, evtName, evtId, eventData[evtId].Name), true); + manifest.ManifestError(SR.Format(SR.EventSource_EventIdReused, evtName, evtId), true); } // We give a task to things if they don't have one. diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryAccessor.cs b/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryAccessor.cs index 0e53df433e78c..78d0dab488a56 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryAccessor.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryAccessor.cs @@ -319,7 +319,7 @@ public void Read(long position, out T structure) where T : struct } else { - throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToRead, typeof(T)), nameof(position)); + throw new ArgumentException(SR.Argument_NotEnoughBytesToRead, nameof(position)); } } @@ -561,7 +561,7 @@ public void Write(long position, ref T structure) where T : struct } else { - throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToWrite, typeof(T)), nameof(position)); + throw new ArgumentException(SR.Argument_NotEnoughBytesToWrite, nameof(position)); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Random.cs b/src/libraries/System.Private.CoreLib/src/System/Random.cs index 05766c724d267..9107044882333 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Random.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Random.cs @@ -192,7 +192,7 @@ protected virtual double Sample() } private static void ThrowMaxValueMustBeNonNegative() => - throw new ArgumentOutOfRangeException("maxValue", SR.Format(SR.ArgumentOutOfRange_NeedNonNegNum, "maxValue")); + throw new ArgumentOutOfRangeException("maxValue", SR.ArgumentOutOfRange_NeedNonNegNum); private static void ThrowMinMaxValueSwapped() => throw new ArgumentOutOfRangeException("minValue", SR.Format(SR.Argument_MinMaxValue, "minValue", "maxValue")); diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/DecoderReplacementFallback.cs b/src/libraries/System.Private.CoreLib/src/System/Text/DecoderReplacementFallback.cs index 8f769f1c45bca..34270ba3c30ad 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/DecoderReplacementFallback.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/DecoderReplacementFallback.cs @@ -57,7 +57,7 @@ public DecoderReplacementFallback(string replacement) break; } if (bFoundHigh) - throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequenceNoIndex, nameof(replacement))); + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(replacement)); _strDefault = replacement; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncoderReplacementFallback.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncoderReplacementFallback.cs index 5c93f4cc2cdb7..709695ce36dd1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncoderReplacementFallback.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncoderReplacementFallback.cs @@ -58,7 +58,7 @@ public EncoderReplacementFallback(string replacement) break; } if (bFoundHigh) - throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequenceNoIndex, nameof(replacement))); + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(replacement)); _strDefault = replacement; } diff --git a/src/libraries/System.Private.Xml/tests/Xslt/XslTransformApi/CXslTransform.cs b/src/libraries/System.Private.Xml/tests/Xslt/XslTransformApi/CXslTransform.cs index 9f561b2554e00..6c320a7295bcd 100644 --- a/src/libraries/System.Private.Xml/tests/Xslt/XslTransformApi/CXslTransform.cs +++ b/src/libraries/System.Private.Xml/tests/Xslt/XslTransformApi/CXslTransform.cs @@ -1234,7 +1234,7 @@ public void LoadGeneric12(InputType inputType, ReaderType readerType, TransformT } catch (System.InvalidOperationException e2) { - CheckExpectedError(e2, "system.xml", "Xslt_NoStylesheetLoaded", new string[] { "IDontExist.xsl" }); + CheckExpectedError(e2, "system.xml", "Xslt_NoStylesheetLoaded", new string[] { "" }); return; } } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Internal/BlobHeap.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Internal/BlobHeap.cs index 302a6167c5563..abd9cf514babf 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Internal/BlobHeap.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Internal/BlobHeap.cs @@ -190,7 +190,7 @@ public string GetDocumentName(DocumentNameBlobHandle handle) int separator = blobReader.ReadByte(); if (separator > 0x7f) { - throw new BadImageFormatException(SR.Format(SR.InvalidDocumentName, separator)); + throw new BadImageFormatException(SR.InvalidDocumentName); } var pooledBuilder = PooledStringBuilder.GetInstance(); diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs index 2d7395e2e83dd..79d11ebe76203 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs @@ -310,7 +310,7 @@ internal static bool TryValidateParseStyleInteger(NumberStyles style, [NotNullWh // Check for undefined flags if ((style & InvalidNumberStyles) != 0) { - e = new ArgumentException(SR.Format(SR.Argument_InvalidNumberStyles, nameof(style))); + e = new ArgumentException(SR.Argument_InvalidNumberStyles, nameof(style)); return false; } if ((style & NumberStyles.AllowHexSpecifier) != 0) diff --git a/src/libraries/System.Security.Cryptography.Cng/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.Cng/src/Resources/Strings.resx index 4c99946a673e8..4577d05e6187c 100644 --- a/src/libraries/System.Security.Cryptography.Cng/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.Cng/src/Resources/Strings.resx @@ -178,7 +178,7 @@ The specified curve '{0}' or its parameters are not valid for this platform. - The specified Oid is not valid. The Oid.FriendlyName or Oid.Value property must be set. + The specified Oid ({0}) is not valid. The Oid.FriendlyName or Oid.Value property must be set. Specified initialization vector (IV) does not match the block size for this algorithm. diff --git a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CspKeyContainerInfo.Windows.cs b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CspKeyContainerInfo.Windows.cs index ce73894fb36e0..cda387503b0f2 100644 --- a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CspKeyContainerInfo.Windows.cs +++ b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CspKeyContainerInfo.Windows.cs @@ -210,7 +210,7 @@ public string UniqueKeyContainerName { if (throwOnNotFound) { - throw new CryptographicException(SR.Format(SR.Cryptography_CSP_NotFound, "Error")); + throw new CryptographicException(SR.Cryptography_CSP_NotFound); } return null; @@ -243,7 +243,7 @@ private object ReadDeviceParameterVerifyContext(int keyParam) { if (hr != CapiHelper.S_OK) { - throw new CryptographicException(SR.Format(SR.Cryptography_CSP_NotFound, "Error")); + throw new CryptographicException(SR.Cryptography_CSP_NotFound); } object retVal = CapiHelper.GetProviderParameter(safeProvHandle, parameters.KeyNumber, keyParam); diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Chain.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Chain.cs index dbefadab57334..7260b772f46ce 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Chain.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Chain.cs @@ -117,13 +117,13 @@ internal bool Build(X509Certificate2 certificate, bool throwOnException) if (_chainPolicy != null && _chainPolicy.CustomTrustStore != null) { if (_chainPolicy.TrustMode == X509ChainTrustMode.System && _chainPolicy.CustomTrustStore.Count > 0) - throw new CryptographicException(SR.Cryptography_CustomTrustCertsInSystemMode, nameof(_chainPolicy.TrustMode)); + throw new CryptographicException(SR.Cryptography_CustomTrustCertsInSystemMode); foreach (X509Certificate2 customCertificate in _chainPolicy.CustomTrustStore) { if (customCertificate == null || customCertificate.Handle == IntPtr.Zero) { - throw new CryptographicException(SR.Cryptography_InvalidTrustCertificate, nameof(_chainPolicy.CustomTrustStore)); + throw new CryptographicException(SR.Cryptography_InvalidTrustCertificate); } } } diff --git a/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx index 84a24a8fc9ef4..dc30b357b0b38 100644 --- a/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx @@ -205,7 +205,7 @@ The specified key parameters are not valid. Q.X and Q.Y, or D, must be specified. Q.X, Q.Y must be the same length. If D is specified it must be the same length as Q.X and Q.Y if also specified for named curves or the same length as Order for explicit curves. - The specified Oid is not valid. The Oid.FriendlyName or Oid.Value property must be set. + The specified Oid ({0}) is not valid. The Oid.FriendlyName or Oid.Value property must be set. The specified DSA parameters are not valid; P, G and Y must be the same length (the key size). diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECCurve.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECCurve.cs index a14e816f799df..5876e483bcb6d 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECCurve.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECCurve.cs @@ -79,7 +79,7 @@ private set throw new ArgumentNullException(nameof(Oid)); if (string.IsNullOrEmpty(value.Value) && string.IsNullOrEmpty(value.FriendlyName)) - throw new ArgumentException(SR.Cryptography_InvalidCurveOid); + throw new ArgumentException(SR.Format(SR.Cryptography_InvalidCurveOid, value.Value)); _oid = value; } @@ -197,7 +197,7 @@ public void Validate() if (Oid == null || (string.IsNullOrEmpty(Oid.FriendlyName) && string.IsNullOrEmpty(Oid.Value))) { - throw new CryptographicException(SR.Cryptography_InvalidCurveOid); + throw new CryptographicException(SR.Format(SR.Cryptography_InvalidCurveOid, Oid?.Value)); } } else if (IsExplicit) diff --git a/src/libraries/System.Text.Encoding/tests/Fallback/DecoderReplacementFallbackTests.cs b/src/libraries/System.Text.Encoding/tests/Fallback/DecoderReplacementFallbackTests.cs index 51d3f2d074e72..7bb51d8a22dd8 100644 --- a/src/libraries/System.Text.Encoding/tests/Fallback/DecoderReplacementFallbackTests.cs +++ b/src/libraries/System.Text.Encoding/tests/Fallback/DecoderReplacementFallbackTests.cs @@ -36,12 +36,12 @@ public void Ctor_Invalid() AssertExtensions.Throws("replacement", () => new DecoderReplacementFallback(null)); // Invalid surrogate pair - AssertExtensions.Throws(null, () => new DecoderReplacementFallback("\uD800")); - AssertExtensions.Throws(null, () => new DecoderReplacementFallback("\uD800a")); - AssertExtensions.Throws(null, () => new DecoderReplacementFallback("\uDC00")); - AssertExtensions.Throws(null, () => new DecoderReplacementFallback("a\uDC00")); - AssertExtensions.Throws(null, () => new DecoderReplacementFallback("\uDC00\uDC00")); - AssertExtensions.Throws(null, () => new DecoderReplacementFallback("\uD800\uD800")); + AssertExtensions.Throws("replacement", () => new DecoderReplacementFallback("\uD800")); + AssertExtensions.Throws("replacement", () => new DecoderReplacementFallback("\uD800a")); + AssertExtensions.Throws("replacement", () => new DecoderReplacementFallback("\uDC00")); + AssertExtensions.Throws("replacement", () => new DecoderReplacementFallback("a\uDC00")); + AssertExtensions.Throws("replacement", () => new DecoderReplacementFallback("\uDC00\uDC00")); + AssertExtensions.Throws("replacement", () => new DecoderReplacementFallback("\uD800\uD800")); } public static IEnumerable Equals_TestData() diff --git a/src/libraries/System.Text.Encoding/tests/Fallback/EncoderReplacementFallbackTests.cs b/src/libraries/System.Text.Encoding/tests/Fallback/EncoderReplacementFallbackTests.cs index 45709bb693e22..1fe7b2499ab16 100644 --- a/src/libraries/System.Text.Encoding/tests/Fallback/EncoderReplacementFallbackTests.cs +++ b/src/libraries/System.Text.Encoding/tests/Fallback/EncoderReplacementFallbackTests.cs @@ -36,12 +36,12 @@ public void Ctor_Invalid() AssertExtensions.Throws("replacement", () => new EncoderReplacementFallback(null)); // Invalid surrogate pair - AssertExtensions.Throws(null, () => new EncoderReplacementFallback("\uD800")); - AssertExtensions.Throws(null, () => new EncoderReplacementFallback("\uD800a")); - AssertExtensions.Throws(null, () => new EncoderReplacementFallback("\uDC00")); - AssertExtensions.Throws(null, () => new EncoderReplacementFallback("a\uDC00")); - AssertExtensions.Throws(null, () => new EncoderReplacementFallback("\uDC00\uDC00")); - AssertExtensions.Throws(null, () => new EncoderReplacementFallback("\uD800\uD800")); + AssertExtensions.Throws("replacement", () => new EncoderReplacementFallback("\uD800")); + AssertExtensions.Throws("replacement", () => new EncoderReplacementFallback("\uD800a")); + AssertExtensions.Throws("replacement", () => new EncoderReplacementFallback("\uDC00")); + AssertExtensions.Throws("replacement", () => new EncoderReplacementFallback("a\uDC00")); + AssertExtensions.Throws("replacement", () => new EncoderReplacementFallback("\uDC00\uDC00")); + AssertExtensions.Throws("replacement", () => new EncoderReplacementFallback("\uD800\uD800")); } public static IEnumerable Equals_TestData() From 0bf7e14c80da09fa92e3cdf65b46dbc4d14bd0b5 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 25 Jan 2022 18:23:52 -0500 Subject: [PATCH 210/308] Add Regex.Count string overloads (#64289) --- .../ref/System.Text.RegularExpressions.cs | 4 + .../src/System.Text.RegularExpressions.csproj | 1 + .../Text/RegularExpressions/Regex.Count.cs | 64 ++++++++++ .../tests/Regex.Count.Tests.cs | 120 ++++++++++++++++++ ...ystem.Text.RegularExpressions.Tests.csproj | 1 + 5 files changed, 190 insertions(+) create mode 100644 src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Count.cs create mode 100644 src/libraries/System.Text.RegularExpressions/tests/Regex.Count.Tests.cs diff --git a/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs b/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs index 75ed12a69731f..251d595081072 100644 --- a/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs +++ b/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs @@ -161,6 +161,10 @@ public static void CompileToAssembly(System.Text.RegularExpressions.RegexCompila public static void CompileToAssembly(System.Text.RegularExpressions.RegexCompilationInfo[] regexinfos, System.Reflection.AssemblyName assemblyname, System.Reflection.Emit.CustomAttributeBuilder[]? attributes) { } [System.ObsoleteAttribute("Regex.CompileToAssembly is obsolete and not supported. Use the RegexGeneratorAttribute with the regular expression source generator instead.", DiagnosticId = "SYSLIB0036", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public static void CompileToAssembly(System.Text.RegularExpressions.RegexCompilationInfo[] regexinfos, System.Reflection.AssemblyName assemblyname, System.Reflection.Emit.CustomAttributeBuilder[]? attributes, string? resourceFile) { } + public int Count(string input) { throw null; } + public static int Count(string input, [System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern) { throw null; } + public static int Count(string input, [System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options) { throw null; } + public static int Count(string input, [System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex, "options")] string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) { throw null; } public static string Escape(string str) { throw null; } public string[] GetGroupNames() { throw null; } public int[] GetGroupNumbers() { throw null; } diff --git a/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj b/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj index acda3098b795c..cfe2c82d38d1a 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj +++ b/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj @@ -18,6 +18,7 @@ + diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Count.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Count.cs new file mode 100644 index 0000000000000..18c08ee3242e2 --- /dev/null +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Count.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. + +using System.Diagnostics.CodeAnalysis; + +namespace System.Text.RegularExpressions +{ + public partial class Regex + { + /// Searches an input string for all occurrences of a regular expression and returns the number of matches. + /// The string to search for a match. + /// The number of matches. + /// is null. + public int Count(string input) + { + if (input is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); + } + + int count = 0; + + Run(input, 0, ref count, static (ref int count, Match match) => + { + count++; + return true; + }, reuseMatchObject: true); + + return count; + } + + /// Searches an input string for all occurrences of a regular expression and returns the number of matches. + /// The string to search for a match. + /// The regular expression pattern to match. + /// The number of matches. + /// or is null. + /// A regular expression parsing error occurred. + public static int Count(string input, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern) => + RegexCache.GetOrAdd(pattern).Count(input); + + /// Searches an input string for all occurrences of a regular expression and returns the number of matches. + /// The string to search for a match. + /// The regular expression pattern to match. + /// A bitwise combination of the enumeration values that specify options for matching. + /// The number of matches. + /// or is null. + /// is not a valid bitwise combination of RegexOptions values. + /// A regular expression parsing error occurred. + public static int Count(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options) => + RegexCache.GetOrAdd(pattern, options, s_defaultMatchTimeout).Count(input); + + /// Searches an input string for all occurrences of a regular expression and returns the number of matches. + /// The string to search for a match. + /// The regular expression pattern to match. + /// A bitwise combination of the enumeration values that specify options for matching. + /// A time-out interval, or to indicate that the method should not time out. + /// The number of matches. + /// or is null. + /// is not a valid bitwise combination of RegexOptions values, or is negative, zero, or greater than approximately 24 days. + /// A regular expression parsing error occurred. + public static int Count(string input, [StringSyntax(StringSyntaxAttribute.Regex, "options")] string pattern, RegexOptions options, TimeSpan matchTimeout) => + RegexCache.GetOrAdd(pattern, options, matchTimeout).Count(input); + } +} diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Count.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Count.Tests.cs new file mode 100644 index 0000000000000..272cbb143d69d --- /dev/null +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Count.Tests.cs @@ -0,0 +1,120 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.RegularExpressions.Tests +{ + public class RegexCountTests + { + [Theory] + [MemberData(nameof(Count_ReturnsExpectedCount_TestData))] + public async Task Count_ReturnsExpectedCount(RegexEngine engine, string pattern, string input, RegexOptions options, int expectedCount) + { + Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options); + Assert.Equal(expectedCount, r.Count(input)); + Assert.Equal(r.Count(input), r.Matches(input).Count); + + if (options == RegexOptions.None && engine == RegexEngine.Interpreter) + { + Assert.Equal(expectedCount, Regex.Count(input, pattern)); + } + + switch (engine) + { + case RegexEngine.Interpreter: + case RegexEngine.Compiled: + case RegexEngine.NonBacktracking: + RegexOptions engineOptions = RegexHelpers.OptionsFromEngine(engine); + Assert.Equal(expectedCount, Regex.Count(input, pattern, options | engineOptions)); + Assert.Equal(expectedCount, Regex.Count(input, pattern, options | engineOptions, Regex.InfiniteMatchTimeout)); + break; + } + } + + public static IEnumerable Count_ReturnsExpectedCount_TestData() + { + foreach (RegexEngine engine in RegexHelpers.AvailableEngines) + { + yield return new object[] { engine, @"", "", RegexOptions.None, 1 }; + yield return new object[] { engine, @"", "a", RegexOptions.None, 2 }; + yield return new object[] { engine, @"", "ab", RegexOptions.None, 3 }; + + yield return new object[] { engine, @"\w", "", RegexOptions.None, 0 }; + yield return new object[] { engine, @"\w", "a", RegexOptions.None, 1 }; + yield return new object[] { engine, @"\w", "ab", RegexOptions.None, 2 }; + + yield return new object[] { engine, @"\b\w+\b", "abc def ghi jkl", RegexOptions.None, 4 }; + + yield return new object[] { engine, @"A", "", RegexOptions.IgnoreCase, 0 }; + yield return new object[] { engine, @"A", "a", RegexOptions.IgnoreCase, 1 }; + yield return new object[] { engine, @"A", "aAaA", RegexOptions.IgnoreCase, 4 }; + + yield return new object[] { engine, @".", "\n\n\n", RegexOptions.None, 0 }; + yield return new object[] { engine, @".", "\n\n\n", RegexOptions.Singleline, 3 }; + } + } + + [Fact] + public void Count_InvalidArguments_Throws() + { + // input is null + AssertExtensions.Throws("input", () => new Regex("pattern").Count(null)); + AssertExtensions.Throws("input", () => Regex.Count(null, @"pattern")); + AssertExtensions.Throws("input", () => Regex.Count(null, @"pattern", RegexOptions.None)); + AssertExtensions.Throws("input", () => Regex.Count(null, @"pattern", RegexOptions.None, TimeSpan.FromMilliseconds(1))); + + // pattern is null + AssertExtensions.Throws("pattern", () => Regex.Count("input", null)); + AssertExtensions.Throws("pattern", () => Regex.Count("input", null, RegexOptions.None)); + AssertExtensions.Throws("pattern", () => Regex.Count("input", null, RegexOptions.None, TimeSpan.FromMilliseconds(1))); + + // pattern is invalid +#pragma warning disable RE0001 // invalid regex pattern + AssertExtensions.Throws(() => Regex.Count("input", @"[abc")); + AssertExtensions.Throws(() => Regex.Count("input", @"[abc", RegexOptions.None)); + AssertExtensions.Throws(() => Regex.Count("input", @"[abc", RegexOptions.None, TimeSpan.FromMilliseconds(1))); +#pragma warning restore RE0001 + + // options is invalid + AssertExtensions.Throws("options", () => Regex.Count("input", @"[abc]", (RegexOptions)(-1))); + AssertExtensions.Throws("options", () => Regex.Count("input", @"[abc]", (RegexOptions)(-1), TimeSpan.FromMilliseconds(1))); + + // matchTimeout is invalid + AssertExtensions.Throws("matchTimeout", () => Regex.Count("input", @"[abc]", RegexOptions.None, TimeSpan.FromMilliseconds(-2))); + } + + [Theory] + [MemberData(nameof(RegexHelpers.AvailableEngines_MemberData), MemberType = typeof(RegexHelpers))] + public async Task Count_Timeout_ThrowsAfterTooLongExecution(RegexEngine engine) + { + if (RegexHelpers.IsNonBacktracking(engine)) + { + // Test relies on backtracking taking a long time + return; + } + + const string Pattern = @"^(\w+\s?)*$"; + const string Input = "An input string that takes a very very very very very very very very very very very long time!"; + + Regex r = await RegexHelpers.GetRegexAsync(engine, Pattern, RegexOptions.None, TimeSpan.FromMilliseconds(1)); + + Stopwatch sw = Stopwatch.StartNew(); + Assert.Throws(() => r.Count(Input)); + Assert.InRange(sw.Elapsed.TotalSeconds, 0, 10); // arbitrary upper bound that should be well above what's needed with a 1ms timeout + + switch (engine) + { + case RegexEngine.Interpreter: + case RegexEngine.Compiled: + sw = Stopwatch.StartNew(); + Assert.Throws(() => Regex.Count(Input, Pattern, RegexHelpers.OptionsFromEngine(engine), TimeSpan.FromMilliseconds(1))); + Assert.InRange(sw.Elapsed.TotalSeconds, 0, 10); // arbitrary upper bound that should be well above what's needed with a 1ms timeout + break; + } + } + } +} diff --git a/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Tests.csproj b/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Tests.csproj index 9641f9665a175..d95fa07ad73f1 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Tests.csproj +++ b/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Tests.csproj @@ -41,6 +41,7 @@ + From b5714997652ed38b28a14365b144d12efb420839 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 25 Jan 2022 17:31:27 -0800 Subject: [PATCH 211/308] Clarify purpose of PDB Document hashing (#64306) Fixes #63505 --- docs/design/specs/PortablePdb-Metadata.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/design/specs/PortablePdb-Metadata.md b/docs/design/specs/PortablePdb-Metadata.md index 811af00510bea..c1d8e3c442066 100644 --- a/docs/design/specs/PortablePdb-Metadata.md +++ b/docs/design/specs/PortablePdb-Metadata.md @@ -64,6 +64,8 @@ There shall be no duplicate rows in the _Document_ table, based upon document na _Name_ shall not be nil. It can however encode an empty name string. +_Hash_ is the file content hashed using the specified _HashAlgorithm_. It is used to validate that a source file matches the one used by the compiler when compiling the source code. + The values for which field _Language_ has a defined meaning are listed in the following tables along with the corresponding interpretation: | _Language_ field value | language | From 518548b96b3369ceb3c54dd62e6cf55e2c5a4ce3 Mon Sep 17 00:00:00 2001 From: Robert Henry Date: Tue, 25 Jan 2022 17:38:52 -0800 Subject: [PATCH 212/308] Fix arm64/PInvoke so that NESTED_ENTRY/NESTED_END labels match. (#64296) This was exposed by building on arm64 with gcc-12, wherein the assembler complained about not being able to evaluate the constant expression for .size for the symbol on NESTED_END. Since the symbol on NESTED_END is not referenced anywhere else in the code base, I concluded that it was wrong, and NESTED_ENTRY was right. I have not tested this on anything but arm64 + gcc-12 --- src/coreclr/nativeaot/Runtime/arm64/PInvoke.S | 2 +- src/coreclr/nativeaot/Runtime/arm64/PInvoke.asm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/arm64/PInvoke.S b/src/coreclr/nativeaot/Runtime/arm64/PInvoke.S index f66851461f278..4d3fbbbce2216 100644 --- a/src/coreclr/nativeaot/Runtime/arm64/PInvoke.S +++ b/src/coreclr/nativeaot/Runtime/arm64/PInvoke.S @@ -188,7 +188,7 @@ NoAbort: EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 0xA0 EPILOG_RETURN - NESTED_END RhpReversePInvokeTrapThread + NESTED_END RhpReversePInvokeAttachOrTrapThread, _TEXT // // RhpPInvoke diff --git a/src/coreclr/nativeaot/Runtime/arm64/PInvoke.asm b/src/coreclr/nativeaot/Runtime/arm64/PInvoke.asm index 7692bfa8341be..4bc165aef0450 100644 --- a/src/coreclr/nativeaot/Runtime/arm64/PInvoke.asm +++ b/src/coreclr/nativeaot/Runtime/arm64/PInvoke.asm @@ -180,7 +180,7 @@ NoAbort EPILOG_RESTORE_REG_PAIR fp, lr, #0xA0! EPILOG_RETURN - NESTED_END RhpReversePInvokeTrapThread + NESTED_END RhpReversePInvokeAttachOrTrapThread ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From cfd725fcd1d446950efd8a7751a78b83f3b3e2c1 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Tue, 25 Jan 2022 19:02:08 -0800 Subject: [PATCH 213/308] When decommitting, leaving one instead of two pages in regions case. (#64243) --- src/coreclr/gc/gc.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index bc4c11771f2b1..4842346ad26af 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -11601,10 +11601,11 @@ void gc_heap::decommit_heap_segment (heap_segment* seg) dprintf (3, ("Decommitting heap segment %Ix(%Ix)", (size_t)seg, heap_segment_mem (seg))); -#ifdef BACKGROUND_GC +#if defined(BACKGROUND_GC) && !defined(USE_REGIONS) page_start += OS_PAGE_SIZE; -#endif //BACKGROUND_GC +#endif //BACKGROUND_GC && !USE_REGIONS + assert (heap_segment_committed (seg) >= page_start); size_t size = heap_segment_committed (seg) - page_start; bool decommit_succeeded_p = virtual_decommit (page_start, size, heap_segment_oh (seg), heap_number); From 9d3ff2659b820f5fa7bf8223f99f54d0ffb34cbc Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 25 Jan 2022 22:32:11 -0500 Subject: [PATCH 214/308] Ensure that canceled Task.Delays invoke continuations asynchronously from Cancel (#64217) --- .../src/System/Threading/Tasks/Task.cs | 14 ++++++++++++++ .../tests/Task/TaskRtTests.cs | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 6e319542ce488..f5a4becbd73b4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -5627,6 +5627,20 @@ internal DelayPromiseWithCancellation(uint millisecondsDelay, CancellationToken _registration = token.UnsafeRegister(static (state, cancellationToken) => { var thisRef = (DelayPromiseWithCancellation)state!; + + // Normally RunContinuationsAsynchronously is set at construction time. We don't want to + // set it at construction because we want the timer firing (already on a thread pool thread with + // a stack in which it's fine to execute arbitrary code) to synchronously invoke any continuations + // from this task. However, a cancellation request will come synchronously from a call to + // CancellationTokenSource.Cancel, and we don't want to invoke arbitrary continuations from + // this delay task as part of that Cancel call. As such, we set RunContinuationsAsynchronously + // after the fact, only when the task is being completed due to cancellation. There is a race + // condition here, such that if the timer also fired concurrently, it might win, in which case + // it might also observe this RunContinuationsAsynchronously, but that's benign. An alternative + // is to make the whole cancellation registration queue, but that's visible in that the Task's + // IsCompleted wouldn't be set synchronously as part of IsCompleted. + thisRef.AtomicStateUpdate((int)TaskCreationOptions.RunContinuationsAsynchronously, 0); + if (thisRef.TrySetCanceled(cancellationToken)) { thisRef.Cleanup(); diff --git a/src/libraries/System.Threading.Tasks/tests/Task/TaskRtTests.cs b/src/libraries/System.Threading.Tasks/tests/Task/TaskRtTests.cs index e763ae63a43d4..ffb2437aa4b3e 100644 --- a/src/libraries/System.Threading.Tasks/tests/Task/TaskRtTests.cs +++ b/src/libraries/System.Threading.Tasks/tests/Task/TaskRtTests.cs @@ -691,6 +691,24 @@ public static void RunDelayTests_NegativeCases() } } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + public static void TaskDelay_Cancellation_ContinuationsInvokedAsynchronously() + { + var cts = new CancellationTokenSource(); + + var tl = new ThreadLocal(); + Task c = Task.Delay(-1, cts.Token).ContinueWith(_ => + { + Assert.Equal(0, tl.Value); + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + + tl.Value = 42; + cts.Cancel(); + tl.Value = 0; + + c.GetAwaiter().GetResult(); + } + // Test that exceptions are properly wrapped when thrown in various scenarios. // Make sure that "indirect" logic does not add superfluous exception wrapping. [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] From 82ff4f89e5997ade30ac1a9de8f343c321dd10a9 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Tue, 25 Jan 2022 19:32:45 -0800 Subject: [PATCH 215/308] Add gen folder moving gen projects from src folder (#64231) --- ...rosoft.Extensions.Logging.Abstractions.sln | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.sln b/src/libraries/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.sln index bf9829d652330..6f3c58066d303 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.sln +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.sln @@ -1,9 +1,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32111.311 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{79CE8C7E-A4AF-413C-A54D-86F17073559C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Logging.Generators", "gen\Microsoft.Extensions.Logging.Generators.Roslyn3.11.csproj", "{1491B9C9-955D-4DB0-B1D5-70137A78EAAE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Logging.Generators.Roslyn3.11", "gen\Microsoft.Extensions.Logging.Generators.Roslyn3.11.csproj", "{1491B9C9-955D-4DB0-B1D5-70137A78EAAE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Logging.Generators", "gen\Microsoft.Extensions.Logging.Generators.Roslyn4.0.csproj", "{A5439E79-96D6-4F02-8DD0-23DFF979851D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Logging.Generators.Roslyn4.0", "gen\Microsoft.Extensions.Logging.Generators.Roslyn4.0.csproj", "{A5439E79-96D6-4F02-8DD0-23DFF979851D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Logging.Abstractions", "ref\Microsoft.Extensions.Logging.Abstractions.csproj", "{7F536552-0E2A-4642-B7CF-863727C2F9CD}" EndProject @@ -23,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{548DF5F7-790 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{7631380A-FB73-4241-9987-0891A21E9769}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{03F31CEE-D63E-4E7F-949F-139B33DC3385}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -71,14 +76,14 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {79CE8C7E-A4AF-413C-A54D-86F17073559C} = {4DE63935-DCA9-4D63-9C1F-AAE79C89CA8B} + {1491B9C9-955D-4DB0-B1D5-70137A78EAAE} = {03F31CEE-D63E-4E7F-949F-139B33DC3385} + {A5439E79-96D6-4F02-8DD0-23DFF979851D} = {03F31CEE-D63E-4E7F-949F-139B33DC3385} + {7F536552-0E2A-4642-B7CF-863727C2F9CD} = {7631380A-FB73-4241-9987-0891A21E9769} + {75C579F7-F20B-41F1-8CAF-641DE7ADA4EE} = {548DF5F7-790C-4A1C-89EB-BD904CA1BA86} {C333EC5A-F386-4A01-AE20-12D499551304} = {4DE63935-DCA9-4D63-9C1F-AAE79C89CA8B} {1CB869A7-2EEC-4A53-9C33-DF9E0C75825B} = {4DE63935-DCA9-4D63-9C1F-AAE79C89CA8B} - {1491B9C9-955D-4DB0-B1D5-70137A78EAAE} = {548DF5F7-790C-4A1C-89EB-BD904CA1BA86} - {A5439E79-96D6-4F02-8DD0-23DFF979851D} = {548DF5F7-790C-4A1C-89EB-BD904CA1BA86} - {75C579F7-F20B-41F1-8CAF-641DE7ADA4EE} = {548DF5F7-790C-4A1C-89EB-BD904CA1BA86} - {F8CF3192-B902-4631-972A-C405FDECC48D} = {548DF5F7-790C-4A1C-89EB-BD904CA1BA86} - {7F536552-0E2A-4642-B7CF-863727C2F9CD} = {7631380A-FB73-4241-9987-0891A21E9769} {DAA1349E-960E-49EB-81F3-FF4F99D8A325} = {7631380A-FB73-4241-9987-0891A21E9769} + {F8CF3192-B902-4631-972A-C405FDECC48D} = {548DF5F7-790C-4A1C-89EB-BD904CA1BA86} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {450DA749-CBDC-4BDC-950F-8A491CF59D49} From 8770287f77c6b218c0d30536544531ba8597faf4 Mon Sep 17 00:00:00 2001 From: Robert Henry Date: Tue, 25 Jan 2022 20:16:44 -0800 Subject: [PATCH 216/308] Fix minor typos in GC documentation. (#64298) --- src/coreclr/gc/gcconfig.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/gc/gcconfig.h b/src/coreclr/gc/gcconfig.h index 886ea17743880..d727a4685c527 100644 --- a/src/coreclr/gc/gcconfig.h +++ b/src/coreclr/gc/gcconfig.h @@ -87,8 +87,8 @@ class GCConfigStringHolder INT_CONFIG (SegmentSize, "GCSegmentSize", NULL, 0, "Specifies the managed heap segment size") \ INT_CONFIG (LatencyMode, "GCLatencyMode", NULL, -1, "Specifies the GC latency mode - batch, interactive or low latency (note that the same " \ "thing can be specified via API which is the supported way") \ - INT_CONFIG (LatencyLevel, "GCLatencyLevel", NULL, 1, "Specifies the GC latency level that you want to optimize for. Must be a number from 0" \ - "3. See documentation for more details on each level.") \ + INT_CONFIG (LatencyLevel, "GCLatencyLevel", NULL, 1, "Specifies the GC latency level that you want to optimize for. Must be a number from 0 " \ + "to 3. See documentation for more details on each level.") \ INT_CONFIG (LogFileSize, "GCLogFileSize", NULL, 0, "Specifies the GC log file size") \ INT_CONFIG (CompactRatio, "GCCompactRatio", NULL, 0, "Specifies the ratio compacting GCs vs sweeping") \ INT_CONFIG (GCHeapAffinitizeMask, "GCHeapAffinitizeMask", "System.GC.HeapAffinitizeMask", 0, "Specifies processor mask for Server GC threads") \ @@ -117,7 +117,7 @@ class GCConfigStringHolder INT_CONFIG (BGCFLkd, "BGCFLkd", NULL, 11, "Specifies kd for above goal tuning") \ INT_CONFIG (BGCFLff, "BGCFLff", NULL, 100, "Specifies ff ratio") \ INT_CONFIG (BGCFLSmoothFactor, "BGCFLSmoothFactor", NULL, 150, "Smoothing over these") \ - INT_CONFIG (BGCFLGradualD, "BGCFLGradualD", NULL, 0, "Enable gradual D instead of cutting of at the value") \ + INT_CONFIG (BGCFLGradualD, "BGCFLGradualD", NULL, 0, "Enable gradual D instead of cutting off at the value") \ INT_CONFIG (BGCMLkp, "BGCMLkp", NULL, 1000, "Specifies kp for ML tuning") \ INT_CONFIG (BGCMLki, "BGCMLki", NULL, 16, "Specifies ki for ML tuning") \ INT_CONFIG (BGCFLEnableKi, "BGCFLEnableKi", NULL, 1, "Enables ki for above goal tuning") \ From 43ceed5514ca93242ff41f9f1ee53fc108c5dc1b Mon Sep 17 00:00:00 2001 From: Egor Chesakov Date: Tue, 25 Jan 2022 20:49:13 -0800 Subject: [PATCH 217/308] Explicitly specify four subdirectories to use as part of the paths for -pmi_path arguments and expand the paths on a remote machine in src/coreclr/scripts/superpmi-collect.proj (#64308) --- src/coreclr/scripts/superpmi-collect.proj | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/coreclr/scripts/superpmi-collect.proj b/src/coreclr/scripts/superpmi-collect.proj index 4a6edd8b5923b..8d59a8218ae88 100644 --- a/src/coreclr/scripts/superpmi-collect.proj +++ b/src/coreclr/scripts/superpmi-collect.proj @@ -44,7 +44,10 @@ --> - + + + + @@ -59,7 +62,7 @@ %HELIX_WORKITEM_UPLOAD_ROOT% $(BUILD_SOURCESDIRECTORY)\artifacts\helixresults - $(SuperPMIDirectory)\superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)\pmi.dll -pmi_path @(PmiPathDirectories->'%(FullPath)', ' ') + $(SuperPMIDirectory)\superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)\pmi.dll -pmi_path @(PmiPathDirectories->'$(SuperPMIDirectory)\%(Identity)', ' ') $HELIX_PYTHONPATH @@ -73,7 +76,7 @@ $HELIX_WORKITEM_UPLOAD_ROOT $(BUILD_SOURCESDIRECTORY)/artifacts/helixresults - $(SuperPMIDirectory)/superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)/pmi.dll -pmi_path @(PmiPathDirectories->'%(FullPath)', ' ') + $(SuperPMIDirectory)/superpmi.py collect -log_level DEBUG --$(CollectionType) -pmi_location $(SuperPMIDirectory)/pmi.dll -pmi_path @(PmiPathDirectories->'$(SuperPMIDirectory)/%(Identity)', ' ') From 4bc40395f9f5d154f7ed2cb5e79bb1aaaa2fc917 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 26 Jan 2022 04:16:26 -0500 Subject: [PATCH 218/308] Disable RegexReductionTests on browser (#64312) --- .../tests/RegexReductionTests.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs index f4fcbf92dadf1..02c6e3a8f2445 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs @@ -6,7 +6,8 @@ namespace System.Text.RegularExpressions.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/64300", TestPlatforms.Browser)] + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Many of these optimizations don't exist in .NET Framework.")] + [SkipOnPlatform(TestPlatforms.Browser, "Internal members accessed via reflection may have been trimmed away")] public class RegexReductionTests { // These tests depend on using reflection to access internals of Regex in order to validate @@ -25,9 +26,9 @@ public class RegexReductionTests static RegexReductionTests() { - if (PlatformDetection.IsNetFramework) + if (PlatformDetection.IsNetFramework || PlatformDetection.IsBrowser) { - // These members may not exist, and the tests won't run. + // These members may not exist or may have been trimmed away, and the tests won't run. return; } @@ -95,7 +96,6 @@ private static int GetMinRequiredLength(Regex r) } [Theory] - [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Many of these optimizations don't exist in .NET Framework.")] // Two greedy one loops [InlineData("a*a*", "a*")] [InlineData("(a*a*)", "(a*)")] @@ -475,7 +475,6 @@ public void PatternsReduceIdentically(string pattern1, string pattern2) } [Theory] - [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Many of these optimizations don't exist in .NET Framework.")] // Not coalescing loops [InlineData("aa", "a{2}")] [InlineData("a[^a]", "a{2}")] @@ -557,7 +556,6 @@ public void PatternsReduceDifferently(string pattern1, string pattern2) } [Theory] - [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Not computed in netfx")] [InlineData(@"a", RegexOptions.None, 1, 1)] [InlineData(@"[^a]", RegexOptions.None, 1, 1)] [InlineData(@"[abcdefg]", RegexOptions.None, 1, 1)] @@ -637,7 +635,6 @@ public void MinMaxLengthIsCorrect(string pattern, RegexOptions options, int expe } [Fact] - [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Not computed in netfx")] public void MinMaxLengthIsCorrect_HugeDepth() { const int Depth = 10_000; From d34c0ff7c104b3c6e39eb17cc0d21b7ca2dc5c6d Mon Sep 17 00:00:00 2001 From: Bar Arnon Date: Wed, 26 Jan 2022 11:58:21 +0200 Subject: [PATCH 219/308] Add UnreachableException (#63922) --- .../src/System/RuntimeType.CoreCLR.cs | 2 +- .../BindingFlagSupport/ConstructorPolicies.cs | 2 +- .../Data/RestrictedTypeHandlingTests.cs | 3 +- .../Formats/Asn1/AsnWriter.GeneralizedTime.cs | 7 +--- .../src/System/Dynamic/Utils/ContractUtils.cs | 2 +- .../src/Resources/Strings.resx | 3 ++ .../System.Private.CoreLib.Shared.projitems | 1 + .../Diagnostics/UnreachableException.cs | 41 +++++++++++++++++++ .../src/Resources/Strings.resx | 3 -- .../Internal/Utilities/ExceptionUtilities.cs | 3 -- .../tests/SerializationGuardTests.cs | 2 +- .../System.Runtime/ref/System.Runtime.cs | 6 +++ .../Diagnostics/UnreachableExceptionTests.cs | 40 ++++++++++++++++++ src/mono/mono/tests/bug-gh-9507.cs | 3 +- .../Interop/COM/ComWrappers/API/Program.cs | 5 ++- .../ObjectiveCMarshalAPI/Program.cs | 3 +- 16 files changed, 105 insertions(+), 21 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/UnreachableException.cs create mode 100644 src/libraries/System.Runtime/tests/System/Diagnostics/UnreachableExceptionTests.cs diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index a0d7026b54407..bf83df6c0f975 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -1941,7 +1941,7 @@ private static PropertyInfo GetPropertyInfo(RuntimeType reflectedType, int tkPro } Debug.Fail("Unreachable code"); - throw new SystemException(); + throw new UnreachableException(); } internal static void ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception? e) diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs index 6b7b539996aec..368105aa0de8a 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs @@ -54,7 +54,7 @@ public sealed override bool OkToIgnoreAmbiguity(ConstructorInfo m1, ConstructorI { // Constructors are only resolvable using an array of parameter types so this should never be called. Debug.Fail("This code path should be unreachable."); - throw new NotSupportedException(); + throw new UnreachableException(); } } } diff --git a/src/libraries/System.Data.Common/tests/System/Data/RestrictedTypeHandlingTests.cs b/src/libraries/System.Data.Common/tests/System/Data/RestrictedTypeHandlingTests.cs index 54644b678a5bc..d42609fed6b5c 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/RestrictedTypeHandlingTests.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/RestrictedTypeHandlingTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data.SqlTypes; +using System.Diagnostics; using System.Drawing; using System.IO; using System.Numerics; @@ -433,7 +434,7 @@ public void ReadXml(XmlReader reader) string tempPath = Path.GetTempFileName(); File.WriteAllText(tempPath, "This better not be written..."); File.Delete(tempPath); - throw new XunitException("Unreachable code (SerializationGuard should have kicked in)"); + throw new UnreachableException("Unreachable code (SerializationGuard should have kicked in)"); } public void WriteXml(XmlWriter writer) diff --git a/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnWriter.GeneralizedTime.cs b/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnWriter.GeneralizedTime.cs index 6b20ca15a3101..7d8df542caf68 100644 --- a/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnWriter.GeneralizedTime.cs +++ b/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnWriter.GeneralizedTime.cs @@ -62,12 +62,7 @@ private void WriteGeneralizedTimeCore( // where "f?" is anything from "f" to "fffffff" (tenth of a second down to 100ns/1-tick) // with no trailing zeros. DateTimeOffset normalized = value.ToUniversalTime(); - - if (normalized.Year > 9999) - { - // This is unreachable since DateTimeOffset guards against this internally. - throw new ArgumentOutOfRangeException(nameof(value)); - } + Debug.Assert(normalized.Year <= 9999, "DateTimeOffset guards against this internally"); // We're only loading in sub-second ticks. // Ticks are defined as 1e-7 seconds, so their printed form diff --git a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/ContractUtils.cs b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/ContractUtils.cs index 8125fc9ac1159..e481185ffa57a 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/ContractUtils.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/ContractUtils.cs @@ -20,7 +20,7 @@ public static Exception Unreachable get { Debug.Fail("Unreachable"); - return new InvalidOperationException("Code supposed to be unreachable"); + return new UnreachableException(); } } diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 8564b3894fa41..383660c6f9a92 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -786,6 +786,9 @@ Unknown TypeCode value. + + The program executed an instruction that was thought to be unreachable. + Missing parameter does not have a default value. 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 8cf5cf0dda601..b7079c0ea1ff5 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 @@ -285,6 +285,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/UnreachableException.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/UnreachableException.cs new file mode 100644 index 0000000000000..be8ff08940eeb --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/UnreachableException.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Diagnostics +{ + /// + /// Exception thrown when the program executes an instruction that was thought to be unreachable. + /// + public sealed class UnreachableException : Exception + { + /// + /// Initializes a new instance of the class with the default error message. + /// + public UnreachableException() + : base(SR.Arg_UnreachableException) + { + } + + /// + /// Initializes a new instance of the + /// class with a specified error message. + /// + /// The error message that explains the reason for the exception. + public UnreachableException(string? message) + : base(message) + { + } + + /// + /// Initializes a new instance of the + /// class with a specified error message and a reference to the inner exception that is the cause of + /// this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. + public UnreachableException(string? message, Exception? innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx b/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx index f4a6f03089790..e85eb5e2a3aa9 100644 --- a/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx +++ b/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx @@ -405,7 +405,4 @@ Unexpected value '{0}' of unknown type. - - This program location is thought to be unreachable. - diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ExceptionUtilities.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ExceptionUtilities.cs index 3d6b4605cf492..c0ebc31d376e8 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ExceptionUtilities.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ExceptionUtilities.cs @@ -14,8 +14,5 @@ internal static Exception UnexpectedValue(object value) return new InvalidOperationException(SR.Format(SR.UnexpectedValueUnknownType, value)); } - - internal static Exception Unreachable => - new InvalidOperationException(SR.UnreachableLocation); } } diff --git a/src/libraries/System.Runtime.Serialization.Formatters/tests/SerializationGuardTests.cs b/src/libraries/System.Runtime.Serialization.Formatters/tests/SerializationGuardTests.cs index 31329577fb637..7c294ff0a6c1c 100644 --- a/src/libraries/System.Runtime.Serialization.Formatters/tests/SerializationGuardTests.cs +++ b/src/libraries/System.Runtime.Serialization.Formatters/tests/SerializationGuardTests.cs @@ -91,7 +91,7 @@ private FileWriter(SerializationInfo info, StreamingContext context) { string tempPath = Path.GetTempFileName(); File.WriteAllText(tempPath, "This better not be written..."); - throw new InvalidOperationException("Unreachable code (SerializationGuard should have kicked in)"); + throw new UnreachableException("Unreachable code (SerializationGuard should have kicked in)"); } public void GetObjectData(SerializationInfo info, StreamingContext context) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 82211a2cca7c8..35930e8deffa9 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -9037,6 +9037,12 @@ public void Start() { } public static System.Diagnostics.Stopwatch StartNew() { throw null; } public void Stop() { } } + public sealed partial class UnreachableException : System.Exception + { + public UnreachableException() { } + public UnreachableException(string? message) { } + public UnreachableException(string? message, System.Exception? innerException) { } + } } namespace System.Diagnostics.CodeAnalysis { diff --git a/src/libraries/System.Runtime/tests/System/Diagnostics/UnreachableExceptionTests.cs b/src/libraries/System.Runtime/tests/System/Diagnostics/UnreachableExceptionTests.cs new file mode 100644 index 0000000000000..24fdc34396655 --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Diagnostics/UnreachableExceptionTests.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. + +using System; +using System.Diagnostics; +using Xunit; + +namespace System.Tests +{ + public static class UnreachableExceptionTests + { + [Fact] + public static void DefaultConstructor() + { + UnreachableException unreachableException = new UnreachableException(); + + Assert.NotNull(unreachableException.Message); + } + + [Fact] + public static void MessageConstructor() + { + string message = "MessageConstructor"; + UnreachableException unreachableException = new UnreachableException(message); + + Assert.Equal(message, unreachableException.Message); + } + + [Fact] + public static void MessageInnerExceptionConstructor() + { + string message = "MessageConstructor"; + Exception innerException = new Exception(); + UnreachableException unreachableException = new UnreachableException(); + + Assert.Equal(message, unreachableException.Message); + Assert.Same(innerException, unreachableException.InnerException); + } + } +} diff --git a/src/mono/mono/tests/bug-gh-9507.cs b/src/mono/mono/tests/bug-gh-9507.cs index 9a6b60e85693f..6291e1ca2e9af 100644 --- a/src/mono/mono/tests/bug-gh-9507.cs +++ b/src/mono/mono/tests/bug-gh-9507.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using type_with_special_array_cast = System.UInt64; // MonoClass::cast_class = long using other_type = System.Double; @@ -9,7 +10,7 @@ public TestIsInst() { array = new T[16]; if (array is other_type[]) // should not crash or throw NullReferenceException - throw new System.Exception("Unreachable"); + throw new System.UnreachableException(); } } diff --git a/src/tests/Interop/COM/ComWrappers/API/Program.cs b/src/tests/Interop/COM/ComWrappers/API/Program.cs index 99a2094c80b91..b5f6b4d09cfdc 100644 --- a/src/tests/Interop/COM/ComWrappers/API/Program.cs +++ b/src/tests/Interop/COM/ComWrappers/API/Program.cs @@ -6,6 +6,7 @@ namespace ComWrappersTests using System; using System.Collections; using System.Collections.Generic; + using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -376,7 +377,7 @@ public enum FailureMode throw new Exception() { HResult = ExceptionErrorCode }; default: Assert.True(false, "Invalid failure mode"); - throw new Exception("UNREACHABLE"); + throw new UnreachableException(); } } @@ -390,7 +391,7 @@ protected override object CreateObject(IntPtr externalComObject, CreateObjectFla throw new Exception() { HResult = ExceptionErrorCode }; default: Assert.True(false, "Invalid failure mode"); - throw new Exception("UNREACHABLE"); + throw new UnreachableException(); } } diff --git a/src/tests/Interop/ObjectiveC/ObjectiveCMarshalAPI/Program.cs b/src/tests/Interop/ObjectiveC/ObjectiveCMarshalAPI/Program.cs index b9d06dd542162..f899919ef9dab 100644 --- a/src/tests/Interop/ObjectiveC/ObjectiveCMarshalAPI/Program.cs +++ b/src/tests/Interop/ObjectiveC/ObjectiveCMarshalAPI/Program.cs @@ -5,6 +5,7 @@ namespace ObjectiveCMarshalAPI { using System; using System.Collections.Generic; + using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ObjectiveC; @@ -269,7 +270,7 @@ public ExceptionException() {} } Assert.True(false, "Unknown exception type"); - throw new Exception("Unreachable"); + throw new UnreachableException(); } class Scenario From 2b1cf1e48c24c534d0e871e06c66e24fe0e8f568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Wed, 26 Jan 2022 12:38:53 +0100 Subject: [PATCH 220/308] [mono] Recognize new names for Xamarin.iOS etc assemblies (#64278) They are being renamed in https://github.com/xamarin/xamarin-macios/pull/13847 --- src/mono/mono/mini/intrinsics.c | 6 +++++- src/mono/mono/mini/mini-native-types.c | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 7dc808d2def83..87ec858a46993 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -1924,7 +1924,11 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } else if (((!strcmp (cmethod_klass_image->assembly->aname.name, "Xamarin.iOS") || !strcmp (cmethod_klass_image->assembly->aname.name, "Xamarin.TVOS") || !strcmp (cmethod_klass_image->assembly->aname.name, "Xamarin.MacCatalyst") || - !strcmp (cmethod_klass_image->assembly->aname.name, "Xamarin.Mac")) && + !strcmp (cmethod_klass_image->assembly->aname.name, "Xamarin.Mac") || + !strcmp (cmethod_klass_image->assembly->aname.name, "Microsoft.iOS") || + !strcmp (cmethod_klass_image->assembly->aname.name, "Microsoft.tvOS") || + !strcmp (cmethod_klass_image->assembly->aname.name, "Microsoft.MacCatalyst") || + !strcmp (cmethod_klass_image->assembly->aname.name, "Microsoft.macOS")) && !strcmp (cmethod_klass_name_space, "ObjCRuntime") && !strcmp (cmethod_klass_name, "Selector")) ) { diff --git a/src/mono/mono/mini/mini-native-types.c b/src/mono/mono/mini/mini-native-types.c index 9faebab38b2e9..a9a3a0f8e484b 100644 --- a/src/mono/mono/mini/mini-native-types.c +++ b/src/mono/mono/mini/mini-native-types.c @@ -374,6 +374,14 @@ mono_class_is_magic_assembly (MonoClass *klass) return TRUE; if (!strcmp ("Xamarin.MacCatalyst", aname)) return TRUE; + if (!strcmp ("Microsoft.iOS", aname)) + return TRUE; + if (!strcmp ("Microsoft.macOS", aname)) + return TRUE; + if (!strcmp ("Microsoft.watchOS", aname)) + return TRUE; + if (!strcmp ("Microsoft.MacCatalyst", aname)) + return TRUE; /* regression test suite */ if (!strcmp ("builtin-types", aname)) return TRUE; From 994d390c7cdc1f91b2b37235cf68605ead5d7c44 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Wed, 26 Jan 2022 14:56:21 +0200 Subject: [PATCH 221/308] Remove usage of codecvt from corerun (#64157) * Remove usage of codecvt from corerun * Update src/coreclr/hosts/corerun/corerun.cpp Co-authored-by: Aaron Robinson Co-authored-by: Aaron Robinson --- src/coreclr/hosts/corerun/corerun.cpp | 8 ++--- src/coreclr/hosts/corerun/corerun.hpp | 48 +++++++++++++++------------ src/coreclr/hosts/corerun/dotenv.cpp | 23 +++---------- 3 files changed, 35 insertions(+), 44 deletions(-) diff --git a/src/coreclr/hosts/corerun/corerun.cpp b/src/coreclr/hosts/corerun/corerun.cpp index 345a18ef6bc62..67a43e28b20d1 100644 --- a/src/coreclr/hosts/corerun/corerun.cpp +++ b/src/coreclr/hosts/corerun/corerun.cpp @@ -291,9 +291,9 @@ static int run(const configuration& config) } // Construct CoreCLR properties. - pal::string_utf8_t tpa_list_utf8 = pal::convert_to_utf8(std::move(tpa_list)); - pal::string_utf8_t app_path_utf8 = pal::convert_to_utf8(std::move(app_path)); - pal::string_utf8_t native_search_dirs_utf8 = pal::convert_to_utf8(native_search_dirs.str()); + pal::string_utf8_t tpa_list_utf8 = pal::convert_to_utf8(tpa_list.c_str()); + pal::string_utf8_t app_path_utf8 = pal::convert_to_utf8(app_path.c_str()); + pal::string_utf8_t native_search_dirs_utf8 = pal::convert_to_utf8(native_search_dirs.str().c_str()); std::vector user_defined_keys_utf8; std::vector user_defined_values_utf8; @@ -334,7 +334,7 @@ static int run(const configuration& config) int propertyCount = (int)propertyKeys.size(); // Construct arguments - pal::string_utf8_t exe_path_utf8 = pal::convert_to_utf8(std::move(exe_path)); + pal::string_utf8_t exe_path_utf8 = pal::convert_to_utf8(exe_path.c_str()); std::vector argv_lifetime; pal::malloc_ptr argv_utf8{ pal::convert_argv_to_utf8(config.entry_assembly_argc, config.entry_assembly_argv, argv_lifetime) }; pal::string_utf8_t entry_assembly_utf8 = pal::convert_to_utf8(config.entry_assembly_fullpath.c_str()); diff --git a/src/coreclr/hosts/corerun/corerun.hpp b/src/coreclr/hosts/corerun/corerun.hpp index 9781299c8049e..14cb9ec6580e1 100644 --- a/src/coreclr/hosts/corerun/corerun.hpp +++ b/src/coreclr/hosts/corerun/corerun.hpp @@ -88,11 +88,28 @@ namespace pal assert(wrote < needed); return { buffer.get() }; } + inline string_utf8_t getenvA(const char* var) + { + DWORD needed = ::GetEnvironmentVariableA(var, nullptr, 0); + if (needed == 0) + return {}; + + malloc_ptr buffer{ (char*)::malloc(needed * sizeof(char)) }; + assert(buffer != nullptr); + DWORD wrote = ::GetEnvironmentVariableA(var, buffer.get(), needed); + assert(wrote < needed); + return { buffer.get() }; + } inline void setenv(const char_t* var, string_t value) { BOOL success = ::SetEnvironmentVariableW(var, value.c_str()); assert(success); } + inline void setenvA(const char* var, string_utf8_t value) + { + BOOL success = ::SetEnvironmentVariableA(var, value.c_str()); + assert(success); + } inline string_t get_exe_path() { char_t file_name[1024]; @@ -177,31 +194,17 @@ namespace pal inline string_utf8_t convert_to_utf8(const char_t* str) { - // Compute the needed buffer - int bytes_req = ::WideCharToMultiByte( - CP_UTF8, 0, // Conversion args - str, -1, // Input string - nullptr, 0, // Null to request side - nullptr, nullptr); + int bytes_req = ::WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr); malloc_ptr buffer{ (char*)::malloc(bytes_req) }; assert(buffer != nullptr); - int written = ::WideCharToMultiByte( - CP_UTF8, 0, // Conversion args - str, -1, // Input string - buffer.get(), bytes_req, // Output buffer - nullptr, nullptr); + int written = ::WideCharToMultiByte(CP_UTF8, 0, str, -1, buffer.get(), bytes_req, nullptr, nullptr); assert(bytes_req == written); return { buffer.get() }; } - inline string_utf8_t convert_to_utf8(string_t&& str) - { - return convert_to_utf8(str.c_str()); - } - inline bool try_load_hostpolicy(pal::string_t mock_hostpolicy_value) { const char_t* hostpolicyName = W("hostpolicy.dll"); @@ -360,11 +363,19 @@ namespace pal return {}; return { val }; } + inline string_utf8_t getenvA(const char* var) + { + return getenv(var); + } inline void setenv(const char_t* var, string_t value) { int error = ::setenv(var, value.c_str(), /* overwrite */ 1); assert(error == 0); } + inline void setenvA(const char* var, string_utf8_t value) + { + setenv(var, value.c_str()); + } inline string_t get_exe_path() { return minipal_getexepath(); } @@ -567,11 +578,6 @@ namespace pal return { str }; } - inline string_utf8_t convert_to_utf8(string_t&& str) - { - return std::move(str); - } - inline bool try_load_hostpolicy(pal::string_t mock_hostpolicy_value) { if (!string_ends_with(mock_hostpolicy_value, pal::nativelib_ext)) diff --git a/src/coreclr/hosts/corerun/dotenv.cpp b/src/coreclr/hosts/corerun/dotenv.cpp index 0e0e37c7919b0..8792d63151f56 100644 --- a/src/coreclr/hosts/corerun/dotenv.cpp +++ b/src/coreclr/hosts/corerun/dotenv.cpp @@ -7,22 +7,8 @@ #include #include -#ifdef TARGET_WINDOWS -#include -#endif - namespace { - pal::string_t convert_to_string_t(std::string str) - { -#ifdef TARGET_WINDOWS - std::wstring_convert> converter; - return converter.from_bytes(str); -#else - return str; -#endif - } - bool read_var_name(std::istream& file, std::string& var_name_out) { std::string var_name; @@ -326,8 +312,7 @@ dotenv::dotenv(pal::string_t dotEnvFilePath, std::istream& contents) { return dot_env_entry->second; } - pal::string_t env_var_name = convert_to_string_t(name); - return pal::convert_to_utf8(pal::getenv(env_var_name.c_str())); + return pal::getenvA(name.c_str()); }, temp_value)) { _environmentVariables = {}; @@ -341,9 +326,9 @@ void dotenv::load_into_current_process() const { for (std::pair env_vars : _environmentVariables) { - pal::string_t name_string = convert_to_string_t(env_vars.first); - pal::string_t value_string = convert_to_string_t(env_vars.second); - pal::setenv(name_string.c_str(), std::move(value_string)); + pal::string_utf8_t name_string = env_vars.first; + pal::string_utf8_t value_string = env_vars.second; + pal::setenvA(name_string.c_str(), std::move(value_string)); } } From 12da7826e7235d9ffde336b9c41123182069b7ac Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Wed, 26 Jan 2022 14:29:28 +0100 Subject: [PATCH 222/308] Refactor FileStatus.Unix. (#62721) * Refactor FileStatus.Unix. - Moves InitiallyDirectory out of FileStatus into FileSystemInfo. In FileSystemInfo it can be a readonly field making its usage clearer. And FileStatus can then directly be used to implement some FileSystem methods without allocating an intermediate FileInfo/DirectoryInfo. - Treat not exists/exist as initialized states to avoid wrongly assuming initialized means the file cache is valid, which isn't so when the file does not exist. - Use 0 for tracking uninitialized to make default(FileStatus) uninitialized. --- .../tests/Directory/SymbolicLinks.cs | 6 +- .../tests/DirectoryInfo/SymbolicLinks.cs | 6 +- .../IO/Enumeration/FileSystemEntry.Unix.cs | 14 +- .../src/System/IO/FileStatus.SetTimes.OSX.cs | 10 +- .../IO/FileStatus.SetTimes.OtherUnix.cs | 8 +- .../src/System/IO/FileStatus.Unix.cs | 218 ++++++++---------- .../src/System/IO/FileSystem.Unix.cs | 40 +--- .../src/System/IO/FileSystemInfo.Unix.cs | 20 +- .../src/System/IO/FileSystemInfo.cs | 1 - 9 files changed, 134 insertions(+), 189 deletions(-) diff --git a/src/libraries/System.IO.FileSystem/tests/Directory/SymbolicLinks.cs b/src/libraries/System.IO.FileSystem/tests/Directory/SymbolicLinks.cs index 43106e3c2a6b7..1052ddfc22b9b 100644 --- a/src/libraries/System.IO.FileSystem/tests/Directory/SymbolicLinks.cs +++ b/src/libraries/System.IO.FileSystem/tests/Directory/SymbolicLinks.cs @@ -47,11 +47,7 @@ protected override void AssertLinkExists(FileSystemInfo link) } else { - // Unix implementation detail: - // When the directory target does not exist FileStatus.GetExists returns false because: - // - We check _exists (which whould be true because the link itself exists). - // - We check InitiallyDirectory, which is the initial expected object type (which would be true). - // - We check _directory (false because the target directory does not exist) + // Unix requires the target to be a directory that exists. Assert.False(link.Exists); } } diff --git a/src/libraries/System.IO.FileSystem/tests/DirectoryInfo/SymbolicLinks.cs b/src/libraries/System.IO.FileSystem/tests/DirectoryInfo/SymbolicLinks.cs index 84658b6f275b9..254c00df40133 100644 --- a/src/libraries/System.IO.FileSystem/tests/DirectoryInfo/SymbolicLinks.cs +++ b/src/libraries/System.IO.FileSystem/tests/DirectoryInfo/SymbolicLinks.cs @@ -44,11 +44,7 @@ protected override void AssertLinkExists(FileSystemInfo link) } else { - // Unix implementation detail: - // When the directory target does not exist FileStatus.GetExists returns false because: - // - We check _exists (which whould be true because the link itself exists). - // - We check InitiallyDirectory, which is the initial expected object type (which would be true). - // - We check _directory (false because the target directory does not exist) + // Unix requires the target to be a directory that exists. Assert.False(link.Exists); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEntry.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEntry.Unix.cs index 89c38584eea32..3c7fb6504473e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEntry.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEntry.Unix.cs @@ -11,6 +11,7 @@ namespace System.IO.Enumeration public unsafe ref partial struct FileSystemEntry { private Interop.Sys.DirectoryEntry _directoryEntry; + private bool _isDirectory; private FileStatus _status; private Span _pathBuffer; private ReadOnlySpan _fullPath; @@ -32,8 +33,8 @@ internal static FileAttributes Initialize( entry._pathBuffer = pathBuffer; entry._fullPath = ReadOnlySpan.Empty; entry._fileName = ReadOnlySpan.Empty; + entry._isDirectory = false; entry._status.InvalidateCaches(); - entry._status.InitiallyDirectory = false; bool isDirectory = directoryEntry.InodeType == Interop.Sys.NodeType.DT_DIR; bool isSymlink = directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK; @@ -41,15 +42,15 @@ internal static FileAttributes Initialize( if (isDirectory) { - entry._status.InitiallyDirectory = true; + entry._isDirectory = true; } else if (isSymlink) { - entry._status.InitiallyDirectory = entry._status.IsDirectory(entry.FullPath, continueOnError: true); + entry._isDirectory = entry._status.IsDirectory(entry.FullPath, continueOnError: true); } else if (isUnknown) { - entry._status.InitiallyDirectory = entry._status.IsDirectory(entry.FullPath, continueOnError: true); + entry._isDirectory = entry._status.IsDirectory(entry.FullPath, continueOnError: true); if (entry._status.IsSymbolicLink(entry.FullPath, continueOnError: true)) { entry._directoryEntry.InodeType = Interop.Sys.NodeType.DT_LNK; @@ -145,16 +146,17 @@ public FileAttributes Attributes public DateTimeOffset CreationTimeUtc => _status.GetCreationTime(FullPath, continueOnError: true); public DateTimeOffset LastAccessTimeUtc => _status.GetLastAccessTime(FullPath, continueOnError: true); public DateTimeOffset LastWriteTimeUtc => _status.GetLastWriteTime(FullPath, continueOnError: true); + public bool IsHidden => _status.IsFileSystemEntryHidden(FullPath, FileName); internal bool IsReadOnly => _status.IsReadOnly(FullPath, continueOnError: true); - public bool IsDirectory => _status.InitiallyDirectory; + public bool IsDirectory => _isDirectory; internal bool IsSymbolicLink => _directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK; public FileSystemInfo ToFileSystemInfo() { string fullPath = ToFullPath(); - return FileSystemInfo.Create(fullPath, new string(FileName), ref _status); + return FileSystemInfo.Create(fullPath, new string(FileName), _isDirectory, ref _status); } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.SetTimes.OSX.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.SetTimes.OSX.cs index 23c46bae4a012..40a887e7210be 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.SetTimes.OSX.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.SetTimes.OSX.cs @@ -7,7 +7,7 @@ namespace System.IO { internal partial struct FileStatus { - internal void SetCreationTime(string path, DateTimeOffset time) + internal void SetCreationTime(string path, DateTimeOffset time, bool asDirectory) { // Try to set the attribute on the file system entry using setattrlist, // if we get ENOTSUP then it means that "The volume does not support @@ -27,11 +27,11 @@ internal void SetCreationTime(string path, DateTimeOffset time) } else if (error == Interop.Error.ENOTSUP) { - SetAccessOrWriteTimeCore(path, time, isAccessTime: false, checkCreationTime: false); + SetAccessOrWriteTimeCore(path, time, isAccessTime: false, checkCreationTime: false, asDirectory); } else { - Interop.CheckIo(error, path, InitiallyDirectory); + Interop.CheckIo(error, path, asDirectory); } } @@ -54,7 +54,7 @@ private unsafe Interop.Error SetCreationTimeCore(string path, long seconds, long return error; } - private void SetAccessOrWriteTime(string path, DateTimeOffset time, bool isAccessTime) => - SetAccessOrWriteTimeCore(path, time, isAccessTime, checkCreationTime: true); + private void SetAccessOrWriteTime(string path, DateTimeOffset time, bool isAccessTime, bool asDirectory) => + SetAccessOrWriteTimeCore(path, time, isAccessTime, checkCreationTime: true, asDirectory); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.SetTimes.OtherUnix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.SetTimes.OtherUnix.cs index d9d9b1eeb7c92..85b01fde17d7c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.SetTimes.OtherUnix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.SetTimes.OtherUnix.cs @@ -7,11 +7,11 @@ namespace System.IO { internal partial struct FileStatus { - internal void SetCreationTime(string path, DateTimeOffset time) => - SetLastWriteTime(path, time); + internal void SetCreationTime(string path, DateTimeOffset time, bool asDirectory) => + SetLastWriteTime(path, time, asDirectory); - private void SetAccessOrWriteTime(string path, DateTimeOffset time, bool isAccessTime) => - SetAccessOrWriteTimeCore(path, time, isAccessTime, checkCreationTime: false); + private void SetAccessOrWriteTime(string path, DateTimeOffset time, bool isAccessTime, bool asDirectory) => + SetAccessOrWriteTimeCore(path, time, isAccessTime, checkCreationTime: false, asDirectory); // This is not used on these platforms, but is needed for source compat private Interop.Error SetCreationTimeCore(string path, long seconds, long nanoseconds) => diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs index 20961a8fbbc2e..91e67d1b9f74c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs @@ -10,44 +10,44 @@ internal partial struct FileStatus { private const int NanosecondsPerTick = 100; - // The last cached lstat information about the file + private const int InitializedExistsDir = -3; // target is directory. + private const int InitializedExistsFile = -2; // target is file. + private const int InitializedNotExists = -1; // entry does not exist. + private const int Uninitialized = 0; // uninitialized, '0' to make default(FileStatus) uninitialized. + + // Tracks the initialization state. + // < 0 : initialized succesfully. Value is InitializedNotExists, InitializedExistsFile or InitializedExistsDir. + // 0 : uninitialized. + // > 0 : initialized with error. Value is raw errno. + private int _state; + + // The last cached lstat information about the file. + // Must only be used after calling EnsureCachesInitialized and checking EntryExists is true. private Interop.Sys.FileStatus _fileCache; - // -1: if the file cache isn't initialized - Refresh should always change this value - // 0: if the file cache was initialized with no errors - // Positive number: the error code returned by the lstat call - private int _initializedFileCache; - - // We track intent of creation to know whether or not we want to (1) create a - // DirectoryInfo around this status struct or (2) actually are part of a DirectoryInfo. - // Set to true during initialization when the DirectoryEntry's INodeType describes a directory - internal bool InitiallyDirectory { get; set; } - - // Is a directory as of the last refresh - // Its value can come from either the main path or the symbolic link path - private bool _isDirectory; - - // Exists as of the last refresh - private bool _exists; - - private bool IsFileCacheInitialized => _initializedFileCache == 0; - - // Check if the main path (without following symlinks) has the hidden attribute set - // Ideally, use this if Refresh has been successfully called at least once. - // But since it is also used for soft retrieval during FileSystemEntry initialization, - // we return false early if the cache has not been initialized - internal bool HasHiddenFlag => IsFileCacheInitialized && - (_fileCache.UserFlags & (uint)Interop.Sys.UserFlags.UF_HIDDEN) == (uint)Interop.Sys.UserFlags.UF_HIDDEN; - - // Checks if the main path (without following symlinks) has the read-only attribute set - // Ideally, use this if Refresh has been successfully called at least once. - // But since it is also used for soft retrieval during FileSystemEntry initialization, - // we return false early if the cache has not been initialized - internal bool HasReadOnlyFlag + private bool EntryExists => _state <= InitializedExistsFile; + + private bool IsDir => _state == InitializedExistsDir; + + // Check if the main path (without following symlinks) has the hidden attribute set. + private bool HasHiddenFlag { get { - if (!IsFileCacheInitialized) + Debug.Assert(_state != Uninitialized); // Use this after EnsureCachesInitialized has been called. + + return EntryExists && (_fileCache.UserFlags & (uint)Interop.Sys.UserFlags.UF_HIDDEN) == (uint)Interop.Sys.UserFlags.UF_HIDDEN; + } + } + + // Checks if the main path (without following symlinks) has the read-only attribute set. + private bool HasReadOnlyFlag + { + get + { + Debug.Assert(_state != Uninitialized); // Use this after EnsureCachesInitialized has been called. + + if (!EntryExists) { return false; } @@ -78,6 +78,7 @@ internal bool HasReadOnlyFlag #if !TARGET_BROWSER // HasReadOnlyFlag cache. + // Must only be used after calling EnsureCachesInitialized. private int _isReadOnlyCache; private bool IsModeReadOnlyCore() @@ -123,20 +124,20 @@ private bool IsModeReadOnlyCore() #endif // Checks if the main path is a symbolic link - // Only call if Refresh has been successfully called at least once private bool HasSymbolicLinkFlag { get { - Debug.Assert(IsFileCacheInitialized); - return (_fileCache.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK; + Debug.Assert(_state != Uninitialized); // Use this after EnsureCachesInitialized has been called. + + return EntryExists && (_fileCache.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK; } } - // Sets the cache initialization flags to -1, which means the caches are now uninitialized + // Sets the cache initialization flags to 0, which means the caches are now uninitialized internal void InvalidateCaches() { - _initializedFileCache = -1; + _state = Uninitialized; } internal bool IsReadOnly(ReadOnlySpan path, bool continueOnError = false) @@ -169,7 +170,7 @@ internal bool IsFileSystemEntryHidden(ReadOnlySpan path, ReadOnlySpan path, bool continueOnError = false) { EnsureCachesInitialized(path, continueOnError); - return _isDirectory; + return IsDir; } internal bool IsSymbolicLink(ReadOnlySpan path, bool continueOnError = false) @@ -182,7 +183,7 @@ internal FileAttributes GetAttributes(ReadOnlySpan path, ReadOnlySpan path, ReadOnlySpan path, ReadOnlySpan