diff --git a/docs/design/features/y2038.md b/docs/design/features/y2038.md index ddee5375d83678..fa4ad1eaa52985 100644 --- a/docs/design/features/y2038.md +++ b/docs/design/features/y2038.md @@ -22,7 +22,7 @@ Normally, ABI breaks like this are not a problem for the Linux ecosystem because ### .NET builds -.NET official builds are produced by building the product on a [dedicated set of build images](https://github.com/dotnet/runtime/blob/main/docs/workflow/building/coreclr/linux-instructions.md). The images run Azure Linux 3.0 with an up-to-date cross-compilation toolchain, and also include a root filesystem of an old Linux distribution that provides an old version of glibc (or musl libc), which determines the libc compatibility of our builds. +.NET official builds are produced by building the product on a [dedicated set of build images](https://github.com/dotnet/runtime/blob/main/docs/workflow/using-docker.md#the-official-runtime-docker-images). The images run Azure Linux 3.0 with an up-to-date cross-compilation toolchain, and also include a root filesystem of an old Linux distribution that provides an old version of glibc (or musl libc), which determines the libc compatibility of our builds. In .NET 8, we [support](https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md#libc-compatibility) glibc 2.23 and musl 1.2.2, by building the product with a root filesystem from Ubuntu 16.04 and Alpine 3.13, respectively. diff --git a/docs/design/specs/runtime-async.md b/docs/design/specs/runtime-async.md index adc1d2ff064046..48985b139b4cec 100644 --- a/docs/design/specs/runtime-async.md +++ b/docs/design/specs/runtime-async.md @@ -11,7 +11,15 @@ These are proposed modifications to the ECMA-335 specification for runtime-async ### I.8.4.5 Sync and Async Methods -Methods may be either 'sync' or 'async'. Async method definitions are methods with a return type of `System.Threading.Task`, `System.Threading.ValueTask`, `System.Threading.Task`, or `System.Threading.ValueTask` attributed with `[System.Runtime.CompilerServices.RuntimeAsyncMethodAttribute]`. Async method definitions are only valid inside async-capable assemblies. An async-capable assembly is one which references a corlib containing an `abstract sealed class RuntimeFeature` with a `public const string` field member named `Async`, or a corelib meeting these requirements. The `RuntimeAsyncMethodAttribute` should only be applied to methods, and may be defined in any assembly. Inside async method bodies, certain methods are also invokable by a special signature encoding, described in [### I.8.6.1.5 Method signatures]. +Methods may be either 'sync' or 'async'. Async method definitions are methods attributed with `[MethodImpl(MethodImplOptions.Async)]`. Inside async method bodies, certain methods are also invokable by a special signature encoding, described in [### I.8.6.1.5 Method signatures]. + +Applicability of `MethodImplOptions.Async`: +* The `[MethodImpl(MethodImplOptions.Async)]` only has effect when applied to method definitions that return generic or nongeneric variants of Task or ValueTask. +* The `[MethodImpl(MethodImplOptions.Async)]` only has effect when applied to method definitions with CIL implementation. +* Async method definitions are only valid inside async-capable assemblies. An async-capable assembly is one which references a corlib containing an `abstract sealed class RuntimeFeature` with a `public const string` field member named `Async`. +* Combining `MethodImplOptions.Async` with `MethodImplOptions.Synchronized` is invalid. +* Applying `MethodImplOptions.Async` to methods with `byref` or `ref-like` parameters is invalid. +* Applying `MethodImplOptions.Async` to vararg methods is invalid. Sync methods are all other methods. @@ -28,9 +36,9 @@ Async methods support the following suspension points: { public static class RuntimeHelpers { - [RuntimeAsyncMethod] + [MethodImpl(MethodImplOptions.Async)] public static Task AwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : INotifyCompletion { ... } - [RuntimeAsyncMethod] + [MethodImpl(MethodImplOptions.Async)] public static Task UnsafeAwaitAwaiterFromRuntimeAsync(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion } } @@ -55,6 +63,13 @@ All async methods effectively have two entry points, or signatures. The first si Callers may retrieve a Task/ValueTask return type from an async method via calling its primary, definitional signature. This functionality is available in both sync and async methods. +### II.23.1.11 Flags for methods [MethodImplAttributes] + +| Flag | Value | Description | +| ------------- | ------------- | ------------- | +| . . . | . . . | . . . | +|Async |0x0400 |Method is an Async Method.| + ### I.8.6.1.5 Method signatures The list of relevant components is augmented to include sync vs. async method types. Async methods have some additions to normal signature compatibility. diff --git a/docs/workflow/building/coreclr/README.md b/docs/workflow/building/coreclr/README.md index ee190315a686e7..5987da06d7bb20 100644 --- a/docs/workflow/building/coreclr/README.md +++ b/docs/workflow/building/coreclr/README.md @@ -3,7 +3,7 @@ - [The Basics](#the-basics) - [Build Results](#build-results) - [What to do with the Build](#what-to-do-with-the-build) - - [The Core_Root for Testing Your Build](#the-core-root-for-testing-your-build) + - [The Core_Root for Testing Your Build](#the-core\_root-for-testing-your-build) - [The Dev Shipping Packs](#the-dev-shipping-packs) - [Cross Compilation](#cross-compilation) - [Other Features](#other-features) diff --git a/docs/workflow/building/coreclr/cross-building.md b/docs/workflow/building/coreclr/cross-building.md index d053569cfbcb3d..6e93e7538ce52b 100644 --- a/docs/workflow/building/coreclr/cross-building.md +++ b/docs/workflow/building/coreclr/cross-building.md @@ -146,7 +146,7 @@ When it comes to building, Docker offers the most flexibility when it comes to t ### Cross-Compiling for ARM32 and ARM64 with Docker -As mentioned in the [Linux Cross-Building section](#linux-cross-building), the `ROOTFS_DIR` environment variable has to be set to the _crossrootfs_ location. The prereqs Docker images already have _crossrootfs_ built, so you only need to specify it when creating the Docker container by means of the `-e` flag. These locations are specified in the [Docker Images table](/docs/workflow/building/coreclr/linux-instructions.md#docker-images). +As mentioned in the [Linux Cross-Building section](#linux-cross-building), the `ROOTFS_DIR` environment variable has to be set to the _crossrootfs_ location. The prereqs Docker images already have _crossrootfs_ built, so you only need to specify it when creating the Docker container by means of the `-e` flag. These locations are specified in the [Docker Images table](/docs/workflow/using-docker.md#the-official-runtime-docker-images). In addition, you also have to specify the `--cross` flag with the target architecture. For example, the following command would create a container to build CoreCLR for Linux ARM64: diff --git a/docs/workflow/requirements/linux-requirements.md b/docs/workflow/requirements/linux-requirements.md index 65c234b41f067e..cb22d31172780a 100644 --- a/docs/workflow/requirements/linux-requirements.md +++ b/docs/workflow/requirements/linux-requirements.md @@ -1,7 +1,7 @@ # Requirements to Set Up the Build Environment on Linux - [Using your Linux Environment](#using-your-linux-environment) - - [Debian/Ubuntu](#debian/ubuntu) + - [Debian and Ubuntu](#debian-and-ubuntu) - [CMake on Older Versions of Ubuntu and Debian](#cmake-on-older-versions-of-ubuntu-and-debian) - [Clang for WASM](#clang-for-wasm) - [Additional Tools for Cross Building](#additional-tools-for-cross-building) @@ -28,7 +28,7 @@ eng/common/native/install-dependencies.sh Note that it is always a good idea to manually double check that all the dependencies were installed correctly if you opt to use the script. -### Debian/Ubuntu +### Debian and Ubuntu These instructions are written assuming the current *Ubuntu LTS*. diff --git a/docs/workflow/testing/coreclr/testing.md b/docs/workflow/testing/coreclr/testing.md index 9b64b7b570b0d1..4db6b2e9dda22e 100644 --- a/docs/workflow/testing/coreclr/testing.md +++ b/docs/workflow/testing/coreclr/testing.md @@ -24,13 +24,12 @@ This guide will walk you through building and running the CoreCLR tests. These a ## Requirements -In order to build CoreCLR tests, you will need to have built the runtime and the libraries (that is, _clr_ and _libs_ subsets). You can find more detailed instructions per platform in their dedicated docs: +In order to build CoreCLR tests, you will need to have built the runtime and the libraries (that is, _clr_ and _libs_ subsets). You can find detailed instructions on how to do it on their respective README's: -* [Windows](/docs/workflow/building/coreclr/windows-instructions.md) -* [macOS](/docs/workflow/building/coreclr/macos-instructions.md) -* [Linux](/docs/workflow/building/coreclr/linux-instructions.md) +* [CoreCLR](/docs/workflow/building/coreclr/README.md) +* [Libraries](/docs/workflow/building/libraries/README.md) -For CoreCLR testing purposes, it is more than enough to simply build the _libs_ subset, as far as it concerns the libraries. If you want to know more in-depth about them, they have their own [libraries dedicated docs section](/docs/workflow/building/libraries/README.md). +For CoreCLR testing purposes, it is more than enough to simply build the _libs_ subset, as far as it concerns the libraries. If you want to know more in-depth about them, they have their own [libraries dedicated docs section](/docs/workflow/building/libraries/). ## Overview diff --git a/docs/workflow/testing/coreclr/unix-test-instructions.md b/docs/workflow/testing/coreclr/unix-test-instructions.md index 2dbde731066ca9..1a452c5e164502 100644 --- a/docs/workflow/testing/coreclr/unix-test-instructions.md +++ b/docs/workflow/testing/coreclr/unix-test-instructions.md @@ -6,7 +6,7 @@ CoreCLR tests ## Building -Build CoreCLR on [Unix](../../building/coreclr/linux-instructions.md). +Build CoreCLR following the instructions in its [main doc](/docs/workflow/building/coreclr/README.md). ## Building the Tests diff --git a/docs/workflow/testing/libraries/testing.md b/docs/workflow/testing/libraries/testing.md index d026dbebf55fbb..b4a4ad43ee2e0e 100644 --- a/docs/workflow/testing/libraries/testing.md +++ b/docs/workflow/testing/libraries/testing.md @@ -79,8 +79,7 @@ cd src\libraries\System.Collections.Immutable\tests dotnet build /t:Test ``` -**NOTE**: if your environment doesn't have the required SDK installed (e.g. inside [Docker container](/docs/workflow/building/coreclr/linux-instructions.md#build-using-docker)), -use `./dotnet.sh`/`.\dotnet.cmd` instead of `dotnet`. +**NOTE**: if your environment doesn't have the required SDK installed (e.g. inside [a Docker container](/docs/workflow/using-docker.md)), use `./dotnet.sh`/`.\dotnet.cmd` instead of `dotnet`. ### Running only certain tests diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index 0a7431072e3fa0..358dab7f43674d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -434,23 +434,10 @@ private bool BindToMethodInfo(object? target, IRuntimeMethodInfo method, Runtime private static MulticastDelegate InternalAlloc(RuntimeType type) { - MulticastDelegate? d = null; - InternalAlloc(new QCallTypeHandle(ref type), ObjectHandleOnStack.Create(ref d)); - return d!; + Debug.Assert(type.IsAssignableTo(typeof(MulticastDelegate))); + return Unsafe.As(RuntimeTypeHandle.InternalAlloc(type)); } - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_InternalAlloc")] - private static partial void InternalAlloc(QCallTypeHandle type, ObjectHandleOnStack d); - - internal static MulticastDelegate InternalAllocLike(MulticastDelegate d) - { - InternalAllocLike(ObjectHandleOnStack.Create(ref d)); - return d; - } - - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_InternalAllocLike")] - private static partial void InternalAllocLike(ObjectHandleOnStack d); - [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static unsafe bool InternalEqualTypes(object a, object b) { diff --git a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs index 0a850691d68678..0846f7060ce38f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs @@ -167,7 +167,7 @@ private static bool TrySetSlot(object?[] a, int index, object o) private MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount, bool thisIsMultiCastAlready) { // First, allocate a new multicast delegate just like this one, i.e. same type as the this object - MulticastDelegate result = InternalAllocLike(this); + MulticastDelegate result = Unsafe.As(RuntimeTypeHandle.InternalAllocNoChecks((RuntimeType)GetType())); // Performance optimization - if this already points to a true multicast delegate, // copy _methodPtr and _methodPtrAux fields rather than calling into the EE to get them diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs index 202a339b680251..ba42162dd03478 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs @@ -596,6 +596,32 @@ internal static void Unbox_Nullable(ref byte destPtr, MethodTable* typeMT, objec } } + [DebuggerHidden] + internal static object? ReboxFromNullable(MethodTable* srcMT, object src) + { + Debug.Assert(srcMT->IsNullable); + + ref byte nullableData = ref src.GetRawData(); + + // If 'hasValue' is false, return null. + if (!Unsafe.As(ref nullableData)) + return null; + + // Allocate a new instance of the T in Nullable. + MethodTable* dstMT = srcMT->InstantiationArg0(); + object dst = RuntimeTypeHandle.InternalAlloc(dstMT); + + // Copy data from the Nullable. + ref byte srcData = ref Unsafe.Add(ref nullableData, srcMT->NullableValueAddrOffset); + ref byte dstData = ref RuntimeHelpers.GetRawData(dst); + if (dstMT->ContainsGCPointers) + Buffer.BulkMoveWithWriteBarrier(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytesIfContainsGCPointers()); + else + SpanHelpers.Memmove(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytes()); + + return dst; + } + [DebuggerHidden] [MethodImpl(MethodImplOptions.NoInlining)] private static ref byte Unbox_Helper(MethodTable* pMT1, object obj) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 17e034811d79c1..b8da46a4bcdc14 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -269,6 +269,36 @@ private static partial void CreateInstanceForAnotherGenericParameter( int cTypeHandles, ObjectHandleOnStack instantiatedObject); + internal static unsafe object InternalAlloc(MethodTable* pMT) + { + object? result = null; + InternalAlloc(pMT, ObjectHandleOnStack.Create(ref result)); + return result!; + } + + internal static object InternalAlloc(RuntimeType type) + { + Debug.Assert(!type.GetNativeTypeHandle().IsTypeDesc); + object result = InternalAlloc(type.GetNativeTypeHandle().AsMethodTable()); + GC.KeepAlive(type); + return result; + } + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAlloc")] + private static unsafe partial void InternalAlloc(MethodTable* pMT, ObjectHandleOnStack result); + + internal static object InternalAllocNoChecks(RuntimeType type) + { + Debug.Assert(!type.GetNativeTypeHandle().IsTypeDesc); + object? result = null; + InternalAllocNoChecks(type.GetNativeTypeHandle().AsMethodTable(), ObjectHandleOnStack.Create(ref result)); + GC.KeepAlive(type); + return result!; + } + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAllocNoChecks")] + private static unsafe partial void InternalAllocNoChecks(MethodTable* pMT, ObjectHandleOnStack result); + /// /// Given a RuntimeType, returns information about how to activate it via calli /// semantics. This method will ensure the type object is fully initialized within @@ -1026,14 +1056,59 @@ internal static MdUtf8String GetUtf8Name(RuntimeMethodHandleInternal method) [DebuggerStepThrough] [DebuggerHidden] - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object? InvokeMethod(object? target, void** arguments, Signature sig, bool isConstructor); + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_InvokeMethod")] + private static partial void InvokeMethod(ObjectHandleOnStack target, void** arguments, ObjectHandleOnStack sig, Interop.BOOL isConstructor, ObjectHandleOnStack result); - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object? ReboxFromNullable(object? src); + [DebuggerStepThrough] + [DebuggerHidden] + internal static object? InvokeMethod(object? target, void** arguments, Signature sig, bool isConstructor) + { + object? result = null; + InvokeMethod( + ObjectHandleOnStack.Create(ref target), + arguments, + ObjectHandleOnStack.Create(ref sig), + isConstructor ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, + ObjectHandleOnStack.Create(ref result)); + return result; + } - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object ReboxToNullable(object? src, RuntimeType destNullableType); + /// + /// For a true boxed Nullable{T}, re-box to a boxed {T} or null, otherwise just return the input. + /// + internal static object? ReboxFromNullable(object? src) + { + // If src is null or not NullableOfT, just return that state. + if (src is null) + { + return null; + } + + MethodTable* pMT = RuntimeHelpers.GetMethodTable(src); + if (!pMT->IsNullable) + { + return src; + } + + return CastHelpers.ReboxFromNullable(pMT, src); + } + + /// + /// Convert a boxed value of {T} (which is either {T} or null) to a true boxed Nullable{T}. + /// + internal static object ReboxToNullable(object? src, RuntimeType destNullableType) + { + Debug.Assert(destNullableType.IsNullableOfT); + MethodTable* pMT = destNullableType.GetNativeTypeHandle().AsMethodTable(); + object obj = RuntimeTypeHandle.InternalAlloc(pMT); + GC.KeepAlive(destNullableType); // The obj instance will keep the type alive. + + CastHelpers.Unbox_Nullable( + ref obj.GetRawData(), + pMT, + src); + return obj; + } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_GetMethodInstantiation")] private static partial void GetMethodInstantiation(RuntimeMethodHandleInternal method, ObjectHandleOnStack types, Interop.BOOL fAsRuntimeTypeArray); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 6b7dc5ddfd8089..941d529b066e98 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6233,7 +6233,8 @@ class Compiler #endif // DEBUG weight_t GetCost(BasicBlock* block, BasicBlock* next); - bool TrySwappingPartitions(unsigned s1Start, unsigned s2Start, unsigned s3Start, unsigned s3End, unsigned s4End); + weight_t GetPartitionCostDelta(unsigned s1Start, unsigned s2Start, unsigned s3Start, unsigned s3End, unsigned s4End); + void SwapPartitions(unsigned s1Start, unsigned s2Start, unsigned s3Start, unsigned s3End, unsigned s4End); void ConsiderEdge(FlowEdge* edge); void AddNonFallthroughSuccs(unsigned blockPos); diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index 8176daab56a5b3..a54f36298ac3eb 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -4945,6 +4945,9 @@ weight_t Compiler::ThreeOptLayout::GetLayoutCost(unsigned startPos, unsigned end // block - The block to consider creating fallthrough from // next - The block to consider creating fallthrough into // +// Returns: +// The cost +// weight_t Compiler::ThreeOptLayout::GetCost(BasicBlock* block, BasicBlock* next) { assert(block != nullptr); @@ -4964,8 +4967,8 @@ weight_t Compiler::ThreeOptLayout::GetCost(BasicBlock* block, BasicBlock* next) } //----------------------------------------------------------------------------- -// Compiler::ThreeOptLayout::TrySwappingPartitions: Evaluates the cost of swapping the given partitions. -// If it is profitable, write the swapped partitions back to 'blockOrder'. +// Compiler::ThreeOptLayout::GetPartitionCostDelta: Computes the current cost of the given partitions, +// and the cost of swapping S2 and S3, returning the difference between them. // // Parameters: // s1Start - The starting position of the first partition @@ -4975,24 +4978,10 @@ weight_t Compiler::ThreeOptLayout::GetCost(BasicBlock* block, BasicBlock* next) // s4End - The ending position (inclusive) of the fourth partition // // Returns: -// True if the swap was performed, false otherwise -// -// Notes: -// Here is the proposed partition: -// S1: s1Start ~ s2Start-1 -// S2: s2Start ~ s3Start-1 -// S3: s3Start ~ s3End -// S4: remaining blocks -// -// After the swap: -// S1: s1Start ~ s2Start-1 -// S3: s3Start ~ s3End -// S2: s2Start ~ s3Start-1 -// S4: remaining blocks +// The difference in cost between the current and proposed layouts. +// A negative delta indicates the proposed layout is an improvement. // -// If 's3End' and 's4End' are the same, the fourth partition doesn't exist. -// -bool Compiler::ThreeOptLayout::TrySwappingPartitions( +weight_t Compiler::ThreeOptLayout::GetPartitionCostDelta( unsigned s1Start, unsigned s2Start, unsigned s3Start, unsigned s3End, unsigned s4End) { BasicBlock* const s2Block = blockOrder[s2Start]; @@ -5019,16 +5008,38 @@ bool Compiler::ThreeOptLayout::TrySwappingPartitions( newCost += s3BlockPrev->bbWeight; } - // Check if the swap is profitable - if ((newCost >= currCost) || Compiler::fgProfileWeightsEqual(newCost, currCost, 0.001)) - { - return false; - } + return newCost - currCost; +} - // We've found a profitable cut point. Continue with the swap. - JITDUMP("Swapping partitions [" FMT_BB ", " FMT_BB "] and [" FMT_BB ", " FMT_BB - "] (current partition cost = %f, new partition cost = %f)\n", - s2Block->bbNum, s3BlockPrev->bbNum, s3Block->bbNum, lastBlock->bbNum, currCost, newCost); +//----------------------------------------------------------------------------- +// Compiler::ThreeOptLayout::SwapPartitions: Swap the specified partitions. +// It is assumed (and asserted) that the swap is profitable. +// +// Parameters: +// s1Start - The starting position of the first partition +// s2Start - The starting position of the second partition +// s3Start - The starting position of the third partition +// s3End - The ending position (inclusive) of the third partition +// s4End - The ending position (inclusive) of the fourth partition +// +// Notes: +// Here is the proposed partition: +// S1: s1Start ~ s2Start-1 +// S2: s2Start ~ s3Start-1 +// S3: s3Start ~ s3End +// S4: remaining blocks +// +// After the swap: +// S1: s1Start ~ s2Start-1 +// S3: s3Start ~ s3End +// S2: s2Start ~ s3Start-1 +// S4: remaining blocks +// +// If 's3End' and 's4End' are the same, the fourth partition doesn't exist. +// +void Compiler::ThreeOptLayout::SwapPartitions( + unsigned s1Start, unsigned s2Start, unsigned s3Start, unsigned s3End, unsigned s4End) +{ INDEBUG(const weight_t currLayoutCost = GetLayoutCost(s1Start, s4End)); // Swap the partitions @@ -5062,8 +5073,6 @@ bool Compiler::ThreeOptLayout::TrySwappingPartitions( Compiler::fgProfileWeightsEqual(newLayoutCost, currLayoutCost, 0.001)); } #endif // DEBUG - - return true; } //----------------------------------------------------------------------------- @@ -5364,6 +5373,7 @@ bool Compiler::ThreeOptLayout::RunGreedyThreeOptPass(unsigned startPos, unsigned const bool isForwardJump = (srcPos < dstPos); unsigned s2Start, s3Start, s3End; + weight_t costChange; if (isForwardJump) { @@ -5378,35 +5388,83 @@ bool Compiler::ThreeOptLayout::RunGreedyThreeOptPass(unsigned startPos, unsigned // S3: dstPos ~ endPos // S2: srcPos+1 ~ dstPos-1 // S4: remaining blocks - s2Start = srcPos + 1; - s3Start = dstPos; - s3End = endPos; + s2Start = srcPos + 1; + s3Start = dstPos; + s3End = endPos; + costChange = GetPartitionCostDelta(startPos, s2Start, s3Start, s3End, endPos); } else { - + // For backward jumps, we will employ a greedy 4-opt approach to find the ideal cut point + // between the destination and source blocks. // Here is the proposed partition: // S1: startPos ~ dstPos-1 - // S2: dstPos ~ srcPos-1 - // S3: srcPos + // S2: dstPos ~ s3Start-1 + // S3: s3Start ~ srcPos // S4: srcPos+1 ~ endPos // // After the swap: // S1: startPos ~ dstPos-1 - // S3: srcPos - // S2: dstPos ~ srcPos-1 + // S3: s3Start ~ srcPos + // S2: dstPos ~ s3Start-1 // S4: srcPos+1 ~ endPos - s2Start = dstPos; - s3Start = srcPos; - s3End = srcPos; + s2Start = dstPos; + s3Start = srcPos; + s3End = srcPos; + costChange = BB_ZERO_WEIGHT; + + // The cut points before S2 and after S3 are fixed. + // We will search for the optimal cut point before S3. + BasicBlock* const s2Block = blockOrder[s2Start]; + BasicBlock* const s2BlockPrev = blockOrder[s2Start - 1]; + BasicBlock* const lastBlock = blockOrder[s3End]; + + // Because the above cut points are fixed, don't waste time re-computing their costs. + // Instead, pre-compute them here. + const weight_t currCostBase = + GetCost(s2BlockPrev, s2Block) + + ((s3End < endPos) ? GetCost(lastBlock, blockOrder[s3End + 1]) : lastBlock->bbWeight); + const weight_t newCostBase = GetCost(lastBlock, s2Block); + + // Search for the ideal start to S3 + for (unsigned position = s2Start + 1; position <= s3End; position++) + { + BasicBlock* const s3Block = blockOrder[position]; + BasicBlock* const s3BlockPrev = blockOrder[position - 1]; + + // Don't consider any cut points that would break up call-finally pairs + if (s3Block->KindIs(BBJ_CALLFINALLYRET)) + { + continue; + } + + // Compute the cost delta of this partition + const weight_t currCost = currCostBase + GetCost(s3BlockPrev, s3Block); + const weight_t newCost = + newCostBase + GetCost(s2BlockPrev, s3Block) + + ((s3End < endPos) ? GetCost(s3BlockPrev, blockOrder[s3End + 1]) : s3BlockPrev->bbWeight); + const weight_t delta = newCost - currCost; + + if (delta < costChange) + { + costChange = delta; + s3Start = position; + } + } } // Continue evaluating partitions if this one isn't profitable - if (!TrySwappingPartitions(startPos, s2Start, s3Start, s3End, endPos)) + if ((costChange >= BB_ZERO_WEIGHT) || Compiler::fgProfileWeightsEqual(costChange, BB_ZERO_WEIGHT, 0.001)) { continue; } + JITDUMP("Swapping partitions [" FMT_BB ", " FMT_BB "] and [" FMT_BB ", " FMT_BB "] (cost change = %f)\n", + blockOrder[s2Start]->bbNum, blockOrder[s3Start - 1]->bbNum, blockOrder[s3Start]->bbNum, + blockOrder[s3End]->bbNum, costChange); + + SwapPartitions(startPos, s2Start, s3Start, s3End, endPos); + // Update the ordinals for the blocks we moved for (unsigned i = s2Start; i <= endPos; i++) { diff --git a/src/coreclr/nativeaot/docs/containers.md b/src/coreclr/nativeaot/docs/containers.md index 35bacdcbc74bde..1a3e613a4506d9 100644 --- a/src/coreclr/nativeaot/docs/containers.md +++ b/src/coreclr/nativeaot/docs/containers.md @@ -14,7 +14,7 @@ The [`releasesapi`](https://github.com/dotnet/dotnet-docker/blob/main/samples/re For cloud native apps, build and runtime OS typically match, at least if you use multi-stage build. Once you step out of containers (for app delivery), it is more likely that you are delivering binaries that you want to work in more places (like on older Linux distros). -The .NET build has this exact same need. We produce several [container images to enable cross-building](https://github.com/dotnet/runtime/blob/main/docs/workflow/building/coreclr/linux-instructions.md#docker-images). +The .NET build has this exact same need. We produce several [container images to enable cross-building](https://github.com/dotnet/runtime/blob/main/docs/workflow/using-docker.md#the-official-runtime-docker-images). You can use these images to build native AOT apps which work on distros as old as Ubuntu 16.04. These build images are not supported, but are expected to work (since we use them to build .NET on daily basis). diff --git a/src/coreclr/tools/dotnet-pgo/SPGO/SampleCorrelator.cs b/src/coreclr/tools/dotnet-pgo/SPGO/SampleCorrelator.cs index 4fd1047c6b8b46..608094a61bb2f3 100644 --- a/src/coreclr/tools/dotnet-pgo/SPGO/SampleCorrelator.cs +++ b/src/coreclr/tools/dotnet-pgo/SPGO/SampleCorrelator.cs @@ -227,7 +227,7 @@ public void AttributeSampleToLbrRuns(Span lbr) bool skip = false; - for (int j = callStack.Count - 1; j >= 0; j++) + for (int j = callStack.Count - 1; j >= 0; j--) { (BasicBlock callFromBB, int callFromILOffs) = callStack[j]; if (callFromBB == bb && mapping.ILOffset >= callFromILOffs) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 205c5105d5a2d8..f13e28fc3cd147 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2024,36 +2024,6 @@ Stub* COMDelegate::GetInvokeMethodStub(EEImplMethodDesc* pMD) } } -extern "C" void QCALLTYPE Delegate_InternalAlloc(QCall::TypeHandle pType, QCall::ObjectHandleOnStack d) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - GCX_COOP(); - - _ASSERTE(pType.AsTypeHandle().AsMethodTable()->IsDelegate()); - - d.Set(pType.AsTypeHandle().AsMethodTable()->Allocate()); - - END_QCALL; -} - -extern "C" void QCALLTYPE Delegate_InternalAllocLike(QCall::ObjectHandleOnStack d) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - GCX_COOP(); - - _ASSERTE(d.Get()->GetMethodTable()->IsDelegate()); - - d.Set(d.Get()->GetMethodTable()->AllocateNoChecks()); - - END_QCALL; -} - void COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(MethodDesc* pMD) { CONTRACTL diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index be68b5ef40dd47..064d6d0177b843 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -123,10 +123,6 @@ extern "C" BOOL QCALLTYPE Delegate_BindToMethodName(QCall::ObjectHandleOnStack d extern "C" BOOL QCALLTYPE Delegate_BindToMethodInfo(QCall::ObjectHandleOnStack d, QCall::ObjectHandleOnStack target, MethodDesc * method, QCall::TypeHandle pMethodType, DelegateBindingFlags flags); -extern "C" void QCALLTYPE Delegate_InternalAlloc(QCall::TypeHandle pType, QCall::ObjectHandleOnStack d); - -extern "C" void QCALLTYPE Delegate_InternalAllocLike(QCall::ObjectHandleOnStack d); - extern "C" void QCALLTYPE Delegate_FindMethodHandle(QCall::ObjectHandleOnStack d, QCall::ObjectHandleOnStack retMethodInfo); extern "C" BOOL QCALLTYPE Delegate_InternalEqualMethodHandles(QCall::ObjectHandleOnStack left, QCall::ObjectHandleOnStack right); diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 723aa5ac02a420..d3e196cfe61bb8 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -146,9 +146,6 @@ FCFuncStart(gSignatureNative) FCFuncEnd() FCFuncStart(gRuntimeMethodHandle) - FCFuncElement("InvokeMethod", RuntimeMethodHandle::InvokeMethod) - FCFuncElement("ReboxFromNullable", RuntimeMethodHandle::ReboxFromNullable) - FCFuncElement("ReboxToNullable", RuntimeMethodHandle::ReboxToNullable) FCFuncElement("GetImplAttributes", RuntimeMethodHandle::GetImplAttributes) FCFuncElement("GetAttributes", RuntimeMethodHandle::GetAttributes) FCFuncElement("GetMethodTable", RuntimeMethodHandle::GetMethodTable) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 2fbd4b04d86d47..e5070194507277 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -3940,18 +3940,17 @@ void MethodTable::CheckRunClassInitAsIfConstructingThrowing() THROWS; GC_TRIGGERS; MODE_ANY; + PRECONDITION(HasPreciseInitCctors()); } CONTRACTL_END; - if (HasPreciseInitCctors()) + + MethodTable *pMTCur = this; + while (pMTCur != NULL) { - MethodTable *pMTCur = this; - while (pMTCur != NULL) - { - if (!pMTCur->GetClass()->IsBeforeFieldInit()) - pMTCur->CheckRunClassInitThrowing(); + if (!pMTCur->GetClass()->IsBeforeFieldInit()) + pMTCur->CheckRunClassInitThrowing(); - pMTCur = pMTCur->GetParentMethodTable(); - } + pMTCur = pMTCur->GetParentMethodTable(); } } diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 47ac585be717b3..ee2d60f6f947b5 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2676,8 +2676,8 @@ class MethodTable // This flavor of Allocate is more efficient, but can only be used // if CheckInstanceActivated(), IsClassInited() are known to be true. // A sufficient condition is that another instance of the exact same type already - // exists in the same appdomain. It's currently called only from Delegate.Combine - // via COMDelegate::InternalAllocLike. + // exists in the same ALC. It's currently called only from Delegate.Combine + // via RuntimeTypeHandle_InternalAllocNoChecks. OBJECTREF AllocateNoChecks(); OBJECTREF Box(void* data); @@ -3921,12 +3921,11 @@ public : TADDR m_ElementTypeHnd; }; public: - union + union { PTR_InterfaceInfo m_pInterfaceMap; TADDR m_encodedNullableUnboxData; // Used for Nullable to represent the offset to the value field, and the size of the value field }; - // VTable slots go here diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 4bcad99e482f73..f6aa4746666839 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1230,7 +1230,7 @@ inline OBJECTREF MethodTable::AllocateNoChecks() } CONTRACTL_END; - // we know an instance of this class already exists in the same appdomain + // We know an instance of this class already exists // therefore, some checks become redundant. // this currently only happens for Delegate.Combine @@ -1239,7 +1239,6 @@ inline OBJECTREF MethodTable::AllocateNoChecks() return AllocateObject(this); } - #ifndef DACCESS_COMPILE //========================================================================================== // unbox src into dest, No checks are done diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index bc6a4a12b3d781..d65f6a838b63b2 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -96,8 +96,6 @@ static const Entry s_QCall[] = DllImportEntry(Delegate_GetMulticastInvokeSlow) DllImportEntry(Delegate_AdjustTarget) DllImportEntry(Delegate_Construct) - DllImportEntry(Delegate_InternalAlloc) - DllImportEntry(Delegate_InternalAllocLike) DllImportEntry(Delegate_FindMethodHandle) DllImportEntry(Delegate_InternalEqualMethodHandles) DllImportEntry(Environment_Exit) @@ -140,9 +138,12 @@ static const Entry s_QCall[] = #endif // FEATURE_COMINTEROP DllImportEntry(RuntimeTypeHandle_GetRuntimeTypeFromHandleSlow) DllImportEntry(RuntimeTypeHandle_CreateInstanceForAnotherGenericParameter) + DllImportEntry(RuntimeTypeHandle_InternalAlloc) + DllImportEntry(RuntimeTypeHandle_InternalAllocNoChecks) DllImportEntry(RuntimeTypeHandle_AllocateTypeAssociatedMemory) DllImportEntry(RuntimeTypeHandle_RegisterCollectibleTypeDependency) DllImportEntry(MethodBase_GetCurrentMethod) + DllImportEntry(RuntimeMethodHandle_InvokeMethod) DllImportEntry(RuntimeMethodHandle_ConstructInstantiation) DllImportEntry(RuntimeMethodHandle_GetFunctionPointer) DllImportEntry(RuntimeMethodHandle_GetIsCollectible) diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index c681e2b9763666..6e93b1b179583c 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -116,6 +116,36 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_CreateInstanceForAnotherGenericParam END_QCALL; } +extern "C" void QCALLTYPE RuntimeTypeHandle_InternalAlloc(MethodTable* pMT, QCall::ObjectHandleOnStack allocated) +{ + QCALL_CONTRACT; + + _ASSERTE(pMT != NULL); + + BEGIN_QCALL; + + GCX_COOP(); + + allocated.Set(pMT->Allocate()); + + END_QCALL; +} + +extern "C" void QCALLTYPE RuntimeTypeHandle_InternalAllocNoChecks(MethodTable* pMT, QCall::ObjectHandleOnStack allocated) +{ + QCALL_CONTRACT; + + _ASSERTE(pMT != NULL); + + BEGIN_QCALL; + + GCX_COOP(); + + allocated.Set(pMT->AllocateNoChecks()); + + END_QCALL; +} + static OBJECTREF InvokeArrayConstructor(TypeHandle th, PVOID* args, int argCnt) { CONTRACTL @@ -279,29 +309,35 @@ class ArgIteratorForMethodInvoke : public ArgIteratorTemplateGetMethod(); TypeHandle ownerType = gc.pSig->GetDeclaringType(); - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - if (ownerType.IsSharedByGenericInstantiations()) { COMPlusThrow(kNotSupportedException, W("NotSupported_Type")); @@ -316,7 +352,7 @@ FCIMPL4(Object*, RuntimeMethodHandle::InvokeMethod, BOOL fCtorOfVariableSizedObject = FALSE; - if (FC_ACCESS_BOOL(fConstructor)) + if (fConstructor) { // If we are invoking a constructor on an array then we must // handle this specially. @@ -423,7 +459,7 @@ FCIMPL4(Object*, RuntimeMethodHandle::InvokeMethod, if (!pMeth->IsStatic() && !fCtorOfVariableSizedObject) { PVOID pThisPtr; - if (FC_ACCESS_BOOL(fConstructor)) + if (fConstructor) { // Copy "this" pointer: only unbox if type is value type and method is not unboxing stub if (ownerType.IsValueType() && !pMeth->IsUnboxingStub()) { @@ -545,7 +581,7 @@ FCIMPL4(Object*, RuntimeMethodHandle::InvokeMethod, CallDescrWorkerWithHandler(&callDescrData); // It is still illegal to do a GC here. The return type might have/contain GC pointers. - if (FC_ACCESS_BOOL(fConstructor)) + if (fConstructor) { // We have a special case for Strings...The object is returned... if (fCtorOfVariableSizedObject) { @@ -618,74 +654,12 @@ FCIMPL4(Object*, RuntimeMethodHandle::InvokeMethod, } Done: - ; - HELPER_METHOD_FRAME_END(); - - return OBJECTREFToObject(gc.retVal); -} -FCIMPLEND - -/// -/// Convert a boxed value of {T} (which is either {T} or null) to a true boxed Nullable{T}. -/// -FCIMPL2(Object*, RuntimeMethodHandle::ReboxToNullable, Object* pBoxedValUNSAFE, ReflectClassBaseObject *pDestUNSAFE) -{ - FCALL_CONTRACT; - - struct { - OBJECTREF pBoxed; - REFLECTCLASSBASEREF destType; - OBJECTREF retVal; - } gc; - - gc.pBoxed = ObjectToOBJECTREF(pBoxedValUNSAFE); - gc.destType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pDestUNSAFE); - gc.retVal = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - MethodTable* destMT = gc.destType->GetType().AsMethodTable(); - - gc.retVal = destMT->Allocate(); - void* buffer = gc.retVal->GetData(); - BOOL result = Nullable::UnBox(buffer, gc.pBoxed, destMT); - _ASSERTE(result == TRUE); + result.Set(gc.retVal); - HELPER_METHOD_FRAME_END(); - - return OBJECTREFToObject(gc.retVal); -} -FCIMPLEND - -/// -/// For a true boxed Nullable{T}, re-box to a boxed {T} or null, otherwise just return the input. -/// -FCIMPL1(Object*, RuntimeMethodHandle::ReboxFromNullable, Object* pBoxedValUNSAFE) -{ - FCALL_CONTRACT; - - struct { - OBJECTREF pBoxed; - OBJECTREF retVal; - } gc; - - if (pBoxedValUNSAFE == NULL) - return NULL; - - gc.pBoxed = ObjectToOBJECTREF(pBoxedValUNSAFE); - MethodTable* retMT = gc.pBoxed->GetMethodTable(); - if (!Nullable::IsNullableType(retMT)) - return pBoxedValUNSAFE; - - gc.retVal = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - gc.retVal = Nullable::Box(gc.pBoxed->GetData(), retMT); - HELPER_METHOD_FRAME_END(); + GCPROTECT_END(); - return OBJECTREFToObject(gc.retVal); + END_QCALL; } -FCIMPLEND struct SkipStruct { StackCrawlMark* pStackMark; diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index ddd6554d23babf..3cd538c67781e6 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -158,6 +158,8 @@ class RuntimeTypeHandle extern "C" void QCALLTYPE RuntimeTypeHandle_GetRuntimeTypeFromHandleSlow(void* typeHandleRaw, QCall::ObjectHandleOnStack result); extern "C" void QCALLTYPE RuntimeTypeHandle_CreateInstanceForAnotherGenericParameter(QCall::TypeHandle pTypeHandle, TypeHandle *pInstArray, INT32 cInstArray, QCall::ObjectHandleOnStack pInstantiatedObject); +extern "C" void QCALLTYPE RuntimeTypeHandle_InternalAlloc(MethodTable* pMT, QCall::ObjectHandleOnStack allocated); +extern "C" void QCALLTYPE RuntimeTypeHandle_InternalAllocNoChecks(MethodTable* pMT, QCall::ObjectHandleOnStack allocated); extern "C" void* QCALLTYPE RuntimeTypeHandle_AllocateTypeAssociatedMemory(QCall::TypeHandle type, uint32_t size); extern "C" PVOID QCALLTYPE QCall_GetGCHandleForTypeHandle(QCall::TypeHandle pTypeHandle, INT32 handleType); @@ -197,41 +199,6 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_RegisterCollectibleTypeDependency(QC class RuntimeMethodHandle { public: - static FCDECL4(Object*, InvokeMethod, Object *target, PVOID* args, SignatureNative* pSig, FC_BOOL_ARG fConstructor); - - static FCDECL2(Object*, ReboxToNullable, Object *pBoxedValUNSAFE, ReflectClassBaseObject *pDestUNSAFE); - static FCDECL1(Object*, ReboxFromNullable, Object *pBoxedValUNSAFE); - - struct StreamingContextData { - Object * additionalContext; // additionalContex was changed from OBJECTREF to Object to avoid having a - INT32 contextStates; // constructor in this struct. GCC doesn't allow structs with constructors to be - }; - - // ******************************************************************************************* - // Keep these in sync with the version in bcl\system\runtime\serialization\streamingcontext.cs - // ******************************************************************************************* - enum StreamingContextStates - { - CONTEXTSTATE_CrossProcess = 0x01, - CONTEXTSTATE_CrossMachine = 0x02, - CONTEXTSTATE_File = 0x04, - CONTEXTSTATE_Persistence = 0x08, - CONTEXTSTATE_Remoting = 0x10, - CONTEXTSTATE_Other = 0x20, - CONTEXTSTATE_Clone = 0x40, - CONTEXTSTATE_CrossAppDomain = 0x80, - CONTEXTSTATE_All = 0xFF - }; - - // passed by value - // STATIC IMPLEMENTATION - static OBJECTREF InvokeMethod_Internal( - MethodDesc *pMethod, OBJECTREF targetUNSAFE, INT32 attrs, OBJECTREF binderUNSAFE, PTRARRAYREF objsUNSAFE, OBJECTREF localeUNSAFE, - BOOL isBinderDefault, Assembly *caller, Assembly *reflectedClassAssembly, TypeHandle declaringType, SignatureNative* pSig, BOOL verifyAccess); - - static FCDECL4(void, SerializationInvoke, ReflectMethodObject *pMethodUNSAFE, Object* targetUNSAFE, - Object* serializationInfoUNSAFE, struct StreamingContextData * pContext); - static FCDECL1(INT32, GetAttributes, MethodDesc *pMethod); static FCDECL1(INT32, GetImplAttributes, ReflectMethodObject *pMethodUNSAFE); static FCDECL1(MethodTable*, GetMethodTable, MethodDesc *pMethod); @@ -268,7 +235,6 @@ class RuntimeMethodHandle static FCDECL1(Object*, GetLoaderAllocator, MethodDesc *pMethod); }; - extern "C" MethodDesc* QCALLTYPE MethodBase_GetCurrentMethod(QCall::StackCrawlMarkHandle stackMark); extern "C" BOOL QCALLTYPE RuntimeMethodHandle_IsCAVisibleFromDecoratedType( @@ -279,6 +245,13 @@ extern "C" BOOL QCALLTYPE RuntimeMethodHandle_IsCAVisibleFromDecoratedType( extern "C" void QCALLTYPE RuntimeMethodHandle_GetMethodInstantiation(MethodDesc * pMethod, QCall::ObjectHandleOnStack retTypes, BOOL fAsRuntimeTypeArray); +extern "C" void QCALLTYPE RuntimeMethodHandle_InvokeMethod( + QCall::ObjectHandleOnStack target, + PVOID* args, + QCall::ObjectHandleOnStack pSigUNSAFE, + BOOL fConstructor, + QCall::ObjectHandleOnStack result); + extern "C" void QCALLTYPE RuntimeMethodHandle_ConstructInstantiation(MethodDesc * pMethod, DWORD format, QCall::StringHandleOnStack retString); extern "C" void* QCALLTYPE RuntimeMethodHandle_GetFunctionPointer(MethodDesc * pMethod); extern "C" BOOL QCALLTYPE RuntimeMethodHandle_GetIsCollectible(MethodDesc * pMethod); diff --git a/src/libraries/Common/tests/System/Reflection/InvokeInterpretedTests.cs b/src/libraries/Common/tests/System/Reflection/InvokeInterpretedTests.cs index 573211876b0fb7..6370e83d41c8f6 100644 --- a/src/libraries/Common/tests/System/Reflection/InvokeInterpretedTests.cs +++ b/src/libraries/Common/tests/System/Reflection/InvokeInterpretedTests.cs @@ -16,7 +16,7 @@ public static void VerifyInvokeIsUsingInterpreter_Method() Exception exInner = ex.InnerException; Assert.Contains("Here", exInner.ToString()); - Assert.Contains(InterpretedMethodName, exInner.ToString()); + Assert.Contains("InterpretedInvoke_Method", exInner.ToString()); Assert.DoesNotContain("InvokeStub_TestClassThatThrows", exInner.ToString()); } @@ -29,18 +29,10 @@ public static void VerifyInvokeIsUsingInterpreter_Constructor() Exception exInner = ex.InnerException; Assert.Contains("Here", exInner.ToString()); - Assert.Contains(InterpretedConstructorName, exInner.ToString()); + Assert.Contains("InterpretedInvoke_Constructor", exInner.ToString()); Assert.DoesNotContain("InvokeStub_TestClassThatThrows", exInner.ToString()); } - private static string InterpretedConstructorName => PlatformDetection.IsMonoRuntime ? - "InterpretedInvoke_Constructor" : - "System.RuntimeMethodHandle.InvokeMethod"; - - private static string InterpretedMethodName => PlatformDetection.IsMonoRuntime ? - "InterpretedInvoke_Method" : - "System.RuntimeMethodHandle.InvokeMethod"; - private class TestClassThatThrows { public TestClassThatThrows() diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs index 0302bc2bc649dd..1c933aaaced78b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs @@ -1115,13 +1115,13 @@ static bool INumberBase.TryConvertToTruncating(byte value, [MaybeN // /// - static byte IShiftOperators.operator <<(byte value, int shiftAmount) => (byte)(value << shiftAmount); + static byte IShiftOperators.operator <<(byte value, int shiftAmount) => (byte)(value << (shiftAmount & 7)); /// - static byte IShiftOperators.operator >>(byte value, int shiftAmount) => (byte)(value >> shiftAmount); + static byte IShiftOperators.operator >>(byte value, int shiftAmount) => (byte)(value >> (shiftAmount & 7)); /// - static byte IShiftOperators.operator >>>(byte value, int shiftAmount) => (byte)(value >>> shiftAmount); + static byte IShiftOperators.operator >>>(byte value, int shiftAmount) => (byte)(value >>> (shiftAmount & 7)); // // ISpanParsable diff --git a/src/libraries/System.Private.CoreLib/src/System/Char.cs b/src/libraries/System.Private.CoreLib/src/System/Char.cs index 7df1b14afc0332..1e718d9786349f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Char.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Char.cs @@ -1943,13 +1943,13 @@ static bool INumberBase.TryConvertToTruncating(char value, [MaybeN // /// - static char IShiftOperators.operator <<(char value, int shiftAmount) => (char)(value << shiftAmount); + static char IShiftOperators.operator <<(char value, int shiftAmount) => (char)(value << (shiftAmount & 15)); /// - static char IShiftOperators.operator >>(char value, int shiftAmount) => (char)(value >> shiftAmount); + static char IShiftOperators.operator >>(char value, int shiftAmount) => (char)(value >> (shiftAmount & 15)); /// - static char IShiftOperators.operator >>>(char value, int shiftAmount) => (char)(value >>> shiftAmount); + static char IShiftOperators.operator >>>(char value, int shiftAmount) => (char)(value >>> (shiftAmount & 15)); // // ISpanParsable diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs index e963c0df013272..2c09c688259489 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs @@ -1322,13 +1322,13 @@ static bool INumberBase.TryConvertToTruncating(short value, [Mayb // /// - static short IShiftOperators.operator <<(short value, int shiftAmount) => (short)(value << shiftAmount); + static short IShiftOperators.operator <<(short value, int shiftAmount) => (short)(value << (shiftAmount & 15)); /// - static short IShiftOperators.operator >>(short value, int shiftAmount) => (short)(value >> shiftAmount); + static short IShiftOperators.operator >>(short value, int shiftAmount) => (short)(value >> (shiftAmount & 15)); /// - static short IShiftOperators.operator >>>(short value, int shiftAmount) => (short)((ushort)value >>> shiftAmount); + static short IShiftOperators.operator >>>(short value, int shiftAmount) => (short)((ushort)value >>> (shiftAmount & 15)); // // ISignedNumber diff --git a/src/libraries/System.Private.CoreLib/src/System/SByte.cs b/src/libraries/System.Private.CoreLib/src/System/SByte.cs index 00bce51b3a2bab..6978e9a97cce06 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SByte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SByte.cs @@ -1283,13 +1283,13 @@ static bool INumberBase.TryConvertToTruncating(sbyte value, [Mayb // /// - static sbyte IShiftOperators.operator <<(sbyte value, int shiftAmount) => (sbyte)(value << shiftAmount); + static sbyte IShiftOperators.operator <<(sbyte value, int shiftAmount) => (sbyte)(value << (shiftAmount & 7)); /// - static sbyte IShiftOperators.operator >>(sbyte value, int shiftAmount) => (sbyte)(value >> shiftAmount); + static sbyte IShiftOperators.operator >>(sbyte value, int shiftAmount) => (sbyte)(value >> (shiftAmount & 7)); /// - static sbyte IShiftOperators.operator >>>(sbyte value, int shiftAmount) => (sbyte)((byte)value >>> shiftAmount); + static sbyte IShiftOperators.operator >>>(sbyte value, int shiftAmount) => (sbyte)((byte)value >>> (shiftAmount & 7)); // // ISignedNumber diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs index 999ad1bedd9c65..0d8d1c258ed4de 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs @@ -1144,13 +1144,13 @@ static bool INumberBase.TryConvertToTruncating(ushort value, [Ma // /// - static ushort IShiftOperators.operator <<(ushort value, int shiftAmount) => (ushort)(value << shiftAmount); + static ushort IShiftOperators.operator <<(ushort value, int shiftAmount) => (ushort)(value << (shiftAmount & 15)); /// - static ushort IShiftOperators.operator >>(ushort value, int shiftAmount) => (ushort)(value >> shiftAmount); + static ushort IShiftOperators.operator >>(ushort value, int shiftAmount) => (ushort)(value >> (shiftAmount & 15)); /// - static ushort IShiftOperators.operator >>>(ushort value, int shiftAmount) => (ushort)(value >>> shiftAmount); + static ushort IShiftOperators.operator >>>(ushort value, int shiftAmount) => (ushort)(value >>> (shiftAmount & 15)); // // ISpanParsable diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.GenericMath.cs index 348795de8b82e6..6be66f1080b869 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.GenericMath.cs @@ -2256,30 +2256,45 @@ public static void MinMagnitudeNumberTest() public static void op_LeftShiftTest() { Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_LeftShift((byte)0x00, 1)); + Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_LeftShift((byte)0x00, 9)); Assert.Equal((byte)0x02, ShiftOperatorsHelper.op_LeftShift((byte)0x01, 1)); + Assert.Equal((byte)0x02, ShiftOperatorsHelper.op_LeftShift((byte)0x01, 9)); Assert.Equal((byte)0xFE, ShiftOperatorsHelper.op_LeftShift((byte)0x7F, 1)); + Assert.Equal((byte)0xFE, ShiftOperatorsHelper.op_LeftShift((byte)0x7F, 9)); Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_LeftShift((byte)0x80, 1)); + Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_LeftShift((byte)0x80, 9)); Assert.Equal((byte)0xFE, ShiftOperatorsHelper.op_LeftShift((byte)0xFF, 1)); + Assert.Equal((byte)0xFE, ShiftOperatorsHelper.op_LeftShift((byte)0xFF, 9)); } [Fact] public static void op_RightShiftTest() { Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_RightShift((byte)0x00, 1)); + Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_RightShift((byte)0x00, 9)); Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_RightShift((byte)0x01, 1)); + Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_RightShift((byte)0x01, 9)); Assert.Equal((byte)0x3F, ShiftOperatorsHelper.op_RightShift((byte)0x7F, 1)); + Assert.Equal((byte)0x3F, ShiftOperatorsHelper.op_RightShift((byte)0x7F, 9)); Assert.Equal((byte)0x40, ShiftOperatorsHelper.op_RightShift((byte)0x80, 1)); + Assert.Equal((byte)0x40, ShiftOperatorsHelper.op_RightShift((byte)0x80, 9)); Assert.Equal((byte)0x7F, ShiftOperatorsHelper.op_RightShift((byte)0xFF, 1)); + Assert.Equal((byte)0x7F, ShiftOperatorsHelper.op_RightShift((byte)0xFF, 9)); } [Fact] public static void op_UnsignedRightShiftTest() { Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0x00, 1)); + Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0x00, 9)); Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0x01, 1)); + Assert.Equal((byte)0x00, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0x01, 9)); Assert.Equal((byte)0x3F, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0x7F, 1)); + Assert.Equal((byte)0x3F, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0x7F, 9)); Assert.Equal((byte)0x40, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0x80, 1)); + Assert.Equal((byte)0x40, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0x80, 9)); Assert.Equal((byte)0x7F, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0xFF, 1)); + Assert.Equal((byte)0x7F, ShiftOperatorsHelper.op_UnsignedRightShift((byte)0xFF, 9)); } // diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/CharTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/CharTests.GenericMath.cs index f1ef4f9bc19604..17453e4b0f03e9 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/CharTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/CharTests.GenericMath.cs @@ -2249,30 +2249,45 @@ public static void MinMagnitudeNumberTest() public static void op_LeftShiftTest() { Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_LeftShift((char)0x0000, 1)); + Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_LeftShift((char)0x0000, 17)); Assert.Equal((char)0x0002, ShiftOperatorsHelper.op_LeftShift((char)0x0001, 1)); + Assert.Equal((char)0x0002, ShiftOperatorsHelper.op_LeftShift((char)0x0001, 17)); Assert.Equal((char)0xFFFE, ShiftOperatorsHelper.op_LeftShift((char)0x7FFF, 1)); + Assert.Equal((char)0xFFFE, ShiftOperatorsHelper.op_LeftShift((char)0x7FFF, 17)); Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_LeftShift((char)0x8000, 1)); + Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_LeftShift((char)0x8000, 17)); Assert.Equal((char)0xFFFE, ShiftOperatorsHelper.op_LeftShift((char)0xFFFF, 1)); + Assert.Equal((char)0xFFFE, ShiftOperatorsHelper.op_LeftShift((char)0xFFFF, 17)); } [Fact] public static void op_RightShiftTest() { Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_RightShift((char)0x0000, 1)); + Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_RightShift((char)0x0000, 17)); Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_RightShift((char)0x0001, 1)); + Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_RightShift((char)0x0001, 17)); Assert.Equal((char)0x3FFF, ShiftOperatorsHelper.op_RightShift((char)0x7FFF, 1)); + Assert.Equal((char)0x3FFF, ShiftOperatorsHelper.op_RightShift((char)0x7FFF, 17)); Assert.Equal((char)0x4000, ShiftOperatorsHelper.op_RightShift((char)0x8000, 1)); + Assert.Equal((char)0x4000, ShiftOperatorsHelper.op_RightShift((char)0x8000, 17)); Assert.Equal((char)0x7FFF, ShiftOperatorsHelper.op_RightShift((char)0xFFFF, 1)); + Assert.Equal((char)0x7FFF, ShiftOperatorsHelper.op_RightShift((char)0xFFFF, 17)); } [Fact] public static void op_UnsignedRightShiftTest() { Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((char)0x0000, 1)); + Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((char)0x0000, 17)); Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((char)0x0001, 1)); + Assert.Equal((char)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((char)0x0001, 17)); Assert.Equal((char)0x3FFF, ShiftOperatorsHelper.op_UnsignedRightShift((char)0x7FFF, 1)); + Assert.Equal((char)0x3FFF, ShiftOperatorsHelper.op_UnsignedRightShift((char)0x7FFF, 17)); Assert.Equal((char)0x4000, ShiftOperatorsHelper.op_UnsignedRightShift((char)0x8000, 1)); + Assert.Equal((char)0x4000, ShiftOperatorsHelper.op_UnsignedRightShift((char)0x8000, 17)); Assert.Equal((char)0x7FFF, ShiftOperatorsHelper.op_UnsignedRightShift((char)0xFFFF, 1)); + Assert.Equal((char)0x7FFF, ShiftOperatorsHelper.op_UnsignedRightShift((char)0xFFFF, 17)); } // diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.GenericMath.cs index 5e1a78029f01e1..c88aa13f0f5449 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.GenericMath.cs @@ -2275,30 +2275,45 @@ public static void MinMagnitudeNumberTest() public static void op_LeftShiftTest() { Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_LeftShift((short)0x0000, 1)); + Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_LeftShift((short)0x0000, 17)); Assert.Equal((short)0x0002, ShiftOperatorsHelper.op_LeftShift((short)0x0001, 1)); + Assert.Equal((short)0x0002, ShiftOperatorsHelper.op_LeftShift((short)0x0001, 17)); Assert.Equal(unchecked((short)0xFFFE), ShiftOperatorsHelper.op_LeftShift((short)0x7FFF, 1)); + Assert.Equal(unchecked((short)0xFFFE), ShiftOperatorsHelper.op_LeftShift((short)0x7FFF, 17)); Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_LeftShift(unchecked((short)0x8000), 1)); + Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_LeftShift(unchecked((short)0x8000), 17)); Assert.Equal(unchecked((short)0xFFFE), ShiftOperatorsHelper.op_LeftShift(unchecked((short)0xFFFF), 1)); + Assert.Equal(unchecked((short)0xFFFE), ShiftOperatorsHelper.op_LeftShift(unchecked((short)0xFFFF), 17)); } [Fact] public static void op_RightShiftTest() { Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_RightShift((short)0x0000, 1)); + Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_RightShift((short)0x0000, 17)); Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_RightShift((short)0x0001, 1)); + Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_RightShift((short)0x0001, 17)); Assert.Equal((short)0x3FFF, ShiftOperatorsHelper.op_RightShift((short)0x7FFF, 1)); + Assert.Equal((short)0x3FFF, ShiftOperatorsHelper.op_RightShift((short)0x7FFF, 17)); Assert.Equal(unchecked((short)0xC000), ShiftOperatorsHelper.op_RightShift(unchecked((short)0x8000), 1)); + Assert.Equal(unchecked((short)0xC000), ShiftOperatorsHelper.op_RightShift(unchecked((short)0x8000), 17)); Assert.Equal(unchecked((short)0xFFFF), ShiftOperatorsHelper.op_RightShift(unchecked((short)0xFFFF), 1)); + Assert.Equal(unchecked((short)0xFFFF), ShiftOperatorsHelper.op_RightShift(unchecked((short)0xFFFF), 17)); } [Fact] public static void op_UnsignedRightShiftTest() { Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((short)0x0000, 1)); + Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((short)0x0000, 17)); Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((short)0x0001, 1)); + Assert.Equal((short)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((short)0x0001, 17)); Assert.Equal((short)0x3FFF, ShiftOperatorsHelper.op_UnsignedRightShift((short)0x7FFF, 1)); + Assert.Equal((short)0x3FFF, ShiftOperatorsHelper.op_UnsignedRightShift((short)0x7FFF, 17)); Assert.Equal((short)0x4000, ShiftOperatorsHelper.op_UnsignedRightShift(unchecked((short)0x8000), 1)); + Assert.Equal((short)0x4000, ShiftOperatorsHelper.op_UnsignedRightShift(unchecked((short)0x8000), 17)); Assert.Equal((short)0x7FFF, ShiftOperatorsHelper.op_UnsignedRightShift(unchecked((short)0xFFFF), 1)); + Assert.Equal((short)0x7FFF, ShiftOperatorsHelper.op_UnsignedRightShift(unchecked((short)0xFFFF), 17)); } // diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.GenericMath.cs index 80b566a8473d0b..ef4a3ca34fd45d 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.GenericMath.cs @@ -2271,30 +2271,45 @@ public static void MinMagnitudeNumberTest() public static void op_LeftShiftTest() { Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_LeftShift((sbyte)0x00, 1)); + Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_LeftShift((sbyte)0x00, 9)); Assert.Equal((sbyte)0x02, ShiftOperatorsHelper.op_LeftShift((sbyte)0x01, 1)); + Assert.Equal((sbyte)0x02, ShiftOperatorsHelper.op_LeftShift((sbyte)0x01, 9)); Assert.Equal(unchecked((sbyte)0xFE), ShiftOperatorsHelper.op_LeftShift((sbyte)0x7F, 1)); + Assert.Equal(unchecked((sbyte)0xFE), ShiftOperatorsHelper.op_LeftShift((sbyte)0x7F, 9)); Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_LeftShift(unchecked((sbyte)0x80), 1)); + Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_LeftShift(unchecked((sbyte)0x80), 9)); Assert.Equal(unchecked((sbyte)0xFE), ShiftOperatorsHelper.op_LeftShift(unchecked((sbyte)0xFF), 1)); + Assert.Equal(unchecked((sbyte)0xFE), ShiftOperatorsHelper.op_LeftShift(unchecked((sbyte)0xFF), 9)); } [Fact] public static void op_RightShiftTest() { Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_RightShift((sbyte)0x00, 1)); + Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_RightShift((sbyte)0x00, 9)); Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_RightShift((sbyte)0x01, 1)); + Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_RightShift((sbyte)0x01, 9)); Assert.Equal((sbyte)0x3F, ShiftOperatorsHelper.op_RightShift((sbyte)0x7F, 1)); + Assert.Equal((sbyte)0x3F, ShiftOperatorsHelper.op_RightShift((sbyte)0x7F, 9)); Assert.Equal(unchecked((sbyte)0xC0), ShiftOperatorsHelper.op_RightShift(unchecked((sbyte)0x80), 1)); + Assert.Equal(unchecked((sbyte)0xC0), ShiftOperatorsHelper.op_RightShift(unchecked((sbyte)0x80), 9)); Assert.Equal(unchecked((sbyte)0xFF), ShiftOperatorsHelper.op_RightShift(unchecked((sbyte)0xFF), 1)); + Assert.Equal(unchecked((sbyte)0xFF), ShiftOperatorsHelper.op_RightShift(unchecked((sbyte)0xFF), 9)); } [Fact] public static void op_UnsignedRightShiftTest() { Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_UnsignedRightShift((sbyte)0x00, 1)); + Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_UnsignedRightShift((sbyte)0x00, 9)); Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_UnsignedRightShift((sbyte)0x01, 1)); + Assert.Equal((sbyte)0x00, ShiftOperatorsHelper.op_UnsignedRightShift((sbyte)0x01, 9)); Assert.Equal((sbyte)0x3F, ShiftOperatorsHelper.op_UnsignedRightShift((sbyte)0x7F, 1)); + Assert.Equal((sbyte)0x3F, ShiftOperatorsHelper.op_UnsignedRightShift((sbyte)0x7F, 9)); Assert.Equal((sbyte)0x40, ShiftOperatorsHelper.op_UnsignedRightShift(unchecked((sbyte)0x80), 1)); + Assert.Equal((sbyte)0x40, ShiftOperatorsHelper.op_UnsignedRightShift(unchecked((sbyte)0x80), 9)); Assert.Equal((sbyte)0x7F, ShiftOperatorsHelper.op_UnsignedRightShift(unchecked((sbyte)0xFF), 1)); + Assert.Equal((sbyte)0x7F, ShiftOperatorsHelper.op_UnsignedRightShift(unchecked((sbyte)0xFF), 9)); } // diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.GenericMath.cs index 7aa8954dbc1933..5a848f3ec6ac09 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.GenericMath.cs @@ -2255,30 +2255,45 @@ public static void MinMagnitudeNumberTest() public static void op_LeftShiftTest() { Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_LeftShift((ushort)0x0000, 1)); + Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_LeftShift((ushort)0x0000, 17)); Assert.Equal((ushort)0x0002, ShiftOperatorsHelper.op_LeftShift((ushort)0x0001, 1)); + Assert.Equal((ushort)0x0002, ShiftOperatorsHelper.op_LeftShift((ushort)0x0001, 17)); Assert.Equal((ushort)0xFFFE, ShiftOperatorsHelper.op_LeftShift((ushort)0x7FFF, 1)); + Assert.Equal((ushort)0xFFFE, ShiftOperatorsHelper.op_LeftShift((ushort)0x7FFF, 17)); Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_LeftShift((ushort)0x8000, 1)); + Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_LeftShift((ushort)0x8000, 17)); Assert.Equal((ushort)0xFFFE, ShiftOperatorsHelper.op_LeftShift((ushort)0xFFFF, 1)); + Assert.Equal((ushort)0xFFFE, ShiftOperatorsHelper.op_LeftShift((ushort)0xFFFF, 17)); } [Fact] public static void op_RightShiftTest() { Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_RightShift((ushort)0x0000, 1)); + Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_RightShift((ushort)0x0000, 17)); Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_RightShift((ushort)0x0001, 1)); + Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_RightShift((ushort)0x0001, 17)); Assert.Equal((ushort)0x3FFF, ShiftOperatorsHelper.op_RightShift((ushort)0x7FFF, 1)); + Assert.Equal((ushort)0x3FFF, ShiftOperatorsHelper.op_RightShift((ushort)0x7FFF, 17)); Assert.Equal((ushort)0x4000, ShiftOperatorsHelper.op_RightShift((ushort)0x8000, 1)); + Assert.Equal((ushort)0x4000, ShiftOperatorsHelper.op_RightShift((ushort)0x8000, 17)); Assert.Equal((ushort)0x7FFF, ShiftOperatorsHelper.op_RightShift((ushort)0xFFFF, 1)); + Assert.Equal((ushort)0x7FFF, ShiftOperatorsHelper.op_RightShift((ushort)0xFFFF, 17)); } [Fact] public static void op_UnsignedRightShiftTest() { Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0x0000, 1)); + Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0x0000, 17)); Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0x0001, 1)); + Assert.Equal((ushort)0x0000, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0x0001, 17)); Assert.Equal((ushort)0x3FFF, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0x7FFF, 1)); + Assert.Equal((ushort)0x3FFF, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0x7FFF, 17)); Assert.Equal((ushort)0x4000, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0x8000, 1)); + Assert.Equal((ushort)0x4000, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0x8000, 17)); Assert.Equal((ushort)0x7FFF, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0xFFFF, 1)); + Assert.Equal((ushort)0x7FFF, ShiftOperatorsHelper.op_UnsignedRightShift((ushort)0xFFFF, 17)); } // diff --git a/src/tests/profiler/transitions/transitions.csproj b/src/tests/profiler/transitions/transitions.csproj index d7d6919c6b3b6d..39fecf80e2165a 100644 --- a/src/tests/profiler/transitions/transitions.csproj +++ b/src/tests/profiler/transitions/transitions.csproj @@ -8,6 +8,8 @@ runincontext loads even framework assemblies into the unloadable context, locals in this loop prevent unloading --> true + + true diff --git a/src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs b/src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs index ec4f2d4fc1de0f..cce064ff93980d 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs @@ -245,8 +245,7 @@ private partial bool TryResolveTypeNameForCreateInstanceAndMark (in MethodProxy return false; } - if (!_reflectionMarker.TryResolveTypeNameAndMark (resolvedAssembly, typeName, _diagnosticContext, out TypeReference? foundType) - || foundType.IsTypeOf (WellKnownType.System_Array)) { + if (!_reflectionMarker.TryResolveTypeNameAndMark (resolvedAssembly, typeName, _diagnosticContext, out TypeReference? foundType)) { // It's not wrong to have a reference to non-existing type - the code may well expect to get an exception in this case // Note that we did find the assembly, so it's not a ILLink config problem, it's either intentional, or wrong versions of assemblies // but ILLink can't know that. In case a user tries to create an array using System.Activator we should simply ignore it, the user